I think this is a very interesting question, which I have already encountered several times during my 20 years as a professional software developer.
This question became even more common with the popularization of Agile methods, that in general focus on simplicity following principles such as KISS and YAGNI. While I agree that we should try to keep things simple, I think that over-simplification is extremely dangerous.
The SOLID principles of object-oriented design are:
– Single Responsibility principle
– Open/Closed principle
– Liskov Substitution principle
– Interface Segregation principle
– Dependency Inversion principle
The goal of these design principles is to improve the Separation of Concerns, through weaker Coupling and stronger Cohesion. The main consequence should be software systems that are easier to maintain and to extend. Thus the application of these principles may be seen as an investment in the quality of the software design that has future benefits for the system’s evolution.
However, some potentially undesirable consequences are:
– The proliferation of relatively small concrete classes.
– The proliferation of abstract classes and interfaces.
– A high number of levels of indirection.
– Too many abstraction layers.
– Increase in the depth of the inheritance tree.
– Yo-yo problem.
Thus the indiscriminate application of SOLID principles may in practice increase too much the complexity of software systems, with negative consequences for maintainability and extensibility. This is the reason we need experienced software developers in a team, who have the wisdom to foresee the consequences of their design decisions.
Back to the original question: “Do the SOLID principles make code slow?” As we have seen, this is one possibility, because of the potential increase in the levels of indirection and in the number of abstraction layers. In other words, we may be forced to make more method calls and aggregate the data we need from several small objects.
My advice is to choose a design that is clean, focusing on the separation of concerns, but still as simple as possible. If there are performance concerns, this should be measured using runtime tools such as a profiler. Only if a clear bottleneck is detected should the initial design be modified to make the code faster. In any case, the definition of “slow” and “fast” depends on specific system requirements.
To end with a quote by Donald Knuth: “Programmers waste enormous amounts of time thinking about, or worrying about, the speed of non-critical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.”
Do you agree? Please share your experience in the comments below.