Clean Architectures in Python A Practical Approach To Better Software Design 2nd Edition 2023 Update Leonardo Giordani
Clean Architectures in Python A Practical Approach To Better Software Design 2nd Edition 2023 Update Leonardo Giordani
Clean Architectures in Python A Practical Approach To Better Software Design 2nd Edition 2023 Update Leonardo Giordani
https://ebookmeta.com/product/clean-architectures-in-python-a-
practical-approach-to-better-software-design-2nd-edition-
leonardo-giordani-2/
https://ebookmeta.com/product/clean-architectures-in-python-a-
practical-approach-to-better-software-design-2nd-edition-
leonardo-giordani/
https://ebookmeta.com/product/embedded-software-design-a-
practical-approach-to-architecture-processes-and-coding-
techniques-1st-edition-jacob-beningo/
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/
https://ebookmeta.com/product/building-evolutionary-
architectures-automated-software-governance-2nd-edition-neal-
ford-2/
https://ebookmeta.com/product/building-evolutionary-
architectures-automated-software-governance-2nd-edition-neal-
ford/
https://ebookmeta.com/product/clean-python-elegant-coding-in-
python-1st-edition-sunil-kapil/
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 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.
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is a software architecture? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Why is it called “clean”? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Why “architectures”? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Why Python? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
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.
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.
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!
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 $
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
Concept
This recaps an important concept that is explained in the text.
About the book 8
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.
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 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 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.
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
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.
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 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.
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
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.
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.
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.
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
Create a virtual environment following your preferred process and install the requirements
1 $ pytest -svv
Later in the project you might want to see the output of the coverage check, so you can activate it
with
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
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
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.”
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