O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Enterprise Architecture Patterns with Python

Book Description

As Python continues to grow in popularity, projects are becoming larger and more complex. Many Python developers are now taking an interest in high-level software architecture patterns such as hexagonal/clean architecture, event-driven architecture, and strategic patterns prescribed by domain-driven design (DDD). But translating those patterns into Python isn’t always straightforward.

With this practical guide, Harry Percival and Bob Gregory from MADE.com introduce proven architectural design patterns to help Python developers manage application complexity. Each pattern is illustrated with concrete examples in idiomatic Python that explain how to avoid some of the unnecessary verbosity of Java and C# syntax. You’ll learn how to implement each of these patterns in a Pythonic way.

Architectural design patterns include:

  • Dependency inversion, and its links to ports and adapters (hexagonal/clean architecture)
  • Domain-driven design’s distinction between entities, value objects, and aggregates
  • Repository and Unit of Work patterns for persistent storage
  • Events, commands, and the message bus
  • Command Query Responsibility Segregation (CQRS)
  • Event-driven architecture and reactive microservices

Table of Contents

  1. Preface
    1. Managing Complexity, Solving Business Problems
    2. Why Python?
    3. Who Should Read This Book
    4. A Brief Overview of What You’ll Learn
      1. Part 1: Dependency Inversion and Domain Modelling
      2. Part 2: Event-Driven Architecture
      3. Epilogue (Chapter 12): How Do I Get There From Here?
    5. Example Code and Coding Along
    6. Conventions Used in This Book
    7. O’Reilly Safari
    8. How to Contact O’Reilly
    9. Acknowledgments
  2. Introduction: Why Do Our Designs Go Wrong?
    1. Encapsulation
    2. Layering
    3. The Dependency Inversion Principle
  3. 1. Domain Modelling
    1. What is a Domain Model?
    2. Exploring the Domain Language
    3. Unit Testing Domain Models
      1. Dataclasses Are Great for Value Objects
      2. Value Objects and Entities
    4. Not Everything Has to Be an Object: A Domain Service Function
      1. Python’s Magic Methods Let Us Use our Models with Idiomatic Python
      2. Exceptions Can Express Domain Concepts Too
  4. 2. Repository Pattern
    1. Persisting our Domain Model
      1. Some Pseudocode: What Are We Going to Need?
    2. Applying the Dependency Inversion Principle to the Database
    3. Reminder: our Model
      1. The “Normal” ORM Way: Model Depends on ORM.
      2. Inverting the Dependency: ORM Depends on Model.
    4. Introducing Repository Pattern.
      1. The Repository in the Abstract
      2. What is the Trade-Off?
    5. Building a Fake Repository for Tests is Now Trivial!
  5. 3. A Brief Interlude: On Coupling and Abstractions
    1. Abstracting State Aids Testability
    2. Choosing the right abstraction(s)
    3. Implementing our chosen abstractions
      1. Testing Edge-to-Edge with Fakes
      2. Why Not Just Patch It Out?
    4. Wrap-up: “Depend on Abstractions.”
  6. 4. our First Use Case: Flask API and Service Layer.
    1. Connecting our Application to the Real World
    2. A First End-To-End (E2E) Test
    3. The Straightforward Implementation
    4. Error Conditions That Require Database Checks
    5. Introducing a Service Layer, and Using Fakerepository to Unit Test It
      1. A Typical Service Function
    6. How is our Test Pyramid Looking?
    7. Should Domain Layer Tests Move to the Service Layer?
    8. On Deciding What Kind of Tests to Write
      1. Low and High Gear
    9. Fully Decoupling the Service Layer Tests From the Domain
      1. Mitigation: Keep All Domain Dependencies in Fixture Functions
      2. Adding a Missing Service
    10. Carrying the Improvement Through to the E2E Tests
    11. Wrap-Up
      1. The DIP in Action
  7. 5. Unit of Work Pattern
    1. The Unit of Work Collaborates with Repository(-Ies)
    2. Test-Driving a UoW with Integration Tests
    3. Unit of Work and Its Context Manager
      1. The Real Unit of Work Uses Sqlalchemy Sessions
    4. Fake Unit of Work for Testing:
    5. Using the UoW in the Service Layer
    6. Explicit Tests for Commit/Rollback Behaviour
    7. Explicit vs Implicit Commits
    8. Examples: Using UoW to Group Multiple Operations Into an Atomic Unit
      1. Example 1: Reallocate
      2. Example 2: Change Batch Quantity
    9. Tidying Up the Integration Tests
    10. Wrap-Up
  8. 6. Aggregates and Consistency Boundaries
    1. Why Not Just Run Everything in a Spreadsheet?
    2. Invariants, Constraints and Consistency
      1. Invariants and Concurrency
    3. Choosing the Right Aggregate
    4. 1 Aggregate = 1 Repository
    5. Version Numbers
    6. Testing for our Data Integrity Rules
      1. Enforcing Concurrency Rules by Using Database Transaction Isolation Levels
      2. SELECT FOR UPDATE Can Also Help
  9. A. A Template Project Structure
    1. Env Vars, 12-Factor, and Config, Inside and Outside Containers.
    2. Config.py
    3. Docker-Compose and Containers Config
    4. Installing Your Source as a Package
    5. Dockerfile
    6. Tests
  10. B. Swapping Out the Infrastructure: Do Everything with CSVs
    1. Implementing a Repository and Unit of Work for CSVs
  11. C. Repository and Unit of Work Patterns with Django
    1. Repository Pattern with Django
      1. Custom Methods on Django ORM Classes to Translate To/From our Domain Model
    2. Unit of Work Pattern with Django
    3. API: Django Views Are Adapters
    4. Conclusions: Would You Bother?