"Where do legs grow from" or what precedes programming?

Hello everyone! The other day, as part of the OTUS educational platform, a new course is launched: “Architecture and Design Patterns” . In connection with the start, we held a traditional open lesson . It studied the features of a monolithic application, multi-level and serverless architectures. We examined in detail the event-driven system, the service-oriented system, and the microservice architecture.



The teacher is Matvey Kalinin , a specialist with more than 20 years of programming experience and the author of the course “Architecture and Design Patterns”.

A little background


Initially, the programs really solved the task set for themselves and were quite isolated. But over time, programs grew, and people began to understand that the emerging complexity of the functional begins to affect the speed of improvements, reliability and resistance to various kinds of complications.

Indeed, when we have one or two programs that are the same and do not change, writing these programs and ensuring their interaction is not difficult. But when there are more and more of them, problems cannot be avoided, and it does not matter what kind of software package is involved.

Today, applications, for the most part, are distributed. They consist of several modules and are interconnected by system messages. That is, a rather large conglomerate of programs interacting with each other is obtained. And for them to interact successfully, we need to consider:

  • quick response;
  • bandwidth
  • performance in terms of one resource unit;
  • ability to scale;
  • integration capabilities;
  • features of the used platforms;
  • features of existing business processes;
  • and much more


At the same time, one cannot help but recall the following quote:

“The correct program code does not require large labor costs for its creation and maintenance. Changes are made quickly and easily. Errors are few. Labor costs are minimal, while functionality and flexibility are maximum . ”

Robert Cecil Martin

That is, writing the program ideally once (if it is well written), the improvements will be minimal. How to achieve this and link one and the other? To answer this question, we turn to history.


?


So, we realized that we need to properly structure the software product. But what is the purpose of software architecture? And anyway, why did we use the phrase “legs grow” in the title of this article?

The thing is that when you start programming, you already know what you want to build. Initially, it all starts with a business process. There is an order and a customer who describes (at least in words) how his system should work. And at first this system exists only in the form described by it. Then this process is formalized and outlined, but this is still half the battle, because further development begins. And the developer needs to convert this process into a software product, which should ...

Then it's time to recall another quote:

"The goal of software architecture is to reduce the human labor required to create and maintain a system."

Robert Cecil Martin


It should not be surprising that the goal is formed by such general phrases. The fact is that architecture lives in abstract ideas. Why? Because the person who is engaged in software architecture transforms the vision of a business customer into a developer’s vision . And if we are talking about the architect of the development team and the Enterprise architect, then each of them has a different goal, but both of them strive for one thing - to reduce human labor costs.

In this context, it is interesting to look at the values ​​of software:

  • The code meets the requirements of the business process;
  • there is the possibility of a quick change in behavior.

And here the question begs: why is it more important, the operation of the system or the simplicity of changing it ? To answer it, let's look at the program from the point of view of utility:

If there is a correctly working program that does not allow changes, then such a program will eventually become irrelevant - when the requirements change.

If the program does not work correctly, but changes can be made in it, then it can be made to work correctly within the framework of changing requirements. This program will remain useful always.

Paradigms (models) of programming


What do you think is the most famous (very first) programming model? Of course, a monolith . It is appropriate here again for a moment to return to 1968 and recall Edsger Dijkstra, who showed that the uncontrolled use of transitions (goto instructions) is harmful to the structure of the program. He suggested replacing the transitions with more understandable if / then / else and do / while / until constructs.

Now goto instructions can be seen less often. But before, goto instructions were very common. In general, this is a form of evil, because when you see the code in which there is a goto instruction, you get the feeling that you might not find the very point where it goes. And the more goto, the more complicated, that is, we get the spaghetti code. We now call that code “spaghetti”, where, for example, 20 nested ifs and, possibly, one goto. This is also not very clear code. Imagine that you have goto 10-15, and you are trying to understand how the cycle works - that is what Dijkstra had in mind.

Spaghetti code is a poorly structured, confusing, and difficult to understand program that contains many goto statements (especially jumps), exceptions, and other constructs that degrade structure. In general, a well-known and fairly common antipattern of programming. Such a program takes a lot of time to understand, support and test.

Structural programming


There were programming languages, they realized some goals. Until a certain point, the structure of the programs did not greatly affect the implementation. But the programs grew, between them numerous ties formed. And at one point, a person felt that it was important to pack the algorithm into a structure that was easy to read, tested. Changes have begun at the program structure level. That is, not only the program itself had to satisfy the result, but the program structure also had to meet some criterion.

Thus, we smoothly switched to structural programming . According to him, the program is built without using the goto operator and consists of three basic control structures:

  • sequence,
  • branching
  • cycle.

Subprograms are used, the development itself is carried out step by step, from top to bottom.
And again, back in 1966 ... This year, Ole-Johan Dahl and Kristen Nyugor noticed that in the ALGOL language it is possible to move the frame of the function call stack to dynamic memory (heap), so that local variables declared inside the function can be saved after exit from it. As a result, the function turned into the constructor of the class, local variables into instance variables, and nested functions into methods. This led to the discovery of polymorphism through the strict use of function pointers.

