chapter six

6 Implementing the Domain Model

 

This chapter covers

  • Implementing the domain model
  • Pure and impure Functions
  • Designing around determinism

This chapter picks up where we left off in Chapter 5. We’ve modeled a complex invoicing domain. Now it's time to start writing code.

But we have to be careful.

A bad implementation can undermine a good data model. Methods in Java are often up to no good. They make us think about too much of our program at once and betray us with unexpected side-effects. We’re going to learn how to get them under control.

We’re also going to spend time learning how to organize our code. So far, our modeling has been purposefully indifferent to details like class ownership. We’ve focused only on the data and how it flowed through our program. But now we need to make architectural choices. Who should own these behaviors? Who can they talk to? Who can talk to them?

If you focus on the right properties, these questions will answer themselves.

6.1 On the criteria by which we break down an implementation

6.1.1 Functions, Purity, and Determinism

6.1.2 How do we write pure functions in Java?

6.1.3 The effect of deterministic functions on reasoning

6.1.4 Functions let you work locally

6.1.5 Functions are tables of immutable data in disguise

6.1.6 Functions let us model relationships

6.1.7 One last note on all this deterministic business

6.2 Organizing code around determinism

6.3 Implementing the deterministic core

6.3.1 Implementing collectPastDue

6.3.2 Implementing BuildDraft

6.3.3 That really gross wrong feeling is a feature

6.3.4 Implementing Assess Draft

6.3.5 Dealing with optional

6.3.6 It’s always OK to introduce more types!

6.4 Implementing the non-deterministic shell

6.4.1 Who owns the save logic?

6.4.2 Your Entities are my Data Transfer Objects (DTOs)

6.5 Data is the ultimate interface

6.6 Putting it all together

6.7 Wrapping up

6.8 Summary