Architecture Patterns in Python

Pablo Campillo
Version 1
Published in
4 min readAug 30, 2023

Complex Software Systems tend toward chaos what is called the Big Ball of Mud anti-pattern. From Version 1 we deal with complexity using Domain Driven Development (DDD) among other methodologies. This post introduces a little example of how to design and organise properly your code using DDD patterns such as repository, service layer, unit of work and adapters.

The repository with the proposed solution is hosted at https://github.com/pablo-campillo/organization_auth.

System Requirements

The problem we are going to face is to develop a system that manages permissions for an organization using roles. The system aims at generating access tokens for users with information about the groups they belong to and with which role. Besides, a command line client will be created to interact with the system.

In the figure below you can see a snapshot of the command that displays the organization in a tree view. Every organization is composed of a set of teams. Each user can belong just to a team and to none, one or many groups of its team. Each group has a list of allowed roles for users and one is marked as default. Each user is added to a group with a given role. You can specify it (one of the list) or not (the default one is assigned).

Snapshot of the oa tree command.
Snapshot of the command for displaying all entities.

Finally, for a given user the system must provide an access token with coded information about the groups and roles the user belongs to. For example, an access token for MyUser1 that belongs to two groups with Admin roles would be:

Snapshot of access token example.
Snapshot of access token generated with command line tool for MyUser1.

Architecture Patterns Introduction

Before providing a solution, a short introduction of architectural patterns and layers employed will be presented. Software must be built into layers. A key concept is that each layer is built based on layers below and they must depend only on abstractions. Commonly, four layers are used:

  • Domain: It is the highest level of abstraction and contains all the elements related to the problem and business logic. Here you can find Entities, Object Values, Aggregates and Services.
  • Adapters: They represent all the code that depends on a specific technology. For example, here we find the repository patterns for abstract querying and serializing objects in a storage system. But you can also find code to send emails using a given provider.
  • Service Layer: It takes care of orchestrating our workflows and defining the use cases of our system. It contains a sublayer and pattern called a Unit of Work that oversees the abstract of our idea of atomic operations.
  • Application Layer: is the connection point of a user or a system with the services layer. An example of an application layer could be an API or a command line tool.

Solution Design

A common mistake when facing a software design is to start modelling the database schema instead of modelling the business logic or functionalities. It is even more important if we are going to use no-SQL databases where their design depends heavily on the required queries.

So, we start designing the service layer with all the services we need to achieve our requirements. Then, we model the domain layer with the entities and services required and finally, we design the repositories (database models) and units of work.

Of course, we create unit, integration or end-to-end tests before every implementation depending on the case, trying to keep a testing pyramid shape. Abstract classes allow us to implement new fake classes for testing. For example, a fake repository. We prefer fake classes over mocking since they make testing clearer and help you to keep a better design.

In the figure below we can see a diagram of our architecture proposal. We can check how it is decoupled and there is high cohesion inside the layers.

Architecture diagram of the Organization Auth solution.
Architecture Diagram of the Organization Auth solution.

Conclusions

In this post, a global overview of architectural patterns has been presented. Besides an application example has been provided and some tips about how to properly design it.

It is intended to be the first of a series of posts where more details or features will be added. For example, how much it would cost to change the database for Postgres? or send an email to an administrator when a new team is created? or access to the services using FastAPI? or integrate it in dapr (Distributed Application Runtime)?

--

--