Domain Modelling – What makes you different from your competition – Anaemic Model (Anti Pattern)



Domain Modelling – What makes you different from your competition – Anaemic Model (Anti Pattern)

1 0


cmx-models-presentation

A short lunchtime presentation for CMX

On Github edblackburn / cmx-models-presentation

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?