85
BEYOND DESIGN PATTERNS & PRINCIPLES WRITING GOOD OO CODE Before? Matthias Noback @matthiasnoback

Beyond design patterns and principles - writing good OO code

Embed Size (px)

Citation preview

Page 1: Beyond design patterns and principles - writing good OO code

BEYOND DESIGN PATTERNS & PRINCIPLESWRITING GOOD OO CODE

Before?

Matthias Noback @matthiasnoback

Page 2: Beyond design patterns and principles - writing good OO code

My goals

To give you some vocabulary for code discussions and reviews

To bring back our focus to the basic ideas behind OOP

Page 3: Beyond design patterns and principles - writing good OO code

Abstract factory

Builder

Factory method

Singleton

Adapter

Bridge

Composite

Facade

Proxy

Chain of responsibility

Command

Mediator

Strategy

Observer

Page 4: Beyond design patterns and principles - writing good OO code

Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle

Page 5: Beyond design patterns and principles - writing good OO code

EVERYTHING IS AN OBJECT

Alan Kay

Page 6: Beyond design patterns and principles - writing good OO code

Strings

Integers Booleans

Floats

Page 7: Beyond design patterns and principles - writing good OO code
Page 8: Beyond design patterns and principles - writing good OO code
Page 9: Beyond design patterns and principles - writing good OO code

Domain concepts

Use cases

Infra-stuff

Page 10: Beyond design patterns and principles - writing good OO code

Objects introduce meaning

Page 11: Beyond design patterns and principles - writing good OO code

Strings

Email addresses

Page 12: Beyond design patterns and principles - writing good OO code

OBJECTS ENCAPSULATE STATE AND BEHAVIOR

enclose

Page 13: Beyond design patterns and principles - writing good OO code

a = … b = …

Page 14: Beyond design patterns and principles - writing good OO code

behaviorA() behaviorB()

Page 15: Beyond design patterns and principles - writing good OO code

Behavior

State

Primitive values

Services

Entities

Value objects

Anemic domain objects

Page 16: Beyond design patterns and principles - writing good OO code

Find a balance

Page 17: Beyond design patterns and principles - writing good OO code

SERVICES SHOULD BE MODELLED AS FUNCTIONS

Page 18: Beyond design patterns and principles - writing good OO code

behaviorA() behaviorB() somewhatUnrelated()

!!!

Page 19: Beyond design patterns and principles - writing good OO code

somewhatUnrelated()

behaviorA() behaviorB()Because: SRP

Page 20: Beyond design patterns and principles - writing good OO code

behaviorA()

behaviorB()

Page 21: Beyond design patterns and principles - writing good OO code

behaviorB()

Because: ISP

behaviorA()

Page 22: Beyond design patterns and principles - writing good OO code

Single-method classes ~=

Functions

Page 24: Beyond design patterns and principles - writing good OO code

Functions

Naturally stateless

Page 25: Beyond design patterns and principles - writing good OO code

class TheClass{ public doSomething(...) { check pre-conditions happy path handle failure check post-conditions }}

Page 26: Beyond design patterns and principles - writing good OO code

Simpler design, easier to test

The unit is smaller

Small number of possible execution paths

No unexpected changes in behavior

Page 27: Beyond design patterns and principles - writing good OO code

OBJECTS SHOULD BE EXPLICIT ABOUT SIDE-EFFECTS

Page 28: Beyond design patterns and principles - writing good OO code

class RegisterUser{ private repository private logger

public void register(name) { repository.add(new User(name)); logger.log(“New user added”); }}

Side effects!

Page 29: Beyond design patterns and principles - writing good OO code

function registerUser(name, repository, logger){ repository.add(new User(name)); logger.log(“New user added”);}

Page 30: Beyond design patterns and principles - writing good OO code

logger

log()

repository

add()

Page 31: Beyond design patterns and principles - writing good OO code

add()

log()

RegisterUser

Page 32: Beyond design patterns and principles - writing good OO code

INJECTED SERVICES SHOULD BE SINGLE-METHOD OBJECTS TOO

Page 33: Beyond design patterns and principles - writing good OO code

function registerUserFactory(repository, logger) { return function(name) { repository.add(new User(name)); logger.log(“New user added”); }}

registerUser = registerUserFactory( repository, logger);

registerUser(“Matthias”);

Page 34: Beyond design patterns and principles - writing good OO code

No service locators

serviceLocator.get(‘service id’).method()

Inject this object instead!

Page 35: Beyond design patterns and principles - writing good OO code

No train wrecks

someService.getOtherService.doSomething()

Inject this

object instead!

Page 36: Beyond design patterns and principles - writing good OO code

Inject only single-method services

Side-effects will be explicit

Responsibilities will be more explicit

Dependencies will be easier to mock

Page 37: Beyond design patterns and principles - writing good OO code

OBJECTS SHOULD ONLY EXIST IN A VALID STATE

condition

Page 38: Beyond design patterns and principles - writing good OO code

?

Page 39: Beyond design patterns and principles - writing good OO code

construct()

Something is not right!!!?

Page 40: Beyond design patterns and principles - writing good OO code

behaviorB() First call behaviorA()!!!?

Page 41: Beyond design patterns and principles - writing good OO code

canCallBehaviorB()

behaviorB()

