📜 ⬆️ ⬇️

The principle of sole responsibility: the foundation of decomposition


Now anyone who does programming has heard about this principle. Slightly less than those who think he knows. Much less than those who really know how to use it. I will try to explain the essence, purpose and application of this principle as simply and as short as possible.


Definition


Each program object has one and only one purpose.
It can be exhaustively described in one sentence, without using alliances.


Example


Lazy <T> is a wrapper for an object whose creation is postponed until the first access to it.


Anti-example


Singleton is a class that does not allow the creation of more than one instance. There are no unions in this description, but it is incomplete - a singleton always has the main functionality besides controlling the uniqueness of its own instance. Singleton is a class that implements useful functionality and controls the uniqueness of its own instance. Now the description is exhaustive, but it has the conjunction "and" —the singleton has two different purposes. It does not comply with the principle of sole responsibility.


Another anti-example


Service Locator - allows access to any application service. This description without an exhaustive list of services is obviously incomplete.


Purpose


Simplify the creation, analysis and modification of software systems.


Analysis


Analysis and evaluation are simplified due to a priori knowledge of the answer to the question "Why is this needed?".
The program object with the sole responsibility will obviously be easier and less than its counterpart with the additional load. On the contrary, an object with many responsibilities often does not allow us to give an exhaustive answer to the question "Why was it created?" even own author. The traditional argument against the application of the principle of sole responsibility is the greater number of small objects in the project. In a smaller number of larger entities, it is supposedly easier to navigate and understand the structure of the application as a whole.


In fact, the simplicity of orientation depends not so much on the number of classes in the project, but on the number of links of each particular class with the others. For applications designed according to the sole responsibility principle, this figure is expected to be lower.
And the most effective way to facilitate the understanding of the project as a whole is the selection of a special object responsible for the composition in the context of the application.


Creature


Creating new and expanding existing software systems is facilitated by simplified reuse. Objects with sole responsibility for the construction of no excess functionality. As a result, they are either needed for the implementation of the project’s objectives or not at all. No need to support redundant features. No need to duplicate the existing implementation due to the high cost of the previous paragraph.


Modification


Modification of existing functionality is cheaper due to better localization of changes. Minor changes are visible in the version control system with an accuracy of specific responsibility. Major modifications are noticeable immediately due to the large number of modified files. Unit tests for single-responsibility objects provide more information about defects in the code.


Contraindications


The only real contraindication is optimization of resource consumption during the development and operation of software systems.


Development


The cost of primary development with consistent adherence to the principle of sole responsibility is higher due to the need for more thorough analysis and increasing the amount of code within a specific task.


The more complex the project, the higher the requirements for internal quality, the greater the amount of code - the fewer reasons to neglect the principle of sole responsibility.


Exploitation


Code with low-level optimizations often cannot follow the sole responsibility principle. Since premature optimization is the root of all evil, it is logical to first develop a functionally correct version, and only then optimize the bottlenecks.


Complexity


The principle itself is very simple, there is no ambiguity and no dialectic in it, the effect of the application is obvious, it bears fruit very quickly. But the skill of detecting and identifying responsibilities is creative, it depends heavily on the abilities of the programmer, it is developed and trained through the experience and study of new methodologies, techniques, tools.


For example, the study of functional programming allows you to notice and highlight responsibilities that are very difficult to detect using only OOP. The main obstacle to using the principle is its counterintuitiveness: the human brain tends to seek and find the only “simple” answer to all complex questions.


Hence the roots of the anti-pattern "Divine Object" grow. That is why many still do not consider singleton antipattern. The other side of the problem is in the desire of developers to find and accept challenges in the form of complex solutions. The principle of sole responsibility reduces the complexity to the necessary minimum, thereby reducing the interest of the programmer. The talent of the developer lies in the ability to select and implement the simplest and most effective solution of the problem, even if the "common sense" intuition and ambition require the opposite.


Results


Understanding and application of the principle of sole responsibility is the most important skill of any programmer, it should be constantly developed and trained, without it the engineer turns into a technician-performer, at best, he works well on someone else's patterns.


Application in .NET


  1. Interfaces - the allocation of contracts as a separate responsibility.
  2. Classes - highlighting contact implementations.
  3. Methods - selection of algorithms.
  4. Delegates - the selection of polymorphism.

Application in principles and patterns


  1. The principle of separation of interfaces - the only responsibility for contracts
  2. The principle of openness-closeness is the only responsibility for implementations.
  3. Dependency injection - highlighting the composition of objects as a separate responsibility.
  4. Factory — Select Object Creation
  5. ORM - highlighting support for displaying objects in databases

')

Source: https://habr.com/ru/post/338064/


All Articles