The first time I read the GoF book, I didn’t understand it. This was because I didn’t had a decent understanding of the principles of object-oriented programming at the time. A while after, I read the book Design Patterns Explained. In this excellent book the author formulated the core thought behind the design patterns in the GoF book. He states that when a particular concept varies, it should be encapsulated (by means of an abstract class or and interface). This was a real eye opener for me and guided me to understanding the design patterns described in the GoF book.
But what I also learned after several years is that introducing abstractions in code is not a free ride either. There is a time and place where you want abstractions. I used to add abstractions in domain models all over the place, as soon as I possible could. Now I try to avoid them until the last responsible moment. Only when I gain a deeper understanding, when I start to see variations of the same concept popping up, when concrete implementations start to cause pain, only then am I prepared to consider adding a new abstraction.
Suppose that we have the concept of a communication channel in a particular domain model. If we have more than one communication channel, say SMS, telephone and email, then an abstraction is warranted. Then we might want to introduce an ICommunicationChannel interface. But if we only have SMS as communication channel, then no abstraction is needed. If new communication channels are being added over time, only then do we refactor the code.
Sometimes my brain tricks me into the premature abstraction path. It also happens that I’ve postponed introducing an abstraction a bit too long. I do make mistakes. Who knew? But I do gained some awareness over the years.