Clean Architectures in Python A Practical Approach To Better Software Design 2nd Edition 2023 Update Leonardo Giordani

Download as pdf or txt
Download as pdf or txt
You are on page 1of 70

Clean Architectures in Python A

practical approach to better software


design 2nd Edition 2023 Update
Leonardo Giordani
Visit to download the full and correct content document:
https://ebookmeta.com/product/clean-architectures-in-python-a-practical-approach-to-
better-software-design-2nd-edition-2023-update-leonardo-giordani/
More products digital (pdf, epub, mobi) instant
download maybe you interests ...

Clean Architectures in Python A practical approach to


better software design 2nd Edition Leonardo Giordani

https://ebookmeta.com/product/clean-architectures-in-python-a-
practical-approach-to-better-software-design-2nd-edition-
leonardo-giordani-2/

Clean Architectures in Python A practical approach to


better software design 2nd Edition Leonardo Giordani

https://ebookmeta.com/product/clean-architectures-in-python-a-
practical-approach-to-better-software-design-2nd-edition-
leonardo-giordani/

Embedded Software Design: A Practical Approach to


Architecture, Processes, and Coding Techniques 1st
Edition Jacob Beningo

https://ebookmeta.com/product/embedded-software-design-a-
practical-approach-to-architecture-processes-and-coding-
techniques-1st-edition-jacob-beningo/

A Practical Approach to VLSI System on Chip SoC Design


A Comprehensive Guide 2nd 2nd Edition Veena S.
Chakravarthi

https://ebookmeta.com/product/a-practical-approach-to-vlsi-
system-on-chip-soc-design-a-comprehensive-guide-2nd-2nd-edition-
veena-s-chakravarthi/
Python 3 Object oriented Programming Building robust
and maintainable software with object oriented design
patterns in Python 2nd Edition Phillips

https://ebookmeta.com/product/python-3-object-oriented-
programming-building-robust-and-maintainable-software-with-
object-oriented-design-patterns-in-python-2nd-edition-phillips/

Building Evolutionary Architectures: Automated Software


Governance, 2nd Edition Neal Ford

https://ebookmeta.com/product/building-evolutionary-
architectures-automated-software-governance-2nd-edition-neal-
ford-2/

Building Evolutionary Architectures: Automated Software


Governance, 2nd Edition Neal Ford

https://ebookmeta.com/product/building-evolutionary-
architectures-automated-software-governance-2nd-edition-neal-
ford/

Clean Python: Elegant Coding in Python 1st Edition


Sunil Kapil

https://ebookmeta.com/product/clean-python-elegant-coding-in-
python-1st-edition-sunil-kapil/

Introduction to Software Testing: A Practical Guide to


Testing, Design, Automation, and Execution 1st Edition
Panagiotis Leloudas

https://ebookmeta.com/product/introduction-to-software-testing-a-
practical-guide-to-testing-design-automation-and-execution-1st-
edition-panagiotis-leloudas/
Clean Architectures in Python
A practical approach to better software design

Leonardo Giordani
This book is for sale at http://leanpub.com/clean-architectures-in-python

This version was published on 2023-05-09

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2018 - 2023 Leonardo Giordani


Tweet This Book!
Please help Leonardo Giordani by spreading the word about this book on Twitter!
The suggested hashtag for this book is #pycabook.
Find out what other people are saying about the book by clicking on this link to search for this
hashtag on Twitter:
#pycabook
To my father, who taught me to be attentive, curious, and passionate. He succeeded.
To my mother, who taught me to be smart, cautious, and careful. She didn’t succeed.
Contents

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is a software architecture? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Why is it called “clean”? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Why “architectures”? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Why Python? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

About the book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6


Prerequisites and structure of the book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Typographic conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Why this book comes for free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Submitting issues or patches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
About the author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Changes in the second edition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Chapter 01 A day in the life of a clean system . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11


The data flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Advantages of a layered architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Chapter 02 Components of a clean architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Chapter 03 A basic example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

Chapter 04 Add a web application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52


Flask setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Test and create an HTTP endpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
WSGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

Chapter 05 Error management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62


Request and responses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Basic structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Requests and responses in a use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Request validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Responses and failures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Error management in a use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
CONTENTS

Integrating external systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Chapter 06 Integration with a real external system postgres . . . . . . . . . . . . . . . . . . . 89


Decoupling with interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
A repository based on PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Label integration tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Create SQLAlchemy classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Orchestration management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Database fixtures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Integration tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

Chapter 07 Integration with a real external system mongodb . . . . . . . . . . . . . . . . . . 114


Fixtures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Docker Compose configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Application configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Integration tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
The MongoDB repository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

Chapter 08 Run a production ready system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125


Build a web stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Connect to a production-ready database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

Colophon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Introduction
Learn about the Force, Luke.
Star Wars, 1977

This book is about a software design methodology. A methodology is a set of guidelines that help you
to reach your goal effectively, thus saving time, implementing far-sighted solutions, and avoiding
the need to reinvent the wheel time and again.
As other professionals around the world face problems and try to solve them, some of them, having
discovered a good way to solve a problem, decide to share their experience, usually in the form
of a “best practices” post on a blog, or talk at a conference. We also speak of patterns¹, which are
formalised best practices, and anti-patterns, when it comes to advice about what not to do and why
it is better to avoid a certain solution.
Often, when best practices encompass a wide scope, they are designated a methodology. The
definition of a methodology is to convey a method, more than a specific solution to a problem.
The very nature of methodologies means they are not connected to any specific case, in favour of a
wider and more generic approach to the subject matter. This also means that applying methodologies
without thinking shows that one didn’t grasp the nature of a methodology, which is to help to find
a solution and not to provide it.
This is why the main advice I have to give is: be reasonable; try to understand why a methodology
leads to a solution and adopt it if it fits your need. I’m saying this at the very beginning of this book
because this is how I’d like you to approach this work of mine.
The clean architecture, for example, pushes abstraction to its limits. One of the main concepts is
that you should isolate parts of your system as much as possible, so you can replace them without
affecting the rest. This requires a lot of abstraction layers, which might affect the performances of
the system, and which definitely require a greater initial development effort. You might consider
these shortcomings unacceptable, or perhaps be forced to sacrifice cleanness in favour of execution
speed, as you cannot afford to waste resources.
In these cases, break the rules.
With methodologies you are always free to keep the parts you consider useful and discard the rest,
and if you have understood the reason behind the methodology, you will also be aware of the reasons
that support your decisions. My advice is to keep track of such reasons, either in design documents
or simply in code comments, as a future reference for you or for any other programmer who might
be surprised by a “wrong” solution and be tempted to fix it.
¹From the seminal book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Vlissides, Johnson, and Helm.
Introduction 2

I will try as much as possible to give reasons for the proposed solutions, so you can judge whether
those reasons are valid in your case. In general let’s say this book contains possible contributions to
your job, it’s not an attempt to dictate THE best way to work.
Spoiler alert: there is no such a thing.

What is a software architecture?


Every production system, be it a software package, a mechanical device, or a simple procedure, is
made of components and connections between them. The purpose of the connections is to use the
output of some components as inputs of other components, in order to perform a certain action or
set of actions.
In a process, the architecture specifies which components are part of an implementation and how
they are interconnected.
A simple example is the process of writing a document. The process, in this case, is the conversion
of a set of ideas and sentences into a written text, and it can have multiple implementations. A
very simple one is when someone writes with a pen on a sheet of paper, but it might become more
complex if we add someone who is writing what another person dictates, multiple proof readers
who can send back the text with corrections, and a designer who curates the visual rendering of the
text. In all these cases the process is the same, and the nature of inputs (ideas, sentences) and outputs
(a document or a book) doesn’t change. The different architecture, however, can greatly affect the
quality of the output, or the speed with which it is produced.
An architecture can have multiple granularities, which are the “zoom level” we use to look at the
components and their connections. The first level is the one that describes the whole process as a
black box with inputs and outputs. At this level we are not even concerned with components, we
don’t know what’s inside the system and how it works. We only know what it does.
As you zoom in, you start discovering the details of the architecture, that is which components
are in the aforementioned black box and how they are connected. These components are in turn
black boxes, and you don’t want to know specifically how they work, but you want to know what
their inputs and outputs are, where the inputs come from, and how the outputs are used by other
components.
This process is virtually unlimited, so there is never one single architecture that describes a complete
system, but rather a set of architectures, each one covering the granularity we are interested in.
Let me go over another simple example that has nothing to do with software. Let’s consider a shop
as a system and let’s discuss its architecture.
A shop, as a black box, is a place where people enter with money and exit with items (if they found
what they were looking for). The input of the system are people and their money, and the outputs
are the same people and items. The shop itself needs to buy what it sells first, so another input is
represented by the stock the shop buys from the wholesaler and another output by the money it pays
Introduction 3

for it. At this level the internal structure of the shop is unknown, we don’t even know what it sells.
We can however already devise a simple performance analysis, for example comparing the amount
of money that goes out (to pay the wholesaler) and the amount of money that comes in (from the
customers). If the former is higher than the latter the business is not profitable.
Even in the case of a shop that has positive results we might want to increase its performances, and
to do this chances are that we need to understand its internal structure and what we can change to
increase its productivity. This may reveal, for example, that the shop has too many workers, who are
underemployed waiting for clients because we overestimated the size of the business. Or it might
show that the time taken to serve clients is too long and many clients walk away without buying
anything. Or maybe there are not enough shelves to display goods and the staff carries stock around
all day searching for display space so the shop is in chaos and clients cannot find what they need.
At this level, however, workers are pure entities, and still we don’t know much about the shop. To
better understand the reasons behind a problem we might need to increase the zoom level and look
at the workers for what they are, human beings, and start understanding what their needs are and
how to help them to work better.
This example can easily be translated into the software realm. Our shop is a processing unit in
the cloud, for example, input and output being the money we pay and the amount of requests
the system serves per second, which is probably connected with the income of the business. The
internal processes are revealed by a deeper analysis of the resources we allocate (storage, processors,
memory), which breaks the abstraction of the “processing unit” and reveals details like the hardware
architecture or the operating system. We might go deeper, discussing the framework or the library
we used to implement a certain service, the programming language we used, or the specific hardware
on which the whole system runs.
Remember that an architecture tries to detail how a process is implemented at a certain granularity,
given certain assumptions or requirements. The quality of an architecture can then be judged on
the basis of parameters such as its cost, the quality of the outputs, its simplicity or “elegance”, the
amount of effort required to change it, and so on.

Why is it called “clean”?


