Architecture and Design Patterns in Front-End

Writing comprehensible code is hard. Each line of code increases the reader's load, so it is difficult to read a lot of code. On the other hand, if the code lacks details and explanations, it is also very difficult to understand its meaning. When writing programmes, we need to keep a balance between brevity and completeness, between abstractions and concreteness. Finding this balance is helped by solutions that the community perceives as standard, template solutions. Sometimes these solutions get names and become patterns or architectural approaches. In this article, we will give a brief overview of architectural approaches and design patterns that are used in modern frontend. Overview Application architecture is a set of decisions about how application modules will communicate with each other and with the outside world. Architecture includes approaches: constraints, rules, and heuristics to follow when writing code. A design pattern is a pattern solution to a frequent architectural problem. The area of responsibility of design patterns is smaller than that of architecture in general. Patterns help us to solve problems at a "lower level", closer to the code itself. Architecture, on the other hand, solves design problems of the whole system. To simplify, architecture is the instruction "How to build a house in general", it covers the whole project. And patterns are instructions for specific tasks: "How to drive piles", "How to mix cement", "How to lay wiring". Architecture in the Front-End Modern frontend is complex. For complex systems to behave predictably, they need to be managed. Architecture helps solve the challenges of designing such systems. Why Architecture is Necessary Humans are not good at predicting the future. It is difficult for us to predict how a programme or its requirements will change. The only thing we know for sure is that the requirements (and therefore the programme) will change. Proper architecture helps to design and develop the system so that it is easier and more convenient to expand and change. If communication between modules is regulated, it is easier to replace their implementation with another one. If communication with the outside world is regulated, there are fewer chances for data leakage. If the code is divided intelligently, the programme is easier to test. If the code is organised in a clear way, it takes less time to add new features and search for bugs in old ones. If the architecture is widely known, immersion into the project is faster. What Architectural Approaches are Available We can roughly categorise architectural approaches according to their goals and scope. Part of the approach assigns responsibility to modules. They define which modules will be responsible for what. The best known of these approaches is the Model-View-Controller. It distinguishes 3 "types" of tasks, according to which it assigns roles to modules. Others determine how close each module is to the business logic. These approaches care about which part of the code deals directly with the application task and which part deals with infrastructure tasks. For example, in a photo processing app, the business logic would be filter functions and the infrastructure tasks would be accessing the phone's camera API. These approaches divide code into "layers" based on the degree of proximity to business logic. The most common approach among such approaches is the Three-Layer architecture. The third manages the data flows in the application. They determine how modules communicate with each other: directly, indirectly, or through special services like the event bus. In frontend, the most probably well-known approach is Flux and its most common implementation, Redux. This is an example of unidirectional data flow. In addition to it, bidirectional flow is used, such as reactive data updates. We talk about each in detail in the article "Architecture: Data Flows". Other approaches define the layout of the application. Whether it will be one large programme (monolith) or a set of several smaller programmes (microservices). What are the Disadvantages of Architecture Creating, organising, and following an architecture always requires resources: time, money, and mental effort. The choice should be made after comparing the costs and benefits of each candidate approach. Design Patterns Some problems are too small to be isolated into an architectural approach, but are common enough to spawn standard solutions. Such standard solutions are called patterns or templates. For example, the server sends us data in the form of: { some_data: ["Name", "LastName"] } And that's what we want them to be: { someData: "Name LastName" } There is an Adapter pattern to solve such a problem. It makes an incompatible third-party API suitable for our application. function serverToClientAdapter(data) { return { someDa

Apr 27, 2025 - 15:43
 0
Architecture and Design Patterns in Front-End

Writing comprehensible code is hard.

Each line of code increases the reader's load, so it is difficult to read a lot of code. On the other hand, if the code lacks details and explanations, it is also very difficult to understand its meaning. When writing programmes, we need to keep a balance between brevity and completeness, between abstractions and concreteness.

Finding this balance is helped by solutions that the community perceives as standard, template solutions. Sometimes these solutions get names and become patterns or architectural approaches.

In this article, we will give a brief overview of architectural approaches and design patterns that are used in modern frontend.

Overview

Application architecture is a set of decisions about how application modules will communicate with each other and with the outside world.

Architecture includes approaches: constraints, rules, and heuristics to follow when writing code.

