The article begins with a hypothetical. You have a class Person with a field called age. What type should it be?
The first suggestion is a String. This is obviously wrong but why is it bad? It's bad because validation would need to be performed on any and every operation. An example would be the age Jeff. This could be done with "stringly-typed" data but is super annoying to do.
The next is an Int. It's easier to write, read and it fails fast. This is better than the String type. This is because we remove the capability for many invalid states! The purpose of the article that the invalid states are now unrepresentable.
There are still many invalid states with an Int though. For instance, -1 and 90210 are technically valid according to the program but invalid ages. The goal is to constrain the type to make these invalid states also unrepresentable.
In a statically-typed language, runtime assertions can be added. For instance, an assertion that throws an error if the age is less than 0 or greater than 150. This is an integer with constraints.
The next, and final, value they consider is using age type constraints. One problem with the current approach is that an integer used for an age is the same as an integer used for weight. So, having an explicit type for the age, as opposed to using integers, works well. They use the newtype pattern from Haskell to talk about this.
They do make a comment that the model needs to be done correctly, which takes time. It's easier to move from more specific than to less specific types. So, prefer specificity over generalization. The restrictions being added should always be carefully thought out.
Overall, a great post. The core concept of make invalid states unrepresentable is a good development principle that will stick with me for a while!