You can talk a lot about application architecture, SOLID, OOP principles, such architectural patterns as layered or onion, etc. design patterns. During my experience, I realized one thing how many people have so many opinions. When you are a novice programmer, you have a lot of ambitions, you’ve got a bit of an increase in qualification, you have a feeling that you know everything, and everything that has been done before you is “bad”, and you will definitely do better ... But years go by and the experience you have learned says the opposite. Under the cut, I will try to briefly, and most importantly in simple words, tell you about how good architecture is. At least expandable and supported, for details I ask under the cat…
First of all, in order to create a good project architecture, it is necessary to determine its features:
- The architecture must be supported.
- Crutch-free system extensibility.
- Flexibility of setting, many tasks should be solved without changing the program code.
- Reliability of architecture.
The first point is the ease of support is solved by following the principles of SOLID, basically of course the principle of "Uniqueness of responsibility", for this architecture you need to choose a system based on microservices or a modular architecture of a monolithic core. There is no fundamental difference between these approaches. For the project I am working on, I chose the 2nd approach, modules.
The second point can be solved using the event-observer programming pattern or the dispatcher. They are similar to each other, so we will not focus on it. The essence of their work is to throw out any message from the module that is currently running, and if necessary, listen to the module that needs to work with this object.
')
The third item is also solved quite simply, the descriptive part of the entity, that is, the attributes of the entities are stored separately from the entity itself. This is a reference to EAV (Entity Attribute Value). You do not need to process all fields of any entity for business logic, some attributes carry informative load, others are used for sorting and filtering, and only a part for building business logic. Therefore, if an entity is stored as EAV, we can add or remove an attribute that we do not need at any time.
The fourth item of our requirements is reliability, which means a minimum of crutches and more automation. Most web applications consist of data display interfaces, tables, filters, sorting, entity cards. And data entry interfaces, forms. For this, you should use factories for forms, factories for tables, factories for cards. More automation, in the end we can abstract away from the field of representation, and focus on business logic and substantive tasks ...
And so the conclusion suggests itself that in order to build a good architecture, it is necessary to abstract, determine the technologies and programming patterns and build the foundation for the beginning of development ...
Now we have developed a plan, decided on the requirements, then we need to decide how to build the architecture. Actually, I don't understand all these layered architectures or onions. I took something from them and invented something myself, and I don’t see anything like that in this, if people just understand what it means rightly. In fact, the whole architecture comes down to simple steps:
- In the foundation of abstraction (abstract classes and interfaces defining the contract of certain components of the system combined into modules)
- Next, I have a kernel layer that runs the modules and manages them.
- Loading system layouts
- After starting the module, each module as a separate microservice
But what makes a good architecture? The question is not simple, but if everything is simplified to the level of philosophical reasoning, then this question will be answered. After the application starts. We have isolated from each other parts, modules. Each module is responsible for only one functional system. We go down every module, designed as an mvc application and has a view, controller, model. And each of this part of the module is also responsible for each of its actions. We go down even deeper and we will see that the presentation also has some parts, these are factory classes, and layout's extensions. In fact, layouts are also a module, it is loaded first of all, all other modules supplement it, and build an interface (or output system). And how do you make all this less dependent you ask? And the answer will be obvious to the observers, for each render of the layout's block they throw out their event's just listen to this event, observer in your application, and add the necessary block update in layers, and get the appropriate output. Also, many modules have their own events, for which other modules are subscribed and are able to add / or update data in the transmitted set. All this leads to the fact that in the application, the modules are little connected with each other and can live without each other.
In the light of the above, a reasonable question arises, if we have one module listening to another, then it is necessary to have some kind of dependency management system for these modules. That is, the module on which the other module depends, we must start first and the one that is dependent we have to start after. This is how a simple dependency implementation was born, we create a queue for launching modules and simply sort it in such a way so that those modules on which any others depend are loaded in the first place, after the kernel is loaded, of course.
In conclusion, I can say the following. Good architecture is not such a difficult and long-term task to save on it. And in the end, it helps to spend resources and time more efficiently. After all, changing the setting in the control panel is a five-minute case. Write two lines to add too not much time. But to make up a conclusion, to rehash every sneeze, to debug large amounts of data is already a time that many times exceeds the time needed to develop an architecture building strategy.