Another essential software concept is what is known as the Open/Closed Principle. It's again a simple concept that is important to follow. The definition is as follows:
"Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification."
The whole point is that in places where you expect to extend the functionality you should work to make sure that you don't need to change existing code to solve it. The code should be designed in a way that enables you to extend the behavior by for instance adding new classes that automatically works with the current model. This is usually solved through abstractions and polymorphism, and a number of patterns can help solve this. A common mantra for code that is expected to change is nonetheless followed: code to abstractions, not implementations.
What the principle tries to achieve is to make sure that changes have as little as possible effect on the current implementation. If you need to modify existing code you need to identify the various parts needing change and you impose the risk of making breaking changes. Extending the behavior can often be a lot easier and can enable a more flexible solution.
Does this mean that every piece of code should be written using abstractions to allow extensions more easily? Certainly not! Abstractions can add unnecessary code, can make the parts that are supposed to change less obvious and can add to the complexity of the solution. Unless you know that something is expected to change, an old childhood rule is nice to follow: Trick me once, shame on you, trick me twice, shame on me. Don't do the extra work up front unless you know it is necessary. But once you need it, don't hesitate to put it in. Uncle Bob has a wise quote about this:
"Resisting premature abstraction is as important as abstraction itself".