Learning the recipes for the effective development of a software project, I tried to find for myself the reasons that make useful the use of the principles of the development of the SOLID architecture (article How not to understand the principles of the development of the SOLID architecture ).
The analysis of these principles allowed us to identify several key laws and basic elements that exist in the development. They allowed to describe, understand and implement SOLID in real work with a software project.
It has become interesting to analyze the applicability of these concepts for generally accepted programming paradigms, for example, for OOP. Well, if the result of this work will be useful to you.
Today there are many approaches for the design and subsequent implementation of software projects. The most popular in work with large software projects are: structured programming , functional programming , object-oriented programming .
For me, it became interesting to analyze the causes of these design approaches. And in the process of analysis, the unexpected discovery was the fact that they all implicitly are based on the following premise:
, .
What is a project without development? Such projects are occasionally found and are mainly characterized by fast piece-rate payment without the occurrence of subsequent obligations on the part of the programmer, for example:
In such situations, the programmer’s efforts to maintain, for example, an object-oriented approach, are wasted. It often happens that I find myself in such a meaningless lesson during the development of a one-time console utility, when I suddenly realize that writing the 4th grade text in this project delayed me for 15 minutes and did not bring the result closer. The saddest thing is that all classes that were hardly written in such projects are forgotten and not reused, that is, they do not facilitate our work further.
In all other situations, the programmer, minimizing his work, must develop a structurally complex project, that is:
If we look for analogies to the development of a software project, then we can recall the evolution of a biological species.
"". - . - .
The work of the programmer is not easy, but the programmer has a "helper". This helper is hidden somewhere deep in the structure of our world, in which there are two features:
For the sake of brevity, this algorithm useful in many areas will be referred to as the universal algorithm. Its implementation for a specific application can be called specialization, since the process of specifying an algorithm for use in a narrow application area is similar to the evolutionary specialization of cells in a living organism.
Obviously, to create an algorithm, it is required to single out features that ensure the applicability of the algorithm. These attributes must be sought in the input data and in the description of the initial situation (context). To create a universal algorithm, it is necessary in each subject area, which has its own sets of data and situation characteristics, to select the signs of applicability, identical for all areas. All other signs that do not provide applicability are ignored by the universal algorithm. Formalizing the universal algorithm, we came to the need to use abstraction - one of the most important principles of OOP. At the same time, OOP is characterized by an emphasis only on data abstraction.
Here I will try to write examples of the use of abstraction from different areas.
Abstraction | Algorithms | Application area |
---|---|---|
Integers | Algorithms of quantitative calculations | Tasks of accounting of economic values |
Mass characteristic of the material body | Algorithms-operations comparison of the amount of substance | The task of comparing the value of the goods, not amenable to the account |
Interface with operations for the collection of elements: a complete traversal, comparison and exchange of positions | Collection sorting algorithms | Programming |
Interface identical operations for the "leaf node" and "branch node" in the tree | Algorithms based on the Linker design pattern | Development of a complex software project |
Key concept "Worker" | The wording in the section "Employment contract" | Labor Code |
Using different methods of abstraction, the programmer performs the implementation of the algorithm in the form of a piece of code, which is a separate and complete element of his work. This element, depending on the programming language used, can be a function, an object, and a sequence of instructions. For the sake of convenience, we will call this code fragment the word " component ".
Component - code segment (procedure, class, deployment component, etc.):
Using the term component , it is possible to formulate a set of simple laws that exist in the development of a software project. I will present these patterns in the form of the following statements, divided into 3 categories.
I will try, using the above statements, to perform an analysis of the basic concepts of object-oriented programming. This analysis bypasses the concept of abstraction , since it has already been described earlier in the formalization of the method for constructing a universal algorithm.
These concepts of OOP reinforce the expediency of using a special type of component , described by a combination of some internal data and methods for working with this data. All the statements of the group [1] and [2] are translated into OOP, for which the term component is replaced by the concept class .
At the same time, at first glance, class and object relations are exhausted by a group of statements [3], in which the base is replaced by the concept class , and the implementation is replaced by the concept object . Moreover, the implementation turns out to be dynamic, that is, changeable during the execution of the program.
The concept of " encapsulation " can be considered from two "sides".
The first side of the concept of " encapsulation " is the separation of the component from other parts of the code. This property allows the programmer to perform changes in the component to perform operations in areas of code that are close to each other. That is, to minimize the time spent by the programmer, excluding from work the search and analysis of the separate interacting elements of the program. This side is determined by the properties of the component , following from its definition.
The second side of the concept of " encapsulation " - is hiding the internal implementation of the component . This concealment is possible using the concepts of base and implementation described in the statement group [3]. To do this, the public class methods are identified with the base , and the private and protected class methods with the implementation . In the places of use, the constraints formed by the base are used , and therefore it is possible to make changes in the implementation that do not concern the basic constraints. And these implementation changes do not need to be checked at the places of use of the database [3.5], which minimizes the effort of the programmer.
It is noteworthy that the concept of " encapsulation " has an analogy in biology. This process is its first party similar to the biological functions of the " Cell membrane ".
The concept of " inheritance " continues to reinforce the importance of using the base + implementation . To do this, in the group of statements [3], it is necessary to identify the methods of the parent class with the base , and the methods of the heir class to identify with the implementation .
In its implementation, the concept of " inheritance " allows you to use the statement [2.3], that is, to use the addition of the code instead of changing and duplicating it. At the same time, it is necessary to eliminate duplication of the basic algorithm. However, the approach that uses inheritance to specialize the universal algorithm has a significant disadvantage. This drawback is the presence of two strongly connected components that are difficult to change independently. These dependencies-dependencies are generated by the parent-heir relationship.
There are many alternative ways to use the base + implementation bundle. I will give further examples of such methods.
Base | Implementation | Application area |
---|---|---|
Public class methods | Private class methods | Encapsulation |
Protected methods of the parent class | Subclass Methods | Inheritance |
Dynamic library interface | Dynamic library functionality | Component = dynamic library |
Template (generic) methods and classes (template, generic) | Instantiating a template with specified arguments | Generalized programming |
Generic delegate methods | Specialization of methods specifying specific processing procedures | Procedures for sorting or forming a tree, with an indication of the method of assessing the order of elements |
Classes involving interaction with the "Visitor" template | Formation of the "Visitor" with the required functionality | Visitor Design Pattern |
NPP control panel | The combination of automation and equipment of nuclear power plants | Hiding the complexity of the system from the NPP operator |
In parallel, I notice that for the concept of " inheritance " from the PLO, it is also possible to find an analogy in the processes of biological evolution. In biology, the term " heredity " is used for this.
In my opinion, the concept of " polymorphism " is the second side when looking at the procedure for creating a universal algorithm. The first side ( abstraction ) is a look from the point of view of how to create a universal algorithm. At the same time, when looking at the universal algorithm from the user's point of view, we get the notion of polymorphism . That is, polymorphism is the useful ability of a function ( component ) to process data of different types. Adding this concept to OOP reinforces the usefulness of using a universal algorithm in the design of a software project.
Implementations of polymorphism in different programming languages ​​are very different. In a Wikipedia article for polymorphism , depending on its implementation, there are 4 subtypes: parametric, inclusions (or subtypes), overload, type conversion. These implementations have significant differences, but they are all united by one goal - this is writing a universal algorithm that will not need to be duplicated for its particular specialization .
And this time, almost without surprise, I found an analogy for the concept of " polymorphism " in biology. The name of this biological term fully coincides with the concept of the PLO. “ Polymorphism ” is the ability of a single organism to exist in states with different internal structures or in different external forms.
Thus, almost all the basic concepts of OOP can be represented as a set of simple statements, formed on the basis of the laws governing the development of a software project. At the same time for OOP, the term component is identified with the concept of class . If we select another value for the term component , for example, a function , then it is possible to formulate the basic concepts of functional programming .
In the process of writing the article, biological analogies were found for the concepts used in programming. These analogies appear due to the similarity of ways of developing a software product and some processes of biological evolution.
IMHO, it is advisable to consider these two scientific areas together. In this case, it may be possible to carry out the transfer of laws from one industry to another, and thereby ensure the development of both information technologies and formal descriptions of biological processes.
Thank you for attention.
I would be very grateful for the feedback, suggestions and suggestions, as they help me to adjust the direction of development of work in this area.
Edited by Borisova M.V.
Source: https://habr.com/ru/post/448026/
All Articles