The architecture explained in this book has many names, but the one that is mainly in use nowadays
is “clean architecture”. This is the name used by Robert Martin in his seminal post² where he
clearly states this structure is not a novelty, but has been promoted by many software designers
over the years. I believe the adjective “clean” describes one of the fundamental aspects of both the
software structure and the development approach of this architecture. It is clean, that is, it is easy
to understand what happens.
The clean architecture is the opposite of spaghetti code, where everything is interlaced and there
are no single elements that can be easily detached from the rest and replaced without the whole
²https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
Introduction 4

system collapsing. The main point of the clean architecture is to make clear “what is where and
why”, and this should be your first concern while you design and implement a software system,
whatever architecture or development methodology you want to follow.
The clean architecture is not the perfect architecture and cannot be applied unthinkingly. Like any
other solution, it addresses a set of problems and tries to solve them, but there is no panacea that
will solve all issues. As already stated, it’s better to understand how the clean architecture solves
some problems and decide if the solution suits your need.

Why “architectures”?
While I was writing the first edition of the book it became clear to me that the goal of this book is
to begin a journey and not to define the specific steps through which each software designer has to
go through. The concepts explained here are rooted in some design principles that are much more
important than the resulting physical structure of the system that you will create.
This is why I wanted to stress that what I show in this book can (and hopefully will) be an inspiration
for many different architectures that you will create to solve the problems you will have to face.
Or maybe I just wanted to avoid looking like a clone of Robert Martin.

Why Python?
I have been working with Python for 20 years, along with other languages, but I came to love its
simplicity and power and so I ended up using it on many projects. When I was first introduced to the
clean architecture I was working on a Python application that was meant to glue together the steps
of a processing chain for satellite imagery, so my journey with the concepts I will explain started
with this language.
I will therefore speak of Python in this book, but the main concepts are valid for any other language,
especially object-oriented ones. I will not introduce Python here, so a minimal knowledge of the
language syntax is needed to understand the examples and the project I will discuss.
The clean architecture concepts are independent of the language, but the implementation obviously
leverages what a specific language allows you to do, so this book is about the clean architecture
and an implementation of it that I devised using Python. I really look forward to seeing more books
about the clean architecture that explore other implementations in Python and in other languages.

Acknowledgments
• Eleanor de Veras, who proofread the introduction.
• Roberto Ciatti, who introduced me to clean architectures.
Introduction 5

• Readers Eric Smith, Faust Gertz, Giovanni Natale, Grant Moore, Hans Chen, Max H. Gerlach,
Michael O’Neill, Paul Schwendenman, Ramces Chirino, Rodrigo Monte, Simon Weiss, Thiago
C. D’Ávila, robveijk, mathisheeren, 4myhw, Jakob Waibel, 1110sillabo, Maxim Ivanov and
many others who fixed bugs, typos and bad grammar submitting issues and pull requests. See
the changelog at the end of the book for a full report of readers’ contributions.
• Łukasz Dziedzic, who developed the free “Lato” font (http://www.latofonts.com), used for the
cover.

The cover photograph is by pxhere³. A detail of the Sagrada Familia in Barcelona, one of the world’s
best contemporary artworks, a bright example of architecture in which every single element has a
meaning and a purpose. Praise to Antoni Gaudí, brilliant architect and saint, who will always inspire
me with his works and his life.
³https://pxhere.com/en/photo/1453753
About the book
We’ll put the band back together, do a few gigs, we get some bread. Bang! Five thousand
bucks.
The Blues Brothers, 1980

In 2015 I was introduced to the clean architecture by a colleague of mine, Roberto Ciatti. I started
working with him following a strict Test-Driven Development (TDD) approach and learning or
better understanding many things I now consider pillars of my programming knowledge.
Unfortunately the project was cancelled, but the clean architecture concepts stuck with me, so I
revisited them for a simple open source project I started working on at the time. Meanwhile I read
“Object Oriented Software Engineering: A Use-Case Driven Approach” by Ivar Jacobson⁴.
In 2013 I started writing a personal blog, The Digital Cat⁵, and after having published many Python-
related posts I began working on a post to show other programmers the beauty of the clean
architecture concepts: “Clean Architectures in Python: a step by step example”, published in 2016,
which was well received by the Python community. For a couple of years I considered expanding
the post, but I couldn’t find the time to do it, and in the meanwhile I realised that many things I had
written needed to be corrected, clarified, or simply updated. So I thought that a book could be the
best way to present the whole picture effectively, and here we are.
In 2020, after having delayed it for a long time, I decided to review the whole book, updating it and
clarifying parts that weren’t particularly well written. I also decided to remove the part on TDD.
While I believe every programmer should understand TDD, the topic of the book is different, so I
updated the material and published it on my blog.
This book is the product of many hours spent thinking, experimenting, studying, and making
mistakes. I couldn’t have written it without the help of many people, some of whose names I don’t
know, who provided free documentation, free software, free help. Thanks everybody! I also want
to specifically say thanks to many readers who came back to me with suggestions, corrections, or
simply with appreciation messages. Thanks all!

Prerequisites and structure of the book


To fully appreciate the book you need to know Python and be familiar with TDD, in particular with
unit testing and mocks. Please refer to the series TDD in Python with pytest⁶ published on my blog
if you need to refresh your knowledge about these topics.
⁴https://www.amazon.com/Object-Oriented-Software-Engineering-Approach/dp/0201544350
⁵https://www.thedigitalcatonline.com/
⁶https://www.thedigitalcatonline.com/blog/2020/09/10/tdd-in-python-with-pytest-part-1/
About the book 7

After the two introductory parts that you are reading, chapter 1 goes through a 10,000 feet overview
of a system designed with a clean architecture, while chapter 2 briefly discusses the components and
the ideas behind this software architecture. Chapter 3 runs through a concrete example of clean
architecture and chapter 4 expands the example adding a web application on top of it. Chapter
5 discusses error management and improvements to the Python code developed in the previous
chapters. Chapters 6 and 7 show how to plug different database systems to the web service
created previously, and chapter 8 wraps up the example showing how to run the application with a
production-ready configuration.

Typographic conventions
This book uses Python, so the majority of the code samples will be in this language, either inline
or in a specific code block like this
some/path/file_name.py

1 def example():
2 print("This is a code block")

Note that the path of the file that contains the code is printed just before the source code.
Shell commands are presented with a generic prompt $

1 $ command --option1 value1 --option2 value 2

which means that you will copy and execute the string starting from command.
I will also use two different asides to link the code repository and to mark important principles.
This box provides a link to the commit or the tag that contains the code that was presented

Source code
https://github.com/pycabook/rentomatic/tree/master

This box highlights a concept explained in detail in the current chapter

Concept
This recaps an important concept that is explained in the text.
About the book 8

Why this book comes for free


The first reason I started writing a technical blog was to share with others my discoveries, and to
save them the hassle of going through processes I had already cracked. Moreover, I always enjoy
the fact that explaining something forces me to better understand that topic, and writing requires
even more study to get things clear in my mind, before attempting to introduce other people to the
subject.
Much of what I know comes from personal investigations, but without the work of people who
shared their knowledge for free I would not have been able to make much progress. The Free
Software Movement didn’t start with Internet, and I got a taste of it during the 80s and 90s, but the
World Wide Web undeniably gave an impressive boost to the speed and quality of this knowledge
sharing.
So this book is a way to say thanks to everybody gave their time to write blog posts, free books,
software, and to organise conferences, groups, meetups. This is why I teach people at conferences,
this is why I write a technical blog, this is the reason behind this book.
That said, if you want to acknowledge my effort with money, feel free. Anyone who publishes a
book or travels to conferences incurs expenses, and any help is welcome. However, the best thing
you can do is to become part of this process of shared knowledge; experiment, learn and share what
you learn. If you’d like to contribute financially you can purchase the book on Leanpub⁷.

Submitting issues or patches


This book is not a collaborative effort. It is the product of my work, and it expresses my personal
view on some topics, and also follows my way of teaching. Both however can be improved, and
they might also be wrong, so I am open to suggestions, and I will gladly receive any report about
mistakes or any request for clarifications. Feel free to use the GitHub Issues of the book repository⁸
or of the projects presented in the book. I will answer or fix issues as soon as possible, and if needed
I will publish a new version of the book with the correction. Thanks!

About the author


My name is Leonardo Giordani, I was born in 1977, a year that gave to the world Star Wars, bash,
Apple II, BSD, Dire Straits, The Silmarillion, among many other things. I’m interested in operating
systems and computer languages, photography, fantasy and science fiction, video and board games,
guitar playing, and (too) many other things.
⁷https://leanpub.com/clean-architectures-in-python
⁸https://github.com/pycabook/pycabook/issues
About the book 9

I studied and used several programming languages, among them my favourite are the Motorola
68k Assembly, C, and Python. I love mathematics and cryptography. I’m mainly interested in open
source software, and I like both the theoretical and practical aspects of computer science.
For 13 years I have been a C/Python programmer and devops for a satellite imagery company, and
I am currently one of the lead developers at WeGotPOP⁹, a UK company based in London and New
York that creates innovative software for film productions.
In 2013 I started publishing some technical thoughts on my blog, The Digital Cat¹⁰, and in 2018 I
published the first edition of the book you are currently reading.

Changes in the second edition


New edition, new typos! I’m pretty sure this is the major change I introduced with this edition.
Jokes aside, this second edition contains many changes, but the core example is the same, and while
the code changed a little (I use dataclasses and introduced a management script to orchestrate tests)
nothing revolutionary happened from that point of view.
So, if you already read the first edition, you might want to have a look at chapters 6, 7, and 8, where
I reworked the way I manage integration tests and the production-ready setup of the project. If you
haven’t read the first edition I hope you will appreciate the effort I made to introduce the clean
architecture with a narrated example in chapter 1, before I start discussing the architecture in more
detail and show you some code.
The biggest change that readers of the first edition might notice in the content is that I removed the
part on TDD and focused only on the clean architecture. What I wrote on TDD has become a series
of 5 posts on my blog, that I reference in the book, but this time I preferred to stay faithful to the title
and discuss only the subject matter. This probably means that the book is not suitable for complete
beginners any more, but since the resources are out there I don’t feel too guilty.
I also experimented with different toolchains. The first edition was created directly with Leanpub’s
Markua¹¹ language, which gave me all I needed to start. While working on the second edition, though,
I grew progressively unsatisfied because of the lack of features like admonitions and file names for
the source snippets, and a general lack of configuration options. I think Leanpub is doing a great
job, but Markua didn’t provide all the features that I needed. So I tried Pandoc¹², and I immediately
hit the wall of Latex, which is obscure black magic to say the least. I spent a great amount of time
hacking templates and Python filters to get more or less what I wanted, but I wasn’t happy.
Eventually I discovered AsciiDoc¹³ and that looked like the perfect solution. I actually published
the first version of the second edition with this toolchain, and I was blown away by AsciiDoc in
comparison with Markdown. Unfortunately I had a lot of issues trying to customise the standard
⁹https://www.wegotpop.com
¹⁰https://www.thedigitalcatonline.com
¹¹https://leanpub.com/markua/read
¹²https://pandoc.org/
¹³https://asciidoc.org/
About the book 10

template, and not knowing Ruby worsened my experience. After a while I got to a decent version
(which I published), but I kept thinking that I wanted more.
So I decided to try to write my own parser and here we go. This version of the book has been written
using Mau, which is available at https://github.com/Project-Mau, and Pelican (https://getpelican.
com), which I already successfully use for my blog. I’m in the process of writing a Mau Visitor that
converts the source code into Markua, so that I can use Leanpub’s tools to produce a PDF.
I hope you will enjoy the effort I put into this new edition!
Chapter 01 A day in the life of a clean
system
Must be my lucky day.
Terminator 2, 1991