Object oriented programming


As you all know, in OOP, programs are represented as a collection of objects, each of which is an instance of a particular class, and classes form an inheritance hierarchy.

Basic principles of structuring:

  • abstraction;
  • inheritance;
  • polymorphism.

You can look at all these principles from another perspective. Robert Martin developed the principles of SOLID, which, on the one hand, determine how a programmer works with abstractions, and on the other hand, form the process of polymorphism, inheritance.

Imperative programming


An imperative program is similar to the orders that a computer must execute. Such programs are characterized by:

  • instructions are written in the source code of the program;
  • instructions must be followed sequentially;
  • data obtained during the execution of previous instructions can be read from memory by subsequent instructions;
  • data obtained by executing the instruction can be written to memory.

Also a very ancient design. The main features of imperative languages:

  • use of named variables;
  • use of assignment operator;
  • use of compound expressions;
  • use of routines.

However, we continue the “time travel”. This time we will return for a moment in 1936 (!). It is interesting that this year Alonzo Church invented the lambda calculus (or λ-calculus), which later, in 1958, formed the basis of the LISP language invented by John McCarthy. The fundamental concept of λ-calculus is immutability - that is, the impossibility of changing the values ​​of symbols.

Functional programming


Functional programming involves doing the calculation of the results of functions from the source data and the results of other functions and does not imply explicit storage of the state of the program.

In fact, this means that a functional language does not have an assignment statement.

Let's look at the difference between imperative and functional styles using an example:

#  
target = []  #   
for item in source_list:  #     
    trans1 = G(item)  #   G()
    trans2 = F(trans1)  #   F()
    target.append(trans2)  #     
#  
compose2 = lambda A, B: lambda x: A(B(x))
target = map(compose2(F, G), source_list)

So what is software architecture?


Software architecture is a set of decisions about the organization of a software system.

It includes:

  • selection of structural elements and their interfaces;
  • the behavior of the selected elements and interfaces, their interaction;
  • combining selected elements of structure and behavior into larger systems;
  • architectural style that guides the whole organization.

Please note: first we came to the conclusion that goto did not suit us, then we saw that there are certain rules (encapsulation, inheritance, polymorphism), then we realized that these rules do not just work, but in accordance with certain principles. The fourth point is the architectural style, and we will talk about it later.

The main purpose of the architecture is to support the life cycle of the system. Good architecture makes the system easy to learn, easy to develop, maintain and deploy. The ultimate goal is to minimize costs over the life of the system and maximize the productivity of the programmer, and more precisely, the development team.

At first we talked about what rules we needed to write programs. But, in addition to writing programs, there is also support, development and deployment. That is, the architecture does not capture a certain area of ​​programming, but the entire development cycle.

A good architecture should provide:

  1. A variety of use cases and effective system operation.
  2. Simplicity of system maintenance.
  3. Ease of system design.
  4. Easy system deployment.

Architectural styles


Monolith


First of all, let's talk about the well-known monolith . This style is still found, however, in small systems. Monolithic architecture means that your application is a large, connected module. All components are designed to work together, share memory and resources. All functions or their main part are concentrated in one process or container, which is divided into internal layers or libraries.



Advantages:

  1. Easy to implement. No need to waste time thinking about interprocess communication.
  2. Easy to develop end-to-end tests.
  3. Easy to deploy.
  4. Easily scale with Loadbalancer across multiple instances of your application.
  5. Easy to operate.



But now he has more shortcomings :

  1. Strong cohesion leads to entanglement with the evolution of the application.
  2. Independent scaling of components leads to complication and complete retest of functionality.
  3. More difficult to understand.
  4. As complexity increases, development time grows.
  5. Lack of isolation of components.

On the one hand, the monolith is good, but as soon as you begin to develop it, difficulties arise.

What is a service?


Now everyone knows what a service is. It can be defined as a visible resource that performs a repetitive task and is described by an external instruction.

Modern services have the following features :

  • services are oriented not on IT capabilities, but on business needs;
  • services are self-sufficient and are described in terms of interfaces, operations, semantics, dynamic characteristics, policies and properties of the service;
  • reuse of services is provided by their modular planning;
  • service agreements are concluded between entities called suppliers and users, and do not affect the implementation of the services themselves;
  • during its life cycle, services are hosted and made visible through service metadata, registries, and repositories;
  • aggregation: combining business processes and complex applications for one or several enterprises are built on loosely coupled services.

As a result of the above features, the concept of service-oriented architecture (SOA) arose.

Service Oriented Architecture (SOA)


SOA is an architectural style for creating an enterprise IT architecture, using the principles of service orientation to achieve a close connection between the business and its supporting information systems.



SOA has the following characteristics :

  1. Improves the relationship between enterprise architecture and business.
  2. Allows you to create complex applications from sets of integrated services.
  3. Creates flexible business processes.
  4. It does not depend on a set of technologies.
  5. Autonomous in the sense of independent evolution and deployment.

