7 Requirements as Types

 

In this chapter you will learn how to

  • model your immutable data to minimize errors
  • model your requirements as immutable data
  • find problems in requirements using the compiler
  • make sure your logic is always executed on valid data

Designing something just powerful enough is an art.

— Barbara Liskov

7.1 Modeling data to minimize programmer’s mistakes

In this chapter we will change the way we model data in our applications. We will use more types to minimize potential programmer’s mistakes. We will learn techniques which enhance and maintainability of our codebase. We will also make implementations smaller and less complicated! Too good to be true? Let’s see this in action using an example.

We focus a lot on maintainability in this book. As a reminder, we say that a given codebase is maintainable if it’s easy to change without introducing bugs.

Music artists catalogue

As always, we’ll start with a potential real-world application. We will implement a music artists catalogue that will help us find artists by genres, their locations or years they were active. There will be lots of corner cases to handle and the main focus will be on data modeling. We will be modeling artists. Each artist will have a name, a main genre and an origin. Seems easy, right? We just need to define a product type:

case class Artist(name: String, genre: String, origin: String)

What problems do you see with this definition of an artist?

7.2      Well-modeled data can’t lie

7.3      Designing using what we know so far (which is primitive types)

7.4      Using data modeled as primitive types

7.5      Coffee Break: The pain of primitive types

7.6      Coffee Break Explained: The pain of primitive types

7.7      Problems with primitive-type approach to modeling

7.8      Using primitive types makes our jobs harder!

7.9      Newtypes protect against misplaced parameters

7.10  Using newtypes in data models

7.11  Practicing newtypes

7.12  Making sure only valid data combinations are possible

7.13  Modeling possibility of absence in your data

7.14  Changes in the model force changes in the logic

7.15  Using data modeled as Options in your logic

7.16  Higher-order functions for the win!

7.17  There probably is a higher-order function for that!

7.18  Coffee Break: forall/exists/contains

7.19  Coffee Break Explained: forall/exists/contains

7.20  Coupling a concept inside a single product type

7.21  Modeling finite possibilities

7.22  Using sum types