← Contents · Runnable Specifications by Eric Normand · Work in progress · Comments
1
A friend in the book business told me the introduction is oen
read by someone standing in a bookstore, deciding whether to
buy the book. If that’s you, then welcome! I hope this introduction
gives you what you need to make a buying decision. If you already
own the book, it will orient and ready you for the rest of the book.
All programmers design soware, so we have a sense for what
it means. However, I will dene it so we are on the same page. I
also want you to understand the slightly cryptic title of the book.
And nally, you should understand how I intended you to use the
book to maximize your learning.
Chapter objectives
Understand the big ideas of this book.
Decide if this book is for you.
Learn how to maximize your learning from this book.
1
Introduct ion
Important terms
soware design
domain modeling
runnable specications
you’ll learn these
terms in this chapter
2
Introduction
Soware design means making programming decisions
This is a book about soware design. There are many denitions
out there for the term. I don’t want to comment on the others, nor
do I want to replace them. I will just dene it for the scope of this
book, because I nd this denition most useful for the material
ahead:
Soware design is making decisions about how we write the
soware.
While coding, we have a lot of choices to make. Do I use a for
loop or a while loop? Do I break this function into two smaller
functions? How do I name them? What types should the func-
tion’s arguments be? What data structure should I use to store this
data in memory? Where should I break up my modules?In short,
soware design is the total of all of your decisions when mak-
ing soware. Thats everything from what the soware should do
to how to architect it to the line-by-line decisions a programmer
must make while coding. Any more limited denition chops up
the creation of soware arbitrarily.
My denition tracks with denitions found in other elds
where they use the term design. Steve Jobs has a famous quote:
Design is not just what it looks like and feels like. Design is how it
works.
To me, that means design is the whole thing. It’s not just pret-
tying up the code. Its also the choice of data structure—which af-
fects the memory usage—which aects its performance—which
aects how the user perceives it. There’s no easy line to draw to
divide design from non-design activity. Soware design is holis-
tic.
Wait, if soware design is everything, isn’t it synonymous with
programming? Well, yes, it is. However, calling it soware design
highlights that we are making those decisions. Programming has
more of a “tell the computer what to do vibe. One purpose of this
book is to bring a new awareness to the many decisions we make
so that we can make dierent decisions from the habits weve
developed over the years.
3Introduction
Making design decisions is hard
Soware design decisions are hard. There are three reasons.
Firstly, there are thousands if not millions of design decisions to
make when building a signicant piece of soware.
Secondly, design decisions have multi-dimensional impact.
Some of design choices we make are small and not meaningful,
while others can seriously impact the performance, readability,
and modiability (among other aspects) of our code—let alone
whether the code does what it’s supposed to.
And thirdly, design decisions are interdependent. For instance,
if I move a function into another module, its name may no longer
make sense in its new context. If I choose to use a hash map be-
cause it makes my function lookup fast, it may lose the order of
insertion that another function needs.
These characteristics add up to a very hard problem. Its too
big to t the entire design in our heads. Its nearly impossible
to understand the rst-order consequences of our decisions, let
alone the second-order ones. Soware design is complicated.
As an industry, we’ve relied on a kind of oral tradition to teach
design. A senior programmer works closely with a junior pro-
grammer to impart what knowledge they can. The junior eventu-
ally graduates to senior. This kind of one-on-one tutoring works,
but it doesn’t scale.
Some skilled programmers have tried to broadcast their so-
ware design skill through books, conference talks, and blog
posts. They develop principles and rules-of-thumb. However,
without the one-on-one interaction to show when the principles
apply and when they don’t, the principles oen get misapplied by
beginners, oen resulting in dogmatic rule adherence instead of
nuanced design skill.
Ive taken it as a challenge to organize the material in this book
not as principles and rules but as perspectives. Each perspective
gives us a dierent way to look at the problem. And through dif-
ferent perspectives we can begin to assemble a holistic view of
the soware we build.
4
Introduction
We make better decisions with more information
Ive dened soware design as making decisions. The quality of
soware design is therefore proportional to the quality of deci-
sions we make. So now our problem is easier: Just make better
decisions. Better design will follow.
But how do we make better decisions? One way we make better
decisions is to have better information. We want more informa-
tion about the consequences of each design decision. What im-
pact does a decision have on the soware’s ability to do its job—
and further on expressivity, on readability, on performance, on
maintainability? And how does that decision aect other design
choices we must make?
For example, we must choose what data structure to use to rep-
resent a coee order. If we use an array of coees, does that en-
able important use cases or hinder them? Does it make the code
easier to write and read?
Further, arrays maintain insertion order. Does that make it
easier or harder to decide how to implement adding a cofee to
an order? What about removing a coee from an order?
We cant immediately answer the questions. Oen, the best
we can do is it depends. What we mean is that we need more
information to decide. Many of the skills in this book are about
extracting as much information as possible from the context so
that we make better decisions.
What I aim to do in this book is to equip you, the reader, to be
an explorer. I will give you questions to ask. I will tell you what
to look for. I will equip you with a vocabulary and important con-
cepts. I will help them exercise your judgment. Then I will set you
loose to make decisions.
5Introduction
The domain is the best source of information
Domain modeling as an approach to soware design uses the do-
main as the most important source of information for making de-
cisions. That means that any time you have a question to answer,
you must seek an answer in the domain. Examples:
Q: How should I name this method? A: What’s it called in the
domain?
Q: Should I split this function in two? A: Is it split in the do-
main?
Q: Should I add a layer of indirection? A: Does it correspond to
anything in the domain?
Q: Have I covered all of the cases? A: Are there more cases in
the domain?
That doesnt mean that you will always do exactly what the do-
main experts say. Soware does impose its own constraints and
considerations. But the domain is an important source of infor-
mation.
The domain is the context in which your program must oper-
ate correctly. If you’re writing accounting soware, the domain is
accounting. Most of your program is organized to get that right
it’s the core of your soware. If you get the domain model wrong
or messy, your code will be riddled with complex workarounds.
A poor domain model is the source of the code complexity other
design methodologies focus on.
Typical soware design approaches rely on code metrics or
code smells. Some measure things in the code like the length
of methods or the number of nested if statements. Others use a
more qualitative analysis to identify problem areas (“code smells
or coupling.). These can be useful to indentify messy code. But
they miss the cause: An incorrect domain model requires more
complex code to use.
These approaches ignore the domain because every domain
is dierent and teaching someone to analyze a domain properly
is dicult. In this book, I will teach you to extract information
from the domain and encode it in your soware.
6
Introduction
We make better decisions by considering more options
Another way we can make better decisions is by considering more
options. When you’re playing chess, you make better moves by
considering more moves. Likewise, you make better decisions by
consider more options for each decision.
When we’re learning to program, there is so much to learn and
so many decisions to make, we are taught simple methodologies
that help us make progress. For instance, I was taught in school
that we should make a class for each concept in the problem de-
scription. That would mean if I had to build a university course
registry, I would make a Student class and a Course class.
Over years of experience, as our skills grow, we should drop
these simplistic methodologies, but oen we do not. They become
ingrained habits that we never question. When we are presented
with a design decision, we apply our habits and never consider
other options.
In my case, it took years of exploration and introspection for
me to rid myself of that habit that went back to my universitys
Object-Oriented Design course. It started with considering other
options. What if I used a plain data structure to hold the data for
a Student? What if I use functions instead of classes? What if I
model something besides what’s in the problem description?
By asking these questions and experimenting with dierent
design decisions, I got rid of the habit and became a better de-
signer. That’s the process I want to guide you through as well. It
requires you to become aware of your default mode of program-
ming and interrupt it with new possibilities.
7Introduction
We make better decisions through iteration and feedback
Most of our decisions will be suboptimal because we cant really
hold the complexity of our soware in our heads. There are too
many choices and the consequences of each choice are hard to
foresee.
The best way to understand the consequences of our coding
decisions is to code it and see. In other words, we have to proceed
empirically. We make a choice, code it, and see what it looks like.
Thats iteration and feedback.
At that point, we may back up and try a dierent decision, or
we may make small adjustments. The essential factor is that we
are working in the medium—code—and not in another medium
that will eventually be translated into code. Because we are ex-
ploring in the soware itself, we can directly understand the ef-
fect design decisions have on the overal design of our soware.
Iteration and feedback are important in other types of design.
Furniture designers might not be able to iterate quickly enough
in the original medium, let’s say walnut, but they can nd aprox-
imations, for instance working in soer plywood or even card-
board to quickly create prototypes to experiment on the shape
of the chair they’re working on. Other media, like oil paint, are
more direct. What you see is what you get.
I want to teach you techniques for working in code that allow
the kind of iteration I’m talking about. It involves working in code
at the right level of abstraction (using types and function signa-
tures), then stubbing them out to be able to run the functions.
Each chapter gives you a high resolution look at how well the
design models the domain so you can increase the amount of rel-
evant information you gather. These perspectives surface prob-
lems early so you can iterate faster, consider more options, and
evaluate them better.
8
Introduction
What are runnable specications?
Okay, it’s time to addres the book’s title, Runnable Specications.
The phrase needs some explanation. It means three things:
separating specication from implementation
modeling your domain in code
seeking fast, rich feedback
Lets consider each one.
Separating specication from implementation
Separating specication from implementation has been called
the most important skill that dierentiates juniors from seniors.
Some people say interface instead of specication. But it
means the same thing. We separate the meaning of the soware
from how it is implemented.
When we say something is messy or undesigned, oen we
mean there is no way to understand the interface except by un-
derstanding exactly what it does. In such cases, there is no sep-
aration between specication and implementation. In this book,
you will learn how to reason about the interfaces separately from
the implementation. In fact, even though there is plenty of code
in this book, we will do very little implementationjust enough
to make things runnable.
Modeling your domain in code
Domain modeling means to encode an abstraction of the problem
domain. That can get technical and a lot of this book is about the
skills of modeling. Its too much to explain in detail here in the
introduction—but here’s a short description.
An abstraction maps information from the concrete to an ab-
stract representation. The mapping is good if it preserves opera-
tions. That is, the important operations in the concrete domain
are also available in the abstract representation.
How do we choose what to represent? What operations are
important? Those are hard questions to answer in general. And
theyre also hard in the specic. It takes trial-and-error and lots
of iteration. And for that, we need rich feedback.
Vocabulary
Why is it that if I use the word
meaning, people are confused,
but if I use the word semantics,
they nod their heads? They
mean the same thing, but se-
mantics is so technical, peo-
ple ignore it. Meaning still has
some impact, so I’m using it.
9Introduction
Seeking fast, rich feedback
Feedback allows us to learn faster. If we learn faster, we can eval-
uate more design alternatives in the same period of time. And
we can also work for longer because we get less frustrated and
achieve little wins along the way.
Because soware design is so dicult, oen the only way we
can understand the consequences of a design is by making the
design and seeing how it works. It is so complicated, we must ex-
ternalize it. The thing we externalize will have good parts and
bad parts. Learning about those is feedback.
I believe the best source of feedback is the medium itselfcode.
Code must be syntactically correct. It must pass the type checker.
And it must run and work. Running the code is the richest form
of feedback possible. UML and other visual modeling media do
provide some feedbackvisual information. But nothing beats
the feedback of running code with interesting tests. In this book,
we’ll learn techniques for increasing the speed and information
content of the feedback.
The trouble is, if we write running code, we run the risk of
crossing the line from specication into implementation. Its a
real problem. This book addresses several concepts and skills to
prevent implementing prematurely while still writing code that
might make it to production.
10
Introduction
This book is organized into lenses
The material in this book is organized into lenses. Each lens gives
a dierent perspective on the domain and how to model it. Each
lens has concepts and skills that help us extract more informa-
tion from the domain and encode that information into our so-
ware. Using the dierent perspectives of these lenses, we can
nd constraints that help us tame the multi-faceted complexity
of our soware design decisions.
I had a real challenge organizing the material. I did not want
to prescribe principles or rules-of-thumb. Those do not work un-
less you are already good enough to apply them correctly. Too
oen, beginners take a good rule and over-apply it. They dont
know how to see when the rule is meant to be applied and when
there is an exceptional case.
Also, I wanted to avoid dictating a process for designing so-
ware. Again, the complexity of the decisions we make does not
allow a neat sequence of steps needed for a design process. I in-
stead opted for increasing the resolution of your vision. With the
concepts and skills in these lenses, you will learn to see things
that have always been there that you weren’t paying attention to.
You will learn what to look for and how to evaluate what you see.
And you will learn to encode what you see into soware. Upgrad-
ed and equipped, the process is up to you.
11Introduction
How does this compare with Unied Modeling Language?
Inevitably, when I mentioned the topic of this book during its
writing, people asked me how it compares to other paradigms.
This is a fair question. I might as well address it here and now to
help you contrast them and understand whether this book is for
you.
Unied Modeling Language (UML) is a visual modeling lan-
guage meant to aid in the soware design process. The creators
of UML wanted to present their design to stakeholders, many
of whom were non-programmers. Code contained too much in-
formation to understand at a glance, and the important design
decisions were intertwined with incidental implementation de-
cisions. So they developed a visual language to capture the main
design decisions without the extraneous details of the syntax of a
programming language. UML diagrams contain important char-
acteristics of the model.
UML is pictorial, while runnable specications use code as the
medium. Instead of using an intermediate modeling language
then translating it into code, in runnable specications we go
directly to code. However, we avoid the problem of having the
extraneous details because in runnable specications we choose
to use a very restricted subset of code. That subset is selected so
that we stay rmly in the specication (where important design
decisions are made) and out of the implementation (which is rife
with extraneous details).
But because we are writing it in code, we get several advantag-
es:
There is no translation step, and no diagrams getting out of
sync with the code.
We can solve many problems sooner because we can use the
tools we have for code such as type checkers.
We can run the code and prototype the system to check if the
model does what we think it should.
The main thing we lose compared to UML is that it is not visual. It
is harder to read for non-programmers. We also risk slipping into
implementation inadvertently.
12
Introduction
How does this compare with Domain Driven Design?
Another popular movement is the Domain Driven Design (DDD)
community which began with a book of the same name by Eric
Evans. In DDD, they design models in code, similar to in runna-
ble specications. In fact, I considered whether to make this a
Domain Driven Design book. But there are several important dif-
ferences that made me want to avoid the DDD branding.
First, the DDD book (and the ensuing community) are using
the typical soware design principles, rules-of-thumb, and pat-
terns approach, which I don’t think works very well to teach so-
ware design. Ive already mentioned why. I dont want runnable
specications to be assimilated into that, with the skills in this
book seen as patterns.
Second, the DDD book has a lot of project management advice,
and this book avoids that. Project management is important and
DDD probably has some great advice in it. But this book focuses
much more on the technical skills of soware design.
Third, DDD is mostly framed in object-oriented terms. Thats
ne, but I am framing runnable specications in functional pro-
gramming (FP) terms. I believe FP has unique advantages for
modeling (in particular, immutable data allows for better model-
ing of changes over time) and I want to highlight those.
Finally, this one is perhaps a little unfair, but its worth men-
tioning. The DDD book is a very large tome and contains a lot of
ideas and wisdom from Eric Evans. Unfortunately, its so big that
people can nd whatever they like. Two people discussing DDD
oen are discussing dierent subsets of ideas. So although they
belong to the same community, they oen don’t share much in
common. I didnt want runnable specications to get lost in that
sea.
All of that said, I do think there is a lot of kinship between run-
nable specications and the ideas specic to modeling from DDD.
One might consider runnable specications to be a very practi-
cal guide to domain modeling that a DDD enthusiast might use to
teach others how to do it.
13Introduction
How does this compare with soware design in general?
Runnable Specications is about soware design, so I should
place it in relation to the soware design movement in general.
Soware design is an important eld. We should be thinking
about the way our soware is constructed and try to optimize it.
However, I believe soware design has taken a wrong turn.
The main problem is that most soware design advice focuses
on the code artefact. That is, it uses code metrics to identify com-
plexity, code smells to nd trouble spots, and coding patterns to
prescribe how to make bad code better.
Now, to be clear, code quality is very important. I don’t want to
diminish the importance of it. But its not all there is. What about
the semantics of your code? Does your code correspond to the
thing it is supposed to do? It is as if we have a whole eld dedicat-
ed to style, but no eld dedicated to substance.
It is akin to giving a novelist writing advice but focusing only
on word choice, rhythm, and other stylistic concerns. What is
missing is the substance of the novel. What about plot, characters,
setting? Those are the things that make a novel worth reading;
style should support those. Analagously, soware design advice
should focus on being useful in the domain; style advice should
support it. What is the soware trying to do? What are the im-
portant facts we need to capture? How does the soware model
those facts so that the problem can be solved? Domain modeling
puts the content (the domain) rst. The style must support the
domain. Runnable specications focus our design decisions on
the information from the domain.
Further, soware design advocates oen talk about so-called
non-functional requirements as the goals of soware design,
particularly maintainability or readability. These are worthy
things to strive for, but in my opinion, the best way to get main-
tainable and readable code is to make sure your domain model
is good. A bad domain model begs for messy code that is hard to
modify. A good domain model makes readable code possible.
14
Introduction
How to use this book
There are three guiding points I’d like to make about how you can
best use this book.
Read the chapters straight through
I’ve written the chapters to be read in order. Some of them build
upon the previous ones, so they are not meant to be read inde-
pendently. They are also ordered to start with the most important
and fundamental skills and build from there.
Do the exercises
This book teaches practical skills, and to do that you need to get
some practice. To maximize what you get out of this book, do the
exercises before moving on. Each exercise has been designed
to practice what was just discussed in the text. And when youre
done, you can compare against the answer. Since it’s code, there
is rarely a single correct answer, but it can help to see how some-
one else has done it.
Note that in the early release version (that you are reading now),
there are very few exercises. I will add more later as I get closer to
publication.
Use the supplements as reference
Some chapters are followed by supplements. You can read the
supplements as you get to them, but feel free to skim or skip them.
They are meant to be used as a reference for some of the material.
For instance, the Data Lens Supplement contains common rela-
tionship structures and lists how they are typically encoded.
15Introduction
Conclusion
In this introduction, we understood soware design as making
decisions, and saw ways to improve our decision making. We also
learned about domain modeling, runnable specications, and
how they relate to other soware design methodologies. Finally,
we learned how to use the rest of the book. I hope this introduc-
tion convinces you to read the rest of the book.
Summary
Soware design is about making design decisions. We make
better decisions with more information, by considering
more options, and with rich feedback.
Domain modeling is soware design where the domain is
the main source of information for making design decisions.
The information from the domain is encoded as a model.
Runnable specications is an approach to domain model-
ing that separates specication from implementation, mod-
els the domain in code, and seeks rich feedback. This book
teaches concepts and skills to do that.
Runnable specications are dierent from Unied Modeling
Language, Domain Driven Design, and the soware design
movement in general, although they share some similari-
ties. I hope runnable specications contribute to the discus-
sion and the general skill of programmers.
The skills of runnable specications are organized into lens-
es. Each lens provides a dierent perspective. With enough
perspectives, design decisions become easier.
Read the chapters in order. Do the exercises. Skim the sup-
plements and use them for later reference.
Up next . . .
We’ve set the stage, now it’s time to get into the nitty gritty. We’ll
start with the data because thats a skill we’ve all developed to an
extent. But we’ll use it as an entry point into using the domain as
the main source of information.