PurelyFunctional.tv Newsletter 449: Domain model correctness and simplicity
From OO to Clojure Workshop!
Watch my free workshop to help you learn Clojure faster and shift your paradigm to functional.
Design Idea 💡
Domain model correctness and simplicity
This essay continues the series about Domain Modeling.
In the last issue, I talked about convenience. It is essential but should not be the primary objective. Convenience is a lagging indicator of model quality. Instead, we should aim for correctness and simplicity first and foremost. And then, only when those are guaranteed should we build in convenience. We do that by spending a lot more time exploring the model before we implement it.
In the Clojure world, we speak of hammock time. We mean we spend lots of time thinking about the problem before we begin implementing it. We take notes, roll the constraints and the goals around in our minds, and take the time to understand the problem before we start to code. I want to explore the hammock time phase and try to make it teachable.
There are many questions to answer: What are the elements that are worth considering in your mind? If we are exploring different paths, what are the steps along those paths? How do we know when we have arrived?
I spoke of correctness, but Conal Elliott uses the term precision. That is, does the notation describe precisely the model we want? And to know that, I know of no better notation than the programming language itself. As Gerald Sussman has shown, programming languages are more precise than math used in physics because a program has to run. We can use no shortcuts or out-of-band knowledge.
If we use the programming language to explore the ideas, we risk implementing them early. We want to talk about meaning without implementation (read premature optimization), so we should use only the signatures of functions. The signature contains the inputs and output of the function, along with a human-language name to convey its purpose. My friend Bert Bates coined the term Signature-Driven Development to describe how the implementation is often straightforward once you have the signature. It's finding the correct signature that's hard. If we work at the level of signatures, we can precisely describe our operations without describing the implementations.
There is a lot to learn from this process. We can identify corner cases and awkward special cases, which we eliminate by changing the signatures of the operations. We look for powerful properties like the closure property. We should seek to find a minimum set of operations out of which everything else may be defined. By adding and removing information, we can play with the generality of our model. Less information means more generality and vice versa. We play with the scope of the model.
If I write a book about this, I estimate that most of the book will focus on this process. Once we have the signatures, implementation is straightforward. In the next issue, I want to discuss one of the weird benefits of using a programming language to write your domain model: runnable specifications. Till next time!
Book update 📘
Grokking Simplicity has been selling well. I'm not doing much to promote it now, so that means word of mouth, which means people like it enough to recommend it! Thank you if you have bought it and/or recommended it. If you're a superfan, please leave a review on Amazon! It really helps people find the book.
In my new episode, What is domain modeling?, I explore a better definition of the term.
Apropos Episode 📽️
Podcast appearance 📢
I was very fortunate to be invited to Lost in Lambduhhs. Jordan is a great new voice in the community.
Pandemic update 😷
I know a lot of people are going through tougher times than I am. If you, for any reason, can't afford my courses, and you think the courses will help you, please hit reply and I will set you up. It's a small gesture I can make, but it might help.
I don't want to shame you or anybody that we should be using this time to work on our skills. The number one priority is your health and safety. I know I haven't been able to work very much, let alone learn some new skill. But if learning Clojure is important to you, and you can't afford it, just hit reply and I'll set you up. Keeping busy can keep us sane.
Stay healthy. Wash your hands. Wear a mask. Get vaccinated if you can. Take care of loved ones.
Clojure Challenge 🤔
Last issue's challenge
- Reverse-Polish calculator - Submissions
This week's challenge
Imagine we have the following sentence.
she sells sea shells by the sea shore
We want phrases that are as big as possible, yet no bigger than 10 characters long. A phrase must contain entire words and a space between them. And an instance of a word should only exist in the first phrase that matches.
We start at the beginning. "she sells" is \<= 10 characters. We can't add the following "sea" because "she sells sea" is 13 characters. That means "she sells" is a maximizing phrase. We now start at "sea" and continue.
Your job is to write a function that takes a sentence and outputs a collection of phrases.
(phrases 10 "she sells sea shells by the sea shore") ;=> ["she sells" "sea shells" "by the sea" "shore"] (phrases 2 "she sells sea shells by the sea shore") ;=> ["by"] (phrases 2 "the big dog jumped over the fence") ;=>  (phrases 13 "she sells sea shells by the sea shore") ;=> ["she sells sea" "shells by the" "sea shore"]
- Trim initial and trailing whitespace, but leave whitespace between words.
- The spaces count in the length of the phrases.
Thanks to this site for the problem idea, where it is rated Expert in Java. The problem has been modified.
Please submit your solutions as comments on this gist.