An SOA deployment model consists of business intelligence and development and IT intelligence and development. The assembly consists of programming services and building complex applications. Hosting consists of hosting applications and runtime tools such as Enterprise Service Buses (ESBs). As for the manual , it consists of supporting the operating environment, monitoring the performance of services and monitoring compliance with service policies.



Microservice architecture


It's time to talk about microservice architecture . In it, the application consists of small independent service applications, each with its own resources. Services interact with each other to perform tasks related to their business opportunities. There are several deployment units. Each service is deployed independently.



Advantages:

  1. Supports modularity of the entire system.
  2. Unrelated services are easier to modify to serve different applications.
  3. Different services may belong to different teams.
  4. Service services can be reused throughout the company.
  5. Easier to understand and test.
  6. Not tied to the technology used in other services.
  7. The isolation of the service increases the overall reliability of all the functionality.



Disadvantages:

  1. Difficulties with the implementation of the overall functionality (logging, access rights, etc.).
  2. It is difficult to conduct end-to-end system tests.
  3. Harder operation and support.
  4. More equipment is needed than for a monolith.
  5. Support by several teams leads to coordination of interaction between them.

It is worth noting that in this architecture it is very difficult to do anything without DevOps.

Layered architecture


Layered architecture is the most common architecture pattern. It is also called n-tier architecture, where n is the number of levels.

The system is divided into levels, each of which interacts with only two neighboring ones.

Architecture does not imply any mandatory number of levels - there can be three, four, five or more. Most often, three-tier systems are used: with a presentation level (client), a logic level, and a data level.
The most common layers are :

  • presentation layer (for working with users);
  • application layer (service - security, access);
  • business logic layer (domain implementation);
  • data access layer (representation of the interface to the database).

Closed layers


The concept of isolation of levels strictly separates one level from another: you can only go from one level to the next and you can’t jump immediately through several.



Open layers


The system allows you to jump over open levels and fall on those located below.



MVC


The concept of MVC was described in 1978. The final version of the MVC concept was published only in 1988 in the journal Technology Object.

The main goal is to separate the business logic (model) from its visualization (presentation, view). What does it give:

  • The possibility of code reuse is increased.
  • the user can see the same data simultaneously in different contexts.



The model provides data and responds to controller commands, changing its state. The view is responsible for displaying model data to the user, responding to model changes. The controller interprets user actions, notifying the model of the need for changes.



Event Driven Architecture


Another interesting architecture. It is used in the development and implementation of systems that transmit events among loosely coupled software elements.

Consists of disparate single-purpose event processing components that receive and process events asynchronously.

The template consists of two main topologies - an intermediary and a broker.

Reseller Topology


There are processes where control over the sequence of steps is needed. Here we are useful intermediary.

The main types of architecture components:

  • event queues;
  • mediator of events;
  • channels of events;
  • event handlers.

Event An

event can be defined as a “significant change in state”. An event can consist of two parts:

  • header (event name, timestamp for the event, and type of event);
  • body (describes what actually happened).

Mediator topology

The client sends an event to the event queue, which is used to send the event to the mediator.

The mediator receives the initial event and sends additional asynchronous events to the event channels for each step of the process.

Event processors that listen for event channels receive an event from an intermediary and execute certain business logic by processing the event.



Broker topology

The broker's topology differs from the intermediary topology in that there is no central event mediator. The message flow is distributed among the event processor components in a chain through a lightweight message broker (for example, ActiveMQ, HornetQ, etc.). This topology is useful when there is a relatively simple flow of event processing and there is no need for a centralized event orchestration.

Each component of an event-processor is responsible for processing an event and publishing a new event indicating the action just completed.



If the first situation was asynchronous “somewhere below”, then the second situation is asynchronous, one might say, completely. One event generates several events, and they can increase and increase.

Advantages event driven architecture:

  • the components are isolated and allow each one to be finalized without affecting the rest of the system;
  • ease of deployment;
  • high performance. Allows parallel asynchronous operations;
  • scales well.

Disadvantages:

  • difficult to test;
  • difficult to develop due to pronounced asynchrony.

Serverless architecture


This is a way to create and run applications and services without the need for infrastructure management. The application still runs on the servers, but the platform completely takes control of these servers.

The entire infrastructure is supported by third-party providers, and the necessary functionality is offered in the form of services that are responsible for authentication, message passing, etc.

The following terminology is distinguished:

  1. (Function-as-a-Service) — , .
  2. (Backend as a Service) — , - API, . , , , .

If we consider the architecture of “Client-server”, then most of the logic in the system (authentication, page navigation, search, transactions) is implemented by the server application.



In serverless architecture, everything is somewhat different. Authentication is replaced by a third-party BaaS service (ready-made cloud service), access to the database is also replaced by another BaaS service. The application logic is partially already inside the client - for example, tracking a user's session.

The client is already on its way to becoming a one-page application. Search can be done through the search service (FaaS - function as a service). The purchase function is also isolated from the customer as a separate service (FaaS).



Well, that's all, if you are interested in the details, watch the entire video. As for the new course, you can familiarize yourself with its program here.

All Articles