In this chapter I will introduce the reader to a (very simple) system designed with a clean architecture.
The purpose of this introductory chapter is to familiarise with main concepts like separation of
concerns and inversion of control, which are paramount in system design. While I describe how
data flows in the system, I will purposefully omit details, so that we can focus on the global idea
and not worry too much about the implementation. This example will be then explored in all its
glorious details in the following chapters, so there will be time to discuss specific choices. For now,
try to get the big picture.

The data flow


In the rest of the book, we will design together part of a simple web application that provides a
room renting system. So, let’s consider that our “Rent-o-Matic” application¹⁴ is running at https:
//www.rentomatic.com, and that a user wants to see the available rooms. They open the browser
and type the address, then clicking on menus and buttons they reach the page with the list of all the
rooms that our company rents.
Let’s assume that this URL is /rooms?status=available. When the user’s browser accesses that
URL, an HTTP request reaches our system, where there is a component that is waiting for HTTP
connections. Let’s call this component “web framework”¹⁵.
The purpose of the web framework is to understand the HTTP request and to retrieve the data that we
need to provide a response. In this simple case there are two important parts of the request, namely
the endpoint itself (/rooms), and a single query string parameter, status=available. Endpoints
are like commands for our system, so when a user accesses one of them, they signal to the system
that a specific service has been requested, which in this case is the list of all the rooms that are
available for rent.
¹⁴I was inspired by the Sludge-O-Matic™ from Day of the Tentacle.
¹⁵There are many more layers that the HTTP request has to go through before reaching the actual web framework, for example the web
server, but since the purpose of those layers is mostly to increase performances, I am not going to consider them until the end of the book.
Chapter 01 A day in the life of a clean system 12

The web framework serving HTTP

The domain in which the web framework operates is that of the HTTP protocol, so when the web
framework has decoded the request it should pass the relevant information to another component
that will process it. This other component is called use case, and it is the crucial and most important
component of the whole clean system as it implements the business logic.

The business logic

The business logic is an important concept in system design. You are creating a system because you
have some knowledge that you think might be useful to the world, or at the very least marketable.
This knowledge is, at the end of the day, a way to process data, a way to extract or present data that
maybe others don’t have. A search engine can find all the web pages that are related to the terms in
a query, a social network shows you the posts of people you follow and sorts them according to a
specific algorithm, a travel company finds the best options for your journey between two locations,
and so on. All these are good examples of business logic.

Business logic
Business logic is the specific algorithm or process that you want to implement, the way you
transform data to provide a service. It is the most important part of the system.

The use case implements a very specific part of the whole business logic. In this case we have a use
case to search for rooms with a given value of the parameter status. This means that the use case
has to extract all the rooms that are managed by our company and filter them to show only the ones
that are available.
Why can’t the web framework do it? Well, the main purpose of a good system architecture is
to separate concerns, that is to keep different responsibilities and domains separated. The web
framework is there to process the HTTP protocol, and is maintained by programmers that are
Chapter 01 A day in the life of a clean system 13

concerned with that specific part of the system, and adding the business logic to it mixes two very
different fields.

Separation of concerns
Different parts a system should manage different parts of the process. Whenever two
separate parts of a system work on the same data or the same part of a process they are
coupled. While coupling is unavoidable, the higher the coupling between two components
the harder is to change one without affecting the other.

As we will see, separating layers allows us to maintain the system with less effort, making single
parts of it more testable and easily replaceable.
In the example that we are discussing here, the use case needs to fetch all the rooms that are in an
available state, extracting them from a source of data. This is the business logic, and in this case it
is very straightforward, as it will probably consist of a simple filtering on the value of an attribute.
This might however not be the case. An example of a more advanced business logic might be an
ordering based on a recommendation system, which might require the use case to connect with
more components than just the data source.
So, the information that the use case wants to process is stored somewhere. Let’s call this component
storage system. Many of you probably already pictured a database in your mind, maybe a relational
one, but that is just one of the possible data sources. The abstraction represented by the storage
system is: anything that the use case can access and that can provide data is a source. It might be a
file, a database (either relational or not), a network endpoint, or a remote sensor.

Abstraction
When designing a system, it is paramount to think in terms of abstractions, or building
blocks. A component has a role in the system, regardless of the specific implementation of
that component. The higher the level of the abstraction, the less detailed are the components.
Clearly, high-level abstractions don’t consider practical problems, which is why the abstract
design has to be then implemented using specific solutions or technologies.

For simplicity’s sake, let’s use a relational database like Postgres in this example, as it is likely to be
familiar to the majority of readers, but keep in mind the more generic case.

The storage
Chapter 01 A day in the life of a clean system 14

How does the use case connect with the storage system? Clearly, if we hard code into the use case
the calls to a specific system (e.g. using SQL) the two components will be strongly coupled, which
is something we try to avoid in system design. Coupled components are not independent, they are
tightly connected, and changes occurring in one of the two force changes in the second one (and
vice versa). This also means that testing components is more difficult, as one component cannot live
without the other, and when the second component is a complex system like a database this can
severely slow down development.
For example, let’s assume the use case called directly a specific Python library to access PostgreSQL
such as psycopg¹⁶. This would couple the use case with that specific source, and a change of database
would result in a change of its code. This is far from being ideal, as the use case contains the business
logic, which has not changed moving from one database system to the other. Parts of the system
that do not contain the business logic should be treated like implementation details.

Implementation detail
A specific solution or technology is called a detail when it is not central to the design as
a whole. The word doesn’t refer to the inherent complexity of the subject, which might be
greater than that of more central parts.

A relational database is hundred of times richer and more complex than an HTTP endpoint, and this
in turn is more complex than ordering a list of objects, but the core of the application is the use case,
not the way we store data or the way we provide access to that. Usually, implementation details are
mostly connected with performances or usability, while the core parts implement the pure business
logic.
How can we avoid strong coupling? A simple solution is called inversion of control, and I will briefly
sketch it here, and show a proper implementation in a later section of the book, when we will
implement this very example.
Inversion of control happens in two phases. First, the called object (the database in this case) is
wrapped with a standard interface. This is a set of functionalities shared by every implementation
of the target, and each interface translates the functionalities to calls to the specific language¹⁷ of
the wrapped implementation.

Inversion of control
A technique used to avoid strong coupling between components of a system, that involves
wrapping them so that they expose a certain interface. A component expecting that interface
can then connect to them without knowing the details of the specific implementation, and
thus being strongly coupled to the interface instead of the specific implementation.

A real world example of this is that of power plugs: electric appliances are designed to be connected
not with specific power plugs, but to any power plug that is build according to the specification
¹⁶https://www.psycopg.org/
¹⁷The word language, here, is meant in its broader sense. It might be a programming language, but also an API, a data format, or a protocol.
Chapter 01 A day in the life of a clean system 15

(size, number of poles, etc). When you buy a TV in the UK, you expect it to come with a UK plug
(BS 1363). If it doesn’t, you need an adapter that allows you to plug electronic devices into sockets
of a foreign nation. In this case, we need to connect the use case (TV) to a database (power system)
that have not been designed to match a common interface.
In the example we are discussing, the use case needs to extract all rooms with a given status, so
the database wrapper needs to provide a single entry point that we might call list_rooms_with_-
status.

The storage interface

In the second phase of inversion of control the caller (the use case) is modified to avoid hard coding
the call to the specific implementation, as this would again couple the two. The use case accepts an
incoming object as a parameter of its constructor, and receives a concrete instance of the adapter at
creation time. The specific technique used to implement this depends greatly on the programming
language we use. Python doesn’t have an explicit syntax for interfaces, so we will just assume the
object we pass implements the required methods.
Chapter 01 A day in the life of a clean system 16

Inversion of control on the storage interface

Now the use case is connected with the adapter and knows the interface, and it can call the entry
point list_rooms_with_status passing the status available. The adapter knows the details of
the storage system, so it converts the method call and the parameter in a specific call (or set of calls)
that extract the requested data, and then converts them in the format expected by the use case. For
example, it might return a Python list of dictionaries that represent rooms.

The business logic extracts data from the storage

At this point, the use case has to apply the rest of the business logic, if needed, and return the result
to the web framework.
Chapter 01 A day in the life of a clean system 17

The business logic returns processed data to the web framework

The web framework converts the data received from the use case into an HTTP response. In this
case, as we are considering an endpoint that is supposed to be reached explicitly by the user of the
website, the web framework will return an HTML page in the body of the response, but if this was
an internal endpoint, for example called by some asynchronous JavaScript code in the front-end, the
body of the response would probably just be a JSON structure.

The web framework returns the data in an HTTP response


Chapter 01 A day in the life of a clean system 18

Advantages of a layered architecture


As you can see, the stages of this process are clearly separated, and there is a great deal of
data transformation between them. Using common data formats is one of the way we achieve
independence, or loose coupling, between components of a computer system.
To better understand what loose coupling means for a programmer, let’s consider the last picture.
In the previous paragraphs I gave an example of a system that uses a web framework for the user
interface and a relational database for the data source, but what would change if the front-end part
was a command-line interface? And what would change if, instead of a relational database, there
was another type of data source, for example a set of text files?

The web framework replaced by a CLI


Chapter 01 A day in the life of a clean system 19

A database replaced by a more trivial file-based storage