Yes

Tell, don’t askAnemic domain

model

?

Page 42: Beyond design patterns and principles - writing good OO code

YesValidatorisValid( )

Page 43: Beyond design patterns and principles - writing good OO code

How to prevent this?

?

Page 44: Beyond design patterns and principles - writing good OO code

What about…

changeState( , , )?

Page 45: Beyond design patterns and principles - writing good OO code

ONLY VALID VALUES SHOULD CROSS OBJECT BOUNDARIES

Page 46: Beyond design patterns and principles - writing good OO code

Crossing boundaries

Arguments Return values, Exceptions

Page 47: Beyond design patterns and principles - writing good OO code

changeState(...) { check pre-conditions ... check post-conditions}

Page 48: Beyond design patterns and principles - writing good OO code

changeState()doSomething()

getSomething()

construct()

Page 49: Beyond design patterns and principles - writing good OO code

Advantages of always-valid objects

Easy to debug

Easy to refactor

Easy to reason about

Page 50: Beyond design patterns and principles - writing good OO code

ALMOST ALL OBJECTS SHOULD BE IMMUTABLE

unable to be changed

Page 51: Beyond design patterns and principles - writing good OO code
Page 52: Beyond design patterns and principles - writing good OO code

changeState( )

Page 53: Beyond design patterns and principles - writing good OO code

??????

!!!!!!!

Page 54: Beyond design patterns and principles - writing good OO code

changeState( )

Page 55: Beyond design patterns and principles - writing good OO code

Advantages of immutability

Clear distinction between using state and changing state

Pass on objects without worrying

Use objects without worrying

Page 56: Beyond design patterns and principles - writing good OO code

Easier to reason about

Page 57: Beyond design patterns and principles - writing good OO code

OBJECTS SHOULD COMMUNICATE USING WELL-DEFINED MESSAGES

“Alan Kay”

Page 58: Beyond design patterns and principles - writing good OO code
Page 59: Beyond design patterns and principles - writing good OO code

call( )

Page 60: Beyond design patterns and principles - writing good OO code

Calling methods ==

Sending messages

Receiving return values ==

Receiving messages

Catching exceptions ==

Receiving messages

Page 61: Beyond design patterns and principles - writing good OO code

Command

Query Document

Page 62: Beyond design patterns and principles - writing good OO code

Command

Query Document

Page 63: Beyond design patterns and principles - writing good OO code

public void doSomething(...) { ...}

public [return-type] getSomething(...) { return ...}

Page 64: Beyond design patterns and principles - writing good OO code

CQS: command-query separation

Asking for information doesn’t change observable state

Page 65: Beyond design patterns and principles - writing good OO code

EVERYTHING IS AN OBJECT

Page 66: Beyond design patterns and principles - writing good OO code

YOUR APPLICATION TOO!Sort of…

Page 67: Beyond design patterns and principles - writing good OO code

“I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages […]”

Alan Kay

Page 68: Beyond design patterns and principles - writing good OO code

a = … b = …

behaviorA() behaviorB()

Page 69: Beyond design patterns and principles - writing good OO code

a = … b = …

behaviorA() behaviorB()

Page 70: Beyond design patterns and principles - writing good OO code
Page 71: Beyond design patterns and principles - writing good OO code

State should always be valid

Command

Command

Command

Page 72: Beyond design patterns and principles - writing good OO code

Apply CQS

Command

Query

Page 73: Beyond design patterns and principles - writing good OO code

Prefer immutability

Query

Document

Page 74: Beyond design patterns and principles - writing good OO code

This design emerges

Page 75: Beyond design patterns and principles - writing good OO code

Your application has side-effects

Filesystem

Keyboard

Screen

Network

Page 76: Beyond design patterns and principles - writing good OO code

Apply hexagonal architecture

Page 77: Beyond design patterns and principles - writing good OO code

IN WHICH WAYS IS YOUR APPLICATION NOT AN OBJECT?

Page 78: Beyond design patterns and principles - writing good OO code
Page 79: Beyond design patterns and principles - writing good OO code
Page 80: Beyond design patterns and principles - writing good OO code
Page 81: Beyond design patterns and principles - writing good OO code

???

Page 82: Beyond design patterns and principles - writing good OO code

Some suggestions

Write the serialization code yourself

The object’s design always comes first

Don’t let tools mess with object encapsulation

Page 83: Beyond design patterns and principles - writing good OO code

Also…

Try Event Sourcing

Page 84: Beyond design patterns and principles - writing good OO code

CONCLUSION

Page 85: Beyond design patterns and principles - writing good OO code

EVERYTHING IS AN OBJECTOBJECTS ENCAPSULATE STATE AND BEHAVIOR

SERVICES SHOULD BE MODELLED AS FUNCTIONSOBJECTS SHOULD BE EXPLICIT ABOUT SIDE-EFFECTS

ALMOST ALL OBJECTS SHOULD BE IMMUTABLE

TREAT YOUR APPLICATION AS AN OBJECT(AND VICE VERSA)

ONLY VALID VALUES SHOULD CROSS OBJECT BOUNDARIESOBJECTS SHOULD ONLY EXIST IN A VALID STATE

OBJECTS SHOULD COMMUNICATE USING WELL-DEFINED MESSAGES