Slide 1

Slide 1 text

avoiding the mud

Slide 2

Slide 2 text

richard miller @mr_r_miller richardmiller.co.uk sensiolabs uk

Slide 3

Slide 3 text

http://www.flickr.com/photos/brostad/8583990904

Slide 4

Slide 4 text

what makes an application fragile?

Slide 5

Slide 5 text

single responsibility principle

Slide 6

Slide 6 text

a class or module should have one, and only one, reason to change

Slide 7

Slide 7 text

dependency inversion principle

Slide 8

Slide 8 text

High-level modules should not depend on low-level modules

Slide 9

Slide 9 text

Both should depend on abstractions.

Slide 10

Slide 10 text

should everything go in a bundle?

Slide 11

Slide 11 text

no

Slide 12

Slide 12 text

no (imo)

Slide 13

Slide 13 text

HumanResourcesBundle

Slide 14

Slide 14 text

HumanResourcesBundle HumanResources responsible for framework related code responsible for domain related code

Slide 15

Slide 15 text

HumanResourcesBundle HumanResources

Slide 16

Slide 16 text

better?

Slide 17

Slide 17 text

still tightly coupled

Slide 18

Slide 18 text

AbsenceEntity Request Absence Form Cancel Absence Form Approve Absence Form Change Absence Type Form

Slide 19

Slide 19 text

entities coupled to forms

Slide 20

Slide 20 text

complex validation

Slide 21

Slide 21 text

form events

Slide 22

Slide 22 text

entity is responsible for validating user input

Slide 23

Slide 23 text

AbsenceEntity Request Absence Form Cancel Absence Form Approve Absence Form Change Absence Type Form Request Absence Command Cancel Absence Command Approve Absence Command Change Absence Type Command

Slide 24

Slide 24 text

simpler validation

Slide 25

Slide 25 text

command name captures the domain action

Slide 26

Slide 26 text

but more classes!

Slide 27

Slide 27 text

simpler classes

Slide 28

Slide 28 text

repetition?

Slide 29

Slide 29 text

technical complexity reduced

Slide 30

Slide 30 text

what else?

Slide 31

Slide 31 text

entities coupled to templates

Slide 32

Slide 32 text

AbsenceEntity upcoming .html .twig details .html .twig calendar .html .twig unapproved .html .twig

Slide 33

Slide 33 text

logic in templates

Slide 34

Slide 34 text

{% if absence.endDate < date() %} past {% else %} absence.status {% endif %} getDisplayStatus() AbsenceEntity getEndDate() getStatus()

Slide 35

Slide 35 text

if in php method it could be tested

Slide 36

Slide 36 text

so let's move it to the entity

Slide 37

Slide 37 text

getDisplayStatus() AbsenceEntity getEndDate() getStatus() getDisplayStatus() {{ absence.displayStatus }}

Slide 38

Slide 38 text

but presentational logic is not a domain responsibility

Slide 39

Slide 39 text

AbsenceEntity Request Absence Form Cancel Absence Form Approve Absence Form Change Absence Type Form Absence View upcoming .html .twig details .html .twig calendar .html .twig unapproved .html .twig getStatus()

Slide 40

Slide 40 text

commands are now responsible for capturing data for an action

Slide 41

Slide 41 text

views are responsible for providing data for presentation

Slide 42

Slide 42 text

so what is our entity responsible for?

Slide 43

Slide 43 text

Request Absence Controller Absence Entity setReason($reason) setStatus(AbsenceEntity::CANCELLED) setCancellationDate(new DateTime()) Cancel Absence Command getReason()

Slide 44

Slide 44 text

the controller is responsible for state in the model

Slide 45

Slide 45 text

Request Absence Controller Absence Entity cancel($reason) Cancel Absence Command getReason()

Slide 46

Slide 46 text

the entity now protects its state

Slide 47

Slide 47 text

it exposes behaviours instead

Slide 48

Slide 48 text

Cancel Absence Command Absence Entity Validate internal consistency Validate user input