As you can see, both changes would require the replacement of some components. After all, we need
different code to manage a command line instead of a web page. But the external shape of the system
doesn’t change, neither does the way data flows. We created a system in which the user interface
(web framework, command-line interface) and the data source (relational database, text files) are
details of the implementation, and not core parts of it.
The main immediate advantage of a layered architecture, however, is testability. When you clearly
separate components you clearly establish the data each of them has to receive and produce, so you
can ideally disconnect a single component and test it in isolation. Let’s take the Web framework
component that we added and consider it for a moment forgetting the rest of the architecture. We
can ideally connect a tester to its inputs and outputs as you can see in the figure
Chapter 01 A day in the life of a clean system 20

Testing the web layer in isolation

Detailed setup of the web layer testing

We know that the Web framework receives an HTTP request (1) with a specific target and a specific
query string, and that it has to call (2) a method on the use case passing specific parameters. When
the use case returns data (3), the Web framework has to convert that into an HTTP response (4).
Since this is a test we can have a fake use case, that is an object that just mimics what the use case
does without really implementing the business logic. We will then test that the Web framework calls
the method (2) with the correct parameters, and that the HTTP response (4) contains the correct data
in the proper format, and all this will happen without involving any other part of the system.

So, now that we had a 10,000 feet overview of the system, let’s go deeper into its components and
Chapter 01 A day in the life of a clean system 21

the concepts behind them. In the next chapter I will detail how the design principles called “clean
architecture” help to implement and use effectively concepts like separation of concerns, abstraction,
implementation, and inversion of control.
Chapter 02 Components of a clean
architecture
Wait a minute. Wait a minute Doc, uh, are you telling me you built a time machine… out of
a DeLorean?
Back to the Future, 1985

In this chapter I will analyse the set of software design principles collectively known as “clean
architecture”. While this specific name has been introduced by Robert Martin, the concepts it pushes
are part of software engineering, and have been successfully used for decades.
Before we dive into a possible implementation of them, which is the core of this book, we need to
analyse more in depth the structure of the clean architecture and the components you can find in
the system designed following it.

Divide et impera
One of the main goals of a well designed system is to achieve control. From this point of view, a
software system is not different from a human working community, like an office or a factory. In
such environments there are workers who exchange data or physical objects to create and deliver a
final product, be it an object or a service. Workers need information and resources to perform their
own job, but most of all they need to have a clear picture of their responsibilities.
While in a human society we value initiative and creativity, however, in a machine such as a software
system, components shouldn’t be able to do anything that is not clearly stated when the system is
designed. Software is not alive, and despite the impressive achievements of artificial intelligence in
the latter years, I still believe there is a spark in a human being that cannot be reproduced by code
alone.
Whatever our position on AIs, I think we all agree that a system works better if responsibilities
are clear. Whether we are dealing with software or human communities, it is always dangerous to
be unclear about what a component can or should do, as areas of influence and control naturally
overlap. This can lead to all sorts of issues, from simple inefficiencies to complete deadlocks.
A good way to increase order and control in a system is to split it into subsystems, establishing clear
and rigid borders between them, to regulate the data exchange. This is an extension of a political
concept (divide et impera) which states that it is simpler to rule a set of interconnected small systems
than a single complex one.
Chapter 02 Components of a clean architecture 23

In the system we designed in the previous chapter, it is always clear what a component expects to
receive when called into play, and it is also impossible (or at least, forbidden) to exchange data in a
way that breaks the structure of the system.
You have to remember that a software system is not exactly like a factory or an office. Whenever
we discuss machines we have to consider both the way they work (run time) and the way they have
been built or will be modified (development time). In principle, computers don’t care where data
comes from and where it goes. Humans, on the other hand, who have to build and maintain the
system, need a clear picture of the data flow to avoid introducing bugs or killing performances.

Data types
An important part in a system is played by data types, that is the way we encapsulate and transmit
information. In particular, when we discuss software systems, we need to make sure that types that
are shared by different systems are known to all of them. The knowledge of data types and formats
is, indeed, a form of coupling. Think about human languages: if you have to talk to an audience, you
have to use a language they understand, and this makes you coupled with your audience. This book
is written (tentatively) in English, which means that I am coupled with English-speaking readers. If
all English speakers in the world suddenly decided to forget the language and replace it with Italian
I should write the book from scratch (but with definitely less effort).
When we consider a software system, thus, we need to understand which part defines the types
and the data format (the “language”), and ensure that the resulting dependencies don’t get in the
way of the implementer. In the previous chapter we discovered that there are components in the
system that should be considered of primary importance and represent the core of the system (use
cases), and others which are less central, often considered implementation details. Again, mind that
calling them “details” doesn’t mean they are not important or that they are trivial to implement, but
that replacing them with different implementations does not affect the core of the system (business
logic).
So, there is a hierarchy of components that spawns from the dependencies between them. Some
components are defined at the very beginning of the design and do not depend on any other
component, while others will come later and depend on them. When data types are involved, the
resulting dependencies cannot break this hierarchy, as this would re-introduce a coupling between
components that we want to avoid.
Let’s go back to the initial example of a shop that buys items from a wholesale, displays them on
shelves, and sells them to customers. There is a clear dependency between two components here:
the component called “shop” depends on the component called “wholesale”, as the data (“items”)
flow from the latter to the former. The size of the shelves in the shop, in turn, depends on the size
of the items (types), which is defined by the wholesale, and this follows the dependency we already
established.
If the size of the items was defined by the shop, suddenly there would be another dependency
opposing the one we already established, making the wholesale depend on the shop. Please note
Chapter 02 Components of a clean architecture 24

that when it comes to software systems this is not a circular dependency, because the first one is
a conceptual dependency while the second one happens at the language level at compile time. At
any rate, having two opposite dependencies is definitely confusing, and makes it hard to replace
“peripheral” components such as the shop.

The main four layers


The clean architecture tries to capture both the conceptual hierarchy of components and the type
hierarchy through a layered approach. In a clean architecture the components of the system are
categorised and belong to a specific layer, with rules relative to the communication between
components belonging to the same or to different layers. In particular, a clean architecture is a
spherical structure, with inner (lower) layers completely encompassed by outer (higher) ones, and
the former being oblivious of the existence of the latter.
Chapter 02 Components of a clean architecture 25

The basic layers of the clean architecture

Remember that in computer science, the words “lower” and “higher” almost always refer to the level
of abstraction, and not to the importance of a component for the system. Each part of a system is
important, otherwise it would not be there.
Let’s have a look at the main layers depicted in the figure, keeping in mind that a specific
implementation may require to create new layers or to split some of these into multiple ones.
Chapter 02 Components of a clean architecture 26

Entities

This layer of the clean architecture contains a representation of the domain models, that is everything
your system needs to interact with and is sufficiently complex to require a specific representation.
For example, strings in Python are complex and very powerful objects. They provide many methods
out of the box, so in general, it is useless to create a domain model for them. If your project was a tool
to analyse medieval manuscripts, however, you might need to isolate sentences and their features,
and at this point it might be reasonable to define a specific entity.

Entities
Chapter 02 Components of a clean architecture 27

Since we work in Python, this layer will likely contain classes, with methods that simplify the
interaction with them. It is very important, however, to understand that the models in this layer are
different from the usual models of frameworks like Django. These models are not connected with
a storage system, so they cannot be directly saved or queried using their own methods, they don’t
contain methods to dump themselves to JSON strings, they are not connected with any presentation
layer. They are so-called lightweight models.
This is the inmost layer. Entities have mutual knowledge since they live in the same layer, so the
architecture allows them to interact directly. This means that one of the Python classes that represent
an entity can use another one directly, instantiating it and calling its methods. Entities don’t know
anything that lives in outer layers, though. They cannot call the database, access methods provided
by the presentation framework, or instantiate use cases.
The entities layer provides a solid foundation of types that the outer layers can use to exchange data,
and they can be considered the vocabulary of your business.

Use cases

As we said before the most important part of a clean system are use cases, as they implement
the business rules, which are the core reason of existence of the system itself. Use cases are the
processes that happen in your application, where you use your domain models to work on real
data. Examples can be a user logging in, a search with specific filters being performed, or a bank
transaction happening when the user wants to buy the content of the cart.
Chapter 02 Components of a clean architecture 28

Use cases

Use cases should be as small as possible. It is very important to isolate small actions into separate
use cases, as this makes the whole system easier to test, understand and maintain. Use cases have
full access to the entities layer, so they can instantiate and use them directly. They can also call each
other, and it is common to create complex use cases composing simple ones.

Gateways

This layer contains components that define interfaces for external systems, that is a common access
model to services that do not implement the business rules. The classic example is that of a data
Chapter 02 Components of a clean architecture 29

storage, which internal details can be very different across implementations. These implementations
share a common interface, otherwise they would not be implementations of the same concept, and
the gateway’s task is to expose it.

Gateways

If you recall the simple example I started with, this is where the database interface would live.
Gateways have access to entities, so the interface can freely receive and return objects which type
has been defined in that layer, as they can freely access use cases. Gateways are used to mask the
implementation of external systems, however, so it is rare for a gateway to call a use case, as this can
be done by the external system itself. The gateways layer is intimately connected with the external
Chapter 02 Components of a clean architecture 30

systems one, which is why the two are separated by a dashed line.

External systems

This part of the architecture is populated by components that implement the interfaces defined in the
previous layer. The same interface might be implemented by one or more concrete components, as
your system might want to support multiple implementations of that interface at the same time. For
example, you might want to expose some use cases both through an HTTP API and a command
line interface, or you want to provide support for different types of storage according to some
configuration value.
Chapter 02 Components of a clean architecture 31

External systems

Please remember that the “external” adjective doesn’t always mean that the system is developed
by others, or that it is a complex system like a web framework or a database. The word has a
topological meaning, which shows that the system we are talking about is peripheral to the core
of the architecture, that is it doesn’t implement business logic. So we might want to use a messaging
system developed in-house to send notifications to the clients of a certain service, but this is again
just a presentation layer, unless our business is specifically centred around creating notification
systems.
External systems have full access to gateways, use cases, and entities. While it is easy to understand
Chapter 02 Components of a clean architecture 32

the relationship with gateways, which are created to wrap specific systems, it might be less clear
what external systems should do with use cases and entities. As for use cases, external systems are
usually the parts of the system that trigger them, being the way users run the business logic. A user
clicking on a button, visiting a URL, or running a command, are typical examples of interactions
with an external system that runs a use case directly. As for entities, an external system can directly
process them, for example to return them in a JSON payload, or to map input data into a domain
model.
I want to point out a difference between external systems that are used by use cases and external
systems that want to call use cases. In the first case the direction of the communication is outwards,
and we know that in the clean architecture we can’t go outwards without interfaces. Thus, when we
access an external system from a use case we always need an interface. When the external system
wants to call use cases, instead, the direction of the communication is inwards, and this is allowed
directly, as external layers have full access to the internal ones.
This, practically speaking, translates into two extreme cases, well represented by a database and a
web framework. When a use case accesses a storage system there should be a loose coupling between
the two, which is why we wrap the storage with an interface and assume that in the use case. When
the web framework calls a use case, instead, the code of the endpoint doesn’t need any interface to
access it.

