As far as I understand, YAGNI recommends that we not allocate abstraction unnecessarily. That is, if we do not need polymorphism at this particular moment, then we should not allocate abstraction, for why then? However, both OCP and DIP call for us to provide an abstraction here. OCP advises to do this so that if we suddenly need to change the behavior of a class, we can do this without changing the type, simply by passing the new implementation of the abstraction to the type. DIP, however, says in plain text that the details should depend on abstractions and not vice versa.

Also highlight abstraction can force the need to test user type. But as part of java, as I understand it, there is no such need.

So, is it necessary to allocate abstraction immediately? Do I need to follow OCP and DIP?

  • Comments are not intended for extended discussion; conversation moved to chat . - Nick Volynkin

1 answer 1

Different design principles are aimed at solving a specific design problem, and in some cases they may contradict each other .

It can be said that different principles “pull” the design in different directions and you need to find the right vector, which is most useful in this particular case: SRP - speaks about the simplicity of the solution, OCP - about the isolation of module components, DIP - about the “correctness” of relations between classes, and LSP is about “correct” polymorphism.

Following one principle may violate another. So, for example, any inheritance can be considered as a violation of SPR , since now a single group of classes is responsible for one responsibility (drawing figures). Following DIP and OCP can lead to the appearance of additional “seams”, i.e. interfaces / base classes in the system, which, again, will lead to violation of SRP and / or ISP .

But this relationship between principles is not fixed. For a simple case, highlighting a hierarchy of figures for drawing is a violation of SRP , since the “drawing” in the first iteration may consist in outputting text to the console and spreading this information across several classes will be redundant. But as the decision becomes more complex, the appearance of the inheritance hierarchy will be justified from the point of view of the SRP , since the complexity of displaying each individual figure will be so high that the concept of “responsibility” will also change. If at the beginning “single responsibility” was the display of all the figures, then now one responsibility will be divided into many: “circle display”, “square display”, etc.

The principle of YAGNI (You Aren't Gonna Need It) is a more fundamental principle (“higher order principle” or “meta principle”), which helps to understand when to follow principles / patterns / rules and when not.

The principle of YAGNI is based on several observations:

  1. Programmers, like people in general, poorly predict the future.
  2. No flexible solution will be flexible enough.

These observations lead to the following conclusions: an attempt to create a flexible solution in the early stages of development is doomed to create an over-complicated solution . This is due to the fact that in the early stages it is not yet known what kind of changes in the system will be needed, and it is simply not clear where to “lay the straw” for future changes.

Since we don’t know at the early stages what kind of flexibility is needed, we will put the flexibility not where it is needed: we will foresee the replacement of the data access layer, but due to “leaky abstractions”, we will still fix the solution on a specific database, or such flexibility just never needed. We will create a “framework” for parsing command line arguments that will be used in one application, and the cost of screwing it into another application will be so great that no one will do it.

Good design is the simplicity of the solution when changing requirements leads to linear labor costs.

The easiest way to achieve this is through evolutionary design: we start by dividing the system into large components, but we are not engaged in isolating the excess. Base classes are not needed if there are currently no at least 2 or 3 heirs. And even if such heirs "may appear in the future," then it is necessary to select the type hierarchy exactly when this very future comes.

The principle of YAGNI can be expressed as follows: the allocation of unnecessary abstractions (and any other complication) is justified only if the cost of their allocation in the future will be significantly more expensive than now.

Investments in the reasonableness of the library programming interface (API) will be justified, since the cost of making changes is very high. The cost of separating the interface / base class of an application is almost the same today or in a year.

Solving the problem as it is received allows you to focus on the tasks that are relevant today and allows you to avoid work that you may not need at all.

PS Well, it seems to me that you have not quite a correct understanding of the principles of OCP and DIP , which are not at all reduced to the need to use inheritance.

Here are some related articles:

And separately, in the article “On Design Principles”, I consider approximately the same thing as in this answer: that blindly following the principles will lead to an over complicated and heavy solution.

  • Found interesting comments on the topic. Just from you to the article by Alexander Bndju. blog.byndyu.ru/2009/10/blog-post_14.html#comment-1550159156 . Alekskand Bindju: Я думаю более "современная" трактовка должна предполагать, что для Stable Dependencies абстракции не нужны, а для Volatile Dependencies стоит добавить слой абстракции. This interpretation is perceived by me as simple and clear as possible. The difficulty is only in determining what is Stable and what is Volatile at this particular moment. But this is probably quite about the skill and comes with experience. - Serg046
  • four
    Разные принципы проектирования направлены на решение определенной задачи проектирования, и в некоторых случаях они могут противоречить друг другу. I suggest this phrase to highlight bold! Brilliant. The universal phrase for the answer to students who pretend to be know-it-all, in sweat, they prove to you how badly they violate SOLID and try to do everything according to the rules - consistently producing a trash code. - Goncharov Alexander
  • 2
    @ Serg046 The concept of stable and changeable dependencies is described in my article "Addiction Management" ( sergeyteplyakov.blogspot.com/2012/11/blog-post.html ), but I don’t agree with Alexander here, who in his comments puts = between abstractions and polymorphism. Abstraction cannot exist without information hiding , polymorphism is not a necessary condition. - Sergey Teplyakov
  • @GoncharovAlexander Good recommendation. Corrected the answer. - Sergey Teplyakov
  • Where to order a book? =) - Alexey Malchenko