A design pattern is a pattern solution to a frequent architectural problem.

The area of responsibility of design patterns is smaller than that of architecture in general. Patterns help us to solve problems at a "lower level", closer to the code itself. Architecture, on the other hand, solves design problems of the whole system.

To simplify, architecture is the instruction "How to build a house in general", it covers the whole project. And patterns are instructions for specific tasks: "How to drive piles", "How to mix cement", "How to lay wiring".

Architecture in the Front-End

Modern frontend is complex. For complex systems to behave predictably, they need to be managed. Architecture helps solve the challenges of designing such systems.

Why Architecture is Necessary

Humans are not good at predicting the future. It is difficult for us to predict how a programme or its requirements will change. The only thing we know for sure is that the requirements (and therefore the programme) will change.

Proper architecture helps to design and develop the system so that it is easier and more convenient to expand and change.

  • If communication between modules is regulated, it is easier to replace their implementation with another one.
  • If communication with the outside world is regulated, there are fewer chances for data leakage.
  • If the code is divided intelligently, the programme is easier to test.
  • If the code is organised in a clear way, it takes less time to add new features and search for bugs in old ones.
  • If the architecture is widely known, immersion into the project is faster.

What Architectural Approaches are Available

We can roughly categorise architectural approaches according to their goals and scope.

Part of the approach assigns responsibility to modules. They define which modules will be responsible for what.

The best known of these approaches is the Model-View-Controller. It distinguishes 3 "types" of tasks, according to which it assigns roles to modules.

Others determine how close each module is to the business logic. These approaches care about which part of the code deals directly with the application task and which part deals with infrastructure tasks.

For example, in a photo processing app, the business logic would be filter functions and the infrastructure tasks would be accessing the phone's camera API.

These approaches divide code into "layers" based on the degree of proximity to business logic. The most common approach among such approaches is the Three-Layer architecture.

The third manages the data flows in the application. They determine how modules communicate with each other: directly, indirectly, or through special services like the event bus.

In frontend, the most probably well-known approach is Flux and its most common implementation, Redux. This is an example of unidirectional data flow.

In addition to it, bidirectional flow is used, such as reactive data updates. We talk about each in detail in the article "Architecture: Data Flows".

Other approaches define the layout of the application. Whether it will be one large programme (monolith) or a set of several smaller programmes (microservices).

What are the Disadvantages of Architecture

Creating, organising, and following an architecture always requires resources: time, money, and mental effort. The choice should be made after comparing the costs and benefits of each candidate approach.

Design Patterns

Some problems are too small to be isolated into an architectural approach, but are common enough to spawn standard solutions. Such standard solutions are called patterns or templates.

For example, the server sends us data in the form of:

{
  some_data: ["Name", "LastName"]
}

And that's what we want them to be:

{
  someData: "Name LastName"
}

There is an Adapter pattern to solve such a problem. It makes an incompatible third-party API suitable for our application.

function serverToClientAdapter(data) {
  return {
    someData: data.some_data.join(" "),
  }
}

There are many such standard solutions. We can divide them into several groups.

Progenitors

Generating patterns help solve problems with the creation of entities or groups of similar entities. They remove unnecessary duplication and make the process of creating entities shorter and more straightforward.

Among the generating patterns we can distinguish:

  • "Factory";
  • "Factory Method";
  • "Abstract Factory."
  • "Builder."

Structural

Structural patterns help to solve the problems of matching and combining entities. They take care of how entities can use each other.

Among the structural patterns we can distinguish:

  • "Adapter";
  • "Decorator";
  • "Facade";
  • "Proxy.

Behavioural

Behavioural patterns allocate responsibility between modules and determine exactly how communication will take place.

Among the behavioural patterns we can distinguish:

  • "Chain of Responsibility."
  • "Strategy."
  • "Team."
  • "Observer."

Architecture and Patterns are not the Goal

Every design approach and pattern is first and foremost a means to solve problems. Developers should not treat them as a goal when writing code.

Sometimes a solution without a complex architecture will be simpler and faster. For example, when developing a prototype, architecture is often unnecessary.

Architectural approaches and patterns are tools. We advise bringing tools to a project as needed and comparing the benefits and costs of each.

Support ❤️

It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.

Make a contribution or Subscription to the author's content: Buy me a Coffee, Patreon, PayPal.