Communication between layers


The deeper a layer is in this architecture, the more abstract the content is. The inner layers contain
representations of business concepts, while the outer layers contain specific details about the real-life
implementation. The communication between elements that live in the same layer is unrestricted,
but when you want to communicate with elements that have been assigned to other layers you have
to follow one simple rule. This rule is the most important thing in a clean architecture, possibly being
the core expression of the clean architecture itself.
The Golden Rule: talk inwards with simple structures, talk outwards through interfaces.
Your elements should talk inwards, that is pass data to more abstract elements, using basic structures,
that is entities and everything provided by the programming language you are using.
Chapter 02 Components of a clean architecture 33

The golden rule of the clean architecture

Your elements should talk outwards using interfaces, that is using only the expected API of a
component, without referring to a specific implementation. When an outer layer is created, elements
living there will plug themselves into those interfaces and provide a practical implementation.

APIs and shades of grey


The word API is of uttermost importance in a clean architecture. Every layer may be accessed by
elements living in inner layers by an API, that is a fixed¹⁸ collection of entry points (methods or
objects).
¹⁸Here “fixed” means “the same among every implementation”. An API may obviously change in time.
Chapter 02 Components of a clean architecture 34

The separation between layers and the content of each layer is not always fixed and immutable. A
well-designed system shall also cope with practical world issues such as performances, for example,
or other specific needs. When designing an architecture it is very important to know “what is where
and why”, and this is even more important when you “bend” the rules. Many issues do not have a
black-or-white answer, and many decisions are “shades of grey”, that is it is up to you to justify why
you put something in a given place.
Keep in mind, however, that you should not break the structure of the clean architecture, and be
particularly very strict about the data flow. If you break the data flow, you are basically invalidating
the whole structure. You should try as hard as possible not to introduce solutions that are based on
a break in the data flow, but realistically speaking, if this saves money, do it.
If you do it, there should be a giant warning in your code and your documentation explaining why
you did it. If you access an outer layer breaking the interface paradigm usually it is because of some
performance issues, as the layered structure can add some overhead to the communications between
elements. You should clearly tell other programmers that this happened, because if someone wants
to replace the external layer with something different, they should know that there is direct access
which is implementation-specific.
For the sake of example, let’s say that a use case is accessing the storage layer through an interface,
but this turns out to be too slow. You decide then to access directly the API of the specific database
you are using, but this breaks the data flow, as now an internal layer (use cases) is accessing an
outer one (external interfaces). If someone in the future wants to replace the specific database you
are using with a different one, they have to be aware of this, as the new database probably won’t
provide the same API entry point with the same data.
If you end up breaking the data flow consistently maybe you should consider removing one layer
of abstraction, merging the two layers that you are linking.
Chapter 03 A basic example
Joshua/WOPR: Wouldn’t you prefer a good game of chess?
David: Later. Let’s play Global Thermonuclear War.
Wargames, 1983

The goal of the “Rent-o-Matic” project is to create a simple search engine for a room renting company.
Objects in the dataset (rooms) are described by some attributes and the search engine shall allow
the user to set some filters to narrow the search.
A room is stored in the system through the following values:

• A unique identifier
• A size in square meters
• A renting price in Euro/day
• Latitude and longitude

The description is purposely minimal so that we can focus on the architectural problems and how
to solve them. The concepts that I will show are then easily extendable to more complex cases.
As pushed by the clean architecture model, we are interested in separating the different layers of
the system. Remember that there are multiple ways to implement the clean architecture concepts,
and the code you can come up with strongly depends on what your language of choice allows you
to do. The following is an example of clean architecture in Python, and the implementation of the
models, use cases and other components that I will show is just one of the possible solutions.

Project setup
Clone the project repository¹⁹ and move to the branch second-edition. The full solution is
contained in the branch second-edition-top, and the tags I will mention are there. I strongly
advise to code along and to resort to my tags only to spot errors.

¹⁹https://github.com/pycabook/rentomatic
Chapter 03 A basic example 36

1 $ git clone https://github.com/pycabook/rentomatic


2 $ cd rentomatic
3 $ git checkout --track origin/second-edition

Create a virtual environment following your preferred process and install the requirements

1 $ pip install -r requirements/dev.txt

You should at this point be able to run

1 $ pytest -svv

and get an output like

1 =========================== test session starts ===========================


2 platform linux -- Python XXXX, pytest-XXXX, py-XXXX, pluggy-XXXX --
3 cabook/venv3/bin/python3
4 cachedir: .cache
5 rootdir: cabook/code/calc, inifile: pytest.ini
6 plugins: cov-XXXX
7 collected 0 items
8
9 ========================== no tests ran in 0.02s ==========================

Later in the project you might want to see the output of the coverage check, so you can activate it
with

1 $ pytest -svv --cov=rentomatic --cov-report=term-missing

In this chapter, I will not explicitly state when I run the test suite, as I consider it part of the standard
workflow. Every time we write a test you should run the suite and check that you get an error (or
more), and the code that I give as a solution should make the test suite pass. You are free to try to
implement your own code before copying my solution, obviously.
You may notice that I configured the project to use black with an unorthodox line length of 75.
I chose that number trying to find a visually pleasant way to present code in the book, avoiding
wrapped lines that can make the code difficult to read.

Source code
https://github.com/pycabook/rentomatic/tree/second-edition
Chapter 03 A basic example 37

Domain models
Let us start with a simple definition of the model Room. As said before, the clean architecture models
are very lightweight, or at least they are lighter than their counterparts in common web frameworks.
Following the TDD methodology, the first thing that I write are the tests. This test ensures that the
model can be initialised with the correct values
tests/domain/test_room.py

1 import uuid
2 from rentomatic.domain.room import Room
3
4
5 def test_room_model_init():
6 code = uuid.uuid4()
7 room = Room(
8 code,
9 size=200,
10 price=10,
11 longitude=-0.09998975,
12 latitude=51.75436293,
13 )
14
15 assert room.code == code
16 assert room.size == 200
17 assert room.price == 10
18 assert room.longitude == -0.09998975
19 assert room.latitude == 51.75436293

Remember to create an empty file __init__.py in every subdirectory of tests/ that you create,
in this case tests/domain/__init__.py.
Now let’s write the class Room in the file rentomatic/domain/room.py.
rentomatic/domain/room.py

1 import uuid
2 import dataclasses
3
4
5 @dataclasses.dataclass
6 class Room:
7 code: uuid.UUID
8 size: int
9 price: int
Chapter 03 A basic example 38

10 longitude: float
11 latitude: float

Source code
https://github.com/pycabook/rentomatic/tree/ed2-c03-s01

The model is very simple and requires little explanation. I’m using dataclasses as they are a compact
way to implement simple models like this, but you are free to use standard classes and to implement
the method __init__ explicitly.
Given that we will receive data to initialise this model from other layers, and that this data is likely
to be a dictionary, it is useful to create a method that allows us to initialise the model from this type
of structure. The code can go into the same file we created before, and is
tests/domain/test_room.py

1 def test_room_model_from_dict():
2 code = uuid.uuid4()
3 init_dict = {
4 "code": code,
5 "size": 200,
6 "price": 10,
7 "longitude": -0.09998975,
8 "latitude": 51.75436293,
9 }
10
11 room = Room.from_dict(init_dict)
12
13 assert room.code == code
14 assert room.size == 200
15 assert room.price == 10
16 assert room.longitude == -0.09998975
17 assert room.latitude == 51.75436293

A simple implementation of it is then


Chapter 03 A basic example 39

rentomatic/domain/room.py

1 @dataclasses.dataclass
2 class Room:
3 code: uuid.UUID
4 size: int
5 price: int
6 longitude: float
7 latitude: float
8
9 @classmethod
10 def from_dict(cls, d):
11 return cls(**d)

Source code
https://github.com/pycabook/rentomatic/tree/ed2-c03-s02

For the same reason mentioned before, it is useful to be able to convert the model into a dictionary,
so that we can easily serialise it into JSON or similar language-agnostic formats. The test for the
method to_dict goes again in tests/domain/test_room.py
tests/domain/test_room.py

1 def test_room_model_to_dict():
2 init_dict = {
3 "code": uuid.uuid4(),
4 "size": 200,
5 "price": 10,
6 "longitude": -0.09998975,
7 "latitude": 51.75436293,
8 }
9
10 room = Room.from_dict(init_dict)
11
12 assert room.to_dict() == init_dict

and the implementation is trivial using dataclasses


