DEV Community

Cover image for Clean Architecture: Business rules first!
Nicolas Lapointe
Nicolas Lapointe

Posted on • Edited on

Clean Architecture: Business rules first!

With this third article on Clean Architecture, let's go into a little more detail! The first article gave an overview of Clean Architecture, followed by a second on the separation between Core (business code) and Infrastructure (technical code). In this article, we're going to look at the Core part, and therefore the business rules, its central role in design and so as an essential (main!) element of Clean Architecture.

Obvious application behavior!

It seems obvious to say it: business rules and features are what govern the behavior of an application, and therefore its design. And yet... Many applications find themselves constrained by the technical aspect that takes precedence, or prevents a rule from evolving.

And that's exactly why I like Clean Architecture: we're simply putting back the basics, which existed years ago. It recognizes the value of business rules, and brings them to the fore. They're not just lines of code, but the pillars on which the design structure rests.

Let's delve into the foundations and examine how it ensures that business rules come first.

Business rules: the foundation of the application

Business rules represent the very essence of what an application does. They define how data is to be manipulated, what actions can be performed and under what circumstances. In short, they are the rules of the game that dictate the application's behavior in all possible situations.

And they must directly influence the way an application is designed and implemented. Quite simply, they must guide the architectural and structural decisions made throughout the development process.

Entities: bearers of business rules

At the heart of Clean Architecture are a set of entities, the main actors that embody the application's business rules from a code standpoint. They encapsulate data and essential business logic. If we take our theme from the play in the previous article, the entities would be the protagonists, carrying the weight of decisions and actions on their shoulders.

  • Role of entities: Entities represent the fundamental objects of the business domain, such as users, products or orders. They capture the business rules specific to these objects, and ensure that they are respected at all times at this single point in the code base.
  • Entity independence: Entities maintain strict independence from technical details. They remain focused on their core responsibility: faithfully representing the business domain, that's all! This independence allows entities to evolve independently of the underlying infrastructure, guaranteeing their reusability and extensibility.

Let's take a look at an example of Typescript code for a :

export class ExistingUser extends User {
  private _id: string;

  constructor({ id }: ExistingUserConstructorArgs) {
    super();
    this._id = id;
  }

  public signAndEncodeUserAccessToken() {
    const accessToken = sign({ sub: this._id }, this.config.secret, {
      expiresIn: 86400, // 24 hours
    });
    return accessToken;
  }

  public get id() {
    return this._id;
  }
}
Enter fullscreen mode Exit fullscreen mode

This entity, which represents an application user, includes a data element (id) and a method or business rule (access token generation).

Use Cases: Executors of business rules

Just as entities represent the central objects of the business domain, use cases direct the execution of rules by coordinating the interactions between the various players in the application - a master of ceremonies in itself!

  • Role of Use Cases: Use cases act as script writers, defining the actions users can perform and the responses the application must provide in return. They translate business requirements into concrete actions.
  • Coordination with Entities: In executing use cases, entities provide the data required to meet the specific business needs defined by each use case. In our theater, this is the coordination between our protagonists and the texts of the play's overall scenario, our application.

Let's look at another example from the code side, for a Use Case :

async execute(
    login: string,
    password: string,
  ): Promise<{ accessToken: string } | 'USER_NOT_FOUND'> {
    this.logger.debug('[Get-user usecase] Start');
    const notExistingUser = new NotExistingUser();
    const user = await this.userRepository.findByLoginAndPassword(
      login,
      notExistingUser.hashPassword(password),
    );
    return user
      ? { accessToken: user.signAndEncodeUserAccessToken() }
      : 'USER_NOT_FOUND';
  }
Enter fullscreen mode Exit fullscreen mode

There's an execution method, which represents our scenario. What does this scenario do? It will use a method to retrieve a user from the database, and user entities to use business methods, such as the generation of an access token seen above.

Alignment with Clean Architecture

Clean Architecture recognizes the importance of business rules in application design. It puts these rules at the forefront of design, and ensures that every development choice is aligned with the application's business needs.

Modularity and scalability of Entities and Use Cases

The application's entire business logic is based on entities and use cases. Designed to be modular and scalable, they provide a solid basis for development.

Modularity: Entities and use cases are designed to be easily modifiable and extensible. This modularity means that new functionalities can be added or existing ones modified without compromising the integrity of the application.

Scalability: Entities and use cases are also designed to evolve with the changing needs of the application. For example, the addition of a new business rule can be easily integrated without disrupting existing parts of the application.

Robustness and scalability

This modular, scalable design of entities and use cases naturally leads to greater robustness and scalability of the application.

Robustness: Because business logic is isolated from the rest of the application, Clean Architecture ensures that business rules are applied consistently and reliably. This reduces the risk of errors and bugs.

Scalability: Modularity and scalability, and therefore adaptability to future growth in functionality or other developments. Clean Architecture provides a solid foundation on which to build and extend the application over time.

Maintaining alignment with business needs

By always keeping an eye on business needs, Clean Architecture ensures that application development remains aligned with them. This approach ensures that every feature developed responds directly to a specific business need, guaranteeing the application's relevance and added value.

This article is an introduction to Clean Architecture and is part of a dedicated series on this topic. Stay tuned for more!

Want to learn how implement it with typescript and express? See my udemy course! In french or english 😉

Articles on Clean Architecture:

Top comments (0)