Domain Modelling

What makes you different from your competition

Created by Ed Blackburn / @ejblackburn

Why do I want to talk about this?

  • I think we have good developers, who solve non-trivial problems
  • I feel some simple concepts can make our code cleaner, easier to test, scale and more maintainable

Why model?

  • Domain models represent part of a business process
  • They include data (state) and business logic (behaviour)
  • Maintainability. Supporting intuitive code that reflects the problem domain is easier to comprehend, test, refactor, change and is heuristic, forcing the team to build domain knowledge?

Anaemic Model (Anti Pattern)

  • There is no behaviour. It's all CRUD
  • Primitive obsession
  • Mutable bags of data that contain little or no behaviour
  • Impossible to enforce business logic because state can be manipulated outside of intended use
  • Business logic in "Services"
  • Write only code
  • Feature Envy anti-pattern

Anaemic

  • Why is this mutable?
  • Why are they strings, do horses have legs, or strings?

public class Horse {
	public string Leg1 { get; set; }
	public string Leg2 { get; set; }
	public string Leg3 { get; set; }
	public string Leg4 { get; set; }
}
					

Example


public class MoveHorse {
	public Gallop(Horse horse, int steps) {
		for(step = 0;step > steps;step++) {
			horse.Leg1 = "Move Fast";
			horse.Leg2 = "Move Fast";
			horse.Leg1 = "Put on ground";
			horse.Leg2 = "Put on Ground";
			horse.Leg3 = "Move Fast";
			horse.Leg4 = "Move Fast";
		}
	}

	public Cantor(Horse horse, int steps) {
		for(step = 0;step > steps;step++) {
			horse.Leg1 = "Move slow";
			horse.Leg1 = "Put on ground";
			horse.Leg2 = "Move slow";
			horse.Leg2 = "Put on ground";
			horse.Leg3 = "Move slow";
			horse.Leg3 = "Put on ground";
			horse.Leg4 = "Move slow";
			horse.Leg4 = "Put on ground";
		}
	}
	.
	.
}

Oops.

The algorithm is wrong. This can get complicated quickly and is not intuitive.

Rich Model

  • Put behaviour and state together
  • Tell don't ask
  • Do not expose internals. Do not expose data structures
  • There is not such thing as a string!
  • Equality v Equivalence

An alternative:

  • No primitives
  • State encapsulated

class Horse {
	private Leg leg1;
	private Leg leg2;
	private Leg leg3;
	private Leg leg4;
	.
	.
	void Gallop() {..}
	void Cantor() {..}
}
	

Different types of object in a model

  • Value Object
  • Entity
  • It's all about the identity
  • Service layer

Value Objects

Immutable types. Enforce invariants: a name is not a string. A name can not be null or empty, can not begin or end with white space.


class Name {
	ctor(string name) {
		throw if null
		name = name.trim()
		throw if empty
	}
	Equals(Name) {..}
}

Money Example


class Money {
	ctor(double value, Currency currency){..}

	Equals(Money other){
		return other.value == this.value && other.currency == this.currency;
	}
}

var five_pounds = new Money(5, new GBP());
var ten_pounds = new Money(10, new GBP());

class Note {
	ctor(SerialNumber serial_number){..}

	Equals(Note other){
		return other.serial_number == this.serial_number;
	}
}

Something closer to home

Represent two different things. Both use Guids..


class AccountId {
	ctor(string id){..}
	Equals(AccountId){..}
}

class AuthToken {
	ctor(string id){..}
	Equals(AuthToken){..}
}
  • Can't accidental confuse them
  • What happens if we want to change the data-type or how it's formed? I.e. sequential guid for more db efficient guids? Or guids formed differently for sharding?

Entities

  • Defined by identity
  • Here lives behaviour!
  • ..a category of objects which seem to have an identity, which remains the same throughout the states of the software. For these objects it is not the attributes which matter, but a thread of continuity and identity, which spans the life of a system and can extend beyond it. Such objects are called Entities

    - Eric Evans

Example


class Product {
	private ProductId;
	Publish(){..}
	AddOffer(Offer){..}
	.
	.

		Equals(Product){
		return Product.ProductId == this.ProductId;
	}

}

Aggregates

  • An encapsulated graph of domain objects
  • Only accessible via the root object
  • Remember do not expose data structures

Further concepts

  • Hypermedia APIs
  • CQRS
  • Repository Pattern
  • Document databases
  • Bounded Contexts
  • Ubiquitous language

Enterprise Bullshit?