search
HomeBackend DevelopmentPython TutorialBuilding Maintainable Python Applications with Hexagonal Architecture and Domain-Driven Design

In today’s fast-paced software development landscape, building applications that are easy to maintain, adapt, and scale is crucial. Hexagonal Architecture (also known as Ports and Adapters) and Domain-Driven Design (DDD) are an effective combo for addressing these challenges. Hexagonal Architecture promotes clean separation of concerns, making it easier to replace, test, or enhance parts of the system without disrupting the core logic. Meanwhile, DDD focuses on aligning your code with real-world business concepts, ensuring your system is both intuitive and resilient. Together, these approaches enable developers to build systems that are robust, resilient, and designed to seamlessly adapt to changing requirements and future growth.

1. Introduction to Hexagonal Architecture

Hexagonal Architecture, also known as the Ports and Adapters pattern, was introduced by Alistair Cockburn to address the rigidity and complexity of traditional layered architecture. Its primary goal is to make the application’s core logic (domain) independent of external systems, enabling easier testing, maintenance, and adaptability.

At its core, Hexagonal Architecture divides the application into three main layers:

  • Core (Business Logic/Domain): The heart of the system where business rules and domain logic reside. This layer is independent and does not rely on external libraries or frameworks.
    Example: Calculating interest on a loan or validating a user’s action against business rules.

  • Ports (Interfaces): Abstract definitions (e.g., interfaces or protocols) for the ways the core interacts with the outside world. Ports represent use cases or application-specific APIs. They define what needs to be done without specifying how.
    Example: Repository Port defines methods to interact with data sources like:

    • get(id: ID): Entity: Retrieve an entity by its unique identifier.
    • insert(entity: Entity): void: Add a new entity.
    • update(entity: Entity): void: Update an existing entity.
src/ports/repository.py
from abc import ABC, abstractmethod
from typing import List
from src.entities import Entity

class Repository(ABC):
    @abstractmethod
    def get(self, id: str) -> Entity:
        pass

    @abstractmethod
    def insert(self, entity: Entity) -> None:
        pass

    @abstractmethod
    def update(self, entity: Entity) -> None:
        pass
  • Adapters (Implementations): Concrete implementations of the ports. They handle the actual interaction with external systems like databases, APIs, or UI. Example: PostgresRepository Adapter implements the Repository Port for PostgreSQL using SQLAlchemy.
# src/adapters/postgres_repository.py
from sqlalchemy import create_engine, Column, String
from sqlalchemy.orm import declarative_base, sessionmaker
from src.entities import Entity
from src.ports.repository import Repository

Base = declarative_base()

# Define the database table for Entity
class EntityModel(Base):
    __tablename__ = "entities"
    id = Column(String, primary_key=True)
    name = Column(String, nullable=False)
    description = Column(String)

class PostgresRepository(Repository):
    def __init__(self, db_url: str):
        """
        Initialize the repository with the PostgreSQL connection URL.
        Example db_url: "postgresql+psycopg2://username:password@host:port/dbname"
        """
        self.engine = create_engine(db_url)
        Base.metadata.create_all(self.engine)
        self.Session = sessionmaker(bind=self.engine)

    def get(self, id: str) -> Entity:
        session = self.Session()
        try:
            entity_model = session.query(EntityModel).filter_by(id=id).first()
            if not entity_model:
                raise ValueError(f"Entity with id {id} not found")
            return Entity(id=entity_model.id, name=entity_model.name, description=entity_model.description)
        finally:
            session.close()

    def insert(self, entity: Entity) -> None:
        session = self.Session()
        try:
            entity_model = EntityModel(id=entity.id, name=entity.name, description=entity.description)
            session.add(entity_model)
            session.commit()
        finally:
            session.close()

    def update(self, entity: Entity) -> None:
        session = self.Session()
        try:
            entity_model = session.query(EntityModel).filter_by(id=entity.id).first()
            if not entity_model:
                raise ValueError(f"Entity with id {entity.id} not found")
            entity_model.name = entity.name
            entity_model.description = entity.description
            session.commit()
        finally:
            session.close()

