This repository is a Python implementation of the buckpal project, which was originally written in Java. The goal is to demonstrate how to achieve Hexagonal Architecture using modern Python packages and practices.
Buckpal is a simple web application that adheres to the principles of Hexagonal Architecture, as outlined in the book "Get Your Hands Dirty on Clean Architecture" by Tom Hombergs. This architecture is an elegant and efficient solution for building complex applications with maintainability, testability, and flexibility.
For a deep dive into Hexagonal Architecture, refer to "Get Your Hands Dirty on Clean Architecture". The book provides invaluable insights and has greatly inspired me.
- API Server: FastAPI (with async/await)
- Containerization: Docker / Docker Compose
- Testing Framework: Pytest
- Database: PostgreSQL (with asyncpg)
- Database Migrations: Alembic
- Dependency Injection: python-dependency-injector
- Static Analysis and Linting: Mypy / Ruff
Run
docker compose up
Then the server will be running at localhost:80
. Check the swagger document at localhost:80/docs
In Hexagonal Architecture, each layer should be decoupled and unaware of the details from other layers. However, the async
function annotation can break this principle. When you are forced to mark a function as async
because it calls another asynchronous function, it inadvertently leaks information about implementation details across layers, compromising the desired separation of concerns.
When working with object-oriented programming and multilevel inheritance in Python, it's important to use type annotations for function/class inputs and outputs, along with Mypy for static analysis. However, I believe the Python typing ecosystem is still evolving, and you may encounter various unexpected challenges when using type hints.
In multilevel inheritance, avoiding dependency injection tools can make development quite challenging. In Python, however, we don't have many options aside from python-dependency-injector
. While it's a powerful tool with excellent documentation, it hasn't gained widespread discussion or adoption in the community, at least from my perspective.
In buckpal, test case for persistence adapter directly call the sql database. But in python we rarely run the unit test with real database. So that I mock the repository function output.
I do not think there is a way for testing dependency rule in python so I did not implement the dependency rule tests. If you know how to do it, please let me know.
Please see here.