Another random document with
no related content on Scribd:
my life, look! Was there ever such a babe? Nay, I am too weak
even to clear my arm from him.”
29. “Rest then, and do not talk. I am here, bachari [little
woman].”
30. “Well said, for there is a bond and a heel-rope [peecharee]
between us now that nothing can break. Look—canst thou see
in this light? He is without spot or blemish. Never was such a
man-child. Ya illah! he shall be a pundit—no, a trooper of the
Queen. And, my life, dost thou love me as well as ever, though
I am faint and sick and worn? Answer truly.”
31. “Yea. I love as I have loved, with all my soul. Lie still, pearl,
and rest.”
32. “Then do not go. Sit by my side here—so. Mother, the lord
of this house needs a cushion. Bring it.” There was an almost
imperceptible movement on the part of the new life that lay in
the hollow of Ameera’s arm. “Aho!” she said, her voice breaking
with love. “The babe is a champion from his birth. He is kicking
me in the side with mighty kicks. Was there ever such a babe!
And he is ours to us—thine and mine. Put thy hand on his
head, but carefully, for he is very young, and men are unskilled
in such matters.”
33. Very cautiously Holden touched with the tips of his fingers
the downy head.
34. “He is of the faith,” said Ameera; “for lying here in the night-
watches I whispered the Call to Prayer and the Profession of
Faith into his ears. And it is most marvellous that he was born
upon a Friday, as I was born. Be careful of him, my life; but he
can almost grip with his hands.”
35. Holden found one helpless little hand that closed feebly on
his finger. And the clutch ran through his body till it settled
about his heart. Till then his sole thought had been for Ameera.
He began to realise that there was some one else in the world,
but he could not feel that it was a veritable son with a soul. He
sat down to think, and Ameera dozed lightly.
36. “Get hence, sahib,” said her mother under her breath. “It is
not good that she should find you here on waking. She must be
still.”
37. “I go,” said Holden submissively. “Here be rupees. See that
my baba gets fat and finds all that he needs.”
38. The chink of the silver roused Ameera. “I am his mother,
and no hireling,” she said weakly. “Shall I look to him more or
less for the sake of money? Mother, give it back. I have borne
my lord a son.”
39. The deep sleep of weakness came upon her before the
sentence was completed. Holden went down to the courtyard
very softly, with his heart at ease. Pir Khan, the old watchman,
was chuckling with delight. “This house is now complete,” he
said, and without further comment thrust into Holden’s hands
the hilt of a sabre worn many years ago when he, Pir Khan,
served the Queen in the police. The bleat of a tethered goat
came from the well-curb.
40. “There be two,” said Pir Khan, “two goats of the best. I
bought them, and they cost much money; and since there is no
birth-party assembled their flesh will be all mine. Strike craftily,
sahib! ’Tis an ill-balanced sabre at the best. Wait till they raise
their heads from cropping the marigolds.”
41. “And why?” said Holden, bewildered.
42. “For the birth-sacrifice. What else? Otherwise the child
being unguarded from fate may die. The Protector of the Poor
knows the fitting words to be said.”
43. Holden had learned them once with little thought that he
would ever speak them in earnest. The touch of the cold sabre-
hilt in his palm turned suddenly to the clinging grip of the child
up-stairs—the child that was his own son—and a dread of loss
filled him.
44. “Strike!” said Pir Khan. “Never life came into the world but
life was paid for it. See, the goats have raised their heads.
Now! With a drawing cut!”
45. Hardly knowing what he did, Holden cut twice as he
muttered the Mohammedan prayer that runs: “Almighty! In
place of this my son I offer life for life, blood for blood, head for
head, bone for bone, hair for hair, skin for skin.” The waiting
horse snorted and bounded in his pickets at the smell of the
raw blood that spirted over Holden’s riding-boots.
46. “Well smitten!” said Pir Khan, wiping the sabre. “A
swordsman was lost in thee. Go with a light heart, heaven-
born. I am thy servant, and the servant of thy son. May the
Presence live a thousand years and ... the flesh of the goats is
all mine?” Pir Khan drew back richer by a month’s pay. Holden
swung himself into the saddle and rode off through the low-
hanging wood-smoke of the evening. He was full of riotous
exultation, alternating with a vast vague tenderness directed
towards no particular object, that made him choke as he bent
over the neck of his uneasy horse. “I never felt like this in my
life,” he thought. “I’ll go to the club and pull myself together.”
47. A game of pool was beginning, and the room was full of
men. Holden entered, eager to get to the light and the
company of his fellows, singing at the top of his voice:
“‘In Baltimore a-walking, a lady I did meet!’”
48. “Did you?” said the club-secretary from his corner. “Did she
happen to tell you that your boots were wringing wet? Great
goodness, man, it’s blood!”
49. “Bosh!” said Holden, picking his cue from the rack. “May I
cut in? It’s dew. I’ve been riding through high crops. My faith,
my boots are in a mess, though!”
50.
“‘And if it be a girl she shall wear a wedding-ring,
And if it be a boy he shall fight for his king,
With his dirk, and his cap, and his little jacket blue,
He shall walk the quarter-deck—’”
51. “Yellow on blue—green next player,” said the marker
monotonously.
52. “He shall walk the quarter-deck'—Am I green, marker?—He
shall walk the quarter-deck'—eh! that's a bad shot—‘As his
daddy used to do!’”
53. “I don’t see that you have anything to crow about,” said a
zealous junior civilian acidly. “The Government is not exactly
pleased with your work when you relieved Sanders.”
54. “Does that mean a wigging from headquarters?” said
Holden with an abstracted smile. “I think I can stand it.”
55. The talk beat up round the ever-fresh subject of each man’s
work, and steadied Holden till it was time to go to his dark
empty bungalow, where his butler received him as one who
knew all his affairs. Holden remained awake for the greater part
of the night, and his dreams were pleasant ones.

II
56. “How old is he now?”
57. “Ya illah! What a man’s question! He is all but six weeks
old; and on this night I go up to the housetop with thee, my life,
to count the stars. For that is auspicious. And he was born on a
Friday under the sign of the Sun, and it has been told to me
that he will outlive us both and get wealth. Can we wish for
aught better, beloved?”
58. “There is nothing better. Let us go up to the roof, and thou
shalt count the stars—but a few only, for the sky is heavy with
cloud.”
59. “The winter rains are late, and maybe they come out of
season. Come, before all the stars are hid. I have put on my
richest jewels.”
60. “Thou hast forgotten the best of all.”
61. “Ai! Ours. He comes also. He has never yet seen the
skies.”
62. Ameera climbed the narrow staircase that led to the flat
roof. The child, placid and unwinking, lay in the hollow of her
right arm, gorgeous in silver-fringed muslin with a small skull-
cap on his head. Ameera wore all that she valued most. The
diamond nose-stud that takes the place of the Western patch in
drawing attention to the curve of the nostril, the gold ornament
in the centre of the forehead studded with tallow-drop emeralds
and flawed rubies, the heavy circlet of beaten gold that was
fastened round her neck by the softness of the pure metal, and
the chinking curb-patterned silver anklets hanging low over the
rosy ankle-bone. She was dressed in jade-green muslin as
befitted a daughter of the Faith, and from shoulder to elbow
and elbow to wrist ran bracelets of silver tied with floss silk, frail
glass bangles slipped over the wrist in proof of the slenderness
of the hand, and certain heavy gold bracelets that had no part
in her country’s ornaments but, since they were Holden’s gift
and fastened with a cunning European snap, delighted her
immensely.
63. They sat down by the low white parapet of the roof,
overlooking the city and its lights.
64. “They are happy down there,” said Ameera. “But I do not
think that they are as happy as we. Nor do I think the white
mem-log are as happy. And thou?”
65. “I know they are not.”
66. “How dost thou know?”
67. “They give their children over to the nurses.”
“I have never seen that,” said Ameera with a sigh, “nor do I
wish to see. Ahi!”—she dropped her head on Holden’s shoulder
—“I have counted forty stars, and I am tired. Look at the child,
love of my life, he is counting too.”
68. The baby was staring with round eyes at the dark of the
heavens. Ameera placed him in Holden’s arms, and he lay
there without a cry.
69. “What shall we call him among ourselves?” she said. “Look!
Art thou ever tired of looking? He carries thy very eyes. But the
mouth—”
70. “Is thine, most dear. Who should know better than I?”
71. “’Tis such a feeble mouth. Oh, so small! And yet it holds my
heart between its lips. Give him to me now. He has been too
long away.”
72. “Nay, let him lie; he has not yet begun to cry.”
73. “When he cries thou wilt give him back—eh? What a man
of mankind thou art! If he cried he were only the dearer to me.
But, my life, what little name shall we give him?”
74. The small body lay close to Holden’s heart. It was utterly
helpless and very soft. He scarcely dared to breathe for fear of
crushing it. The caged green parrot that is regarded as a sort of
guardian spirit in most native households moved on its perch
and fluttered a drowsy wing.
75. “There is the answer,” said Holden. “Mian Mittu has
spoken. He shall be the parrot. When he is ready he will talk
mightily and run about. Mian Mittu is the parrot in thy—in the
Mussulman tongue, is it not?”
76. “Why put me so far off?” said Ameera fretfully. “Let it be like
unto some English name—but not wholly. For he is mine.”
77. “Then call him Tota, for that is likest English.”
78. “Ay, Tota, and that is still the parrot. Forgive me, my lord,
for a minute ago, but in truth he is too little to wear all the
weight of Mian Mittu for name. He shall be Tota—our Tota to
us. Hearest thou, O small one? Littlest, thou art Tota.” She
touched the child’s cheek, and he waking, wailed, and it was
necessary to return him to his mother, who soothed him with
the wonderful rhyme of “Aré koko, Jaré koko!” which says:
“Oh, crow! Go crow! Baby’s sleeping sound,
And the wild plums grow in the jungle, only a penny a pound,
Only a penny a pound, baba, only a penny a pound.”

79. Reassured many times as to the price of those plums, Tota