The architecture is often visualized as a hexagon, symbolizing multiple ways to interact with the core, with each side representing a different adapter or port.

Building Maintainable Python Applications with Hexagonal Architecture and Domain-Driven Design

2. Introduction to Domain-Driven Design (DDD)

Domain-Driven Design (DDD) is a software design approach that emphasizes a close alignment between business goals and the software being built to achieve them. This methodology was introduced by Eric Evans in his book Domain-Driven Design: Tackling Complexity in the Heart of Software.

At its core, DDD focuses on understanding and modeling the domain (the business problem space) with the help of domain experts and translating that understanding into the software system. DDD promotes the decoupling of domains, ensuring that different parts of the system remain independent, clear, and easy to manage.
Key Concepts of Domain-Driven Design:

  • Domain: The specific area of knowledge or activity that the software addresses. For example, in a banking application, the domain includes concepts like accounts, transactions, and customers.

  • Ubiquitous Language: A common language developed collaboratively by developers and domain experts. This shared vocabulary ensures clear communication and consistent understanding across all stakeholders.

  • Entities and Value Objects:

    • Entities: Objects that have a distinct identity and lifecycle, such as a customer or an order.
    • Value Objects: Immutable objects that are defined by their attributes rather than a unique identity, like a date or a monetary amount.
  • Aggregates: Clusters of related entities and value objects treated as a single unit for data changes. Each aggregate has a root entity that ensures the integrity of the entire cluster.

  • Repositories: Mechanisms for retrieving and storing aggregates, providing a layer of abstraction over data access.

  • Services: Operations or processes that don't naturally fit within entities or value objects but are essential to the domain, such as processing a payment.

src/ports/repository.py
from abc import ABC, abstractmethod
from typing import List
from src.entities import Entity

class Repository(ABC):
    @abstractmethod
    def get(self, id: str) -> Entity:
        pass

    @abstractmethod
    def insert(self, entity: Entity) -> None:
        pass

    @abstractmethod
    def update(self, entity: Entity) -> None:
        pass

In this section, I do not provide a detailed example of implementing Domain-Driven Design (DDD) because it is a comprehensive methodology primarily focused on addressing complex business logic challenges. DDD excels at structuring and managing intricate business rules, but to fully realize its potential and address other coding concerns, it is best utilized within a complementary architectural framework. So, in the following section, Domain-Driven Design will be combined with Hexagonal Architecture to highlights it strengths and provide a solid foundation for solving additional coding problems beyond business logic, accompanied by a detailed example.

3. How Hexagonal Architecture and Domain-Driven Design Complement Each Other

Why Hexagonal Architecture and Domain-Driven Design?

Domain-Driven Design (DDD) and Hexagonal Architecture complement each other by emphasizing clear boundaries and aligning software with business needs. DDD focuses on modeling the core domain and isolating business logic, while Hexagonal Architecture ensures this logic remains independent of external systems through ports and adapters. They address distinct but complementary concerns:

  • Hexagonal Architecture as the Framework:

    • Hexagonal Architecture defines how the overall system is organized and how different parts (e.g., domain, infrastructure, user interfaces) interact.
    • It provides the environment where the domain logic can function independently of external concerns, offering freedom from infrastructure details.
  • Domain-Driven Design as the Core Logic:

    • DDD enriches the core domain defined by Hexagonal Architecture by ensuring that the business logic is not only encapsulated but also reflective of real-world business needs.
    • It focuses on how to design and implement the domain layer effectively, ensuring it remains meaningful and adaptable.

Together, they enable scalable, testable, and flexible systems where the domain remains the central focus, insulated from changes in infrastructure or technology. This synergy ensures a robust design that adapts easily to evolving business requirements.
The following section offers a practical example of how Domain-Driven Design (DDD) and Hexagonal Architecture work together to create robust, maintainable, and adaptable software systems.

