PurelyFunctional.tv Newsletter 452: Domain Invariants
Issue 452 - November 29, 2021 · Archives · Subscribe
Design Idea 💡
Domain Invariants
This essay continues the series about Domain Modeling.
A domain model has three pieces:
- Information
- Operations
- Invariants
Today, I'd like to talk about invariants and how we can encode them in a programming language.
Invariants are things that always hold in our model, no matter its current state. There are some simple invariants, like the first name of a person is always a string. And there are more sophisticated invariants like that a particular operation is idempotent. Invariants help us understand the properties and relationships of and between operations and information.
We want to encode our domain invariants in code if possible. Different languages give us different ways to do that. Here are some places to encode invariants:
- Types
- Tests
- Language features
- Data structures
- Runtime checks
- Documentation
- External proofs
- Your brain (not code!)
Types
Your language might give you a type system that lets you easily enforce that a first name is always a string. Some type systems are more expressive and might let you encode sophisticated invariants.
Tests
Tests are a common way to encode invariants. Property-based tests can encode algebraic properties such as idempotence and associativity.
Language features
Many languages have features that maintain invariants. For instance,
Clojure's data is immutable by default, so you can be sure nothing gets
modified. Java's synchronized
keyword ensures that a method can not be
called more than once at the same time. That may be useful for
implementing idempotence.
Data structures
Data structures often have invariants. For example, sets do not contain duplicates. Adding to a set is idempotent. You can use that property to implement idempotence.
Runtime checks
It is common to add assertions near the beginning of a function to check that the arguments maintain essential invariants. These can communicate to the reader of the code and help find bugs during development.
Documentation
You can write down the invariants in documentation to help readers understand the domain model.
External proofs
You can ensure that invariants hold by writing a proof, optionally using a proof assistant. A common language for writing these is TLA+.
Your brain
You can also hold your invariants in your head. It is a widespread practice. The biggest downside is that your invariants don't work when you're not there. Also, our brains are very limited and often overlook corner cases.
Each of these places has costs and benefits, and not all are possible for every language.
Upcoming presentation 📢
December 4th I am speaking at re:clojure 2021 about Domain Modeling.
It's all online so see if you can attend, too! It's all free!
Book update 📘
I wrote Grokking Simplicity because I couldn't find a book for beginner functional programmers. People kept asking what book I recommended and I had no answer. Through countless discussions about what functional programming is and what its value is, I refined the idea of actions, calculations, and data. That idea became the core of the book. I've received lots of messages from people saying that idea was instrumental in their understanding of functional programming. It's very rewarding.
You can order the book on Amazon. You can order the print and/or eBook versions on Manning.com (use TSSIMPLICITY for 50% off).
Apropos Episode 📽️
Another one in the can! We're working on our new website in Clojure. All code, all the time! Watch here. Please join the Discord server so you can watch live!
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
Issue 451 -- Ulam sequence -- Submissions
This week's challenge
Consecutive numbers
Write a function that determines whether a sequence of integers can be
rearranged into a sequence of consecutive numbers without duplicates.
The function should return the sequence of consecutive numbers or nil
if it is not possible.
Examples
(consec []) ;=> () ;; trivially true
(consec [1]) ;=> (1) ;; ditto
(consec [3 1 2]) ;=> (1 2 3)
(consec [5 3 2 1]) ;=> nil ;; non-consecutive (4 is missing)
(consec [7 8 9 7]) ;=> nil ;; 7 repeats
Thanks to this site for the problem idea, where it is rated Hard in Java. The problem has been modified.
Please submit your solutions as comments on this gist.
Rock on!
Eric Normand