cuddled himself down to sleep. The two sleek, white well-
bullocks in the courtyard were steadily chewing the cud of their
evening meal; old Pir Khan squatted at the head of Holden’s
horse, his police sabre across his knees, pulling drowsily at a
big water-pipe that croaked like a bull-frog in a pond. Ameera’s
mother sat spinning in the lower veranda, and the wooden gate
was shut and barred. The music of a marriage-procession
came to the roof above the gentle hum of the city, and a string
of flying-foxes crossed the face of the low moon.
80. “I have prayed,” said Ameera, after a long pause, “I have
prayed for two things. First that I may die in thy stead if thy
death is demanded, and in the second that I may die in the
place of the child. I have prayed to the Prophet and to Beebee
Miriam [the Virgin Mary]. Thinkest thou either will hear?”
81. “From thy lips who would not hear the lightest word?”
82. “I asked for straight talk, and thou hast given me sweet talk.
Will my prayers be heard?”
83. “How can I say? God is very good.”
84. “Of that I am not sure. Listen now. When I die, or the child
dies, what is thy fate? Living, thou wilt return to the bold white
mem-log, for kind calls to kind.”
85. “Not always.”
86. “With a woman, no; with a man it is otherwise. Thou wilt in
this life, later on, go back to thine own folk. That I could almost
endure for I should be dead. But in thy very death thou wilt be
taken away to a strange place and a paradise that I do not
know.”
87. “Will it be paradise?”
88. “Surely, for who would harm thee? But we two—I and the
child—shall be elsewhere, and we cannot come to thee, nor
canst thou come to us. In the old days, before the child was
born, I did not think of these things; but now I think of them
always. It is very hard talk.”
89. “It will fall as it will fall. To-morrow we do not know, but to-
day and love we know well. Surely we are happy now.”
90. “So happy that it were well to make our happiness assured.
And thy Beebee Miriam should listen to me; for she is also a
woman. But then she would envy me! It is not seemly for men
to worship a woman.”
91. Holden laughed aloud at Ameera’s little spasm of jealousy.
92. “Is it not seemly? Why didst thou not turn me from worship
of thee, then?”
93. “Thou a worshipper! And of me? My king, for all thy sweet
words, well I know that I am thy servant and thy slave, and the
dust under thy feet. And I would not have it otherwise. See!”
94. Before Holden could prevent her she stooped and touched
his feet; recovering herself with a little laugh she hugged Tota
close to her bosom. Then, almost savagely:
95. “Is it true that the bold white mem-log live for three times
the length of my life? Is it true that they make their marriages
not before they are old women?”
96. “They marry as do others—when they are women.”
97. “That I know, but they wed when they are twenty-five. Is
that true?”
98. “That is true.”
99. “Ya illah! At twenty-five! Who would of his own will take a
wife even of eighteen? She is a woman—aging every hour.
Twenty-five! I shall be an old woman at that age, and—those
mem-log remain young forever. How I hate them!”
100. “What have they to do with us?”
101. “I cannot tell. I know only that there may now be alive on
this earth a woman ten years older than I who may come to
thee and take thy love ten years after I am an old woman, gray-
headed, and the nurse of Tota’s son. That is unjust and evil.
They should die too.”
102. “Now, for all thy years thou art a child, and shalt be picked
up and carried down the staircase.”
103. “Tota! Have a care for Tota, my lord! Thou at least art as
foolish as any babe!” Ameera tucked Tota out of harm’s way in
the hollow of her neck, and was carried downstairs laughing in
Holden’s arms, while Tota opened his eyes and smiled after the
manner of the lesser angels.
104. He was a silent infant, and almost before Holden could
realise that he was in the world, developed into a small gold-
coloured little god and unquestioned despot of the house
overlooking the city. Those were months of absolute happiness
to Holden and Ameera—happiness withdrawn from the world,
shut in behind the wooden gate that Pir Khan guarded. By day
Holden did his work with an immense pity for such as were not
so fortunate as himself, and a sympathy for small children that
amazed and amused many mothers at the little station
gatherings. At nightfall he returned to Ameera—Ameera, full of
the wondrous doings of Tota; how he had been seen to clap his
hands together and move his fingers with intention and
purpose—which was manifestly a miracle; how, later, he had of
his own initiative crawled out of his low bedstead on to the floor
and swayed on both feet for the space of three breaths.
105. “And they were long breaths, for my heart stood still with
delight,” said Ameera.
106. Then Tota took the beasts into his councils—the well-
bullocks, the little gray squirrels, the mongoose that lived in a
hole near the well, and especially Mian Mittu, the parrot, whose
tail he grievously pulled, and Mian Mittu screamed till Ameera
and Holden arrived.
107. “O villain! Child of strength! This to thy brother on the
housetop! Tobah, tobah! Fie! Fie! But I know a charm to make
him wise as Suleiman and Aflatoun [Solomon and Plato]. Now
look,” said Ameera. She drew from an embroidered bag a
handful of almonds. “See! we count seven. In the name of
God!”
108. She placed Mian Mittu, very angry and rumpled, on the
top of his cage, and seating herself between the babe and the
bird she cracked and peeled an almond less white than her
teeth. “This is a true charm, my life, and do not laugh. See! I
give the parrot one half and Tota the other.” Mian Mittu with
careful beak took his share from between Ameera’s lips, and
she kissed the other half into the mouth of the child, who ate it
slowly with wondering eyes. “This I will do each day of seven,
and without doubt he who is ours will be a bold speaker and
wise. Eh, Tota, what wilt thou be when thou art a man and I am
gray-headed?” Tota tucked his fat legs into adorable creases.
He could crawl, but he was not going to waste the spring of his
youth in idle speech. He wanted Mian Mittu’s tail to tweak.
109. When he was advanced to the dignity of a silver belt—
which, with a magic square engraved on silver and hung round
his neck, made up the greater part of his clothing—he
staggered on a perilous journey down the garden to Pir Khan
and proffered him all his jewels in exchange for one little ride
on Holden’s horse, having seen his mother’s mother chaffering
with peddlers in the veranda. Pir Khan wept and set the untried
feet on his own gray head in sign of fealty, and brought the bold
adventurer to his mother’s arms, vowing that Tota would be a
leader of men ere his beard was grown.
110. One hot evening, while he sat on the roof between his
father and mother watching the never-ending warfare of the
kites that the city boys flew, he demanded a kite of his own with
Pir Khan to fly it, because he had a fear of dealing with
anything larger than himself, and when Holden called him a
“spark” he rose to his feet and answered slowly in defence of
his new-found individuality: “Hum 'park nahin hai. Hum admi
hai [I am no spark, but a man].”
111. The protest made Holden choke and devote himself very
seriously to a consideration of Tota’s future. He need hardly
have taken the trouble. The delight of that life was too perfect
to endure. Therefore it was taken away as many things are
taken away in India—suddenly and without warning. The little
lord of the house, as Pir Khan called him, grew sorrowful and
complained of pains who had never known the meaning of
pain. Ameera, wild with terror, watched him through the night,
and in the dawning of the second day the life was shaken out
of him by fever—the seasonal autumn fever. It seemed
altogether impossible that he could die, and neither Ameera
nor Holden at first believed the evidence of the little body on
the bedstead. Then Ameera beat her head against the wall and
would have flung herself down the well in the garden had
Holden not restrained her by main force.
112. One mercy only was granted to Holden. He rode to his
office in broad daylight and found waiting him an unusually
heavy mail that demanded concentrated attention and hard
work. He was not, however, alive to this kindness of the gods.

III
113. The first shock of a bullet is no more than a brisk pinch.
The wrecked body does not send in its protest to the soul till
ten or fifteen seconds later. Holden realised his pain slowly,
exactly as he had realised his happiness, and with the same
imperious necessity for hiding all traces of it. In the beginning
he only felt that there had been a loss, and that Ameera
needed comforting where she sat with her head on her knees
shivering as Mian Mittu from the housetop called: Tota! Tota!
Tota! Later, all his world and the daily life of it rose up to hurt
him. It was an outrage that any one of the children at the band-
stand in the evening should be alive and clamorous, when his
own child lay dead. It was more than mere pain when one of
them touched him, and stories told by over-fond fathers of their
children’s latest performances cut him to the quick. He could
not declare his pain. He had neither help, comfort, nor
sympathy; and Ameera at the end of each weary day would
lead him through the hell of self-questioning reproach which is
reserved for those who have lost a child, and believe that with
a little—just a little—more care it might have been saved.
114. “Perhaps,” Ameera would say, “I did not take sufficient
heed. Did I, or did I not? The sun on the roof that day when he
played so long alone and I was—ahi! braiding my hair—it may
be that the sun then bred the fever. If I had warned him from
the sun he might have lived. But oh, my life, say that I am
guiltless! Thou knowest that I loved him as I love thee. Say that
there is no blame on me, or I shall die—I shall die!”
115. “There is no blame—before God, none. It was written, and
how could we do aught to save? What has been, has been. Let
it go, beloved.”
116. “He was all my heart to me. How can I let the thought go
when my arm tells me every night that he is not here? Ahi! Ahi!
O Tota, come back to me—come back again, and let us be all
together as it was before!”
117. “Peace, peace! For thine own sake, and for mine also, if
thou lovest me—rest.”
118. “By this I know thou dost not care; and how shouldst thou?
The white men have hearts of stone and souls of iron. Oh, that
I had married a man of mine own people—though he beat me
—and had never eaten the bread of an alien!”
119. “Am I an alien—mother of my son?”
120. “What else—sahib?... Oh, forgive me—forgive! The death
has driven me mad. Thou art the life of my heart, and the light
of my eyes, and the breath of my life, and—and I have put thee
from me, though it was but for a moment. If thou goest away, to
whom shall I look for help? Do not be angry. Indeed, it was the
pain that spoke and not thy slave.”
121. “I know, I know. We be two who were three. The greater
need therefore that we should be one.”
122. They were sitting on the roof as of custom. The night was
a warm one in early spring, and sheet-lightning was dancing on
the horizon to a broken tune played by far-off thunder. Ameera
settled herself in Holden’s arms.
123. “The dry earth is lowing like a cow for the rain, and I—I
am afraid. It was not like this when we counted the stars. But
thou lovest me as much as before, though a bond is taken
away? Answer!”
124. “I love more because a new bond has come out of the
sorrow that we have eaten together, and that thou knowest.”
125. “Yea, I knew,” said Ameera in a very small whisper. “But it
is good to hear thee say so, my life, who art so strong to help. I
will be a child no more but a woman and an aid to thee. Listen!
Give me my sitar and I will sing bravely.”
126. She took the light silver-studded sitar and began a song of
the great hero Rajah Rasalu. The hand failed on the strings,
the tune halted, checked, and at a low note turned off to the
poor little nursery-rhyme about the wicked crow:
“‘And the wild plums grow in the jungle, only a penny a pound,
Only a penny a pound, baba—only....’”