Slide 49

Slide 49 text

Request Absence Controller Absence Entity cancel($reason) Cancel Absence Command getReason()

Slide 50

Slide 50 text

AbsenceEntity cancel($reason) Cancel Absence Command Handler Request Absence Controller Absence Entity cancel($reason) Cancel Absence Command

Slide 51

Slide 51 text

infrastructure?

Slide 52

Slide 52 text

persistence is not a domain responsibility

Slide 53

Slide 53 text

but the repository is part of the domain

Slide 54

Slide 54 text

Absences (Interface) findById($id) findUpcomingByMember($member) findAllByMember($member) Doctrine ORM Absence Repository Doctrine ODM Absence Repository Guzzle Client Absence Repository Infrastructure Domain

Slide 55

Slide 55 text

AbsenceEntity Absences Domain Bundle Service Config Infrastructure Doctrine ORM Absence Repository Mapping Config

Slide 56

Slide 56 text

Absences findById($id) findUpcomingByMember($member) findAllByMember($member) add(AbsenceEntity $absence)

Slide 57

Slide 57 text

how often is persistence changed?

Slide 58

Slide 58 text

doctrine events

Slide 59

Slide 59 text

OnUpdate Event AbsenceEntity Dispatches

Slide 60

Slide 60 text

doctrine domain events

Slide 61

Slide 61 text

OnUpdate Event AbsenceEntity Dispatches

Slide 62

Slide 62 text

Absence Cancelled Event Cancel Absence Command Handler Dispatches

Slide 63

Slide 63 text

what bundles should I have?

Slide 64

Slide 64 text

how big should they be?

Slide 65

Slide 65 text

maybe just one

Slide 66

Slide 66 text

don't split if they will be coupled anyway

Slide 67

Slide 67 text

so could be quite big

Slide 68

Slide 68 text

split out code reusable in other applications

Slide 69

Slide 69 text

HumanResources CustomLoggingBundle HumanResourcesBundle

Slide 70

Slide 70 text

HumanResourcesBundle HumanResources CustomLoggingBundle CustomLogging CustomLoggingBundle CustomLoggingBundle CustomLogging HumanResourcesBundle

Slide 71

Slide 71 text

HumanResources CustomLoggingBundle CustomLogging CustomLoggingBundle CustomLoggingBundle CustomLogging HumanResourcesBundle

Slide 72

Slide 72 text

so could be quite small

Slide 73

Slide 73 text

split application bundles when domain is big enough to split

Slide 74

Slide 74 text

and can be decoupled

Slide 75

Slide 75 text

AbsencePlannerBundle AbsencePlanner CustomLoggingBundle CustomLogging CustomLoggingBundle RecruitmentBundle Recruitment

Slide 76

Slide 76 text

Message Queue/REST AbsencePlannerBundle AbsencePlanner CustomLoggingBundle CustomLogging CustomLoggingBundle RecruitmentBundle Recruitment

Slide 77

Slide 77 text

anything else to split out?

Slide 78

Slide 78 text

AbsencePlannerBundle AbsencePlanner RecruitmentBundle Recruitment AbsencePlannerBundle AbsencePlanner CustomLoggingBundle CustomLogging CustomLoggingBundle RecruitmentBundle Recruitment User Management

Slide 79

Slide 79 text

!= Staff Member Entity User Entity

Slide 80

Slide 80 text

AbsencePlannerBundle AbsencePlanner AbsencePlannerBundle AbsencePlanner CustomLoggingBundle CustomLogging CustomLoggingBundle RecruitmentBundle Recruitment UserManagementBundle

Slide 81

Slide 81 text

so bundles could vary hugely in size

Slide 82

Slide 82 text

being decoupled is the important thing

Slide 83

Slide 83 text

http://www.flickr.com/photos/burge5000/22568539/

Slide 84

Slide 84 text

http://williamdurand.fr/ http://verraes.net/#blog http://www.whitewashing.de/

Slide 85

Slide 85 text

questions? thank you