Practical example

This project applies Hexagonal Architecture and Domain-Driven Design (DDD) to create scalable and maintainable systems, providing a modern and robust foundation for application development. Built with Python, it uses FastAPI as the web framework and DynamoDB as the database.

The project is organized as follows:

src/ports/repository.py
from abc import ABC, abstractmethod
from typing import List
from src.entities import Entity

class Repository(ABC):
    @abstractmethod
    def get(self, id: str) -> Entity:
        pass

    @abstractmethod
    def insert(self, entity: Entity) -> None:
        pass

    @abstractmethod
    def update(self, entity: Entity) -> None:
        pass

You can find the source code in my GitHub repository.

4. Conclusion

Incorporating Hexagonal Architecture and Domain-Driven Design (DDD) into Python applications fosters the development of systems that are maintainable, adaptable, and closely aligned with business objectives. Hexagonal Architecture ensures a clear separation between the core business logic and external systems, promoting flexibility and ease of testing. DDD emphasizes modeling the domain accurately, resulting in software that truly reflects business processes and rules. By integrating these methodologies, developers can create robust applications that not only meet current requirements but are also well-prepared to evolve with future business needs.

Connect me if you enjoyed this article!

The above is the detailed content of Building Maintainable Python Applications with Hexagonal Architecture and Domain-Driven Design. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
How to solve the permissions problem encountered when viewing Python version in Linux terminal?How to solve the permissions problem encountered when viewing Python version in Linux terminal?Apr 01, 2025 pm 05:09 PM

Solution to permission issues when viewing Python version in Linux terminal When you try to view Python version in Linux terminal, enter python...

How Do I Use Beautiful Soup to Parse HTML?How Do I Use Beautiful Soup to Parse HTML?Mar 10, 2025 pm 06:54 PM

This article explains how to use Beautiful Soup, a Python library, to parse HTML. It details common methods like find(), find_all(), select(), and get_text() for data extraction, handling of diverse HTML structures and errors, and alternatives (Sel

How to Perform Deep Learning with TensorFlow or PyTorch?How to Perform Deep Learning with TensorFlow or PyTorch?Mar 10, 2025 pm 06:52 PM

This article compares TensorFlow and PyTorch for deep learning. It details the steps involved: data preparation, model building, training, evaluation, and deployment. Key differences between the frameworks, particularly regarding computational grap

How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python?How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python?Apr 01, 2025 pm 11:15 PM

When using Python's pandas library, how to copy whole columns between two DataFrames with different structures is a common problem. Suppose we have two Dats...

How to Create Command-Line Interfaces (CLIs) with Python?How to Create Command-Line Interfaces (CLIs) with Python?Mar 10, 2025 pm 06:48 PM

This article guides Python developers on building command-line interfaces (CLIs). It details using libraries like typer, click, and argparse, emphasizing input/output handling, and promoting user-friendly design patterns for improved CLI usability.

What are some popular Python libraries and their uses?What are some popular Python libraries and their uses?Mar 21, 2025 pm 06:46 PM

The article discusses popular Python libraries like NumPy, Pandas, Matplotlib, Scikit-learn, TensorFlow, Django, Flask, and Requests, detailing their uses in scientific computing, data analysis, visualization, machine learning, web development, and H

Explain the purpose of virtual environments in Python.Explain the purpose of virtual environments in Python.Mar 19, 2025 pm 02:27 PM

The article discusses the role of virtual environments in Python, focusing on managing project dependencies and avoiding conflicts. It details their creation, activation, and benefits in improving project management and reducing dependency issues.

What are regular expressions?What are regular expressions?Mar 20, 2025 pm 06:25 PM

Regular expressions are powerful tools for pattern matching and text manipulation in programming, enhancing efficiency in text processing across various applications.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft