[Series of clean architecture] (4) Software architect and software architecture

I have been reading the book "Clean Architecture" recently. The book's explanation of software design and architecture is very profound. So I opened a column to record some excellent architectural design concepts in the book "Clean Architecture" and my thoughts on these contents.


1. What is a software architect

A software architect must first be a programmer, and must be a first-line programmer with strong technical skills. They will gradually guide the team towards the best system design direction while undertaking programming tasks themselves. If you don't code yourself on the front line, you won't realize the good and bad of the design, and you will lose the correct design direction.

2. The purpose of software architecture

The purpose of designing the software architecture is to better develop, deploy, operate, and maintain these components in the work.

In the design process, we need to keep as many "optional options" as possible for as long as possible on the basis of ensuring that the system can work normally, so that we can respond more flexibly to future functional changes.

For example, in the early development stage, we don't need to care too much about which database we want to use, and we don't need to introduce frameworks such as DI and ORM prematurely. The advantage of this is that if we can deliberately free ourselves from the entanglement of implementation details when designing the architecture, we can make decisions more flexibly.

3. Business logic

Business logic is the meaning of the existence of a software system, the core function, and the part of the code that creates revenue for us.

These business logics should be kept pure and not mixed with user interface or database related things used. Ideally, this part of code representing business logic should be the core of the entire system, and the implementation of other low-level concepts should be plugged into the system in the form of plug-ins. Business logic should be the most independent and reusable code in the system.

4. Demarcation of boundaries

Designing software architecture itself is an act of dividing boundaries. We need to divide a software into various modules. How to reasonably divide the boundary of each module is something that an architect must consider.

The principle of dividing the boundary line: the boundary line should be drawn between those irrelevant things, such as GUI has nothing to do with business logic, and a boundary line should be drawn between the two.

And when we cut the system into modules one after another, we will find that some modules are the core business logic of the system, and the other parts are not related to the core business logic but also provide necessary functions. For the latter, we can regard them as plug-ins one after another, and then make these plug-ins depend on core business components by modifying the source code. In this way, we can use the plug-in method to switch many different types of modules and improve the flexibility of the system in the face of function changes.

The systems we design in this way usually have the following characteristics:

1. Framework independent: The architecture of these systems does not depend on a function in a feature-rich framework. Frameworks can be used as tools, but there is no need to adapt the system to the framework.
2. Can be tested: The business logic of these systems can be tested without external elements such as UI, database or other.
3. Independent of UI: The UI of these systems can be easily changed without modifying other system parts. For example, we can replace the UI of a system from a web interface to a command line interface without modifying the business logic.
4. Independent of database: We can easily replace the database used by the system. Because the decoupling between business logic and database has been completed.
5. Independence from any external system: The business logic of these systems does not need to know the existence of any other external interfaces.

Five, give an example

Suppose we want to make a text-based adventure game. The operation of this game is completed by the player inputting simple text commands such as "up, down, left, and right". After the player enters a command, the computer returns the event triggered by the player's role.

Now, suppose we decide to keep this text-based interaction, but need to decouple the UI from the business logic of the game so that our game version can use different languages ​​in different regions. How should we do it - we need to use an API that has nothing to do with natural language to communicate between the business logic of the game and the UI, and the UI is responsible for converting the information passed by the API into a suitable natural language, just like The picture below looks like this:

insert image description here

At the same time, assuming that the player's state in the game will be saved in some kind of persistent storage module (such as flash memory, or cloud storage), but we don't want the game engine to know these details, so we still need to create an API to Responsible for the communication between the game's business logic components and data storage components.

insert image description here

In addition, the language is not the only direction for UI changes. We may also change the input and output methods of text (such as using the command line or the information window), so that we have to build another set of APIs, which makes the whole system more complicated.

insert image description here

Then we simplify it, remove the specific implementation, and it becomes the following:

insert image description here

It can be seen that all modules and arrows together form a directed acyclic graph, and the arrows finally point to the core module of Game Rules. This design is very reasonable. But in practice, it is difficult for us to encounter such a situation where all data flows converge on the same component. Take this Game Rules as an example, I need to deal with the logic of the player's movement, as well as the logic of the player's blood volume and attack power. Then the architecture of this system will become like this:

insert image description here

For another example, if we need to turn this game into a multiplayer online game, and then we stipulate that the player's logic is processed locally, and the movement logic is processed on the server side, then the system becomes more complicated:

insert image description here

So you see, a very simple text adventure game can also be expanded into a complex program with quite a lot of modules and boundaries.

6. To sum up

As architects, we have to look carefully at exactly where we need to design architectural boundaries. Also, we have to figure out how much it will cost to fully implement these boundaries. At the same time, we must also understand how difficult it is to add later if these boundaries are ignored up front.

So as architects, what should we do? There is probably no general answer to this question.

On the one hand, as some very smart people have been telling us for years, future needs should not be abstracted, imaginary needs often do not exist in fact, and over-engineering is often worse than under-engineering. To be bad.

But on the other hand, if we find that we really need to set architectural boundaries in a certain position, but we have not prepared in advance, the cost and risk of adding boundaries are often very high.

That's the reality. As software architects, we must have a little foresight. Sometimes you have to rely on guesswork, sometimes you need to rely on past experience, and of course the most important thing is to use your brains. Software architects must carefully weigh costs and decide where architectural boundaries need to be designed, and whether these places need complete boundaries, partial boundaries, or negligible boundaries.

When problems arise, we also need to weigh the cost of achieving this boundary and compare it to the cost of not achieving this boundary. Our goal is to find the inflection point where the benefits of setting a boundary outweigh its cost, and that is the optimal time to achieve that boundary.

おすすめ

転載: blog.csdn.net/u011748319/article/details/126000410