When you develop software applications at different levels – from architecture design to coding – some ideas on universal principles to make the right decisions come to your mind.
In the book “Perfect code”, S. McConnell formulates the main technical imperative of software development – fighting the complexity . Each time when you stop and look through the work done, you ask yourself, how is it possible to simplify it? Otherwise, the subsequent development will make developed system unmanageable. The answer to this question is not always obvious. A developer has various choices. However, which of them are correct? At an early stage, how can you be sure that you are moving towards the right direction?
Watching the complex systems created by nature, people do not cease to admire the apparent complexity of these systems and their brevity. A simple calculation of our brains’ data size shows only 1.5 GB, and the difference between the information amount stored in each person’s mind is usually less than one percent!
The systems created by people are simpler: cities, social and engineering structures etc. However, they are still rather complexed to take them into consideration.
In the first and second cases, it is possible to observe in action such universal principles as Modularity, Hierarchy, Typification.
I would like to quote the definition of a complex system:
A complex system is a system consisting of a set of interacting components (subsystems) that result into the complex system’s gaining new properties that are omitted at the subsystem level and cannot be reduced to the properties of the subsystem level .
When designing a complex system, it is necessary to strive for reducing the subsystems and the connections between them. Therefore, it becomes possible to minimize the possibility of unpredictable system behavior, which is a consequence of its complexity.
Modularity. Parts of a complex system always conceal the features of their implementation and functioning, and also interact with the outside world through a certain interface. In programming field, this aspect has received maximum development in the object-oriented paradigm. Perhaps this is why OOP is used the most often, while creating complex software systems.
Creating a module, a designer has an opportunity to distract from the details of its internal implementation. In terms of human cognitive abilities, this approach allows to simplify the design process, allowing you to focus on the essential functions of the object and its interface. However, you might get distracted from the environment during module’s content development, since the module must have a clear interface specification.
The principle of modularity is useful both for the object creating and functioning.
The object is more sustainable if the environment does not have access to its insides. On bumping into this problem when developing software, I can think of an analogy: a person with his entrails sticking out. For how long could he live? In software, a violation of the modularity principle results into errors and instable workflow.
Hierarchy. In most complex objects, you can point out the levels on which the entities of the same class are located. A very simple example of this claim is a book. Letters, words, sentences, paragraphs, chapters and so on are the levels of hierarchy. In this case, objects of a higher level include low-level objects. However, there can be other options. For example, the hierarchy of management. The information or the administrational impact is transmitted in sequence, level by level. We can see it in many social structures. The cortex of the human brain has six layers, which conduct certain functions . This principle reflexes in software design as a simply outlined architecture . The hierarchy can be considered as a logical separation of object classes.
Typification. Analyzing objects of the same hierarchy level, you can notice that these objects are same in complex systems. There are many examples in both things of alive and artificial nature: component blocks of buildings, cells in human body, workers employed in law enforcement agencies, etc. Typification means that objects have similar properties, equal interface. This feature makes it possible to interact with the system elements similarly, and control them from higher levels. It is hard to imagine a large building, which first floor is made of wood, the second of brick, and the third constructed with monolithic frame technology.
Here you can see some examples of typification principles use in software development: a microkernel architecture in which the expansion of functionality is realized by plug-ins with a typical interface; design patterns “Strategy”; “Chain of duties”; “Abstract factory”, etc. 
What are the practical consequences of the described principles?
First, it is important to keep these principles in mind at the stage of analysis and design. Unfortunately, the separation into modules and layers is not always clear. Building a domain model is a complex analytical task. You should reprocess the model until it complies with the described principles.
When designing project’s concept or programing, do not forget to check upon your workflow to conform these principles. Modules must be closed from outside influence. Hierarchy levels must not mix. Objects that perform the same functions should be typificated.
Design patterns (, ) – time-tested solutions which can be used as large building blocks of your system can be very useful.
Solution correctness can be illustrated with a rule “1 or a lot”. If there are several objects with the same functions / responsibilities in your implementation, but their types are different, it means that you did something wrong, and when you add new objects you will drown in the constantly increasing complexity.
Also I would like to add some words about a combination of the Hierarchy and Typification principles, specifically about the self-similarity of the system components (fractality): when the same type of object appear at different levels of the hierarchy. The easiest way to understand this principle is using the example of a tree (and the forest as a whole). Each tree branch is similar in structure to the tree.
It’s an interesting (but quite logical) fact that the same laws operate at the different levels of hierarchy: the distribution of the thickness of the trunks in the forest corresponds to the distribution of the thickness of tree branches growing in the same forest, or the “Leonardo rule”: “If the thickness of all tree branches at any height combine together, we’ll get the thickness of the trunk “. But it is another story.
If on solving a problem you can build a model according to the principle described above, that would be of a great help. Such solutions are elegant, although they contain components with increased complexity (primarily because of the recursion).
The last issue I wanted discuss, are the rules for combining objects in the system. It is necessary to limit the number object types that interact with each other. You should try to present this interaction in a structured form, or with the help of an object that regulates such interaction. In other words, you need to reduce the number of links between the system elements.
We can take the access rights partition process in the operating system as an example. A lot of users and files interact with each other through a group object. The file owner is a certain group, and only the users included in this group can access it. On creating a group, you can regulate the access of any user to any file.
Anyway, the number of interacting objects should not be more than three (maximum – four). Otherwise, an increase in the number of connections can cause the appearance of uncontrolled effects of the system level and, as a result, unpredictable behavior of the system.
In this article, I have considered the principles that can be observed in any complex and stable functioning system. When working on the system, the developer has to monitor its compliance with these principles. Otherwise, the complexity of the system will grow uncontrollably, and will lead to a slowdown in the pace of system development and problems of functioning.
There are some simple rules mentioned above which you can employ to learn about splitting the system into components.
- Стив Макконнелл, Совершенный код.
- Mark Richards. Software Architecture Patterns.
- Jeff Hawkins with Sandra Blakeslee. On intelligence.
- Design Patterns: Elements of Reusable Object-Oriented Software. Erich Gamma, Richard Helm, John Vlissides, Ralph Johnson.
- Лес дробной размерности, lenta.ru
- How Much Information is Stored in the Human Genome? Evgeniy Grigoryev.
- Patterns of Enterprise Application Architecture. Martin Fowler.