Application architecture or how to spoil karma on Habré
You can talk a lot about application architecture, SOLID, OOP principles, architectural patterns like layered or onion, etc. design patterns. Throughout my experience, I realized one thing how many people have so many opinions. When you are a beginner programmer you have a lot of ambitions, you grow a little in qualification, you have the feeling that you know everything, and everything that has been done to you is “bad”, and you will definitely do better ... But the years go by and the experience gained suggests 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, I ask for details under cat ...
First to first, to create a good project architecture, you need to decide on its features:
The first point is the ease of support is solved following the principles of SOLID, basically, of course, the principle of "Uniqueness of Responsibility", so you need to choose an architecture based on microservices or a modular architecture of a monolithic core system. There is no fundamental difference between these approaches. For the project I'm working on, I chose the 2nd approach, modules.
The second point can be solved using the event-observer or dispatcher programming pattern. They are similar to each other, so we will not focus on this. The essence of their work is to throw some message out of the module that is currently being executed, and, if necessary, listen to the module that needs to work with this object.
The third paragraph is also solved quite simply, the descriptive part of the entity, that is, the attributes of the entities stored separately from the entity itself. This is a reference to EAV (Entity Attribute Value). You do not have to process all the fields of an entity for business logic, some attributes carry an informative load, others are used for sorting and filtering, and only a part for building business logic. Therefore, if the entity is stored as EAV, we can at any time add or remove an attribute we do not need.
The fourth point 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. Therefore, it is worth using factories for forms, factories for tables, factories for cards. More automation, in the end, we can abstract from the field of presentation, and focus on business logic and objective tasks ...
And so the conclusion suggests itself that in order to build a good architecture, you need to abstract, decide on technologies and programming patterns and build a foundation for starting development ...
Now we have developed a plan, decided on the requirements, then we need to decide how to build the architecture. In fact, I do not understand all these layered architectures or onions. I took something from them and invented something myself, and I don’t see anything in it if people just understand what it means. In fact, the whole architecture comes down to simple steps:
But what makes architecture good? 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 parts, modules. Each module is responsible for only one system functionality. We go down each module, designed as an mvc application and have a view, controller, model. And each part of the module is also responsible for each of its actions. We go down even deeper and we will see that the view also has certain 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 complement it, and build an interface (or output system). But how do you make all this less dependent you ask? And the answer will be obvious to the observers, on each render of a layout’s block, they throw out their event's, you just need to listen to this event, observer in your application, and add the necessary block update in the layers, and get the appropriate output. Many modules also have their own events, which other modules subscribe to and are able to add / or update data in the transferred 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 light of the above, a reasonable question arises: if one module listens to another, then it is necessary to have some kind of dependency management system for these modules. That is, the module on which another module depends, we must start in the first place, and the one which is dependent, we must run after. And so a simple implementation of the dependency was born, we create a queue for launching the modules and simply sort it in such a way that those modules on which any others depend are loaded first of all, after loading the kernel, 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 affair. To write two lines for adding is also not so much time. But making a conclusion, reversing every one, debugging large amounts of data is already a time that is many times longer than the time to develop an architecture construction strategy.
First to first, to create a good project architecture, you need to decide on its features:
- The architecture must be supported.
- System extensibility without crutches.
- Flexibility of settings, many tasks must be solved without changing the program code.
- Reliability of architecture.
The first point is the ease of support is solved following the principles of SOLID, basically, of course, the principle of "Uniqueness of Responsibility", so you need to choose an architecture based on microservices or a modular architecture of a monolithic core system. There is no fundamental difference between these approaches. For the project I'm working on, I chose the 2nd approach, modules.
The second point can be solved using the event-observer or dispatcher programming pattern. They are similar to each other, so we will not focus on this. The essence of their work is to throw some message out of the module that is currently being executed, and, if necessary, listen to the module that needs to work with this object.
The third paragraph is also solved quite simply, the descriptive part of the entity, that is, the attributes of the entities stored separately from the entity itself. This is a reference to EAV (Entity Attribute Value). You do not have to process all the fields of an entity for business logic, some attributes carry an informative load, others are used for sorting and filtering, and only a part for building business logic. Therefore, if the entity is stored as EAV, we can at any time add or remove an attribute we do not need.
The fourth point 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. Therefore, it is worth using factories for forms, factories for tables, factories for cards. More automation, in the end, we can abstract from the field of presentation, and focus on business logic and objective tasks ...
And so the conclusion suggests itself that in order to build a good architecture, you need to abstract, decide on technologies and programming patterns and build a foundation for starting development ...
Now we have developed a plan, decided on the requirements, then we need to decide how to build the architecture. In fact, I do not understand all these layered architectures or onions. I took something from them and invented something myself, and I don’t see anything in it if people just understand what it means. In fact, the whole architecture comes down to simple steps:
- The foundation is abstraction (abstract classes and interfaces that define the contract of various components of the system combined into modules)
- Next, I have a kernel layer that runs the modules and manages them.
- Loading the layout system
- After starting the module, each module as a separate microservice
But what makes architecture good? 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 parts, modules. Each module is responsible for only one system functionality. We go down each module, designed as an mvc application and have a view, controller, model. And each part of the module is also responsible for each of its actions. We go down even deeper and we will see that the view also has certain 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 complement it, and build an interface (or output system). But how do you make all this less dependent you ask? And the answer will be obvious to the observers, on each render of a layout’s block, they throw out their event's, you just need to listen to this event, observer in your application, and add the necessary block update in the layers, and get the appropriate output. Many modules also have their own events, which other modules subscribe to and are able to add / or update data in the transferred 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 light of the above, a reasonable question arises: if one module listens to another, then it is necessary to have some kind of dependency management system for these modules. That is, the module on which another module depends, we must start in the first place, and the one which is dependent, we must run after. And so a simple implementation of the dependency was born, we create a queue for launching the modules and simply sort it in such a way that those modules on which any others depend are loaded first of all, after loading the kernel, 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 affair. To write two lines for adding is also not so much time. But making a conclusion, reversing every one, debugging large amounts of data is already a time that is many times longer than the time to develop an architecture construction strategy.