PurelyFunctional.tv Newsletter 455: How and when to apply domain modeling
Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.
Design Idea 💡
How and when to apply domain modeling
This essay continues the series about Domain Modeling.
During my re:Clojure talk Q&A, Filipe Silva asked whether I had successfully applied domain modeling to a real project. I wasn't prepared to answer it, and it seemed like a process question, so I took it as such. But I've since had time to think about it, and I have realized that I do indeed have successes to report. For brevity's sake, I'll focus on one interesting success that shows that domain modeling doesn't have to be all-or-nothing.
I was working at an e-contract company (similar service to DocuSign) and we were trying to expand our market. We could do a basic contract signing flow: Create a contract, enter email addresses, and it sends it to everyone to sign. But customers wanted more control. They wanted to say what order people had to sign in. And they wanted other things besides signing, like a review step. It was hard to see how to fit these new ideas into our originally simple model of contracts.
We knew we could do it. The direct path was just more HTTP endpoints, more SQL UPDATE statements, and a bunch of conditionals. It's easy to dismiss when stated like this, but it works. Some of the biggest, most reliable systems in the world are just a mess of spaghetti.
But I to model the domain better than that. I thought on it for a while and saw that we had different actions that were allowed at different times. I got the idea that a state machine would model that really well, especially the non-determinism of allowing parties to sign in different orders. A state machine was simple enough to manage but capable enough to handle all of the steps.
I made a simple proof of concept (outside of production) and started showing it around. Some people liked it. Some people thought it "looked complicated". But I pointed out that what they were calling complicated was just a diagram of what the system already did. I got some support from people on the team who were more academically minded. And I got some pushback from people who were more engineering-minded. Both were useful.
Ironically, the academic folks saw the state diagram and immediately said, "Yes, that can do everything we know we need now and can easily adapt to the future." The engineering-minded folks wanted "proof" that it could handle everything. I always thought academicians wanted proof and engineers wanted pudding. The engineers didn't really want proof. They were dismissing it out of hand because they worried that it would require a significant rewrite and still not be able to do everything (so we'd still need if statements everywhere).
I wrote out the results of my proof of concept as a big proposal, with a roadmap and everything. But after shopping the proof of concept around a bit, I knew it wouldn't have enough support to happen.
However, some of the immediate steps on the roadmap toward the vision would be immediately beneficial. One step was to separate some of the SQL updates into more atomic actions. I don't remember exactly what they were, but one action was something like "Add party X's signature AND close the contract if all parties have signed." In my state machine model, these would need to be separate transitions. I wrote up a half-page proposal about separating them into "Add party X's signature" and "Close the contract if all parties have signed." (Clojure's notion of simplicity shining through there.)
I sent it to the team and it turned out that the CTO was in the middle of wrestling with the SQL and loved the idea of simplifying it. A couple of other improvements (some user-facing) came straight from that vision of a state-machine domain model.
A state machine would have been a better fit for our domain than the spaghetti we had. It would have simplified our code. And it would have given us a distinct business advantage in supporting very sophisticated signing workflows. Although the state machine never got implemented (at least not while I was there), I considered it a success. Just the thought exercise of figuring out a better model generated several improvements that were obvious and immediate. It's worth thinking about your domain model even if you never implement it. But imagine if you did!
Book update 📘
Good news: Grokking Simplicity is going into another printing! That gave me the opportunity to correct some errors my readers and I have found in the book. The book is only getting better!
You can order the book on Amazon. Please consider leaving a rating and/or review. Reviews are a primary signal that Amazon uses to promote the book. And they help others learn whether the book is for them.
You can order the print and/or eBook versions on Manning.com (use TSSIMPLICITY for 50% off).
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
This week's challenge
I always liked flexible autocomplete where you can type a few letters, even skipping some letters, and it can find the file or word for you.
Your task is to write a function that determines if you can complete a sequence of characters to a given string.
(completes? "a" "autocomplete") ;=> true (completes? "atc" "autocomplete") ;=> true (completes? "hello" "hello") ;=> true (completes? "ll" "hello") ;=> true (completes? "llh" "hello") ;=> false
The rules. The function returns true if all of the following are true (otherwise false):
- The first string contains only letters in the second string.
- The first string's letters are in the same order as in the second string.
Note that this means that you can match any number of letters between typed letters.
Thanks to this site for the problem idea, where it is rated Very Hard in Java. The problem has been modified.
Please submit your solutions as comments on this gist.