PurelyFunctional.tv Newsletter 452: Domain Invariants

Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.

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:

  1. Information
  2. Operations
  3. 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