How to apply functional concepts in modelling domain aggregate roots. Shown on example going from typical imperative, into more functional side-effect free one. Examples are in Scala. Presented on DevFest 2013 Vienna
an Aggregate Main entity is Aggregate Root AR is the only referenced Entity from outside AR is Boundary for transactional consistency AR ensures business invariants
... no in-place mutation They can be shared freely ... no locks, no semaphores etc. / / D e f i n i t i o n o f c l a s s w i t h v a l u e s i n s t e a d o f v a r i a b l e s c l a s s O r d e r ( i d : O r d e r I d , c u s t o m e r I d : C u s t o m e r I d , s h i p m e n t A d d r e s s : A d d r e s s , l i n e s : V e c t o r [ O r d e r L i n e ] = V e c t o r . e m p t y , c r e a t e d : D a t e T i m e = D a t e T i m e . n o w ( ) ) { . . . }
are referentially transparent / / D e f i n i t i o n o f f u n c t i o n i n s t e a d o f p r o c e d u r e d e f a d d P r o d u c t ( p r o d u c t I d : P r o d u c t I d , q u a n t i t y : I n t , u n i t : P r o d u c t U n i t , p r i c e : B i g D e c i m a l ) : O r d e r = { . . . / / N o s i d e - e f f e c t s i n s i d e , i n c l u d i n g I / O , t h r o w i n g E x c e p t i o n s . . . }
version of itself when it is modified Effectively immutable with no in-place mutation / / S u p p o s e w e h a v e a v e c t o r o f n u m b e r s . . . v a l n u m b e r s = V e c t o r ( 1 , 2 , 3 ) / / T h e n w e a d d a i t e m t o i t v a l n u m b e r s W i t h F o u r = n u m b e r s : + 4 a s s e r t ( n u m b e r s ! = n u m b e r s W i t h F o u r ) / / y i e l d s t r u e
and values can be represented using product types case classes are best fit in Scala / / T u p l e i s s i m p l e s t p r o d u c t t y p e v a l u s e r = ( u s e r n a m e , p a s s w o r d ) / / P r o d u c t t y p e v i a c a s e c l a s s c a s e c l a s s O r d e r L i n e ( p r o d u c t I d : P r o d u c t I d , q u a n t i t y : I n t , u n i t : P r o d u c t U n i t , p r i c e : B i g D e c i m a l )
and enums can be represented using sum types Inheritance and sealed traits/classes are best fit in Scala / / E x a m p l e o f s u m - t y p e , O p t i o n f r o m S c a l a l i b r a r y ( c o d e s i m p l i f i e d ) s e a l e d a b s t r a c t c l a s s O p t i o n [ + A ] f i n a l c a s e c l a s s S o m e [ + A ] ( x : A ) e x t e n d s O p t i o n [ A ] c a s e o b j e c t N o n e e x t e n d s O p t i o n [ N o t h i n g ] / / S u m t y p e v i a c a s e o b j e c t s s e a l e d t r a i t P r o d u c t U n i t c a s e o b j e c t P i e c e e x t e n d s P r o d u c t U n i t c a s e o b j e c t K g e x t e n d s P r o d u c t U n i t c a s e o b j e c t L i t r e e x t e n d s P r o d u c t U n i t
no side-effects Side-effects do not compose s c a l a > d e f f o o ( s o m e t h i n g : S t r i n g ) : S t r i n g = s " f o o ( $ s o m e t h i n g ) " s c a l a > d e f b a r ( s o m e t h i n g : S t r i n g ) : S t r i n g = s " b a r ( $ s o m e t h i n g ) " v a l c o m p o s i t = f o o _ c o m p o s e b a r _ v a l r e v e r s e C o m p o s i t = f o o _ a n d T h e n b a r _ c o m p o s i t ( " a n y t h i n g " ) > f o o ( b a r ( a n y t h i n g ) ) r e v e r s e C o m p o s i t ( " a n y t h i n g " ) > b a r ( f o o ( a n y t h i n g ) )
functions Pure functions as domain invariants and behavior f o u n d m a p { f o u n d L i n e = > p a r t i t i o n s . s u c c e s s } / / | | / / C o m b i n a t o r H i g h - o r d e r f n / / M o n a d i c c h a i n i n g , v i a f o r - c o m p r e h e n s i o n s f o r { _ < - q u a n t i t y I n v a r i a n t ( q u a n t i t y ) _ < - p r i c e I n v a r i a n t ( p r i c e ) ( f o u n d , r e s t ) < - p r o d u c t A l r e a d y E x i s t s ( p r o d u c t I d ) } y i e l d { / * d o s o m e t h i n g * / }
from pure domain logic Known side-effects (not insignigicant) 1. DB access 2. Logging 3. IO operations Example r e s u l t . f o r e a c h { o r d e r = > o r d e r R e p o s i t o r y . s a v e O r U p d a t e ( o r d e r ) }
9. Pure Function (Wikipedia) Referenctial Transparency (Wikipedia) Persistent Data Structure (Wikipedia) Presistend Data Structures and Managed References ADT, Product and Sum Types (Bob Harper, PFPL) Simple Made Easy (Rich Hickey) Function Composition (Wikipedia) Building Apps w/ Functional Domain Models (Debasish Ghosh) CQRS and EventSourcing (Daniel Westheide)