Hello friends. On the eve of the launch of the course
“Backend Developer in PHP” , we traditionally share with you the translation of useful material.
The software solves more and more everyday tasks, while becoming more and more difficult. As Mark Andressen once said, it absorbs the world.

')
As a result, over the past few years, approaches to developing and delivering applications have seriously changed. These were tectonic shifts that resulted in the emergence of a set of principles. These principles have proven to be useful in team building, designing, developing, and delivering your application to end users.
The principles can be summarized as follows: the
application must be small, networked, and have a developer-oriented architecture . Based on these three principles, you can create a reliable, integrated application that can be quickly and safely delivered to the end user, and easily scaled and expanded.

Each of the proposed principles has a number of aspects that we will discuss in order to show how each principle contributes to the achievement of the ultimate goal, which is to quickly deliver reliable applications that are easy to maintain and use. We will consider the principles in comparison with their opposites, in order to clarify what it means, let's say, "Make sure that you use the
principle of smallness ."
We hope that this article will encourage you to use the proposed principles for building modern applications that will provide a unified approach to design in the context of a continuously growing stack of technologies.
By applying these principles, you will find that you are using the latest trends in software development, including the
DevOps approach to developing and delivering applications, using containers (for example,
Docker ) and container orchestration frameworks (for example,
Kubernetes ), using microservices (including the
NGINX Microservice Architecture). and
network communication architecture for microservice applications.
What is a modern application?Modern applications? Modern stack? What exactly does “modern” mean?
Most developers have only a general idea of what constitutes a modern application, so it is necessary to give a clear definition of this concept.
A modern application supports several clients, whether it is the user interface in the JavaScript React library, a mobile application for Android or iOS, or an application that connects to another via the API. A modern application implies an unspecified number of clients for which it provides data or services.
A modern application provides an API for accessing the requested data and services. API should be constant and constant, and not written specifically for a specific request from a particular client. The API is available over HTTP (S) and provides access to all the functionality that is in the GUI or CLI.
The data must be available in a common, compatible format, such as JSON. The API provides objects and services in a clear, organized form, for example, a RESTful API or GraphQL provides a decent interface.
Modern applications are built on a modern stack, and a modern stack is one that supports such applications, respectively. This stack allows the developer to easily create an application with an HTTP interface and clear endpoints API. The chosen approach will allow your application to easily receive and send data in JSON format. In other words, a modern stack corresponds to elements of the Twelve-Factor
microservice application.
Popular versions of this type of stack are based on
Java ,
Python ,
Node ,
Ruby ,
PHP and
Go . The
NGINX microservice architecture embodies an example of a modern stack implemented in each of the languages mentioned.
Please note that we do not advocate an exclusively microservice approach. Many of you work with monoliths that need to evolve, while others deal with SOA applications that expand and evolve to become microservice applications. Still others are moving towards using serverless applications, and some are implementing combinations of the above. The principles outlined in the article apply to each of these systems with only a few minor changes.
PrinciplesNow that we have a common understanding of what a modern application and modern stack are, it is time to dive into the principles of architecture and development that will serve you well in developing, implementing and maintaining a modern application.
One of the principles sounds like “create small applications,” let's just call it the
principle of smallness . There are incredibly complex applications that consist of a large number of moving components. In turn, building an application from small discrete components simplifies its design, maintenance, and work with it as a whole. (Notice, we said “simplifies,” not “makes it simple.”)
The second principle is that we can increase the productivity of developers by helping them focus on the functions they develop, while freeing them from infrastructure and CI / CD worries during implementation. So, in a nutshell, our approach is
focused on developers .
Finally, everything related to your application must be connected to the network. Over the past 20 years, we have made great strides toward the network future, because networks have become faster and applications are more complicated. As we have already found out, a modern application should be used over the network by many different clients. The use of network thinking in architecture has significant advantages that are well combined with the
principle of smallness and the concept of a
developer-oriented approach.
If during the development and implementation of the application you will remember these principles, you will have an undeniable advantage in the development and delivery of your product.
Let's look at these three principles in more detail.
Principle of smallnessThe human brain is difficult to simultaneously perceive a large amount of information. In psychology, the term cognitive load means the total amount of mental effort required to store information in memory. Reducing the cognitive burden on developers is a priority, because in this case they can focus on solving the problem, instead of keeping in mind the current integrated model of the entire application and the functions being developed.
Applications are decomposed for the following reasons:
- Reducing cognitive load on developers;
- Acceleration and simplification of testing;
- Fast delivery of changes in the application.
There are several ways to reduce the cognitive load on developers, and it is here that the principle of smallness comes into play.
So, three ways to reduce cognitive load:
- Reduce the time frame that they should take into account when developing a new function - the shorter the timeframe, the lower the cognitive load.
- Reduce the amount of code over which one-time work is carried out - less code - less load.
- Simplify the process of making incremental changes to the application.
Reduced development time frameLet's go back to the days when the
waterfall
methodology was the standard for the development process, and the time frame from six months to two years for developing or updating the application was common practice. As a rule, engineers first read the relevant documents, such as product requirements (PRD), system reference document (SRD), architecture plan, and started to combine all these things together into one cognitive model, according to which they wrote the code. As the requirements and, accordingly, the architecture changed, it was necessary to make serious efforts to inform the whole team about the updates of the cognitive model. In the worst case, such an approach could simply paralyze the work.
The biggest change in the application development process was the introduction of the agile methodology. One of the main features of the
agile
methodology is iterative development. In turn, this leads to a decrease in cognitive load on engineers. Instead of requiring the development team to implement the application in one long cycle, the
agile
approach allows you to focus on small amounts of code that can be quickly tested and deployed, while also receiving feedback. The cognitive load of the application has shifted from a timeframe from six months to two years, taking into account the huge amount of specifications for a two-week addition or change of function, focused on a more vague understanding of a large application.
The shift in focus from a massive application to specific small functions that can be completed in a two-week sprint, with no more than one function looking forward from the next sprint in the head, is a significant change. This made it possible to increase the productivity of development while reducing the cognitive load, which constantly fluctuated.
The
agile
methodology assumes that the final application will be a slightly modified version of the original concept, so the final development point is necessarily ambiguous. Only the results of each specific sprint can be clear and precise.
Small code basesThe next step in reducing cognitive load is reducing the code base. As a rule, modern applications are massive - reliable, a corporate application can consist of thousands of files and hundreds of thousands of lines of code. Depending on the organization of the link files and the dependencies of the code and files may be obvious or vice versa. Even debugging the execution of the code itself can cause problems, depending on the libraries used and how well the debugging tools distinguish between the libraries / packages / modules and user code.
Building a working mental model of the application code can take an impressive amount of time, and once again impose on the developer a great cognitive load. This is especially characteristic of monolithic code bases, where there is a large amount of code, the interaction between the functional components of which is not clearly defined, and the separation of objects of attention is often blurred, since functional boundaries are not observed.
One of the effective ways to reduce the cognitive load on engineers is the transition to the microservice architecture. In the microservice approach, each service focuses on one set of functions; while the meaning of the service is usually defined and understood. The boundaries of the service are also clear - remember that communication with the service is done using an API, so the data generated by one service can easily be transferred to another.
Interaction with other services is usually limited to several user services and several provider services that use simple and clean API calls, for example using REST. This means that the cognitive load on the engineer is seriously reduced. The most difficult task is to understand the model of interaction between services and how such things as transactions occur in several services. In summary, the use of microservices reduces cognitive load by reducing the amount of code, denoting clear service boundaries and providing an understanding of the relationship between users and providers.
Small incremental changesThe last element of the
small principle is change management. A special temptation for developers is to look at the code base (even, perhaps, on their own, older code) and declare: “This is crap, we need to rewrite it all.” Sometimes this is the right decision, and sometimes not. It imposes on the development team the burden of a global model change, which in turn leads to a massive cognitive load. It is better that engineers focus on the changes that they can make during the sprint, in order to roll out the necessary functionality in a timely manner, albeit gradually. The final product should resemble a pre-planned, but with some changes and testing to meet the needs of the client.
When rewriting large parts of the code, sometimes it is impossible to quickly deliver the change, because other system dependencies come into play. In order to control the flow of changes, you can use feature hiding. In principle, this means the functionality is on the production, but it is not available using the environment variable settings (env-var) or some other configuration mechanism. If the code has passed all quality control processes, then it may be in production in a hidden state. However, this strategy only works if the feature is eventually enabled. Otherwise, it will only clutter up the code and add cognitive load, which the developer will have to cope with for productive work. Change management and incremental change in and of themselves help maintain the cognitive load of developers at an affordable level.
Engineers have to overcome many difficulties, even with the simple introduction of additional functionality. On the part of the management, it would be prudent to reduce the extra burden on the team so that it can focus on the key elements of the functionality. There are three things you can do to help your development team:
- Use
agile
methodology to limit the time frame in which the team should focus on key functions. - Implement your application as several microservices. This will limit the number of functions to be implemented and will strengthen the boundaries that keep cognitive load during work.
- Prefer incremental changes to large and cumbersome, change small pieces of code. Use function hiding to implement changes, even if they are not immediately visible after being added.
If you apply the principle of smallness in your work, your team will become much happier, focus better on the implementation of the necessary functions and are more likely to roll out qualitative changes faster. But this does not mean that the work can not become complicated, sometimes on the contrary, the introduction of new functionality requires the modification of several services and this process can be more complicated than the analogous one in the monolithic architecture. In any case, the benefits of applying the approach are worth it.
The end of the first part.
Soon we will publish the second part of the translation, and now we are waiting for your comments and invite you to
the open day , which will be held today at 20.00.