There I am, mid-shower, when the whole introduction to my book hits me.
I was on vacation with my family. For two weeks, we slept in. We hiked. We admired nature. We played and cooked single-pot meals. Very relaxing.
I usually like to write the introduction after I finish everything else because then I know what to introduce. But I was getting so many questions about whether I was going to talk about X or Y and whether I was going to define domain modeling or runnable specifications that I decided to write something before finishing. Sharing a book in progress has different needs. In the worst case, I will rewrite the introduction when I finish.
And now, being so relaxed, and after months of not making much progress on my book, it was bound to happen: The Muse struck.
I finished my shower, got dry and dressed, and went back to my notebook. Luckily, I found the camper quiet. I sat down with my notebook and wrote down the words almost fully formed.
Well, it was slightly deformed. It’s always better immediately after it starts to flow—when it first arrives. But I managed to stop it and hold it in my mind until I got paper and pen ready. And when it did come out, it was still pretty good.
And, it turns out, it’s not a complete introduction, but it’s a significant chunk. It will change over the many revisions in its future. But here it is as I recorded it in my notebook as the slow summer sun set serenely in the sea (with a few corrections and expansions):
What does Runnable Specifications mean?
I should explain the title of this book, Runnable Specifications (RS). By RS, I mean three things:
separating specification from implementation
modeling the domain in code
seeking rich feedback
I hate to simplify the term too much. It makes me feel like I’m taking this wonderous, mysterious object, chopping it up, and leaving parts out. But these are the pieces, plus their interactions, plus each piece is complex on its own. So it feels okay. And the more I state these three things, the less I worry I’m leaving something out.
Separating specification from implementation
Separating specification from implementation has been called the most crucial skill that distinguishes juniors from seniors. Some people say “interface” instead of “specification,” but it means the same thing. We separate the definition of what a thing means from how it is implemented. And when we say something is messy or undesigned, often we mean there is no way to understand the interface separately from its implementation. Another word for specification is design—the total of all the decisions that define how the software works. We will write a lot of code in this book, but very little of it will be implementation.
Modeling the domain in code
Modeling the domain in code is more complex than it sounds. Modeling itself is about encoding an abstraction of the problem domain. That can get very technical and a lot of this book is about those skills. It’s too much to explain in detail here—but here’s a short description.
An abstraction maps information from the concrete to an abstract representation. The mapping is good if it preserves operations. That is, the important operations in the concrete domain are still available in the abstract representation. For example, if our domain is “ordering coffee,” we know we can add a coffee to an order. We want to preserve that operation when we encode it on the computer.
When we encode our domain model in a programming language, then we can run it and play with it. We can get feedback. We’re also making progress toward an actual implementation. The best case scenario is that we can use our specification in code as is, without ever having to write a separate implementation.
How do we choose what to represent? What operations are important? Those are questions are hard to answer in general and even in the specific. The worst case is we learn our specification is wrong, and we have to start over. It takes trial-and-error and lots of iteration. And for that, we need rich feedback.
Seeking rich feedback
Feedback allows us to learn faster. We will try things and be wrong, but we won’t know how we are wrong until we try it out. I believe the best source of feedback is the medium itself—code. Code must be syntactically correct. It must pass the type checker. And it must run and work. This is the richest form of feedback possible. UML and other visual forms of modeling do let you have some feedback. Visual representations contain a lot of information. But nothing beats the feedback of running code with interesting tests. This book will address several ways to get feedback from your design.
But if we write running code, we run the risk of crossing the line from specification into implementations. It’s a real problem. This book addresses several concepts and skills to prevent implementing prematurely while still writing code that might make it to production.
To summarize, by specifying our model in code, we can quickly experiment and iterate on the design. I hope these skills help you as much as they have helped me.
Seeing this all written out makes the book a fascinating prospect -- especially writing code while avoiding implementations.