127. Then came the tears and the piteous rebellion against fate
till she slept, moaning a little in her sleep, with the right arm
thrown clear of the body as though it protected something that
was not there. It was after this night that life became a little
easier for Holden. The ever-present pain of loss drove him into
his work, and the work repaid him by filling up his mind for nine
or ten hours a day. Ameera sat alone in the house and
brooded, but grew happier when she understood that Holden
was more at ease, according to the custom of women. They
touched happiness again, but this time with caution.
128. “It was because we loved Tota that he died. The jealousy
of God was upon us,” said Ameera. “I have hung up a large
black jar before our window to turn the evil eye from us, and we
must make no protestations of delight, but go softly underneath
the stars, lest God find us out. Is that not good talk, worthless
one?”
129. She had shifted the accent on the word that means
“beloved,” in proof of the sincerity of her purpose. But the kiss
that followed the new christening was a thing that any deity
might have envied. They went about henceforward saying: “It is
naught, it is naught”; and hoping that all the Powers heard.
130. The Powers were busy on other things. They had allowed
thirty million people four years of plenty wherein men fed well
and the crops were certain, and the birth-rate rose year by
year; the districts reported a purely agricultural population
varying from nine hundred to two thousand to the square mile
of the overburdened earth; and the Member for Lower Tooting,
wandering about India in pot-hat and frock-coat, talked largely
of the benefits of British rule and suggested as the one thing
needful the establishment of a duly qualified electoral system
and a general bestowal of the franchise. His long-suffering
hosts smiled and made him welcome, and when he paused to
admire, with pretty picked words, the blossom of the blood-red
dhak-tree that had flowered untimely for a sign of what was
coming, they smiled more than ever.
131. It was the Deputy Commissioner of Kot-Kumharsen,
staying at the club for a day, who lightly told a tale that made
Holden’s blood run cold as he overheard the end.
132. “He won’t bother any one any more. Never saw a man so
astonished in my life. By Jove, I thought he meant to ask a
question in the House about it. Fellow passenger in his ship—
dined next him—bowled over by cholera and died in eighteen
hours. You needn’t laugh, you fellows. The Member for Lower
Tooting is awfully angry about it; but he’s more scared. I think
he’s going to take his enlightened self out of India.”
133. “I’d give a good deal if he were knocked over. It might
keep a few vestrymen of his kidney to their own parish. But
what’s this about cholera? It’s full early for anything of that
kind,” said the warden of an unprofitable salt-lick.
134. “Don’t know,” said the Deputy Commissioner reflectively.
“We’ve got locusts with us. There’s sporadic cholera all along
the north—at least we’re calling it sporadic for decency’s sake.
The spring crops are short in five districts, and nobody seems
to know where the rains are. It’s nearly March now. I don’t want
to scare anybody, but it seems to me that Nature’s going to
audit her accounts with a big red pencil this summer.”
135. “Just when I wanted to take leave, too!” said a voice
across the room.
136. “There won’t be much leave this year, but there ought to
be a great deal of promotion. I’ve come in to persuade the
Government to put my pet canal on the list of famine-relief
works. It’s an ill wind that blows no good. I shall get that canal
finished at last.”
137. “Is it the old programme then,” said Holden; “famine,
fever, and cholera?”
138. “Oh, no. Only local scarcity and an unusual prevalence of
seasonal sickness. You’ll find it all in the reports if you live till
next year. You’re a lucky chap. You haven’t got a wife to send
out of harm’s way. The hill stations ought to be full of women
this year.”
139. “I think you’re inclined to exaggerate the talk in the
bazars,” said a young civilian in the secretariat. “Now I have
observed—”
140. “I daresay you have,” said the Deputy Commissioner, “but
you’ve a great deal more to observe, my son. In the meantime,
I wish to observe to you—” and he drew him aside to discuss
the construction of the canal that was so dear to his heart.
Holden went to his bungalow and began to understand that he
was not alone in the world, and also that he was afraid for the
sake of another—which is the most soul-satisfying fear known
to man.
141. Two months later, as the Deputy had foretold, Nature
began to audit her accounts with a red pencil. On the heels of
the spring reapings came a cry for bread, and the Government,
which had decreed that no man should die of want, sent wheat.
Then came the cholera from all four quarters of the compass. It
struck a pilgrim-gathering of half a million at a sacred shrine.
Many died at the feet of their god; the others broke and ran
over the face of the land carrying the pestilence with them. It
smote a walled city and killed two hundred a day. The people
crowded the trains, hanging on to the foot-boards and
squatting on the roofs of the carriages, and the cholera
followed them, for at each station they dragged out the dead
and the dying. They died by the roadside, and the horses of the
Englishmen shied at the corpses in the grass. The rains did not
come, and the earth turned to iron lest man should escape
death by hiding in her. The English sent their wives away to the
hills and went about their work, coming forward as they were
bidden to fill the gaps in the fighting-line. Holden, sick with fear
of losing his chiefest treasure on earth, had done his best to
persuade Ameera to go away with her mother to the
Himalayas.
142. “Why should I go?” said she one evening on the roof.
143. “There is sickness, and people are dying, and all the white
mem-log have gone.”
144. “All of them?”
145. “All—unless perhaps there remain some old scald-head
who vexes her husband’s heart by running risk of death.”
146. “Nay; who stays is my sister, and thou must not abuse
her, for I will be a scald-head too. I am glad all the bold mem-
log are gone.”
147. “Do I speak to a woman, or a babe? Go to the hills and I
will see to it that thou goest like a queen’s daughter. Think,
child. In a red-lacquered bullock-cart, veiled and curtained, with
brass peacocks upon the pole and red cloth hangings. I will
send two orderlies for guard, and—”
148. “Peace! Thou art the babe in speaking thus. What use are
those toys to me? He would have patted the bullocks and
played with the housings. For his sake, perhaps—thou hast
made me very English—I might have gone. Now, I will not. Let
the mem-log run.”
149. “Their husbands are sending them, beloved.”
150. “Very good talk. Since when hast thou been my husband
to tell me what to do? I have but borne thee a son. Thou art
only all the desire of my soul to me. How shall I depart when I
know that if evil befall thee by the breadth of so much as my
littlest finger-nail—is that not small?—I should be aware of it
though I were in paradise. And here, this summer thou mayest
die—ai, janee, die! and in dying they might call to tend thee a
white woman, and she would rob me in the last of thy love!”
151. “But love is not born in a moment or on a death-bed!”
152. “What dost thou know of love, stone-heart? She would
take thy thanks at least and, by God and the Prophet and
Beebee Miriam the mother of thy Prophet, that I will never
endure. My lord and my love, let there be no more foolish talk
of going away. Where thou art, I am. It is enough.” She put an
arm round his neck and a hand on his mouth.
153. There are not many happinesses so complete as those
that are snatched under the shadow of the sword. They sat
together and laughed, calling each other openly by every pet
name that could move the wrath of the gods. The city below
them was locked up in its own torments. Sulphur fires blazed in
the streets; the conches in the Hindu temples screamed and
bellowed, for the gods were inattentive in those days. There
was a service in the great Mohammedan shrine, and the call to
prayer from the minarets was almost unceasing. They heard
the wailing in the houses of the dead, and once the shriek of a
mother who had lost a child and was calling for its return. In the
gray dawn they saw the dead borne out through the city gates,
each litter with its own little knot of mourners. Wherefore they
kissed each other and shivered.
154. It was a red and heavy audit, for the land was very sick
and needed a little breathing space ere the torrent of cheap life
should flood it anew. The children of immature fathers and
undeveloped mothers made no resistance. They were cowed
and sat still, waiting till the sword should be sheathed in
November if it were so willed. There were gaps among the
English, but the gaps were filled. The work of superintending
famine-relief, cholera-sheds, medicine-distribution, and what
little sanitation was possible, went forward because it was so
ordered.
155. Holden had been told to keep himself in readiness to
move to replace the next man who should fall. There were
twelve hours in each day when he could not see Ameera, and
she might die in three. He was considering what his pain would
be if he could not see her for three months, or if she died out of
his sight. He was absolutely certain that her death would be
demanded—so certain that when he looked up from the
telegram and saw Pir Khan breathless in the doorway, he
laughed aloud. “And?” said he—
156. “When there is a cry in the night and the spirit flutters into
the throat, who has a charm that will restore? Come swiftly,
heaven-born! It is the black cholera.”
157. Holden galloped to his home. The sky was heavy with
clouds, for the long-deferred rains were near and the heat was
stifling. Ameera’s mother met him in the courtyard, whimpering:
“She is dying. She is nursing herself into death. She is all but
dead. What shall I do, sahib?”
158. Ameera was lying in the room in which Tota had been
born. She made no sign when Holden entered, because the
human soul is a very lonely thing and, when it is getting ready
to go away, hides itself in a misty border-land where the living
may not follow. The black cholera does its work quietly and
without explanation. Ameera was being thrust out of life as
though the Angel of Death had himself put his hand upon her.
The quick breathing seemed to show that she was either afraid
or in pain, but neither eyes nor mouth gave any answer to
Holden’s kisses. There was nothing to be said or done. Holden
could only wait and suffer. The first drops of the rain began to
fall on the roof, and he could hear shouts of joy in the parched
city.
159. The soul came back a little and the lips moved. Holden
bent down to listen. “Keep nothing of mine,” said Ameera.
“Take no hair from my head. She would make thee burn it later
on. That flame I should feel. Lower! Stoop lower! Remember
only that I was thine and bore thee a son. Though thou wed a
white woman to-morrow, the pleasure of receiving in thy arms
thy first son is taken from thee forever. Remember me when
thy son is born—the one that shall carry thy name before all
men. His misfortunes be on my head. I bear witness—I bear
witness”—the lips were forming the words on his ear—“that
there is no God but—thee, beloved!”
160. Then she died. Holden sat still, and all thought was taken
from him—till he heard Ameera’s mother lift the curtain.
161. “Is she dead, sahib?”
162. “She is dead.”
163. “Then I will mourn, and afterwards take an inventory of the
furniture in this house. For that will be mine. The sahib does
not mean to resume it? It is so little, so very little, sahib, and I
am an old woman. I would like to lie softly.”
164. “For the mercy of God be silent a while. Go out and mourn
where I cannot hear.”
165. “Sahib, she will be buried in four hours.”
166. “I know the custom. I shall go ere she is taken away. That
matter is in thy hands. Look to it, that the bed on which—on
which she lies—”
167. “Aha! That beautiful red-lacquered bed. I have long
desired—”
168. “That the bed is left here untouched for my disposal. All
else in the house is thine. Hire a cart, take everything, go
hence, and before sunrise let there be nothing in this house but
that which I have ordered thee to respect.”
169. “I am an old woman. I would stay at least for the days of
mourning and the rains have just broken. Whither shall I go?”
170. “What is that to me? My order is that there is a going. The
house-gear is worth a thousand rupees, and my orderly shall
bring thee a hundred rupees to-night.”
171. “That is very little. Think of the cart-hire.”
172. “It shall be nothing unless thou goest, and with speed. O
woman, get hence and leave me with my dead!”
173. The mother shuffled down the staircase, and in her
anxiety to take stock of the house-fittings forgot to mourn.
Holden stayed by Ameera’s side and the rain roared on the
roof. He could not think connectedly by reason of the noise,
though he made many attempts to do so. Then four sheeted
ghosts glided dripping into the room and stared at him through
their veils. They were the washers of the dead. Holden left the
room and went out to his horse. He had come in a dead, stifling
calm through ankle-deep dust. He found the courtyard a rain-
lashed pond alive with frogs; a torrent of yellow water ran
under the gate, and a roaring wind drove the bolts of the rain
like buckshot against the mud walls. Pir Khan was shivering in
his little hut by the gate, and the horse was stamping uneasily
in the water.
174. “I have been told the sahib’s order,” said Pir Khan. “It is
well. This house is now desolate. I go also, or my monkey face
would be a reminder of that which has been. Concerning the
bed, I will bring that to thy house yonder in the morning; but
remember, sahib, it will be to thee a knife turning in a green
wound. I go upon a pilgrimage, and I will take no money. I have
grown fat in the protection of the Presence whose sorrow is my
sorrow. For the last time I hold his stirrup.”
175. He touched Holden’s foot with both hands, and the horse
sprang out into the road, where the creaking bamboos were
whipping the sky and all the frogs were chuckling. Holden
could not see for the rain in his face. He put his hands before
his eyes and muttered:
176. “Oh, you brute! You utter brute!”
177. The news of his trouble was already in his bungalow. He
read the knowledge in his butler’s eyes when Ahmed Khan
brought in food, and for the first and last time in his life laid a
hand upon his master’s shoulder, saying: “Eat, sahib, eat. Meat
is good against sorrow. I also have known. Moreover the

You might also like