Applying Domain Driven Design and Patterns With Examples in C Sharp and Dot Net 9780321268204 0321268202
Applying Domain Driven Design and Patterns With Examples in C Sharp and Dot Net 9780321268204 0321268202
NET, 1/e
By Jimmy Nilsson
...............................................
Publisher: Addison W e sle y Pr ofe ssion a l
Pub Dat e: M a y 0 8 , 2 0 0 6
Print I SBN- 10: 0 - 3 2 1 - 2 6 8 2 0 - 2
Print I SBN- 13: 9 7 8 - 0 - 3 2 1 - 2 6 8 2 0 - 4
Pages: 5 7 6
" [ This] is a book about design in t he .NET world, driven in an agile m anner and infused wit h t he
product s of t he ent erprise pat t erns com m unit y. [ I t ] shows you how t o begin applying such t hings as
TDD, obj ect relat ional m apping, and DDD t o .NET proj ect s...t echniques t hat m any developers t hink
are t he key t o fut ure soft ware developm ent .... As t he t echnology get s m ore capable and
sophist icat ed, it becom es m ore im port ant t o underst and how t o use it well. This book is a valuable
st ep t oward advancing t hat underst anding."
Mart in Fowler, aut hor of Refact or ing and Pat t erns of Ent erprise Applicat ion Archit ect ure
Pat t erns, Dom ain- Driven Design ( DDD) , and Test - Driven Developm ent ( TDD) enable archit ect s and
developers t o creat e syst em s t hat are powerful, robust , and m aint ainable. Now, t here's a
com prehensive, pract ical guide t o leveraging all t hese t echniques prim arily in Microsoft .NET
environm ent s, but t he discussions are j ust as useful for Java developers.
Drawing on sem inal work by Mart in Fowler ( Pat t erns of Ent erprise Applicat ion Archit ect ure) and Eric
Evans ( Dom ain- Driven Design ) , Jim m y Nilsson shows how t o creat e real- world archit ect ures for any
.NET applicat ion. Nilsson illum inat es each principle wit h clear, well- annot at ed code exam ples based
on C# 1.1 and 2.0. His exam ples and discussions will be valuable bot h t o C# developers and t hose
working wit h ot her .NET languages and any dat abaseseven wit h ot her plat form s, such as J2EE.
Coverage includes
· Using dom ain m odels t o support business rules and validat ion
· Applying ent erprise pat t erns t o provide persist ence support via NHibernat e
· Planning effect ively for t he present at ion layer and UI t est ing
· Designing for Dependency I nj ect ion, Aspect Orient at ion, and ot her new paradigm s
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET, 1/e
By Jimmy Nilsson
...............................................
Publisher: Addison W e sle y Pr ofe ssion a l
Pub Dat e: M a y 0 8 , 2 0 0 6
Print I SBN- 10: 0 - 3 2 1 - 2 6 8 2 0 - 2
Print I SBN- 13: 9 7 8 - 0 - 3 2 1 - 2 6 8 2 0 - 4
Pages: 5 7 6
Copyright
Praise for Applying Domain-Driven Design and Patterns
About the Author
Forewords
Preface: Bridging Gaps
Acknowledgments
Part I: Background
Chapter 1. Values to Value: Or Embarrassing Ramblings When Self-Reflecting on the Last Few Years
Overall Values
Architecture Styles to Value
Process Ingredients to Value
Continuous Integration
Don't Forget About Operations
Summary
Chapter 2. A Head Start on Patterns
A Little Bit About Patterns
Design Patterns
Architectural Patterns
Design Patterns for Specific Types of Applications
Domain Patterns
Summary
Chapter 3. TDD and Refactoring
Test-Driven Development (TDD)
Mocks and Stubs
Refactoring
Summary
Part II: Applying DDD
Chapter 4. A New Default Architecture
The Basis of the New Default Architecture
A First Sketch
Making a First Attempt at Hooking the UI to the Domain Model
Yet Another Dimension
Summary
Chapter 5. Moving Further with Domain-Driven Design
Refining the Domain Model Through Simple TDD Experimentation
Fluent Interface
Summary
Chapter 6. Preparing for Infrastructure
POCO as a Lifestyle
Dealing with Save Scenarios
Let's Build the Fake Mechanism
Database Testing
Querying
Summary
Chapter 7. Let the Rules Rule
Categorization of Rules
Principles for Rules and Their Usage
Starting to Create an API
Requirements for a Basic Rules API Related to Persistence
Focus on Domain-Related Rules
Extending the API
Refining the Implementation
Binding to the Persistence Abstraction
Generics and Anonymous Methods to the Rescue
What Others Have Done
Summary
Part III: Applying PoEaa
Chapter 8. Infrastructure for Persistence
Requirements on the Persistence Infrastructure
Where to Store Data
Approach
Classification
Another Classification: Infrastructure Patterns
Summary
Chapter 9. Putting NHibernate into Action
Why NHibernate?
A Short Introduction to NHibernate
Requirements of the Persistence Infrastructure
Classification
Another Classification: Infrastructure Patterns
NHibernate and DDD
Summary
Part IV: What's Next?
Chapter 10. Design Techniques to Embrace
Context Is King
An Introduction to SOA
Inversion of Control and Dependency Injection
Aspect-Oriented Programming (AOP)
Summary
Chapter 11. Focus on the UI
A Prepilogue
The Model-View-Controller Pattern
Test-Driving a Web Form
Mapping and Wrapping
Summary
Epilogue
Part V: Appendices
Appendix A. Other Domain Model Styles
Object-Oriented Data Model, Smart Service Layer, and Documents
The Database Model Is the Domain Model
Pragmatism and the Nontraditional Approach
Summary
Appendix B. Catalog of Discussed Patterns
Abstract Factory [GoF Design Patterns]
Aggregate [Evans DDD]
Bounded Context [Evans DDD]
Chain of Responsibility [GoF Design Patterns]
Class Table Inheritance [Fowler PoEAA]
Coarse-Grained Lock [Fowler PoEAA]
Collecting Parameter Pattern [Beck SBPP]
Concrete Table Inheritance [Fowler PoEAA]
Data Mapper [Fowler PoEAA]
Data Transfer Objects [Fowler PoEAA]
Decorator [GoF Design Patterns]
Dependency Injection
Domain Model [Fowler PoEAA]
Embedded Value [Fowler PoEAA]
Entity [Evans DDD]
Factory [Evans DDD]
Factory Method [GoF Design Patterns]
Foreign Key Mapping [Fowler PoEAA]
Generation Gap [Vlissides Pattern Hatching]
Identity Field [Fowler PoEAA]
Identity Map [Fowler PoEAA]
Implicit Lock [Fowler PoEAA]
Layer Supertype [Fowler PoEAA]
Layers [POSA]
Lazy Load [Fowler PoEAA]
Metadata Mapping [Fowler PoEAA]
Model View Controller [Fowler PoEAA]
Model View Presenter [Fowler PoEAA2]
Notification [Fowler PoEAA2]
Null Object [Woolf Null Object]
Optimistic Offline Lock [Fowler PoEAA]
Party Archetype [Arlow/Neustadt Archetype Patterns]
Pessimistic Offline Lock [Fowler PoEAA]
Pipes and Filters [POSA]
Presentation Model [Fowler PoEAA2]
Proxy [GoF Design Patterns]
Query Object [Fowler PoEAA]
Recordset [Fowler PoEAA]
Reflection [POSA]
Registry [Fowler PoEAA]
Remote Façade [Fowler PoEAA]
Repository [Evans DDD]
Separated Presentation [Fowler PoEAA2]
Service Layer [Fowler PoEAA]
Service Locator [Alur/Crupi/Malks Core J2EE Patterns]
Services [Evans DDD]
Single Table Inheritance [Fowler PoEAA]
Singleton [GoF Design Patterns]
Specification [Evans DDD]
State [GoF Design Patterns]
Table Module [Fowler PoEAA]
Template Method [GoF Design Patterns]
Transaction Script [Fowler PoEAA]
Unit of Work [Fowler PoEAA]
Value Object [Evans DDD]
References
Index
Copyright
Many of t he designat ions used by m anufact urers and sellers t o dist inguish t heir product s are claim ed
as t radem arks. Where t hose designat ions appear in t his book, and t he publisher was aware of a
t radem ark claim , t he designat ions have been print ed wit h init ial capit al let t ers or in all capit als.
The aut hor and publisher have t aken care in t he preparat ion of t his book, but m ake no expressed or
im plied warrant y of any kind and assum e no responsibilit y for errors or om issions. No liabilit y is
assum ed for incident al or consequent ial dam ages in connect ion wit h or arising out of t he use of t he
inform at ion or program s cont ained herein.
The publisher offers excellent discount s on t his book when ordered in quant it y for bulk purchases or
special sales, which m ay include elect ronic versions and/ or cust om covers and cont ent part icular t o
your business, t raining goals, m arket ing focus, and branding int erest s. For m ore inform at ion, please
cont act :
Nilsson, Jim m y.
Applying dom ain- driven design and pat t erns wit h exam ples in C# and .NET / Jim m y Nilsson.
p. cm .
I ncludes bibliographical references.
I SBN 0- 321- 26820- 2
1. Com put er soft ware- -
Developm ent . 2. C# ( Com put er program language) 3. Microsoft .NET. I . Tit le.
QA76.76.D47N645 2006
005.1- - dc22
2006004371
All right s reserved. Print ed in t he Unit ed St at es of Am erica. This publicat ion is prot ect ed by copyright ,
and perm ission m ust be obt ained from t he publisher prior t o any prohibit ed reproduct ion, st orage in
a ret rieval syst em , or t ransm ission in any form or by any m eans, elect ronic, m echanical,
phot ocopying, recording, or likewise. For inform at ion regarding perm issions, writ e t o:
Pearson Educat ion, I nc.
Right s and Cont ract s Depart m ent
75 Arlingt on St reet , Suit e 300
Bost on, MA 02116
Fax: ( 617) 848- 7047
Dedication
To Lot t a, Tim , and Leo: t he cent ers of m y universe.
Praise for Applying Domain-Driven Design
and Patterns
" I don't know what it was I professed t o doing before I had added Dom ain- Driven Design and
Test - Driven Developm ent t o m y t oolkit , but from m y present perspect ive, I 'm ret icent t o call it
anyt hing but chaot ic hacking. Dom ain- Driven Design and Test - Driven Developm ent are t wo
approaches t hat have consist ent ly guided m e t oward a pract ical applicat ion of soft ware design
principles, and brought m y proj ect s t o fruit ion wit h healt hy, sust ainable soft ware. This is a book
t hat put s it s m oney where it s m out h is in t erm s of concret ely com m unicat ing Agile soft ware
developm ent pract ice. I t 's pot ent ially one of t he m ost im pact ful guides t o soft ware developm ent
success pract ices yet offered t o t he .NET soft ware developm ent com m unit y."
" Jim m y Nilsson does his readers a great service by showing t hem how t o apply t he foundat ional
principles of ent erprise applicat ion design and developm ent t aught by Evans, Fowler, and ot her
t hought leaders. The book uses a worked exam ple not only t o explain, but also t o dem onst rat e
Dom ain- Driven Design, Pat t erns of Ent erprise Applicat ion Archit ect ure, and Test - Driven
Developm ent . Jim m y's insight and experience m ake reading it a pleasure, and leave t he reader
wit h t he cert aint y t hat t hey have learned from a m ast er pract it ioner. Ent erprise developers
looking t o m ast er t hese principles will find t he book a valuable guide."
Jack Greenfield, Ent erprise Tools archit ect , Visual St udio Team Syst em , Microsoft
" Good soft ware archit ect s reserve t he right t o get sm art er. Beyond t he goal of shipping t heir
current syst em , t hey're on a quest t o discover bet t er ways t o design and build soft ware. This
book is t ravelogue of sort s in which Jim m y docum ent s his j ourney t hrough a wide range of
pat t erns, pract ices, and t echnologies, explaining how his t hinking about ent erprise syst em s has
evolved along t he way. I f you're t raveling t he sam e road, t his book is a good com panion."
Tim Ewald, principal archit ect at Foliage Soft ware Syst em s and aut hor of Transact ional COM+ :
Building Scalable Applicat ions
" This book does an excellent j ob at m aking t angible t he large but very im port ant ideas of
Dom ain- Driven Design."
Floyd Marinescu, aut hor of EJB Design Pat t erns and creat or of I nfoQ.com and
TheServerSide.com
" Underst anding t he concept s and driving forces in t he problem dom ain is param ount t o t he
success of soft ware developm ent . Jim m y Nilsson has drawn inspirat ion from t he past t en years
of st udies int o pat t erns and Dom ain- Driven Design as well as recorded his own experiences
from concret e developm ent proj ect s. This book cont ains com pelling exam ples of how t heory can
be t ranslat ed int o pract ice. I t dem onst rat es t he aut hor's profound underst anding of design
choices and t rade- offs involved in obj ect - orient ed developm ent ."
" This book t ackles an area t hat is a challenge for m ost developers on t he .NET plat form . As t he
pat t erns and pract ices archit ect who init iat ed and drove t he effort s around ent erprise guidance
for .NET, I know how im port ant t his area is for our cust om ers, and am painfully aware of t he
gaps t hat st ill exist in our guidance.
" I was t hrilled t o see Jim m y would be sharing his insight s based on his experience doing DDD
and TDD. I believe t his t opic can be best t ackled at t his point in t im e t hrough a focus on
sim plicit y, pat t erns, and awareness of t he social aspect s of building applicat ions.
" I t rust Jim m y's experience and knowledge of .NET, and have enj oyed his st yle of sharing
concept s and st ories. I can hardly im agine som eone bet t er suit ed t o explain t his t opic on t he
plat form I work on every day.
" I will definit ively recom m end Jim m y's book t o m y cust om ers, m y t eam , and ot her Microsoft
engineer s.
" Ult im at ely, I hope t hat our indust ry can get bet t er at expressing rich concept s in code, and
t hat it get s bet t er at t he social process of art iculat ing and evolving shared knowledge. TDD and
DDD lie t oget her at t he heart of t his pat h."
Edward Jezierski, archit ect of Microsoft pat t erns and pract ices
" Jim m y has woven t oget her best - of- bread t echniquesDom ain- Driven Design, Test - Driven
Developm ent , refact oring, and design pat t ernsint o a convincing alt ernat ive t o t he Dat a- Driven
Developm ent st yle t hat has been t he m ainst ay of Microsoft applicat ions. The core of t he book
breat hes life int o t he t echniques advocat ed in Dom ain- Driven Design; it is relent lessly pract ical,
gives t he reader insight int o t he t hought process t hat underlies applying proven t echniques and
t echnologies, and, like all of Jim m y's work, is an easy read well done Jim m y! "
" I 've been working on a j oint proj ect wit h Jim m y for 18 m ont hs now. Jim m y really lives as he
preaches. I n t his book he t ells you how he is working in pract ice. He uses O/ R Mapping and
NHibernat e daily and he also really uses TDD t o help underst and and dist ill t he cust om er's
business logic and t o m ake sure t hat he only delivers t est ed, high- qualit y code. Just as he
delivers a high- qualit y book cont aining t est ed concept s t o you. Enj oy."
" By showing how t o apply Dom ain- Driven Design and ent erprise applicat ion pat t erns, Jim m y
m akes a difficult t opic approachable for a larger audience. This book has som et hing for t he
experienced archit ect and aspiring pat t ern im plem ent er alike. I n fact , any developer or archit ect
who want s t o im prove t he way he/ she designs and im plem ent s soft ware solut ions should read
t his book."
Per- Ola Nilsson, head of developm ent and soft ware archit ect for Luvit
" Const ant ly abreast wit h t he lat est t rends in soft ware developm ent but never swept away by
t he hype, Jim m y expert ly ext ract s t he value and leaves t he fluff behind. Always hum ble and
wit h bot h his ears wide open, he is uniquely well suit ed t o guide and enlight en t he reader using
t he pract ical applicabilit y as t he st andard, shunning t he ivory t ower. Jim m y doesn't offer his
help from above he act ually m anages t o convince us t hat we have j ust learned about t he cut t ing
edge from a peer."
" As wit h Jim m y's previous book, t his book is a t rue m ast erpiece: a well- laid out balance
bet ween pragm at ic soft ware engineering and deep t heory."
Paul Gielens, senior consult ant for Capgem ini, weblogs.asp.net / pgielens
" Speaking from experience, com bining t he subst ance behind acronym s such as DDD, DP, and
TDD in .NET can lead t o very efficient and adapt ive ent erprise soft ware archit ect ures. This book
out lines how, and why, t hese concept s t oget her m ake such a powerful whole. Hence, t he reader
is given an invaluable short cut t o successful ent erprise soft ware archit ect ures, m aking it a m ust
read for any developer of such."
Mart in Rosén- Lidholm , soft ware archit ect for Exense Healt hcare
" Do you want t o build a high- qualit y ent erprise syst em wit h obj ect orient at ion and a relat ional
dat abase? Don't m iss t his one. Jim m y shows you how Test - Driven Developm ent can be t he
driving force t hroughout t he whole proj ect . He shows how t o m ap t he OO design t o t he
dat abase, a st ep oft en t reat ed very briefly in lit erat ure, which alone m akes t he book wort h t he
m oney. There are also plent y of design t ips and discussions so you can follow his reasoning."
" This im port ant and t im ely book is a m ust read for anyone want ing t o get int o Dom ain- Driven
Design in C# ."
" This book deals wit h several im port ant concept s used in m odern soft ware developm ent , such
as Test - Driven Developm ent , refact oring, pat t erns, and of course, Dom ain- Driven Design.
Jim m y Nilsson writ es about t hese t hings in a very conversat ional t one, and you alm ost get t he
feeling t hat he is act ually sit t ing next t o you, showing you his exam ples and having a
conversat ion about t he pros and cons of different solut ions wit h you personally."
Niclas Nilsson, soft ware developer and educat or for Act iva; not a brot her t o Jim m y, not even
relat ed
" This book does an excellent j ob of bringing Dom ain- Driven Design ( DDD) int o pract ical cont ext
by bridging t he gaps bet ween different abst ract ion levels st art ing from t he business perspect ive
down t o t he syst em level. The book is ideal for soft ware archit ect s and developers because it is
writ t en in a way t hat allows it t o be used as a prim er or reference. The aut hor excels in
present ing all aspect s of DDD in a way t hat is not only educat ional but also fun t o read."
" Not so very long ago, I blogged about m y overall feeling t hat as archit ect s we m ay be failing t o
provide enough guidance for developers t o sort t hrough t he hundreds of different ways t o build
soft ware. There are m any ideas out t here t hat are excellent by t hem selves and com e wit h
perfect ly well- reasoned j ust ificat ions, working exam ples, and an im passioned com m unit y of
believers. Very few of t hem can be used by t hem selves t o build applicat ions, m uch less syst em s
of applicat ions and services. This leaves it up t o developers t o find ways t o put t he individual
ideas t oget her int o applicat ions. This is always m uch harder in realit y t han t he proponent s of
any part icular approach, like t o t hink about . Developers, on t he ot her hand, need t o get som e
work done and oft en don't care t o wade t hrough all t his every t im e t hey st art a new applicat ion.
This is t rue even when t hey are t ruly int erest ed in t he pot ent ial gains of new approaches or
ideas. Jim m y's book is point ed direct ly at t his problem . How do you apply som e of t he great
ideas t hat have com e forward in t he last few years t o real, live developm ent ? I t hink t his book
does a great j ob of bot h explaining t he underlying ideas wit h enough det ail t o m ake t hem
pract ical and put t ing t he group of ideas t oget her in a way t hat will help developers see a pat h
from st art t o end. Dom ain- Driven Design, Test - Driven Developm ent , Dependency I nj ect ion,
persist ence, and m any ot her pract ical issues are covered. Aft er reading t his book, I t hink a
reader will really be able t o t ake t hese im port ant ideas and use t hem t oget her effect ively.
Considering t he great value of t he individual ideas present ed, but t he lim it ed num bers of
exam ples of people really using t hem , t his work represent s a great win for us all. I highly
recom m end it ."
Philip Nelson, chief scient ist for PAi, xcskiwinn.org/ com m unit y/ blogs/ panm anphil/ default .aspx
" Taking t he leap from a dat a- cent ric m indset t o t he deeper realizat ion of OOP found in Dom ain-
Driven Design, Test - Driven Developm ent , obj ect / relat ional persist ence, and ot her Agile m et hods
and pat t erns can be an arduous and disorient ing undert aking for t he uninit iat ed.
" Wit h a pat ient , pragm at ic, and m ent oring st yle, Jim m y t akes t he reader along for t he leap,
exploring t he issues and t he opt ions, giving sound advice along t he way. This book shows you
how t o int egrat e t he various m et hods and pat t erns int o a fully coherent approach t o designing
and creat ing superbly m aint ainable .Net soft ware."
" I f you have ever read his blog, you already know t hat Jim m y Nilsson likes t o challenge
est ablished 't rut hs' in t he .NET com m unit y, looking for bet t er ways t o design soft ware. He
acknowledges t hat soft ware design is hard, and t hat one- size- fit s- all solut ions do not work; pros
and cons have t o be balanced in cont ext of t he problem at hand before ruling a winner. For
building t est able and m aint ainable soft ware wit h com plex business requirem ent s, Jim m y
chooses t o use Dom ain- Driven Design, and he brings along a t oolbox of proven and est ablished
principles, pat t erns, and pract ices t o carry it out . Jim m y's inform al writ ing st yle and use of
exam ples and Test - Driven Developm ent m ake t his book very approachable, especially
considering all t he ground t hat is covered. Because he is on t op of t he DDD st uff, Jim m y ( and
friends) brings you dist illed knowledge on, and references t o, m any of t he m ost valuable
t echniques and resources wit hin soft ware developm ent t oday. I believe t his book t o be a
valuable guide t o applying DDD, and for developers who want t o im prove t heir general design
skills."
" I n Applying Dom ain- Driven Design and Pat t erns, Jim m y Nilsson st rengt hens his posit ion as an
aut horit y on applied soft ware archit ect ure. Wit h a nice blend of his personal t hought s on t he
subj ect s, Jim m y t akes t he reader on a t our t hrough m ost of t he m odern m ust - know design
t echniques, leaving not hing unt ouched. Jim m y shows how t o im plem ent t he t hought s of ot her,
m ore t heoret ical t hought leaders in an appealing and easy t o follow st ruct ure. I am cert ain t hat
Applying Dom ain- Driven Design and Pat t erns will becom e a m andat ory t it le in t he ent erprise
bookshelf."
Mikael Freidlit z, vice president of Cont ent and Knowledge Program s at I ASA
" Dom ain- Driven Design is an im port ant t echnique t hat can help produce qualit y business
applicat ions t hat evolve wit h t he needs of t he business. I n an ideal world, pract icing DDD would
be about OO designbut in realit y, t he t echnologies we work wit h im pose num erous const raint s.
" This book t ackles t hat challenge head on, bridging t he gap bet ween DDD concept s and t he
act ion of t ranslat ing t hem int o pract ice on t he .NET plat form . Jim m y not only has a deep
underst anding of DDD and ent erprise t echnologies, but has learned m any lessons from his
ext ensive indust ry experience, and t akes a refreshingly pragm at ic approach. This is a valuable
book."
Rod Johnson, founder of Spring Fram ework, CEO of I nt erface21
" This is a great book. I t t akes you on a hands- on inform at ive t ravel in t he world of Dom ain-
Driven Design. A great num ber of im port ant issues are discussed, explained, and shown in
relevant cont ext s. These will give you a great foundat ion when you are working wit h your own
Dom ain Model- based syst em . Bot h t he act ual developm ent t echniques as well as pract ical work
m et hods ( as incorporat ion of Test - Driven Developm ent ) are discussed."
Lot t a, wife
" Aaa, dee, dee, dee, pee..." ( Swedish pronunciat ion of t he book abbreviat ion)
" Dad, do you really t hink som eone will read it ?"
When I st art ed writ ing Pat t erns of Ent erprise Applicat ion Archit ect ure ( Addison- Wesley, 2002) , I
looked for t his kind of design advice in t he Microsoft world. I st ruggled t o find m uch of anyt hing, but
one rare book t hat t ackled t he t errit ory was Jim m y's earlier book. I liked his inform al writ ing st yle
and eagerness t o dig int o concept s t hat m any ot hers skim m ed over. So it 's fit t ing t hat Jim m y decided
t o t ake m any of t he ideas from m e and t he ot hers in t he ent erprise pat t erns com m unit y and show
how you can apply t hem in writ ing .NET applicat ions.
The focus of t his ent erprise pat t erns com m unit y is docum ent ing good designs, but anot her t hread
runs t hrough us. We are also big fans of agile m et hods, em bracing t echniques such as Test - Driven
Developm ent ( TDD) and refact oring. So Jim m y also brought t hese ideas int o t his book. Many people
t hink t hat pat t ern- people's focus on design and TDD's focus on evolut ion are at odds. The huge
overlap bet ween pat t ern- people and TDDers shows t his isn't t rue, and Jim m y has weaved bot h of
t hese t hreads int o t his book.
The result is a book about design in t he .NET world, driven in an agile m anner and infused wit h t he
product s of t he ent erprise pat t erns com m unit y. I t 's a book t hat shows you how t o begin applying
such t hings as TDD, obj ect - relat ional m apping, and dom ain- driven design t o .NET proj ect s. I f you
haven't yet com e across t hese concept s, you'll find t hat t his book is an int roduct ion t o t echniques
t hat m any developers t hink are t he key for fut ure soft ware developm ent . I f you are fam iliar wit h
t hese ideas, t he book will help you pass t hose ideas on t o your colleagues.
Many people feel t he Microsoft com m unit y has not been as good as ot hers in propagat ing good
design advice for ent erprise applicat ions. As t he t echnology becom es m ore capable and
sophist icat ed, it becom es m ore im port ant t o underst and how t o use it well. This book is a valuable
st ep in advancing t hat underst anding.
M a r t in Fow le r
h t t p:/ / m a r t in fow le r .com
The best way t o learn how t o do Dom ain- Driven Design ( DDD) is t o sit down next t o a friendly,
pat ient , experienced pract it ioner and work t hrough problem s t oget her, st ep- by- st ep. That is what
reading t his book is like.
This book does not push a new grand schem e. I t unaffect edly report s on one expert pract it ioner's use
of and com binat ion of t he current pract ices he has been drawn t o.
Jim m y Nilsson reit erat es what m any of us have been saying: t hat several current ly t rendy
t opicsspecifically, DDD, Pat t erns of Ent erprise Applicat ion Archit ect ure ( PoEAA) , and Test - Driven
Developm ent ( TDD) are not alt ernat ives t o each ot her, but are m ut ually reinforcing elem ent s of
successful developm ent .
Furt herm ore, all t hree of t hese are harder t han t hey look at first . They require ext ensive knowledge
over a wide range. This book does spend som e t im e advocat ing t hese approaches, but m ost ly it
focuses on t he det ails of how t o m ake t hem work.
Effect ive design is not j ust a bunch of t echniques t o be learned by rot e; it is a way of t hinking. As
Jim m y dives int o an exam ple he gives us a lit t le window int o his m ind. He not only shows his solut ion
and explains it , he let s us see how he got t here.
When I am designing som et hing, dozens of considerat ions flit t hrough m y m ind. I f t hey are fact ors
I 've dealt wit h oft en, t hey pass so quickly I am barely conscious of t hem . I f t hey are in areas where I
have less confidence, I dwell on t hem m ore. I presum e t his is t ypical of designers, but it is difficult t o
com m unicat e t o anot her person. As Jim m y walks t hrough his exam ples, it is as if he were slowing
t his process down t o an observable pace. At every lit t le j unct ure, t hree or four alt ernat ives present
t hem selves and get weighed and rej ect ed in favor of t he one he event ually chooses.
For exam ple, we want m odel obj ect s t hat are im plem ent ed free of ent anglem ent wit h t he persist ence
t echnology. So what are eight ways ( eight ! ) t hat a persist ence fram ework can force you t o
cont am inat e t he im plem ent at ion of a dom ain obj ect ? What considerat ions would lead you t o
com prom ise on som e of t hese point s? What do t he current ly popular fram eworks, including t he .NET
plat form , im pose?
Jim m y t hinks pragm at ically. He draws on his experience t o m ake a design choice t hat will likely t ake
him t oward t he goal, adhering t o t he deeper design principle, rat her t han t he choice t hat looks t he
m ost like a t ext book exam ple. And all of his decisions are provisional.
The first design principle Jim m y holds in front of him self is t he fundam ent al goal of DDD: a design
t hat reflect s deep underst anding of t he business problem at hand in a form t hat allows adapt at ion t o
new wrinkles. So why so m uch discussion of t echnical fram ework and archit ect ure?
I t is a com m on m ispercept ion, perhaps a nat ural one, t hat such a priorit y on t he dom ain dem ands
less t echnical t alent and skill. Would t hat t his were t rue. I t would not be quit e so difficult t o becom e a
com pet ent dom ain designer. I ronically, t o render clear and useful dom ain concept s in soft ware, t o
keep t hem from being suffocat ed under t echnical clut t er, requires part icularly deft use of t echnology.
My observat ion is t hat t hose wit h t he great est m ast ery of t echnology and archit ect ural principles
oft en know how t o keep t echnology in it s place and are am ong t he m ost effect ive dom ain m odelers.
I do not refer t o t he knowledge of every quirk of com plex t ools, but t o t he m ast ery of t he sort of
knowledge laid out in Mart in Fowler's PoEAA, because naïve applicat ion of t echnology paradoxically
m akes t hat t echnology m ore int rusive int o t he applicat ion.
For m any people t his book will fill in gaps of how t o im plem ent expressive obj ect m odels in pract ice.
I picked up a num ber of useful ways of t hinking t hrough t he applicat ion of t echnical fram eworks, and
I especially firm ed up m y underst anding of som e part iculars of doing DDD in a .NET set t ing.
I n addit ion t o t echnical archit ect ure, Jim m y spends a great deal of t im e on how t o writ e t est s. TDD
com plem ent s DDD in a different way. I n t he absence of a focus on refining an ever m ore useful
m odel, TDD is prone t o fragm ent ed applicat ions, where a single- m inded at t ack on one feat ure at a
t im e leads t o an unext endable syst em . A com prehensive t est suit e act ually allows such a t eam t o
cont inue m aking progress longer t han would be possible wit hout it , but t his is j ust t he basest value of
TDD.
At it s best , t he t est suit e is t he laborat ory for t he dom ain m odel and a t echnical expression of t he
ubiquit ous language. Test s of a part icular st yle drive t he m odeling process forward and keep it
focused. This book st eps us t hrough exam ples of developing such t est s.
Jim m y Nilsson has a rare com binat ion of self- confidence and hum ilit y, which I have observed t o be
charact erist ic of t he best designers. We get a glim pse of how he got t o his current underst anding as
he t ells us what he used t o believe and why t hat opinion changed, which helps t o t ake t he reader
past t he specifics of t he t echniques t o t he underlying principles. This hum ilit y m akes him open t o a
wide range of influences, which gives us t his fusion of ideas from different sources. He has t ried a lot
of t hings and has let his result s and experience be his guide. His conclusions are not present ed as
revealed t rut h, but as his best underst anding so far wit h an im plicit recognit ion t hat we never have
com plet e knowledge. All t his m akes t he advice m ore useful t o t he reader. And t his at t it ude, in it self,
illust rat es an im port ant elem ent of successful soft ware developm ent leadership.
Er ic Eva n s
Preface: Bridging Gaps
On t he cover of t his book is a pict ure of t he Øresund Bridge t hat connect s Sweden and Denm ark. I t
seem s t hat all soft ware archit ect ure books m ust have a bridge on t he cover, but t here are som e
addit ional reasons t he bridge is appropriat e for t his book.
This bridge replaced a ferry t hat I t ook m any t im es as a child. I enj oy very m uch driving over it even
aft er dozens of t im es.
On a personal not e, m y fat her was on t he t eam t hat built t he highest part s of t he bridge.
But beyond t hese, t he m ain reason is t hat t his book is very m uch about bridging gaps; bridging gaps
bet ween users and developers; bridging gaps bet ween business and soft ware; bridging gaps bet ween
logic and st orage. Bridging gaps bet ween " DB- guys" and " OO- guys" ...
I will refrain from m aking a j oke about t he Bridge pat t ern [ GoF Design Pat t erns] . Hey, how geeky
can a preface be?
Put anot her way, m y vision has been t o provide a book t hat will put Eric Evans' Dom ain- Driven
Design [ Evans DDD] and Mart in Fowler's Pat t erns of Ent erprise Applicat ion Archit ect ure [ Fowler
PoEAA] in cont ext .
DDD m ight be perceived as a bit abst ract . Therefore, m ore concret e exam ples are helpful regarding
persist ence, for exam ple. Mine m ay be fairly basic, but it is a plat form t o st art from . This book not
only explains how t o use t he pat t erns, but also how t he pat t erns are used in O/ R Mappers, for
exam ple.
I t has becom e very clear t o m e t hat " one size does not fit all" when it com es t o archit ect ure. Having
said t hat , pat t erns have proven t o be general enough t o use and reuse in cont ext aft er cont ext .
The focus isn't on t he pat t erns t hem selves, but t his book uses pat t erns in every chapt er as a t ool and
language for discussing different design aspect s. A nice side effect is t hat pat t erns- ignorant readers
will also gain som e insight and int erest int o pat t erns along t he way.
That also goes for TDD. Not all developers have becom e int erest ed in t his yet . I t hink it 's especially
com m on in t he .NET com m unit y t hat TDD ( j ust as pat t erns) is considered a niche t echnique at best ,
or it m ight even be t ot ally unknown. Readers will learn how t o apply TDD.
My change of heart st art ed when I read t wo recent books t hat inspired m e and changed m y t hinking.
First , t here was Mart in Fowler's Pat t erns of Ent erprise Applicat ion Archit ect ure [ Fowler PoEAA] . This
book inspired m e t o give t he Dom ain Model pat t ern anot her t ry aft er having failed wit h several
earlier at t em pt s.
Then I read Eric Evans' book Dom ain- Driven Design [ Evans DDD] . This book provided m e wit h
insight s about how t o t hink and act regarding developm ent wit h a st rong dom ain focus and wit h a
cert ain st yle of how t o apply t he Dom ain Model pat t ern.
Anot her im port ant influence was all t hat I learned from t eaching m y pat t erns course over a couple of
years. As I int eract ed wit h st udent s and t he m at erial evolved, I had insight s m yself.
My views of DDD t ransform ed as I worked on an am bit ious ( t hough unfort unat ely unfinished) open
source proj ect called Valhalla, which I developed in collaborat ion wit h Christ offer Skj oldborg.
( Christ offer did by far t he m ost work.)
To sum m arize all t his, I felt t hat a book t hat dealt m ore wit h applicat ion t han t heory was needed, but
one t hat was based on solid ground, such as t he DDD and PoEAA books. " Applying" feels close t o m y
heart because I consider m yself a developer above anyt hing else.
Target Audience
This book is aim ed at a wide t arget audience. I t will help if you have som e knowledge of
However, int erest and ent husiasm will com pensat e for any lack of prior experience.
I 'd like t o elaborat e on m y st at em ent t hat t he t arget audience is wide. First , we can t hink about t he
way we put people int o plat form boxes. The book should serve .NET people who want a m ore core-
based approach t han drag- t ill- you- drop ( if I m ay use som e weak generalizat ions) . Java people should
get som et hing out of t he discussions and exam ples of how t o com bine DDD and O/ R Mapping.
I t hink t he chosen language/ plat form is less and less im port ant , so it feels a lit t le st range t o t alk
about .NET people and Java people. Let 's t ry t o describe t he t arget audience by using anot her
dim ension. Then I t hink t hat t he book is for developers, t eam leaders, and archit ect s.
Choosing yet anot her dim ension, I t hink t here m ight be som et hing in t his book bot h for int erm ediat e
and advanced readers. There's probably also som et hing for beginners.
This chapt er discusses propert ies of archit ect ure and process t o value for creat ing qualit y
result s when it com es t o syst em developm ent . The discussion is influenced by Ext rem e
Program m ing.
This chapt er focuses on providing exam ples and discussions about pat t erns from different
fam ilies, such as design pat t erns, archit ect ural pat t erns and dom ain pat t erns.
Chapt er 1 t alks quit e a lot about TDD and refact oring, but in t his chapt er t here is m ore in- dept h
coverage wit h pret t y long exam ples and also different flavors of TDD.
This chapt er list s a set of requirem ent s of an exam ple applicat ion, and a first - t ry m odel is
creat ed as a st art for t he com ing chapt ers. A Dom ain Model- based archit ect ure is used.
Chapt er 5, " Moving Furt her wit h Dom ain- Driven Design"
The requirem ent s set up in t he prior chapt er are used in t his chapt er as t he basis for slowly,
wit h TDD, st art ing t o build t he Dom ain Model in a DDD- ish st yle.
Even t hough we t ry t o push t he infrast ruct ure aspect s as far off in t he fut ure as possible, it 's
good t o t hink a lit t le bit ahead and prepare t he Dom ain Model for t he infrast ruct ure needs. I n
t his chapt er, t here is a lot of discussion about pros and cons of Persist ence I gnorant Dom ain
Models.
This chapt er t alks about business rules in t he form of validat ion and how a Dom ain Model- based
solut ion can deal wit h t he need for such rules, connect ing back t o t he requirem ent s set up in
Chapt er 4.
Part III: Applying PoEAA
I n t his part , we put several of t he pat t erns in Fowler's Pat t erns of Ent erprise Applicat ion Archit ect ure
[ Fowler PoEAA] int o cont ext by discussing what we need from t he infrast ruct ure for providing
persist ence support t o our Dom ain Model. We will t ake a look at how t hose requirem ent s are fulfilled
by an exam ple t ool.
When we have a fairly good Dom ain Model, it 's t im e t o t hink about infrast ruct ure, and t he m ain
t ype of infrast ruct ure in t his book is infrast ruct ure for persist ence. This chapt er discusses
different propert ies of persist ence solut ions and how t o cat egorize a cert ain solut ion.
This chapt er uses t he cat egorizat ions of t he prior chapt er wit h an exam ple of a persist ence
solut ion, nam ely NHibernat e [ NHibernat e] .
Aft er a short discussion about Bounded Cont ext , t his chapt er discusses design t echniques t o
keep an eye on now and for t he fut ure, such as Service Orient at ion, Dependency
I nj ect ion/ I nversion of Cont rol, and Aspect Orient at ion.
This chapt er focuses on how t he UI can be connect ed t o t he Dom ain Model and how t o increase
t est abilit y for t he user int erface when using a Dom ain Model, bot h for rich client applicat ions
and Web applicat ions.
Appendices
There are t wo appendices providing furt her exam ples of Dom ain Model st yles and an overview- t ype
pat t erns cat alog.
The reasons for t he choice are m ainly t hat C# is m y current m ain language and t hat m ost VB.NET
and Java developers can read C# code pret t y easily.
Regarding t he version, m ost of t he code exam ples work in bot h C# 1.1 and 2.0, but t here are som e
rare sect ions t hat are focused on 2.0.
Distribution
I t was in m y early plans of t he book t o include t horough coverage of t he dist ribut ion aspect s, but
lat er on I cam e t o t he conclusion t hat t he book would becom e t oo unfocused. St ill, t here is som e
coverage here and t here.
Advanced Modeling
The t it le of t he book m ight suggest t hat you find advanced and int erest ing exam ples of m odeling of
cert ain problem areas. That 's not exact ly t he case. I nst ead, t he applicat ion focus is m ore about
applying TDD and adding infrast ruct ure t o DDD.
finally{}
As you can appreciat e, a book proj ect like t his is hardly ever t he work of only one person. On t he
cont rary, it 's a j oint effort . See t he list of people in t he Acknowledgm ent s sect ion, and also rem em ber
t hat even m ore people have been involved, especially during product ion. That said, any errors we
didn't cat ch before t he book went t o print are m ine and m ine alone.
I will post inform at ion of int erest t o readers of t he book at w w w .j nsk.se/ adddp.
Get t ing back t o bridging gaps, t he phot o of t he Øresund Bridge was t aken by m y friend Magnus von
Schenck on one of his sailing t rips.
Even t hough t his book has not been as t ough t o writ e as t he first one, t here has been a fair am ount
of blood, sweat , and t ears. I hope t he book m ight save you som e of t hat . Have fun and good luck!
Jim m y Nilsson
www.j nsk.se/ weblog/
List erby, Sw eden
Sept em ber 2005
Acknowledgments
Wit h t he risk of forget t ing som e people t hat should get a m ent ion here ( if so, you know who you are
and a big t hanks t o you, t oo) , I say a huge t hanks t o t he following:
My guest aut hors: Frans Boum a, Dan Byst röm , Udi Dahan, Erik Dörnenburg, Mat s Helander, I ngem ar
Lundberg, Philip Nelson, Claudio Perrone, Aleksandar Seovi , and Christ offer Skj oldborg.
My reviewers who provided lot s of valuable feedback: William Bulley, Mark Burhop, Dan Byst röm ,
Russ Condick, Andy Conrad, Christ ian Crowhurst , Mike Dörfler, St eve Eichert , Eric Evans, Mart in
Fowler, Paul Gielens, Chris Haddad, Kim Harding Christ ensen, Mat s Helander, Neeraj Gupt a, Anders
Hessellund, Roger Johansson, Roger Krat z, Trond- Eirik Kolloen, I ngem ar Lundberg, Pat rik Löwendahl,
Marcus Mac I nnes, Philip Nelson, Per- Ola Nilsson, Fredrik Norm én, Johan Norm én, Michael O'Brien,
Michael Plat t , Sébast ien Ros, Mart in Rosén- Lidholm , Enrico Sabbadin, Aleksandar Seovi , Christ offer
Skj oldborg, George Vish I I , Gregory Young, and Christ er Åkesson.
My art ist of t he figures for t he part s int roduct ions: Kj ell Warnquist
My acquisit ions edit or: Karen Get t m an ( and Sondra Scot t who t alked m e int o t he proj ect in t he first
place)
Wit hout you t here would be no book, or at least a book of inferior qualit y. Thanks guys, I owe you!
Part I: Background
I n t he " Background" part , we discuss archit ect ure and processes in general t erm s. There is a lot
of em phasis on Dom ain Models and Dom ain- Driven Design ( DDD) [ Evans DDD] . We also
int roduce pat t erns and Test - Driven Developm ent ( TDD) .
We will j um p around quit e a lot and cover a lot of ground, but t he overall idea is t o discuss values t o
value regarding archit ect ure and processes for developm ent .
On t his j ourney, we will int roduce and t alk about m any concept s t hat we will discuss in dept h lat er on
in t he book.
Over t he last few years, we've been encouraged t o use anot her approach: " Do t he sim plest t hing t hat
could possibly work." To a large ext ent , t he idea com es from t he Ext rem e Program m ing ( XP)
m ovem ent [ Beck XP] . Anot her fairly sim ilar way t o put it is " You Aren't Going t o Need I t " ( YAGNI ) ,
which is a good way of helping you st ay in line. I guess " Keep I t Sim ple St upid" ( KI SS) could go
here, t oo.
Bot h approaches are kind of t he t wo ext rem es ( add all you can t hink of up front versus do t he
sim plest t hing) , but I t hink t hey bot h m iss som et hing in t hat t hey don't address t he t radeoffs t hey
m ake. Just about every quest ion regarding " is t his or t hat best " can be answered wit h " it depends."
I t 's about t radeoffs. I t end t o prefer an approach t hat is som ewhere in t he m iddle, m oving in one or
t he ot her direct ion depending upon t he sit uat ion. The word " lagom " is a Swedish word m eaning
som et hing like " j ust right " or " not t oo m uch, not t oo lit t le." Lagom or " t o balance" t oget her wit h
being cont ext sensit ive are t he overall values I 'd like t o value, as well as cont inuous learning.
Let 's have a closer look at a couple of m ore specific areas of values ( archit ect ure and process
ingredient s) , st art ing wit h som e aim ed at archit ect ure t o get us int o t he right m ood.
Architecture Styles to Value
Archit ect s and developers m ust m ake design decisions based on t he requirem ent s of t he proj ect . I
haven't collect ed an exhaust ive list of values regarding archit ect ure st yles here, but I have decided
on a few m ain t hings I 'd like t o com m ent on t o som e ext ent , such as m odel focus, dom ain m odels,
dat abases, dist ribut ion, and m essaging. First , I t hink it 's wise t o keep a m odel focus.
N ot e
As a reviewer point ed out , m at urit y depends on t he plat form we are t alking about . I f you
com e from a VB background, what was j ust said is reasonable, but if you com e from Java,
Sm allTalk, C# , and so on, t he plat form has been m at ure for quit e som e t im e.
Around 13 years ago, I t ried t o use a visual m odel t o com m unicat e m y underst anding of t he
requirem ent s of a syst em I was about t o build, and I used som e OMT [ Rum baugh OMT] sket ches.
( OMT st ands for Obj ect Modeling Technique and was a m et hod wit h a process and a not at ion. The
not at ion was very sim ilar t o t he one in Unified Modeling Language, UML, which isn't j ust a
coincidence because OMT was t he m ain inspirat ion for t he not at ion in UML.) We were discussing
m ult iplicit y bet ween classes, where behavior should belong, and so on. I realized aft er a few sessions
t hat using m y t echnique for discussion wit h expert users, inst ead of t heir t echnique, was a com plet e
failure. They answered m y quest ions random ly and didn't see or add m uch value at all in t he
discussion. ( The syst em at large wasn't a failure, it 's st ill being used and it 's t he core syst em t here,
but t he developm ent process didn't go as sm oot hly as it could have. I had t o change m et hod.)
I t was very nat ural t o users and could be m ade nat ural t o developers, t oo, so it becam e t he bridging
t ool of m ine for years. The way I did t he bridging was t o have one class per use case in t he soft ware.
I t did com e t o m y at t ent ion t hat t hanks t o m y way of applying use cases, I becam e pret t y procedural
in m y t hinking. I was designing a lit t le bit like Transact ion Script [ Fowler PoEAA] , but I t ried t o
balance it by generalizing as m uch behavior as possible ( or at least suit able) .
A few years ago I heard I var Jacobson t alking about use cases, and I was pret t y surprised when I
realized t hat he didn't encapsulat e t he use cases in classes of t heir own as I had expect ed and had
done for a long t im e.
Anot her t hing t hat got m e kind of worried about t his m et hod was t he const ant st ruggle I was having
wit h m y friend and Valhalla- developer Christ offer Skj oldborg when we worked wit h t he Dom ain Model
pat t ern [ Fowler PoEAA] . He saw lit t le value in t he use case classes, m aint aining t hat t hey could even
get in t he way because t hey m ight becom e a hindrance when m ixing and m at ching use case part s.
Before we cont inue, I m ust say a few words about Transact ion Script and Dom ain Model,
which we have already t ouched upon.
Mart in Fowler discusses t hree ways of st ruct uring t he m ain logic in applicat ion
archit ect ure in his book Pat t erns of Ent erprise Applicat ion Archit ect ure [ Fowler PoEAA] .
Those are Transact ion Script , Table Module, and Dom ain Model.
Transact ion Script is sim ilar t o bat ch program s in t hat all funct ionalit y is described from
st art t ill end in a m et hod. Transact ion Script is very sim ple and useful for sim ple
problem s, but breaks down when used for dealing wit h high com plexit y. Duplicat ion will
be hard t o avoid. St ill, very m any very large syst em s are built t his way. Been t here,
done t hat , and I 've seen t he evidence of duplicat ion even t hough we t ried hard t o reduce
it . I t crops up.
Table Module encapsulat es a Recordset [ Fowler PoEAA] , and t hen you call m et hods on
t he Table Module for get t ing inform at ion about t hat cust om er wit h id 42. To get t he
nam e, you call a m et hod and send id 42 as a param et er. The Table Module uses a
Recordset int ernally for answering t he request . This cert ainly has it s st rengt hs, especially
in environm ent s when you have decent im plem ent at ions for t he Recordset pat t ern. One
problem , t hough, is t hat it also has a t endency t o int roduce duplicat ion bet ween different
Table Modules. Anot her drawback is t hat you t ypically can't use polym orphist ic solut ions
t o problem s because t he consum er won't see t he obj ect ident it ies at all, only value-
based ident it ies. I t 's a bit like using t he relat ional m odel inst ead of t he obj ect - orient ed
m odel.
Dom ain Model inst ead uses obj ect orient at ion for describing t he m odel as close t o t he
chosen abst ract ions of t he dom ain as possible. I t shines when dealing wit h com plexit y,
bot h because it m akes usage of t he full power of obj ect orient at ion possible and because
it is easier t o be t rue t o t he dom ain. Usage of t he Dom ain Model pat t ern isn't wit hout
problem s, of course. A t ypical one is t he st eep learning curve for being able t o use it
effect ively.
The real eye- opener for m e regarding t he usage of use cases was Dom ain- Driven Design ( DDD)
[ Evans DDD] . ( We will t alk a lot about DDD soon, but for now, let 's j ust say it 's about focusing on t he
dom ain and let t ing it affect t he soft ware very m uch.) I st ill t hink t hat t he use case t echnique is a
great way of com m unicat ing wit h users, but DDD has m ade m e t hink it can help a lot if we can
m anage t o act ively involve t he users in discussions about t he core m odel. I t can head off m ist akes
very early and help t he developers underst and t he dom ain bet t er.
N ot e
" Model" is one of t hose ext rem ely overloaded t erm s in soft ware. I t hink we all have an
int uit ive idea about what it is, but I 'd like t o describe how I t hink about it . I nst ead of t rying
t o com e up wit h t he definit ion, here in all sim plicit y ( t his could fill a book of it s own by t he
right aut hor) are a few propert ies of a m odel t hat you can com pare t o your own
underst anding of t he t erm . A m odel is
Part ial
Also,
A m odel has several present at ions ( for exam ple: language, code, and diagram s) .
I f you would like t o read m ore, very m uch has been writ t en about what a m odel is. A good
place t o st art is t he first pages in Eric Evans' book [ Evans DDD] . ( A special t hanks t o
Anders Hessellund and Eric Evans for inspirat ion.)
The m odel is a great t ool for com m unicat ion bet ween developers and users, and t he bet t er t he
com m unicat ion is bet ween t hose groups, t he bet t er t he soft ware will becom e, bot h in t he short and
t he long run.
We ( including m e) have been using m odels forever, of course, but t he difference bet ween one of m y
old m odels and t hose t hat have been built wit h t he ideas of DDD is t hat m y old m odels had m uch
m ore infrast ruct ure focus and t echnical concept focus. My new m odels are m uch cleaner from such
dist ract ions and inst ead focus t ot ally on t he core dom ain, it s m ain concept s, and t he dom ain
problem s at hand. This is a big m ind shift .
Anot her way of expressing it is t hat t echnicalit ies ( such as user int erface fashion) com e and go. Core
business last s. And when t he core business changes, we want t o change t he m odel and t he soft ware.
I t 's not rocket science so far, and I 'm probably j ust kicking in open doors. I t hink, however, t his lies
at t he very core of how t o achieve efficient soft ware developm ent , and in m y experience it is rarely
used. By t his I m ean focusing on t he m odel, having a m odel ( wit h different present at ions) t hat is
used by bot h users and developers, and not get t ing dist ract ed by unim port ant det ails.
Finding developers like t hat does happen, but in m y experience it 's m ore t he except ion t han t he rule.
I n t he case of t he developer being able t o m ove on t o anot her dom ain for a new syst em when t he
financial syst em is up and running, t hat except ion becom es even m ore rare. This is because
developers j ust can't have t en years of experience in logist ics, healt h care, insurance, and t he rest .
Anot her solut ion can be t o let t he dom ain expert users develop t he soft ware t hem selves. This has
been an old dream for decades, and t o a degree it 's slowly becom ing m ore and m ore viable all t he
t im e. At t he sam e t im e, it t akes away t im e from t hem , t im e t hey oft en can use bet t er for t heir core
work. There's also t oo m any t echnical problem s st ill involved.
So what 's t he next best t hing? The answer is obvious ( at least from t oday's st andpoint ) : m ake t he
developer learn as m uch as possible about t he dom ain he or she is working on and add users t o t he
pict ure t o bring t he dom ain expert ise t o t he proj ect t eam and t o act ively and const ruct ively work
wit hin t he proj ect . The users would not j ust set t he requirem ent salt hough t hat is also very
im port ant but would act ually help out wit h designing t he core of t he syst em . I f we can m anage t o
creat e t his at m osphere, nobody is m ore skilled t han t he dom ain expert user at deciding on what t he
core is, what t he key abst ract ions are, and so on.
Of course, as developers we are also necessary. The whole t hing is done in cooperat ion. For exam ple,
what m ight be seen as a t iny det ail t o businesspeople can be a huge t hing t o us in t he dom ain m odel.
They m ight say: " Oh, som et im es it 's like t his inst ead," and everyt hing is t ot ally different , but
because it 's not t he m ost com m on variant , t hey t hink it 's unim port ant .
Why would I now succeed in discussing t he m odel wit h t he cust om ers when I failed before? Many
t hings have changed. First , it 's im port ant t o have a sense of t he cont ext and t he proj ect group.
Second, use cases can help a lot when get t ing st art ed, and t hen you can swit ch t he focus lat er t o t he
core m odel it self. Third, building syst em s is som et hing m any m ore people have experience in and
have been t aught about now. Fourt h, t o be picky, t he m odel represent ed as graphical, UML- like
sket ch for exam ple is not t he m ost im port ant t hing t o have users work on; it 's st ill t ypically a
represent at ion t hat developers like bet t er t han users. What we are looking for is t he ubiquit ous
language [ Evans DDD] .
The ubiquit ous language is not som et hing like UML, XML Schem a, or C# ; it 's a nat ural, but very
dist illed, language for t he dom ain. I t 's a language t hat we share wit h t he users for describing t he
problem at hand and t he dom ain m odel. I nst ead of us list ening t o t he users and t rying t o t ranslat e it
t o our own words, a ubiquit ous language would creat e fewer reasons for m isunderst andings, and it
will becom e easier for t he users t o underst and our sket ches and act ually t o help correct m ist akes,
helping us gain new knowledge about t he dom ain. I f it 's suit able, you can discuss ubiquit ous
language in t he cont ext of t he graphical/ code m odels wit h t he users. I f not , you st ill have t he m ost
im port ant t hing done if you cat ch t he ubiquit ous language.
N ot e
Eric Evans com m ent ed on t he previous wit h t he following: " Som et hing t o m ake clear is t hat
t he ubiquit ous language isn't j ust t he dom ain expert 's current lingo. That has t oo m any
am biguit ies and assum pt ions and also probably t oo large a scope. The ubiquit ous language
evolves as a collaborat ion bet ween t he dom ain expert s and t he soft ware expert s. ( Of
course, it will resem ble a subset of t he dom ain j argon.) "
The ubiquit ous language is som et hing t hat you should work hard t o keep well- defined and in synch
wit h t he soft ware. For exam ple, a change in t he ubiquit ous should lead t o a change in t he soft ware
and vice versa. Bot h art ifact s should influence each ot hers.
N ot e
I f you aren't up t o speed on UML, I t hink a good book t o read is UML Dist illed [ Fowler UML
Dist illed] . I t 's not essent ial t hat you underst and UML, but I t hink it will be helpful t o know
t he bones because I will be using UML as a sket ch t ool here and t here ( of course, you will
benefit from it at ot her t im es as well, not j ust wit h t his book) .
Even t hough Figure 1- 1 shows j ust an early sket ch of a sm all dom ain m odel, I t hink we can see t hat
t he m odel expresses dom ain concept s and not t echnical dist ract ions. We can also see t hat it cont ains
several cooperat ing sm all pieces, which t oget her form a whole.
N ot e
I f you wonder why Figure 1- 1 is handwrit t en, it is t o st ress t he point t hat it is a sket ch. We
will explore and develop t he det ails in codefor exam ple, wit h t he help of Test - Driven
Developm ent ( TDD) . ( We will discuss TDD lat er in t his chapt er, as well as in Chapt er 3,
" TDD and Refact oring." )
Before we t alk m ore about t he specific st yle I used for t he Dom ain Model, I t hink it 's t im e t o look
back again.
I st ill rem em ber t he first t im e I t ried t o use t he Dom ain Model, even t hough I didn't call it t hat at t he
t im e. I t was around 1991, and I couldn't underst and how it should m at ch up in t he UI . I don't
rem em ber what t he applicat ion was, but I rem em ber t hat I t ried t o decide on what t he m enus should
look like in order t o be obj ect - orient ed. I didn't com e over t hat first hurdle t hat t im e. I t hink I was
looking for a very close m apping bet ween t he UI and t he Dom ain Model and couldn't find out how t o
achieve it .
A few years prior t o t hat , I worked on an applicat ion t hat was said t o use obj ect - orient ed ideas, for
exam ple, for t he UI . There were no big breakt hroughs, perhaps, but it m anaged t o achieve sm all
t hings. For exam ple, inst ead of first choosing a funct ion and t hen deciding t o what obj ect ( such as a
port folio) t o apply it , t he user first chose t he obj ect and t hen decided bet ween t he different funct ions
t hat were possible for t he chosen obj ect . At t he t im e t his was pret t y different from how m ost
business applicat ions were navigat ed in t he UI .
A Few Words About Naked Objects
Perhaps I wasn't t ot ally off wit h m y int ent ions. Perhaps what I was t rying t o achieve was
som et hing like Naked Obj ect s [ Pawson/ Mat t hews Naked Obj ect s] , but I really didn't get
very far wit h it .
Wit hout going int o det ails about Naked Obj ect s, I t hink a short explanat ion is in order.
The basic idea is t hat not only developers but users also like obj ect - orient at ion. They like
it even m ore t han we norm ally t hink, and t hey would quit e oft en be happy wit h a UI t hat
is very close t o t he Dom ain Model it self, so close t hat t he UI can be creat ed
aut om at ically by a fram ework direct ly based on t he Dom ain Model.
A syst em based on naked obj ect s aut om at ically present s a form t o a user t hat cont ains
widget s exposing t he propert ies in t he Dom ain Model class.
For m ore com plex t asks, t here is som e need for cust om izat ion ( as always) , but t he idea
is t o cut down on t hat as well, again t hanks t o t he fram ework t hat underst ands what UI
t o creat e from t he Dom ain Model fragm ent s. So when t he Dom ain Model is " done," t he
UI is m ore or less done as well.
For t he m om ent I don't have first - hand experience wit h t he concept and t echnique, but
an appealing t wist t o m e of t he idea is t hat t he users will really get a chance t o see and
feel t he m odel, which should be very helpful in bridging t he gap bet ween developers and
users.
Aft er t hat , I t ried Dom ain Model approaches m any t im es over t he years. I found problem s wit h using
it , especially relat ed t o perform ance overhead ( especially in dist ribut ed scenarios) . That said, som e
of m y real world applicat ions were built in t hat st yle, especially t he sim pler ones. What is also
im port ant t o say is t hat however m uch I want ed t o build very powerful, well- designed Dom ain
Models, t hey didn't t urn out as I had ant icipat ed.
I 've believed in Dom ain Models and t ried t o use t hem several t im es in t he past , but m ost at t em pt s t o
im plem ent it in obj ect - orient ed fashion led m e t o t he conclusion t hat it doesn't work. That was, for
exam ple, t he case wit h m y COM+ applicat ions in Visual Basic 6 ( VB6) . The m ain problem was t hat
perform ance overhead was t oo high.
When I wrot e m y previous book [ Nilsson NED] , which described a default - archit ect ure for .NET
applicat ions, I reused m y old VB6/ COM+ knowledge and didn't m ake t he discussed archit ect ure
Dom ain Model- based at all.
Lat er on I st art ed up new experim ent s again, t rying t o see if I could get down t o som et hing like 10%
in response- t im e overhead on com m on scenarios ( such as fet ching a single order, fet ching a list of
orders for a cust om er, or saving an order) when using Dom ain Model in .NET com pared wit h
Transact ion Script s and Recordset . To m y surprise, I could get low er overhead. The old t rut hs had
becom e wrong. The Dom ain Model- based archit ect ure is very m uch m ore possible now in .NET t han
in VB6. One reason for t his is t hat t he inst ant iat ion t im e is reduced by orders of m agnit ude.
Therefore, t he overhead is j ust m uch lower when you have very m any inst ances. Anot her reason is
t hat it 's t rivial t o writ e Marshal By Value ( so t hat not only is t he reference t o t he inst ance m oved, but
t he whole inst ance, at least concept ually, is m oved) com ponent s in .NET. I t was not sim ple in t he
COM world. ( I t wasn't even possible t o do it in t he ordinary sense in VB6.)
N ot e
The im port ance of Marshal By Value is of less im port ance because we now m ost oft en
prefer t o not send t he Dom ain Model as- is over t he wire, but m y early t est s were using
t hat .
Yet anot her reason is t hat .NET bet t er support s obj ect - orient at ion; it 's j ust a m uch bet t er t oolbox.
N ot e
Also wort h m ent ioning is t hat t here hasn't been m uch em phasis on t he Dom ain Model in
t he Microsoft com m unit y in t he past . The Java com m unit y, on t he ot her hand, is alm ost t he
opposit e. I rem em ber when I went t o a workshop wit h m ost ly Java people. I asked t hem
about what t heir favorit e st ruct ure for t he logic was, perhaps if t hey used Recordset ( added
in JDBC version 3) a lot . They looked at m e funnily as if t hey hadn't underst ood t he
quest ion. I quickly realized t hat Dom ain Model was m ore or less t he de fact o st andard in
t heir case.
To set all t his st raight , I 'd like t o clarify t wo t hings. First , I do not say t hat you should choose t he
Dom ain Model pat t ern because of perform ance reasons. Rat her t hat you oft en can choose t he
Dom ain Model pat t ern wit hout get t ing perform ance problem s.
Second, I do not say t hat t o be able t o use a m odel focus, you need a cert ain t echnology. Different
t echnologies are m ore or less appropriat e for expressing t he m odel in soft ware in close resem blance
wit h t he dom ain. Of course, t here is not a single t echnology t hat is always best . Different dom ains
and different problem s set different fact ors for what is an appropriat e t echnology. So I see
t echnology as an enabler. Different t echnologies can be bet t er enablers t han ot hers.
To sum m arize t his, it 's very m uch a m at t er of design if t he Dom ain Model pat t ern can be used
efficient ly enough or not .
Som e good news regarding t his is t hat t here is lot s of good inform at ion t o gain. Dom ain- Driven
Design and it s st yle for st ruct uring Dom ain Models provides lot s of valuable help, and t hat is
som et hing we will spend a lot of t im e t rying out in t he book.
So if we choose t o focus on a Dom ain Model, it m eans t hat we will get all t he people on t he proj ect t o
buy int o t he m odel. This goes for t he developers, of course.
I t m ight even be t hat t he DBAs can agree on seeing t he Dom ain Model as t he root , even t hough t he
dat abase design will be slight ly different . I f so, we have probably accom plished get t ing t he DBA t o
speak t he ubiquit ous language, t oo! ( As a m at t er of fact , t he m ore you can get your DBA t o like t he
Dom ain Model and adhere t o it , t he easier it will be t o im plem ent it . This is because you will need t o
creat e less m apping code if t he dat abase design isn't radically different from t he Dom ain Model, but
m ore like a different view of t he sam e m odel.) Oh, and even t he users could buy int o t he Dom ain
Model. Sure, different st akeholders will have different needs from t he Dom ain Model, different views
regarding t he det ail level, for exam ple, but it 's st ill one root st ruct urea st ruct ure t o live wit h, grow
wit h, change....
As you will find, I 'm going t o put a lot of energy int o discussing Dom ain Model- based solut ions in t his
book from now on, but before doing t hat , I 'd like t o t alk a bit about ot her archit ect ure values. Let 's
leave t he dom ain focus for a while and discuss som e m ore t echnically focused areas. First is how t o
deal wit h t he dat abase.
Even t hough hardware capabilit y is probably st ill growing in accordance wit h som et hing like Moore's
law, t he problem of perform ance is an everyday one. At t he sam e t im e as t he hardware capabilit ies
increase, t he size of t he problem s we t ry t o solve wit h soft ware also increases.
I n m y experience, perform ance problem s are m ore oft en t han not t he result of bad dat abase access
code, bad dat abase st ruct ure, or ot her such t hings. One com m on reason for all t his is t hat no effort
at all has been spent on t uning t he dat abase, only on obj ect - orient at ion purit y. This in it s t urn has
led t o an ext rem e num ber of roundt rips, inefficient and even incorrect t ransact ion code, bad indexing
schem es, and so on.
To m ake it a bit m ore concret e, let 's look at an exam ple where obj ect orient at ion has been t hought of
as im port ant while dat abase handling has not . Let 's assum e you have a Customer class wit h a list of
Orders. Each Order inst ance has a list of OrderLine inst ances. I t looks som et hing like Figure 1- 2 .
//A consumer
Customer c = new Customer();
c.GetById(id);
N ot e
I f you wonder about //A consumer in t he previous code snippet , t he idea is t o show t he
class nam e ( and som et im es m et hods) for code snippet s like t hat t o increase clarit y.
Som et im es t he specific class nam e ( as in t his case) isn't im port ant , and t hen I use a m ore
generic nam e inst ead.
C+ + kind of has t his concept built in because m et hod nam es are writ t en like
ClassName::MethodName, but I t hink som e sm all com m ent s should provide t he sam e effect .
Next t he customer's GetById() m et hod will fet ch a list of orders, but only t he keys will be fet ched by
calling GetIdsOfChildren() , which will execut e som et hing like t his:
Aft er t hat , t he Customer will inst ant iat e Order aft er Order by it erat ing over t he DataReader for Order
ident ifiers, delegat ing t he real work t o t he GetById() m et hod of t he Order like t his:
//Customer.GetById()
...
Order o;
while theReader.Read()
{
o = new Order();
o.GetById(theReader.GetInt32(0));
c.AddOrder(o);
}
Then for each Order it 's t im e t o fet ch t he ident ifiers of all t he OrderLines...well, you get t he pict ure.
What happened here was t hat t he obj ect perspect ive was used t o a cert ain ext ent ( at least t hat was
t he int ent ion of t he designer) inst ead of t hinking in set s, as is what relat ional dat abases are based
on. Because of t hat , t he num ber of roundt rips t o t he dat abase was ext rem ely high ( one for every row
t o fet ch plus a few m ore) . The efficiency plum m et ed t hrough t he floor.
N ot e
Wort h m ent ioning is t hat t he behavior j ust described m ight be exact ly what you need t o
avoid m assive loading of dat a in a specific scenario. I t 's hard t o point out som et hing t hat is
always bad. Rem em ber t he cont ext .
On t he ot her hand, if we t hink about t he ot her ext rem e, handwrit t en and hand opt im ized st ored
procedures, it could look like t his:
They are oft en efficient ( as I said) during runt im e. They are very inefficient during m aint enance.
They will give you lot s of code t o m aint ain by hand. What 's m ore, st ored procedures in Transact SQL
( T- SQL, t he SQL dialect used for Sybase SQL Server and Microsoft SQL Server) , for exam ple, don't
lend t hem selves well t o ordinary t echniques for avoiding code duplicat ion, so t here will be quit e a lot
of duplicat e code.
N ot e
I know, som e of m y readers will now say t hat t he previous exam ple could be solved very
efficient ly wit hout st ored procedures or t hat t hat st ored procedure wasn't t he m ost efficient
one in all circum st ances. I 'm j ust t rying t o point out t wo ext rem e exam ples from an
efficiency point of view. I m ean badly designed codeat least from an efficiency point of
viewt hat uses dynam ic SQL com pared t o bet t er design and well- writ t en st ored procedures.
So t he quest ion is if runt im e efficiency is t he m ost im port ant fact or for choosing how t o design?
Maintainability Focus
I f I only have t o choose one " abilit y" as t he m ost im port ant one, t hese days I would choose
m aint ainabilit y. Not t hat it 's t he only one you need, it absolut ely is not , but I t hink it 's oft en m ore
im port ant t han scalabilit y, for exam ple. Wit h good m aint ainabilit y, you can achieve t he ot her abilit ies
easily and cost - effect ively. Sure, t his is a huge sim plificat ion, but it m akes an im port ant point .
Anot her way t o see it is t o com pare t he t ot al cost of producing a new syst em wit h t he t ot al cost of
t he m aint enance of t he syst em during it s ent ire life cycle. I n m y experience, t he m aint enance cost
will be m uch great er for m ost successful syst em s.
To conclude t his, m y current belief is t hat it is wort h giving som e at t ent ion t o t he dat abase. You
should see it as your friend and not your enem y. At t he sam e t im e, however, hand writ ing all t he
code t hat deals wit h t he dat abase is m ost oft en not t he " right " approach. I t has lit t le or not hing t o do
wit h t he m odel t hat I want t o focus on. To use a com m on quot e by Donald Knut h, " Prem at ure
opt im izat ion is t he root of all evil." I t 's bet t er t o avoid opt im izat ions unt il you have m et rics saying
t hat you have t o do t hem .
To m ake a quick and long j um p here, I t hink t hat decent design, t oget her wit h Obj ect Relat ional
Mapping ( O/ R Mapping) , is oft en good enough, and when it isn't , you should hand t une. O/ R Mapping
is a bit like t he opt im izer of dat abase serversm ost of t he t im e it is sm art enough, but t here are
sit uat ions when you m ight need t o give it a hand.
N ot e
Decent design and O/ R Mapping will be discussed a lot t hroughout t he book. For now, let 's
define O/ R Mapping as a t echnique for bridging bet ween obj ect orient at ion and relat ional
dat abases. You describe t he relat ionship bet ween your obj ect - orient ed m odel and your
relat ional dat abase and t he O/ R Mapper does t he rest for you.
So one approach is t o use t ools such as O/ R Mappers for m ost of t he dat abase access code and t hen
hand writ e t he code t hat needs t o be handwrit t en for t he sake of execut ion efficiency.
Let 's t ake a closer look at t he problem som et hing like an O/ R Mapper will have t o deal wit h, nam ely
m apping bet ween t wo different worlds, t he obj ect - orient ed and t he relat ional.
I 'd like t o give m y t hought s on what t hat im pedance m ism at ch is, alt hough it is som et hing of a pop
version. For furt her and m ore form al inform at ion see Cat t el [ Cat t ell ODM] .
First of all, t here are t wo t ype syst em s if you use bot h a relat ional dat abase and an obj ect - orient ed
m odel. One part of t he problem is caused by t he fact t hat t he t ype syst em s are in different address
spaces ( even if not on different m achines) , so you have t o m ove dat a bet ween t hem .
Secondly, not even prim it ive t ypes are exact ly t he sam e. For exam ple a string in .NET is of variable
lengt h, but in Microsoft SQL Server a st ring is t ypically a varchar or a char or text. I f you use
varchar/char, you have t o decide on a m axim um widt h. I f you use text, t he program m odel is t ot ally
different t han for t he ot her st ring t ypes in SQL Server.
Anot her exam ple is DateTime . DateTime in .NET is pret t y sim ilar t o SQL Server, but t here are
differences. For inst ance, t he precision is down t o 100 nanoseconds for .NET, but " only" down t o
3/ 1000 of a second in SQL Server. Anot her " fun" difference is if you set a DateTime in .NET t o
DateTime.MinValue it will lead t o an except ion if you t ry t o st ore it in a SQL Server DateTime .
Yet anot her difference is t hat of nullabilit y. You can't st ore null in an ordinary int in .NET, but t hat 's
perfect ly valid in SQL Server.
N ot e
The problem s m ent ioned so far exist whet her you use a Dom ain Model or not .
A big difference is how relat ionships are dealt wit h. I n a relat ional dat abase, relat ionships are form ed
by duplicat ed values. The prim ary key of t he parent ( for exam ple, Customers.Id) is duplicat ed as a
foreign key in t he children ( for exam ple, Orders.CustomerId) , effect ively let t ing t he child rows " point "
t o t heir parent s. So everyt hing in a relat ional m odel is dat a, even t he relat ionships. I n an obj ect -
orient ed m odel, relat ionships can be set up in m any different ways ( for exam ple, via values sim ilar t o
t hose in t he relat ional, but t hat is not t ypical) . The m ost t ypical solut ion is t o use t he built - in obj ect
ident ifiers let t ing t he parent have references t o obj ect ident ifiers of it s children. This is, as you can
see, a com plet ely different m odel.
Navigat ion in a relat ional m odel can be done in t wo ways. First , one can use a parent prim ary key
and t hen use a query t o find all children t hat have foreign keys wit h t he sam e value as t he prim ary
key of t he parent . Then, for each child, t he child prim ary key can be used wit h a new query t o ask for
all t he children of t he child, and so on. The ot her and probably m ore t ypical way of navigat ing in t he
relat ional m odel is t o use relat ional j oins bet ween t he parent set and t he children set . I n an obj ect -
orient ed m odel, t he t ypical way of navigat ing is t o sim ply t raverse t he relat ionships bet ween
inst ances.
Next you find t wo code snippet s where I h av e an order wit h ordernum ber 42. Now I want t o see
what t he nam e of t he cust om er for t hat order is.
C# :
anOrder.Customer.Name
SQL:
SELECT Name
FROM Customers
WHERE Id IN
(SELECT CustomerId
FROM Orders
WHERE OrderNumber = 42)
N ot e
I could j ust as well have used a JOI N for t he SQL case, of course, but I t hink a subquery
was clearer here.
Anot her navigat ion- relat ed difference is t hat for obj ect s, t he navigat ion is oneway. I f you need
bidirect ional navigat ion it is act ually done wit h t wo separat e m echanism s. I n t he relat ional m odel, t he
navigat ion is always bidirect ional.
N ot e
The quest ion about direct ionalit y can be seen as t he opposit e also t o what I j ust explained,
because in t he relat ional dat abase, t here is j ust a " point er" in one direct ion. I st ill t hink t hat
" point er" is bidirect ional because you can use it for t raversal in bot h direct ions, and t hat 's
what I t hink is im port ant .
As we have already t ouched upon, t he relat ional m odel is set - based. Every operat ion deals wit h set s.
( A set can be j ust one row, of course, but it is st ill a set .) However, in t he obj ect - orient ed m odel, we
deal wit h one obj ect at a t im e inst ead.
Moreover, t he dat a in t he relat ional m odel is " global," while we st rive hard t o m aint ain privacy of t he
dat a in an obj ect - orient ed m odel.
When it com es t o design, t he granularit y is quit e different . Let 's t ake an exam ple t o m ake t his clear.
Assum e t hat we are int erest ed in keeping t rack of one hom e phone num ber and one work phone
num ber for cert ain people. I n a relat ional m odel it is norm ally alright t o have one t able called People
( plural is t he de fact o nam e st andardat least am ong dat abase peoplet o m ake it obvious we are
dealing wit h a set ) .
N ot e
I f I 'm picky, I should use t he word " relat ion" inst ead of " t able" when I 'm t alking about t he
r elat ional m odel.
The t able has t hree colum ns ( probably m ore, but so far we have only t alked about t he phone
num bers) represent ing one prim ary key and t wo phone num bers. Perhaps t here could be five
colum ns, because we m ight want t o break down t he phone num bers int o t wo colum ns each for area
code and local num ber, or seven if we add count ry code as well. See Figure 1- 4 for a com parison.
N ot e
The relat ional m odel has a pret t y st rong concept when it com es t o definit ion reuse, which is
called dom ain. Unfort unat ely, t he support for t hat concept st ill isn't very st rong in t oday's
pr oduct s.
I t 's also t he case t hat m any of t he product s have support for com plex dat at ypes, but it 's
st ill in it s infancy.
We j ust discussed one exam ple of granularit y where a relat ional m odel is m ore coarse- grained t han
an obj ect - orient ed m odel. We could also look at it t he ot her way around. For exam ple, in a relat ional
m odel an order m ight have m any orderLines, but t he orderLines are on t heir own, so t o speak. Each
orderLine is j ust a row; each order is ot her such rows. There is a relat ionship bet ween t hem , but t he
rows are t he unit s. I n an obj ect - orient ed m odel, it m ight be a good solut ion t o see t he order as t he
unit and let it be a com posit ion of orderLines. This t im e t he relat ional m odel was finer- grained t han
t he obj ect - orient ed m odel.
N ot e
I 'm not im plying t hat t here won't be an OrderLine class in t he Dom ain Model. There should
be. What I 'm saying is t hat what I ask for and work wit h as t he unit is an order, and
orderLines is part of t he order.
Last but not least , t he relat ional m odel doesn't support inherit ance ( again, at least it 's not
m ainst ream in t he m ost popular product s) . I nherit ance is at t he core of t he obj ect - orient ed m odel.
Sure, you can sim ulat e inherit ance in t he relat ional m odel, but t hat is all it is, a sim ulat ion. The
different sim ulat ion solut ions t o choose am ong are all com prom ises and carry overhead in st orage,
speed, and/ or relat ional ugliness.
N ot e
Deep and nat ive XML int egrat ion in t he dat abase seem s t o be t he newest way of t rying t o
lessen t he problem of im pedance m ism at ch. But XML is act ually also a t hird m odel, a
hierarchical one, which has im pedance m ism at ch wit h t he obj ect - orient ed world and t he
relat ional world.
Because it has been t ypical for m y applicat ions t o use relat ional dat abases, t he im pedance m ism at ch
has creat ed a big problem .
The Dat a Mapper pat t ern [ Fowler PoEAA] can be used for dealing wit h t he problem . The Dat a Mapper
pat t ern is about describing t he relat ionship bet ween t he Dom ain Model and t he Dat abase, and t hen
t he shuffling work is t aken care of aut om at ically. Unfort unat ely t he Dat a Mapper pat t ern it self is a
t ough one, especially in t he .NET plat form where Obj ect - Relat ional Mapper ( O/ R- m apper) product s
are a couple of years behind. I n Java- land t here are several m at ure product s and even a
st andardized spec called JDO [ Jordan/ Russell JDO] , which m akes t he t wo plat form s, as sim ilar as
t hey are, t ot ally different from each ot her in t his respect .
So it 's t im e t o leave t he area of Dom ain Models and dat abases and end t he archit ect ure sect ion by
t alking about dist ribut ion.
OK, now I have set up som e excuses before t elling you som e horror st ories from m y past . About t en
years ago, out cam e Microsoft Transact ion Server ( MTS) and suddenly it becam e pret t y easy for all
COM developers t o build dist ribut ed syst em s. What happened? Loads of dist ribut ed syst em s have
been built . I was t here wit h t he rest of t hem .
N ot e
I 'm going t o use MTS as t he nam e here, but you could j ust as well use COM+ or COM+
Com ponent Services or Ent erprise Services.
Fine, for som e syst em s it was very suit able t o be dist ribut ed. Moving som e processing out from t he
client and from t he dat abase t o an applicat ion server had it s benefit s, like resource sharing ( for
exam ple, connect ion pooling at t he server- side so t hat hundreds of client s could be served by j ust a
handful of dat abase connect ions) . These benefit s were very m uch needed for som e syst em s, and it
becam e easier and m ore product ive t o get t hose benefit s.
Unfort unat ely, t he benefit s were so appealing t hat t hings went a bit overboard from t im e t o t im e. For
exam ple, t he server- side work m ight be split at several different applicat ion servers. Not t hat t he
applicat ion servers were cloned so t hat all client s could use any of t hem and get all services needed,
but rat her t he client called one of t he applicat ion servers. That server called anot her applicat ion
server, which called anot her applicat ion server. There were sm all benefit s, but huge drawbacks
because of increased lat ency and lower availabilit y.
Anot her m ist ake was t hat sim ple applicat ions wit h j ust t wo sim ult aneous users were writ t en for and
execut ed in MTS. I t 's a very good exam ple of m aking a m ount ain out of a m olehill because of a belief
t hat t he applicat ion will probably be very popular in som e dist ant fut ure and be used by t housands of
users sim ult aneously. The problem wasn't j ust a m ore com plex operat ional environm ent , but t hat t he
design of t he applicat ion had lot s of im plicat ions if you want ed t o be a good MTS cit izen. A t ypical
exam ple of t his was t o avoid chat t y com m unicat ion bet ween cert ain ( or even worse, bet ween all)
layers. Those im plicat ions did increase t he com plexit y of t he design t o quit e an ext ent . Well, overuse
is never good.
Did you not ice t hat I avoided t alking about t he norm al pit falls t hat beginners of dist ribut ed syst em s
encount er when m aking t heir first at t em pt s wit h dist ribut ed syst em s, such at chat t y com m unicat ion?
Well, even if, against all odds, for som e reason t hose m ist akes were avoided, t here are ot her, slight ly
m ore subt le problem s.
All t hese problem s led Mart in Fowler t o com e up wit h his First Law of Dist ribut ed Obj ect Design,
which is " Don't dist ribut e" [ Fowler PoEAA] . I f you absolut ely don't have t o, don't do it . The cost and
com plexit y will j ust go sky high. I t 's a law of nat ure.
St ill, t here are good t hings about dist ribut ion t oo, bot h now and in t he fut ure, for exam ple:
Fa u lt t ole r a n ce
I f t here is j ust one single m achine t hat runs everyt hing, you have a problem if t hat m achine
st art s burning. For som e applicat ions t hat risk is OK; for ot hers it 's unt hinkably bad.
Se cu r it y
There is a heat ed debat e over whet her or not it increases securit y t o split t he applicat ion across
several m achines. Anyway, securit y concern is a com m on reason for why it is done.
Sca la bilit y
For som e applicat ions, t he load is j ust t oo high for a single m achine t o cope wit h it . I t m ight
also be t hat , financially, you don't want t o buy t he m ost expensive m achine around on day one.
You m ay inst ead want t o add m ore m achines t o t he problem when t he problem increases,
wit hout t hrowing away t he old m achines.
I f you do need a dist ribut ed syst em , it 's ext rem ely im port ant t o t hink long and hard about t he
design, because t hen you have one big design challenge t hat can easily creat e big t hroughput
problem s, for exam ple. When t alking about dist ribut ion, m essaging is an im port ant concept .
Messaging Focus
The focus of t his book is design of one applicat ion or one service, not so m uch about how t o
orchest rat e several services. Even so, I t hink it 's good t o at least st art t hinking about m essaging ( if
you haven't already) . I guess t his will j ust becom e m ore and m ore im port ant for us in t he fut ure.
I used t o t hink it was good t o abst ract away or hide t he net work in dist ribut ed syst em s. I n t his way,
t he client program m er didn't know if a m et hod call was going t o t ranslat e t o a net work j um p or if it
was j ust a local funct ion call. I liked t hat approach because I want ed t o sim plify t he life of t he client
program m er so he or she could focus on st uff t hat 's im port ant t o creat e great user int erfaces and not
get dist ract ed wit h t hings such as net work com m unicat ion.
Let 's t ake a look at a sim ple exam ple. Assum e you have a Customer class, as shown in Figure 1- 5 .
I nst ances of t hat Customer class would t ypically ( and hopefully) live t heir life in t he sam e address
space as t he consum er code, so t hat when t he consum er asks for t he nam e of t he Customer , it 's j ust
a local call.
There is not hing, however, t o physically st op you from let t ing Customer j ust be a Proxy [ GoF Design
Pat t erns] , which in it s t urn will relay t he calls t o a Customer inst ance living at an applicat ion server.
( OK, it 's a bit sim plified, but t hat 's m ore or less what is going on behind t he scenes if you configure
t he Customer class in MTS at an applicat ion server, for exam ple.)
Szyperski point s out [ Szyperski Com ponent Soft ware] t hat locat ion t ransparency is bot h an
advant age and a burden. The advant age is t hat all t ypes of com m unicat ion ( in process, int erprocess,
and int erm achine) are m apped t o one abst ract ion, t he procedure call. The burden is t hat it hides t he
significant cost difference bet ween t he different t ypes of calls. The difference is norm ally orders of
m agnit ude in execut ion t im e.
I t hink t he current t rend is t he opposit e of locat ion t ransparency and t o m ake t he cost ly m essages
obvious by m aking m essages a core t hing in t he program m ing m odel. Trend- conscious as I am , I do
like t hat evolut ion. I like it j ust because it 's obvious t o t he client program m er t hat t here is going t o
be a net work callit doesn't really m ean t hat it m ust be hard t o m ake. For exam ple, m essage fact ories
could be provided, yet it st ill m akes it m uch clearer what will probably t ake t im e and what will not .
You m ight wonder how will m essaging affect a dom ain m odel? The need for a dom ain m odel won't go
away, but t here will probably be slight changes. The first exam ple t hat com es t o m ind is t hat insert s,
as in a j ournal, are favored over updat es ( even for m odificat ions) . That m akes asynchronous
com m unicat ion m uch m ore usable.
One very im port ant advant age of m essaging is t hat it increases t he execut ion flexibilit y so m uch. I n
t he past , I t hink I 've been pret t y good at using bat ch j obs for long execut ions t hat didn't have t o
execut e in real t im e. I t 's an old, and in m y opinion underused, m et hod for vast ly increasing response
t im e for t he real t im e part of t he work, because t hen t he long execut ions would execut e in windows
of low load, t ypically at night , for exam ple.
A m ore efficient solut ion t o t he problem would be t o t hink asynchronous m essages from t he st art as
oft en as possible. Then t he funct ionalit y could run in real t im e if it 's appropriat e or be put on a
m essage queue t o be execut ed as soon as possible or at given int ervals. ( The bat ch solut ion would
be kind of built in from t he beginning.)
A solut ion based on asynchronous m essages m ight require quit e a different m indset when you build
your user int erface, but if you really challenge t he different design problem s, I t hink you will find t hat
asynchronicit y is possible and a suit able way t o go m ore oft en t han you m ay have t hought in t he
past .
A few words t o end t his discussion: I n m y opinion it 's a good idea t o focus on t he core m odel it self,
no m at t er what t he execut ion environm ent is. Then you can probably use it in several different
sit uat ions, as t he need arises.
Those were a few words about archit ect ure values t o value. Let 's m ove over t o t he process side.
Process Ingredients to Value
I 'm not m uch of a process guy, but I st ill would like t o add a couple of t hought s. Before I get st art ed,
what do I m ean by " process" ? I t 's t he m et hodology for m oving forward in proj ect s: What should be
done, when, and how?
The classic process was t he so- called wat erfall. Each phase followed aft er t he ot her in a st rict ly linear
fashion wit h no going back what soever. A condensed descript ion could be t hat first a specificat ion
was writ t en, and t hen t he syst em was built from t hat specificat ion, t hen t est ed, t hen deployed.
Since t hen, num erous different processes have been int roduced over t he years, all wit h m erit s and
pit falls of t heir own. A recent one, Ext rem e Program m ing ( XP) [ Beck XP] , gat hered as one process
under t he um brella of Agile [ Cockburn Agile] processes, could probably be described as t he opposit e
of wat erfall. One of t he basic ideas of XP is t hat it 's im possible t o know enough t o writ e a really good,
det ailed specificat ion on day one. Knowledge evolves during t he proj ect , not j ust because t im e
passes, but because part s of t he syst em are built , which is a very efficient way of gaining insight .
N ot e
There's m uch m ore t o XP t han what I j ust said. See, for exam ple, [ Beck XP] for m ore
inform at ion. I will discuss TDD and Refact oring, which have t heir root s in XP.
Also not e t hat XP doesn't always st art from scrat ch. I n t he XP forum s t here is also a lot of
int erest for XP and legacy syst em s. See, for exam ple, Obj ect - Orient ed Reengineering
Pat t erns [ Dem eyer/ Ducasse/ Nierst rasz OORP] .
I t ry t o find a good com binat ion of sm aller ingredient s for t he sit uat ion. I have a couple of different
current favorit e ingredient s. I 'd like t o discuss Dom ain- Driven Design, Test - Driven Developm ent , and
Refact oring, but let 's st art wit h Up- Front Archit ect ure Design.
Anot her t hing t hat was considered new wit h XP was it s focus on user- cent ric
developm ent . Users should be involved in t he proj ect s t hroughout t he com plet e
developm ent .
For a Swedish guy, t hat wasn't very revolut ionary. I don't know why, but we have a
fairly long hist ory of user- cent ric developm ent in Sweden, long before XP.
Wit hout m eaning t o sound as if Sweden is bet t er t han any ot her count ry, we have a long
hist ory of also using t he wat erfall processes.
Up-Front Architecture Design
Even t hough I like m any of t he Agile ideas about not m aking up front and prem at ure decisions about
t hings t hat couldn't possibly be known at t hat st age, I don't t hink t hat we should st art t he
const ruct ion of new proj ect s wit h only a blank sheet of paper, eit her. Most oft en, we have a fair
am ount of inform at ion from t he very beginning ( t he m ore t he bet t er) about product ion environm ent ,
expect ed load, expect ed com plexit y, and so on. At least keep t hat in t he back of your m ind and use
t he inform at ion for doing som e init ial/ early proof of concept of your up- front archit ect ure.
We can't afford t o st art from scrat ch wit h every new applicat ion, and t his is especially t rue when it
com es t o t he archit ect ure. I usually t hink about m y current favorit e default archit ect ure and see how
it fit s wit h t he sit uat ion and requirem ent s of t he new applicat ion t hat is t o be built . I also evaluat e
t he last few applicat ions t o t hink of how t hey could have been im proved from an archit ect ure
perspect ive, again wit h t he cont ext of t he new applicat ion in m ind. Always evaluat ing and t rying t o
im prove is definit ely som et hing t o value.
I f I assum e for t he m om ent t hat you like t he idea of t he Dom ain Model pat t ern [ Fowler PoEAA] , t he
archit ect ure decisions could act ually be a bit less hard t o m ake init ially because a great deal of t he
focus will go j ust t here, on t he Dom ain Model. Deciding whet her or not t o use t he Dom ain Model
pat t ern is act ually an up- front archit ect ure design decision, and a very im port ant one because it will
affect a lot of your upcom ing work.
I t is also im port ant t o point out t hat even t hough you do m ake an up front decision, it 's not writ t en in
st one, not even your decision about whet her or not t o ut ilize t he Dom ain Model pat t ern.
N ot e
I recent ly heard t hat t he recom m endat ion from som e gurus was t o im plem ent t he
Transact ion Script pat t ern [ Fowler PoEAA] wit h t he Recordset pat t ern [ Fowler PoEAA] for as
long as possible and m ove t o anot her solut ion when it proved t o be a necessit y. I disagree.
Sure, t here are worse t hings t hat could happen, but t hat t ransit ion is not som et hing I 'd like
t o do lat e in t he proj ect because it will affect so m uch.
Consistency
An im port ant reason for why it 's good t o m ake early archit ect ure decisions is so t hat your t eam of
several developers will work in t he sam e direct ion. Som e guidelines are needed for t he sake of
consist ency.
The sam e is also t rue for I S depart m ent s t hat build m any applicat ions for t he com pany. I t 's very
beneficial if t he archit ect ures of t he applicat ions are som ewhat sim ilar as it m akes it m uch easier and
m ore efficient t o m ove people bet ween proj ect s.
Software Factories
This brings us nicely t o t alking a lit t le bit about Soft ware Fact ories [ Greenfield/ Short SF] ( wit h
inspirat ion from Product Line Archit ect ure [ Bosch Product Line] ) . The idea of Soft ware Fact ories is t o
have t wo lines in t he soft ware com pany. One line creat es archit ect ures, fram eworks, and such t o be
used for fam ilies of applicat ions. The ot her line creat es t he applicat ions by using what t he first line
has produced, and t hereby am ort izing t he cost of t he fram eworks on several proj ect s.
N ot e
A problem is t hat it 's t roublesom e t o j ust invent a fram ework. I t 's probably a bet t er idea t o
harvest inst ead [ Fowler Harvest edFram ework] .
Anot her t hing t hat is som ewhat problem at ic wit h Soft ware Fact ories, t hough, is t hat t hey probably
require pret t y large organizat ions before being efficient t o use. A friend t hat has used Product Line
Archit ect ures said t hat t he organizat ion needs t o have a head count of t housands rat her t han fift y or
a hundred because of t he large invest m ent s and overhead cost s. He also said ( and I 've heard t he
sam e from ot hers) t hat even in organizat ions t hat have st art ed t o use Product Line Archit ect ures, it 's
not necessarily and aut om at ically used all t he t im e. The overhead and bureaucracy it brings wit h it
should not be underest im at ed. Think about a t iny fram ework t hat you use in several applicat ions and
t hen t hink m uch bigger and you get a feeling for it .
That said, I definit ely t hink t he Soft ware Fact ories init iat ive is int erest ing.
At t he heart of Soft ware Fact ories is t hat of Dom ain Specific Languages ( DSL) [ Fowler LW] . A pop-
descript ion could be t hat DSL is about dealing wit h sub- problem s wit h languages specialized for t he
t ask at hand. The languages t hem selves can be graphical or t ext ual. They can also be generic, as
wit h XML, UML and C# , or specific, like t he WinForm s edit or in VS.NET or a lit t le language you define
on your own for a cert ain t ask.
Anot her approach, but wit h m any sim ilarit ies t o DSL, is Model- Driven Archit ect ure.
Model-Driven Architecture
Model- Driven Archit ect ure ( MDA) [ OMG MDA] is som et hing like " program m ing by drawing diagram s
in UML." One com m on idea from t he MDA arena is t o creat e a Plat form I ndependent Model ( PI M) t hat
can t hen be t ransform ed int o a Plat form Specific Model ( PSM) , and from t here t ransform ed int o
execut able form .
Thinking about it , it feels like writ ing 100% of a new program wit h a 3GL, such as C# , is overkill. I t
should be t im e t o increase t he abst ract ion level.
I t hink one problem m any are seeing wit h MDA is it s t ight coupling t o UML. One part of t he problem
is t he loss of precision when going bet ween code and UML; anot her part of t he problem is t hat UML is
a generic language wit h t he pros and cons t hat com es wit h t hat .
For t he m om ent , let 's sum m arize t hose approaches ( bot h DSL and MDA) wit h t he t erm Model- Driven
Developm ent . I feel confident t o say t hat we are m oving in t hat direct ion, so Model- Driven
Developm ent will probably be a big t hing. Even t oday, you can go a pret t y long way wit h t he current
t ools for Model- Driven Developm ent .
Furt her on, I also t hink bot h approaches of DSL and MDA fit very well wit h Dom ain- Driven Design,
especially t he m indset of focusing on t he m odel.
Domain-Driven Design
We have already discussed m odel focus and Dom ain- Driven Design ( DDD) in t he archit ect ure sect ion,
but I 'd like t o add a few words about DDD in t he process perspect ive also. Using DDD [ Evans DDD]
as t he process will focus m ost of t he energy on building a good m odel and im plem ent ing it as closely
as possible in soft ware.
What it 's all about is creat ing as sim ple a m odel as possible, one t hat st ill capt ures what 's im port ant
for t he dom ain of t he applicat ion. During developm ent , t he process could really be described as
knowledge- crunching by t he developers and dom ain expert s t oget her. The knowledge t hat is gained
is put int o t he m odel.
Of course, not all knowledge has t o be gained from scrat ch. Depending upon t he dom ain, t here could
well be loads of knowledge available in books, and not j ust in specific books for t he dom ain in
quest ion. There is act ually inform at ion in a couple of soft ware books, t oo. Unt il recent ly, I would only
consider t he books called Dat a Model Pat t erns [ Hay Dat a Model Pat t erns] and Analysis Pat t erns
[ Fowler Analysis Pat t erns] , but I would st rongly suggest t hat you get your hands on a book about
Archet ype Pat t erns as well. The book is called Ent erprise Pat t erns and MDA [ Arlow/ Neust adt
Archet ype Pat t erns] .
A value I definit ely t hink should be valued is cont inuous evaluat ion, and t hat goes for DDD, as well.
I s t he current m odel t he best one? Every now and t hen, quest ion t he current m odel const ruct ively,
and if you com e up wit h im port ant sim plificat ions, don't be afraid t o refact or.
The sam e also applies when you find som et hing new. A couple of sim ple refact orings m ight m ake
t hat new feat ure not only possible but also easy t o achieve so it fit s well wit hin t he m odel.
Refact orings alone m ight also lead t o deeper knowledge, like when you do a refact oring t hat can
open everyt hing up and lead t o one of t hose rare " eureka! " m om ent s.
We will com e back t o refact oring short ly, but first I 'd like t o t alk about som et hing closely relat ed,
nam ely Test - Driven Developm ent .
Test-Driven Development
I 've oft en heard developers say t hat t hey can't use aut om at ic unit t est ing because t hey don't have
any good t ools. Well, t he m indset is m uch m ore im port ant t han t he t ools, alt hough t ools do help, of
course.
I wrot e m y own t ool ( see Figure 1- 6 ) a couple of years ago and used it for regist ering and execut ing
t est s of st ored procedures, COM com ponent s, and .NET classes. Thanks t o t his t ool, I could skip
t hose form s wit h 97 but t ons t hat have t o be pressed in a cert ain order in order t o execut e t he t est s.
Figu r e 1 - 6 . Scr e e n sh ot of m y old t e st t ool ca lle d Jn sk Te st
Lat er on, when NUnit [ NUnit ] ( a derivat e from t he ot her xUnit versions) was released ( see Figure 1-
7) , I st art ed using t hat t ool inst ead. Using NUnit is way m ore product ive. For exam ple, m y t ool didn't
reflect on what t he exist ing t est s were. I nst ead you had t o explicit ly regist er inform at ion about t hem .
N ot e
Now I use anot her t ool, called Test driven.Net , but as I said, what t ool you use is of less
im port ance.
No m at t er what process you use, you can use aut om at ic unit t est s. For an even larger posit ive effect ,
I st rongly recom m end you find out if Test - Driven Developm ent ( TDD) is for you.
The Next Level
TDD is about writ ing t est s before writ ing t he real code. I n doing t his, t he t est s will drive your design
and program m ing.
TDD sounds dull and boring, and developers oft en expect it t o be a pain in t he backside. They
couldn't be m ore wrong! I n m y experience, t he opposit e is t rueit 's act ually great fun, which cam e as
a surprise t o m e. I guess t he reason t hat it is such fun is t hat you get inst ant feedback on your
changes, and because we are professionals, we enj oy creat ing high- qualit y applicat ions.
Anot her way t o put it is t hat TDD isn't about t est ing. I t 's about program m ing and design. I t 's about
writ ing sim pler, clearer, and m ore robust code! ( Sure, t he " side- effect " of creat ed unit t est s is
ext rem ely im port ant ! )
Why TDD?
The reason I st art ed wit h TDD in t he first place was t hat I want ed t o im prove t he qualit y of m y
proj ect s. I m provem ent in qualit y is probably t he m ost obvious and im port ant effect . We don't want
t o creat e applicat ions t hat crash when t he cust om er uses t hem for t he first t im e or applicat ions t hat
break down when we need t o enhance t hem . I t 's j ust not accept able anym ore.
TDD won't aut om at ically help you never release product s wit h bugs again, but t he qualit y will
im prove.
N ot e
The aut om at ic t est s t hem selves aren't t he prim ary reason for TDD; t hey are nice side
effect s. I f qualit y is everyt hing, t here are ot her form al m et hods, but for m any scenarios
t hey are considered t oo " expensive." Again, cont ext is im port ant .
You can see t he effect of im proved qualit y by writ ing t est s aft er t he real code. What I m ean is t hat
you don't have t o apply TDD ( which m eans writ ing t est s before t he real code) , you j ust need a lot of
discipline. On t he ot her hand, using TDD get s t he t est s writ t en. Ot herwise, t here is a very great risk
t hat you won't writ e any t est s when you're pressed for t im e, which always happens when it get s t o a
lat e st age in t he proj ect s. Again, TDD m akes t he t est s happen.
The second effect you can expect when applying TDD is t o see im proved sim plicit y of design. I n t he
words of t wo popular sayings, " Sim ple is beaut iful" and " KI SS." They are very im port ant because, for
exam ple, com plexit y produces bugs.
I nst ead of creat ing loads of advanced blueprint s covering every lit t le det ail upfront , when using TDD
you will focus on t he core cust om er requirem ent s and j ust add t he st uff t he cust om er needs. You get
m ore of a cust om er perspect ive t han a t echnical perspect ive.
TDD is not about skipping design. On t he cont rary, you are doing design t he whole t im e when using
TDD.
I n t he past I 've been very good at overcom plicat ing sim ple t hings. TDD helps m e keep focused and
not do anyt hing ot her t han what is really necessary now . This effect ( get t ing im proved sim plicit y of
design) requires TDD. I t 's not enough t o j ust writ e t he t est s aft erwards.
Yet anot her effect of TDD is t hat you will get high product ivit y all t he way. This m ight sound
count erint uit ive at first . When you st art a new proj ect , it feels very product ive t o get going and writ e
t he real code. At first you are very product ive, but it 's very com m on t hat t he product ivit y com plet ely
drops near t he end of t he proj ect . Bugs st art cropping up; t he cust om er decides on a couple of pret t y
subst ant ial changes t hat upset everyt hing; you find out t hat you have m isunderst ood som e
t hings...well, you get t he pict ure.
Test s will force you t o challenge t he requirem ent s and t o challenge t hem early. Thereby, you will find
out early if you have underst ood. You will also reveal lacking and cont radict ory requirem ent sagain,
early.
By t he way, you shouldn't ask t he cust om er if you should use TDD or not , at least not if you're asking
for m ore paym ent / t im e/ what ever at t he sam e t im e. He will j ust t ell you t o do it right inst ead. When
considering t he proj ect from st art t o finish, if using TDD incurs no ext ra cost , I believe you should
j ust go ahead. The cust om er will be happy aft erward when he get s t he qualit y he expect s.
N ot e
Let 's for a m om ent skip TDD and focus only on aut om at ic t est s.
A colleague of m ine has been ext rem ely skept ical of t he need for aut om at ic unit t est s
( creat ed before or aft er real code) . He t old m e t hat during his t wo- decade career,
aut om at ic unit t est s would not have helped him once. However, I t hink he changed his
m ind a bit recent ly. We were working t oget her on a proj ect where he wrot e a COM
com ponent in C+ + and I wrot e t est s as specificat ions and as j ust t est s. When we were
done, t he cust om er changed one t hing in t he requirem ent s. My colleague m ade a sm all
change, but t he t est s caught a bug t hat occurred j ust four t im es in 1,000 execut ions. The
bug was found aft er only seconds of t est ing, com pared t o hours if it had been done
m anually. And if it had been done m anually, t he bug would m ost probably not have been
found at all, but would have shown it self during product ion.
Now I have t ried t o get you m ot ivat ed t o st art wit h TDD, so let 's have a closer look at how t he
process flows. ( We'll get back t o t his in Chapt er 3 when we will invest igat e it in a bit m ore dept h wit h
a real world dem o.) Assum ing you have a decent idea about t he requirem ent s, t he flow goes like
t his:
First of all, you st art writ ing a t est . You m ake t he t est fail m eaningfully so t hat you can be sure t hat
t he t est is t est ing what you t hink. This is a sim ple and im port ant rule, but even so, I have skipped
over it several t im es and t hat is j ust asking for t rouble.
The second st ep is t o writ e t he sim plest possible code t hat m akes t he t est pass.
The t hird st ep is t o refact or if necessary, because you ident ify code t hat sm ells ( for exam ple, code
duplicat ion) , and t hen you st art all over again, adding anot her t est .
I f we use NUnit lingo, t he first st ep should give you a red light / bar, and t he second st ep should give
you a green light / bar.
I m ent ioned refact oring previously and as t he t hird st ep in t he general process of TDD, and I t hink I
should briefly explain t he t erm a bit m ore.
Refactoring
Cont inuous learning was som et hing we heard about in school all t he t im e. I t 's very m uch t rue in t he
case of refact oring [ Fowler R] refact oring t o get a bet t er m odel, for exam ple.
Refact oring is about m aking sm all, well- known changes st ep by st ep in order t o im prove t he design
of exist ing code. That is, t o im prove it s m aint ainabilit y wit hout changing it s observed behavior.
Anot her way t o say it is t o change how , not what .
I n a nut shell, what refact oring does is t o t ake you from sm elly code t o nice code. I t 's as sim ple as
t hat .
So you don't have t o com e up wit h a perfect design up- front . That is good news, because it can't be
done anyway.
None of us have any t rouble in recognizing sm elly code. What m ight be m ore t roublesom e is t o know
when t o fix it . As I see it , you should deal wit h t he problem as soon as it arises. You should use
refact oring because wit hout cont inuous m aint enance of your code, it will st art t o degenerat e and
cr um ble.
N ot e
Mark Burhop said t he following: " A good friend keeps a list of Soft ware Developm ent Laws.
One goes som et hing like " Code, left unt ouched, will develop bugs."
Let 's use t he analogy of your hom e. Problem s you choose t o ignore, such as fixing windows, repairing
t he roof, paint ing t he woodwork, and so on, ignored problem s like t hese will grow in t im e. That 's an
im m ut able law. So sooner or lat er your house will fall t o bit s, and at t hat point it 's wort hless. Nobody
want s t hat sit uat ion, right ?
Soft ware is different because it 's not built of organic m at erial and won't becom e affect ed from
weat her and wind if not changed. St ill, we int uit ively have a feeling for what 's happening over t im e
wit h soft ware when refact oring isn't applied during bug fixes and when t he soft ware is ext ended.
Refact oring can be used in all phases of t he applicat ion lifecycle; for inst ance, during developm ent of
t he first version of an applicat ion. But j ust assum e we don't use refact oring, but an up- front ,
t radit ional design heavy process inst ead ( now oft en referred t o as Big Design Up- Front , BDUF) . We
will spend quit e a lot of t im e on init ial det ailed design, creat ing loads of det ailed UML diagram s, but
as a result we will expect t he developm ent t o go very sm oot hly and quickly. Even assum ing t hat it
does, t here is st ill a risk t hat t he code will be, well, sm elly.
I nst ead, let 's say we j ust accept t he fact t hat we can't get it right up front t he first t im e. I n t his case,
a slight ly different approach is t o m ove som e of t he effort from init ial det ailed design over t o
developm ent inst ead ( and of course all developm ent , especially in t his case, is design) and t o be
prepared for doing refact oring cont inuously when we learn m ore. Learning m ore is exact ly what we
do during developm ent , and as I see it , t his approach result s in higher qualit y code.
N ot e
I was probably overly posit ive t o BDUF so as t o not dist ract you from t he point t hat I was
aft er regarding sm elly code. Doing a lot of guesswork on day one will oft en lead t o wast ed
t im e because it is j ust guesswork.
My friend Jim m y Ekbäck com m ent ed on t his by saying, " BDUF can be even worse t han
wast ed t im e because of incorrect guesses. BDUF can also lead t o self- fulfilled prophesies."
I n order t o be able t o use refact oring in a safe way, you m ust carry out ext ensive t est s. I f you don't ,
you will int roduce bugs and/ or you will priorit ize, not m aking any changes sim ply for t he sake of
m aint ainabilit y, because t he risk of int roducing bugs is j ust t oo large. And when you st op m aking
changes because of m aint ainabilit y, your code has slowly st art ed t o degrade.
N ot e
You will find m uch m ore coverage, wit h focus on hands- on exam ples, about bot h TDD and
Refact oring in Chapt er 3.
I t 's a good idea t o use TDD and refact oring for bugfixing also. First expose t he bug wit h a red t est ,
t hen solve t he bug so you get green, and t hen refact or.
As I see it , you can m ix up- front design and TDD successfully. For exam ple, set up som e up- front
archit ect ure, work wit h Dom ain- Driven Design, and for each piece of behavior build it wit h TDD
( including refact oring) . Then go back t o your archit ect ure and change it in accordance wit h what you
have learned. Then work wit h Dom ain- Driven Design, and cont inue like t hat .
N ot e
I have t o adm it t hat I oft en fall back int o t he old habit of doing det ailed up- front design.
However, t hinking about t he problem in different ways is oft en t he m ost efficient t hing t o
do. A lit t le bit t op- down, a lit t le bit bot t om - up. A lit t le bit inside out , a lit t le bit out side in.
I t hink it 's pret t y well known t hat a Big Design Up- Front ( BDUF) has som e big problem s. At t he sam e
t im e, m ost oft en we know som e t hings from day one. I t 's a m at t er of balance.
Finally, a last rem ark regarding DDD and TDD: Dom ain Models are very suit able for TDD. Sure, you
can also apply TDD wit h m ore dat abase- orient ed design, but I haven't been able t o apply it as
gracefully and product ively as when I 'm working wit h Dom ain Models.
N ot e
When I discussed TDD and/ or DDD wit h Eric Evans he said t he following, which I t hink is
spot on:
" Myself, I act ually play wit h t he m odel while writ ing t he t est s. Writ ing t he t est let s m e see
what sort of client code different assignm ent s of responsibilit y would produce, as well as
t he fine- t uning of m et hod nam es and so on t o com m unicat e int ent ion and have a good
flow."
No m at t er if you focus on TDD or BDUF, t here are lot s of t echniques t hat are useful anyway. The
chapt er will end wit h focusing on a couple of such t hings, such as operat ional aspect s, but t he first
exam ple is called Cont inuous I nt egrat ion.
Continuous Integration
I 'm sure you all recognize how big a showst opper m anual int egrat ion on a m ont hly basis, for
exam ple, can beeven if your t eam j ust consist s of t wo developers on a proj ect . The problem
increases exponent ially when you add m ore developers. Am ong ot her t hings, it cost s lot s of t im e, it
is error prone, and you will find t hat it won't happen as planned. " Just one m ore day" will be a
com m on sent ence used in t he proj ect . My friend Claudio Perrone is j ust t he right guy t o describe t he
popular solut ion t o t his, known as cont inuous int egrat ion.
By Claudio Perrone
Sooner or lat er, all t he com ponent s t hat have been creat ed and m odified by different developers
need t o be built and assem bled t oget her t o form a single syst em .
I n t he past , I 've wit nessed ( and, yes, occasionally caused) spect acular delays in proj ect s originat ed
by last - m inut e int egrat ion effort s where unexpect ed defect s were discovered in t he final phases of a
developm ent cycle.
A build m ay fail for a variet y of reasons, oft en in com binat ion, such as
Wrong ( but oft en plausible) assum pt ions about except ion handling, null values, param et ers,
global variables, and so on
Weak design
Not e t hat , despit e all t he best effort s, only som e of t hese problem s can be lim it ed by t he discipline
and com m unicat ion capabilit ies of t he developers involved. The realit y is t hat if t he t eam does not
int egrat e oft en and if t he num ber of new classes in t he syst em is sufficient ly large, you m ay find
yourself anxiously hunt ing com bined bugs foreveran unpleasant scenario com m only known as
" I nt egrat ion Hell."
The fundam ent al part s t hat const it ut e a cont inuous int egrat ion syst em are as follows:
A source cont rol syst em t hat act s as a cent ral reposit ory for all source code
A m onit oring service t hat checks t he source cont rol syst em for changes t o t he source code
A script ing engine t hat , when t riggered by t he previous service, is able t o creat e builds
A report ing syst em t hat can give im m ediat e feedback about t he result s of a build
There are several int egrat ion product s available t hat you m ay want t o invest igat e. Current ly, m y
favorit e is CruiseCont rol.NET [ CC.NET] , which I use in com binat ion wit h NAnt , a very popular XML-
based build engine. Bot h t ools are open source. I t t akes quit e an effort t o configure
CruiseCont rol.NET but , once up and running, it t akes care of calling NAnt script s whenever t here is a
change in t he codebase. I t not ifies you of t he progress and st at us of all current builds using a wide
variet y of client m odules, including a lit t le applicat ion t hat uses a Windows t ray icon t o show
sum m ary inform at ion at a glance t hrough color coding and not ificat ion balloons.
Today we have about 500 cont inuously int egrat ed solut ions, and t he num ber is st ill increasing. A
t hird of t hese solut ions share a cust om - built com m on fram ework, which is also int egrat ed.
I nt egrat ion st eps for all t hese solut ions include com pilat ion, obfuscat ion, packaging, t est ing, and
deploym ent using different configurat ions and plat form s.
Before we st art ed t his proj ect , we were t old t hat it would be im possible t o int egrat e all of t hese
solut ions cont inuously. However, I 'm convinced t hat it would have been im possible t o do ot herwise
and t hat t his effort const it ut es a crit ical fact or in our success.
Further Information
A good st art ing point for learning m ore about cont inuous int egrat ion is a paper writ t en by Mart in
Fowler and Mat t hew Foem m el called " Cont inuous I nt egrat ion" [ Fowler/ Foem m el CI ] .
Thanks, Claudio! Now let 's m ove on t o som e operat ional aspect s.
Don't Forget About Operations
Not t oo long ago, I was t alking t o a t eam at a large Swedish com pany. I t alked, for exam ple, about
t he Valhalla fram ework and how it looked at t hat part icular point in t im e.
They asked m e how we had dealt wit h operat ional m echanism s, such as logging, configurat ion,
securit y, and so on. When I t old t hem t hat we hadn't added t hat yet , t hey first went quiet and t hen
t hey st art ed laughing out loud. They said t hey had spent years in t heir own fram ework wit h t hose
aspect s, and we hadn't even st art ed t hinking about it .
Luckily, I could defend m yself t o som e ext ent . We had been t hinking quit e a lot about it , but we
want ed t o set t he core part s of t he fram ework before adding t he operat ional m echanism s. Aft er all,
t he core part s influence how t he m echanism should look. I could also direct t hem t o m y last book
[ Nilsson NED] where I t alked a lot in t he init ial chapt ers about m echanism s like t hose ( such as
t racing, logging, and configurat ion) .
No Tracing in Place
You could always add t racing at t hat part icular point in t im e, but it would probably t ake you a couple
of days at least . I f t he problem is serious, t he cust om er will expect you t o find and solve t he problem
in less t im e t han a couple of days.
A com m onand m ost oft en pret t y inefficient way t o approach t his is t o m ake ad- hoc changes and aft er
each change cross your fingers and hope t hat t he problem is gone.
What you probably do inst ead is add ad- hoc t racing here and t here. I t will m ake your code m uch
uglier, and it will t ake som e t im e before you t rack down t he problem . The next t im e t here is anot her
problem , very lit t le has changed. You will be back at square one.
What m ight also be possible is t o run a debugger in t he product ion environm ent . However, t here are
problem s wit h t his such as you m ight int erfere t oo m uch wit h ot her syst em s or you m ight have
obfuscat ed t he code wit h som e t ool so t hat it 's hard t o debug.
I t 's also risky t o change t he code in product ion, even if t he change is as sm all as adding t racing. Not
a big risk, but it 's t here.
N ot e
I f you have t he possibilit y of using Aspect - Orient ed Program m ing ( AOP) , it m ight not t ake
m ore t han a few m inut es t o add t racing aft erward. We will discuss AOP quit e a lot in
Chapt er 10, " Design Techniques t o Em brace."
Tracing in Place
I f you have a working t racing solut ion in place, you know how efficient it m ight be t o find and solve
t he problem inst ead. The days- long delay is gone, and you are on t he way t o t racking down t he
problem in m inut es.
So it 's im port ant t o be careful and not t hink " You Aren't Going t o Need I t " ( YAGNI ) t oo oft en when it
com es t o operat ional m echanism s. Using YAGNI oft en will cost t oo m uch when it com es t o adding t he
m echanism if ( or rat her when) you will need it . Rem em ber, t he idea wit h YAGNI is t hat t he cost of
adding som et hing is pret t y m uch t he sam e now and lat er, in which case you can always wait unt il
you really need it . When t he cost is low now and high lat er, and t here's a good chance you will need
it , you should m ake a different decision.
Tr a cin g
As we j ust discussed, it 's nice t o be able t o list en t o what is going on at t he sam e t im e as users
run scenarios in t he syst em . This is not only a very efficient solut ion for t racking down bugs, but
it can be used for invest igat ing where t he bot t lenecks are locat ed, for exam ple.
Loggin g
Errors, warnings, and inform at ion m essages m ust be logged. This is ext rem ely im port ant for
invest igat ing problem s aft er t hey have occurred. We can't expect t he users t o writ e down t he
exact m essages for us. I t m ight also be t hat we want t o collect inform at ion t hat we don't want
t o show t o t he users.
Con fig
Have you had t o recom pile old applicat ions j ust because t he dat abase server was swit ched t o a
new m achine wit h a new nam e? I have. Of course, t hat kind of inform at ion should be
configurable and depending on t he applicat ion, t his m ight be t he case for loads of inform at ion.
Pe r for m a n ce m on it or in g
Get t ing perform ance m onit oring based on Dom ain Model inform at ion and ot her part s of your
applicat ion is ext rem ely helpful for t racking down problem s, but also for keeping a proact ive eye
on t he syst em . By doing t hat , you can easily t rack t hat it now t akes perhaps 30% longer t o
execut e a cert ain scenario com pared t o a t im e t wo m ont hs ago.
Se cu r it y
These days, t his one probably doesn't need any furt her explanat ion. We obviously need t o
carefully t hink t hrough t hings like aut hent icat ion and aut horizat ion. We also m ust prot ect our
applicat ions against at t acks of different kinds.
Au dit in g
As one part of t he securit y aspect s, it 's im port ant t o have audit ing so t hat it 's possible t o check
aft erwards who did what when.
That said, an appealing way of dealing wit h t his is t o, if you can, get som e resources from t he
operat ions side early on t o act explicit ly as a st akeholder on t he syst em , so t hat you creat e t he
operat ional m echanism s t hat are really needed. The ordinary cust om er of t he syst em isn't a good
requirem ent creat or here. The operat ional m echanism s are t ypical exam ples of non- funct ional
requirem ent s, and t he ordinary cust om ers won't norm ally add m uch t here.
The flexibilit y for your m echanism s m ight be im port ant because different cust om ers use different
operat ional plat form s. There are st andards such as Windows Managem ent I nst rum ent at ion ( WMI ) ,
but it 's wise t o build in flexibilit y if you build a fram ework for t his so you can easily swit ch t o different
out put form at s for t he logging, for exam ple. One cust om er uses CA Unicent er, anot her uses Microsoft
Operat ions Manager ( MOM) , yet anot her m ight use som e product t hat won't underst and WMI , and so
on.
Summary
We ended t he chapt er wit h a few words about operat ional aspect s. We won't discuss t hat m uch m ore
in t his book. I nst ead, t he focus will be about t he core of t he applicat ions, t he core business value.
The discussion in t his chapt er about what is im port ant for m odern soft ware developm ent is cert ainly
not exhaust ive. My hope was t o briefly discuss a couple of values wort h considering for every
developer. On t he way we int roduced Dom ain- Driven Design, Dom ain Models, Test - Driven
Developm ent , Pat t erns, and a lot of ot her concept s, bot h regarding archit ect ure and regarding
processes.
The t hree values I would like t o st ress again are balance, cont ext - awareness, and cont inuous
learning. Those are valuable values for developers and archit ect s, and everybody else, t oo.
So wit h t he scene set up, it 's now t im e t o discuss pat t erns of different t ypes som e m ore.
Chapter 2. A Head Start on Patterns
We are const ant ly facing new design problem s. We always solve t he problem s, but som et im es we
find t hat we have backed ourselves int o a corner. Som et im es we find t hat t he solut ion has serious
drawbacks, and som et im es we creat e bad solut ions. By reusing good, well- proven, and flexible
solut ions we m inim ize t hese risks and we reach t he desired result fast er. A t ool t o use for t his is
pat t erns. Thanks t o t he higher abst ract ion level t hat com es from pat t erns, we can also st art and
succeed wit h even larger design problem s. Pat t ern awareness also leads t o bet t er underst anding
bet ween developerssyst em developm ent is very m uch about com m unicat ion.
I 've heard it m any t im es. Pat t erns are academ ic nonsense, useless and elit ist . I f t his is also how you
feel, m y aim in t his chapt er is t o show you t he opposit e, because not hing could be m ore wrong.
Pat t erns can be very pragm at ic, highly useful in day- t o- day work, and ext rem ely int erest ing t o all ( or
at least m ost ) developers. Maybe you haven't not iced, but I have already discussed several pat t erns.
One exam ple is t he Dom ain Model pat t ern [ Fowler PoEAA] t hat I brought up in Chapt er 1, " Values t o
Value." I n t his chapt er, we will discuss t hree different cat egories of pat t erns: nam ely Design Pat t erns
( generic and applicat ion- t ype specific) , Archit ect ural Pat t erns, and Dom ain Pat t erns.
N ot e
Please not e t hat t he cat egorizat ions here are a bit fuzzy, and not at all as im port ant or
int erest ing as t he pat t erns t hem selves. So if t he cat egorizat ions don't provide any help t o
you, don't let t hem get in t he way for you.
Even if you are already pat t ern- conscious, I t hink you'll find t his chapt er int erest ing. I won't reuse old
explanat ions, but will provide m y own view of t he pat t erns. For exam ple, t he discussion I 'm going t o
use will be very Dom ain Model- focused, which is not t ypically t he case when it com es t o Design
Pat t erns, for exam ple. I f not hing else, I hope you'll find t he reflect ions here and t here of int erest .
Before get t ing st art ed, t hough, I 'd like t o t ake you t hrough a generic discussion of t he concept of
pat t erns and why you should learn about t hem .
A Little Bit About Patterns
Pat t erns provide sim ple, elegant solut ions t o recurring design problem s. The key advant ages pat t erns
provide are flexibilit y, m odularit y, and creat ing underst andable and clear design. Not e t hat I skipped
reusabilit y, alt hough it 's a bit unfair. Pat t erns t ake away focus from code reuse and m ove t he focus
t o knowledge reuse inst ead. So pat t erns are very m uch about reusabilit y, t oo, but j ust not in t he way
we usually t hink about reuse.
N ot e
Gregory Young point ed out t hat m any pat t erns are about reuse, t hrough decoupling. The
Dependency I nj ect ion pat t ern ( which will be discussed in Chapt er 10, " Design Techniques
t o Em brace" ) is a good exam ple of t hat .
When you st udy pat t erns, you m ight t hink " OK, isn't t hat how we always do it ?" An im port ant point
about pat t erns is t hat t hey aren't inv ent ed, but rat her harvest ed or dist illed. I t 's about proven
solut ions. But t he solut ion part isn't t he only piece of a pat t ern. They are described in t hree pieces:
t he cont ext , t he problem , and t he solut ion.
Learning from your m ist akes is very powerful, but from t im e t o t im e it 's nice t o t ake a short cut by
st udying ot her people's am assed knowledge, which is a good reason for learning pat t erns. Let 's see if
we can find ot her reasons.
I f a developm ent t eam is pat t erns- conscious, pat t erns becom e a very im port ant part of t he language.
I nst ead of having t o describe each and every design idea in m inut e det ail, it 's oft en enough t o say a
pat t ern nam e and everybody in t he t eam can evaluat e whet her or not it 's a good idea for t hat
part icular problem . Adding pat t erns t o t he t eam 's language m ight be t he single m ost im port ant
reason for em bracing pat t erns because t he com m on underst anding, richness, and expressiveness of
t he language increase. Again, developm ent is very m uch about com m unicat ion.
Anot her reason I like pat t erns is t hat being able t o ut ilize pat t erns is a long- last ing skill. As a
com parison, I learned SQL in around 1988, and I can st ill m ake a good living from j ust working wit h
t hat . The product s and plat form s I work wit h have changed several t im es, t hough t he underlying
concept s are t he sam e. Pat t erns are sim ilar. The Design Pat t erns book [ GoF Design Pat t erns] cam e
out in 1995, and it 's st ill ext rem ely relevant t oday. Also wort h point ing out is t hat pat t erns are
language- / product - / plat form - agnost ic. ( Different plat form s m ight have specific support for cert ain
im plem ent at ion variat ions, and it 's also t he case t hat t he [ GoF Design Pat t erns] have been writ t en
wit h obj ect orient at ion as an assum pt ion.)
I f you st udy Design Pat t erns [ GoF Design Pat t erns] , you will find t hat t he pat t erns t here are very
m uch in line wit h t he principles of good obj ect - orient ed design. What is good obj ect - orient ed design,
you m ight ask? Robert C. Mart in discusses som e such principles in Agile Soft ware Developm ent :
Principles, Pat t erns, and Pract ices [ Mart in PPP] . Exam ples include t he Single Responsibilit y Principle
( SRP) , t he Open- Closed Principle ( OCP) and t he Liskov Subst it ut ion Principle ( LSP) .
An it em such as a class should j ust have one responsibilit y and solve t hat
responsibilit y well. I f a class is responsible bot h for present at ion and dat a access,
t hat 's a good exam ple of a class breaking SRP.
A class should be closed for m odificat ion, but open for ext ension. When you change
a class, t here is always a risk t hat you will break som et hing. But if inst ead of
m odifying t he class you ext end it wit h a sub- class, t hat 's a less risky change.
Assum e t hat you have an inherit ance hierarchy wit h Person and Student. Wherever
you can use Person, you should also be able t o use a Student, because Student is a
subclass of Person. At first t his m ight sound like t hat 's always t he case
aut om at ically, but when you st art t hinking about reflect ion ( reflect ion is a t echnique
for being able t o program m at ically inspect t he t ype of an inst ance and read and set
it s propert ies and fields and call it s m et hods, wit hout knowing about t he t ype
beforehand) , for exam ple, it 's not so obvious anym ore. A m et hod t hat uses
reflect ion for dealing wit h Person m ight not expect Student.
The reflect ion problem is a synt act ical one. Mart in uses a m ore sem ant ical exam ple
of Square t hat is a Rectangle. But when you use SetWidth() for t he Square, t hat
doesn't m ake sense, or at least you have t o int ernally call SetHeight() as well. A
pret t y different behavior from what Rectangle needs.
Sure, all t hese principles are debat able in cert ain cont ext s. They should be used as a
guide only, not as t he " only t rut h." For exam ple, OCP can easily be over- applied. You
m ight have com e t o a point where you underst and bet t er how a m et hod should be
im plem ent ed and want t o m odify it rat her t han ext end it . And adding a m et hod t o a class
could also be seen as an ext ension.
Pat t erns are not only great wit h up- front design, t hey are very usable ( perhaps even m ore) during
refact oring..." My code is j ust becom ing m essier and m essier. Ah, I need t o use t hat pat t ern! " I t 's like
t he chicken or t he egg problem , but I decided t o st art wit h pat t erns in t his book and discuss
refact oring aft er t hat ( in t he next chapt er) .
What m ight st ay around for a lit t le longer is t he risk of over- design. I f not 17 pat t erns, t here m ight
at least be a lot of t hought about how a problem should be solved. The init ial solut ion doesn't feel
right because it doesn't use a cert ain pat t ern.
N ot e
A friend of m ine t old m e about a recent design problem he discussed wit h som e developers
at a com pany. I t t ook him t hree m inut es t o com e up wit h a very sim ple solut ion t o t he
problem . ( The problem it self was a sim ple one.) Yet t he ot her developers weren't happy
wit h t he solut ion so t hey spent t hree days of hard t hinking t o get it j ust right .
Been t here, done t hat . I n m y opinion, Test - Driven Developm ent ( TDD) is a good t echnique
for avoiding t hat over- design problem . The design focus will be m uch m ore on solving t he
problem at hand and not hing else, and pat t erns will be int roduced when needed via
refact oring.
You m ight get t he feeling t hat t he pat t erns concept is t he silver bullet . I t 's not of course not it 's j ust
anot her t ool for t he t oolbox.
Pat t erns are oft en perceived individually as being pret t y " sim ple," but t hey get very com plex in
cont ext and com binat ion wit h ot her pat t erns. I don't rem em ber how m any t im es I 've heard people on
t he newsgroups say som et hing like " I underst and pat t ern X, but when I t ry t o use it in m y applicat ion
t oget her wit h pat t ern Y and pat t ern Z, it 's ext rem ely com plex. Please help! " That isn't really a reason
not t o learn about pat t erns. This book will address t hat t o som e degree, but not here and now; first
we will discuss som e pat t erns in isolat ion.
I believe Joshua Kerievsky's Refact oring t o Pat t erns [ Kerievsky R2P] set s t his st raight by point ing out
again and again t hat t he way t o m ost oft en use pat t erns isn't t o use t hem in up- front design, but t o
refact or t oward or t o pat t erns.
Pattern Adoption
" For m e, m any concept s, like pat t erns, are learned in st ages:
6 . You learn m ore and apply it " less naïvely" and m ore im plicit ly
9 . You eit her forget about it or add knowledge and experience ( Repeat st eps 59 as
necessary)
1 0 . You use it wit hout being aware t hat you're using it "
OK, t im e t o m ove over t o t he first pat t ern cat egory. Let 's see if we can creat e an " Aha! " and not j ust
a " Huh?" for t hose of you who are pat t ern newcom ers.
Design Patterns
When I say Design Pat t erns here, t he first t hought s of m any will go t o t he Design Pat t erns book [ GoF
Design Pat t erns] , which has been m ent ioned a whole bunch of t im es by now. I t 's by no m eans t he
only book about Design Pat t erns, but it 's considered t he st andard work on t he subj ect .
Design Pat t erns are abst ract and pret t y low- level in t hat t hey are t echnical and general in regard t o
dom ain. I t doesn't m at t er what t ier or what t ype of syst em you are building, Design Pat t erns are st ill
useful.
One way t o describe Design Pat t erns is t hat t hey are about refining t he subsyst em s or com ponent s.
You will find when we m ove t o t he ot her t wo cat egories I 'm about t o discuss here t hat it 's com m on
t hat t he pat t erns t here use one or m ore Design Pat t erns or t hat som e specific Design Pat t erns can be
applied in a m ore specific way in t hose cat egories.
N ot e
While we're t alking about low- level, here is a fun lit t le st ory. I was asked what t he
difference was bet ween m e and a friend on a professional level. I said t hat m y friend
worked wit h low- level program m ing and I worked wit h high- level program m ing. The person
asking didn't know anyt hing about program m ing, but he got t hat look on his face you get
when list ening t o som eone blowing his own t rum pet way t oo m uch.
The Design Pat t erns book [ GoF Design Pat t erns] is pret t y hard- going. Each t im e I read it I
underst and and learn m ore about it . For exam ple, I have oft en t hought , " That 's not correct " or
" That 's not t he best solut ion" or even " That 's st upid." But aft er som e deliberat ion, I decide t hat t hey
are " right " each t im e.
So far t here has been a lot of t alk and lit t le act ion. I t 's t im e t o becom e concret e by giving an
explanat ion of a Design Pat t ern. I have chosen one of m y favorit e Design Pat t erns called St at e, so
here goes.
Problem
A sales order can be in different st at es, such as " NewOrder," " Regist ered," " Grant ed," " Shipped,"
" I nvoiced," and " Cancelled." There are st rict rules concerning t o which st at es t he order can " go" from
which st at es. For exam ple, it 's not allowed t o go direct ly from Regist ered t o Shipped.
There are also differences in behavior depending upon t he st at es. For exam ple, when Cancelled, you
can't call AddOrderLine() for adding m ore it em s t o t he order. ( That also goes for Shipped and
I nvoiced, by t he way.)
One m ore t hing t o rem em ber is t hat cert ain behavior will lead t o st at e t ransform at ion. For exam ple,
when AddOrderLine() is called, t he st at e t ransform s from Grant ed back t o New Order.
I n order t o solve t his problem , I need t o describe a st at e graph in code. I n Figure 2- 1 you find a very
sim ple and classic st at e graph describing how st at e of t he but t on is changed bet ween Up and Down
each t im e t he user pushes t he but t on.
Figu r e 2 - 1 . St a t e gr a ph for a bu t t on
Figu r e 2 - 2 . St a t e gr a ph for a n Or de r
NewOrder,
Registered,
Granted,
Shipped,
Invoiced,
Cancelled
}
and t hen t o use a privat e field for t he current st at e in t he Order class, like t his:
Then, in t he m et hods, you need t o deal wit h t wo t hings on t op of what t he m et hods should do. You
m ust check if t he m et hod m ight be called at all in t hat st at e, and you need t o consider if a t ransit ion
should t ake place and, if so, t o what new st at e. I t could look like t his in t he AddOrderLine() m et hod:
As you saw in t he code snippet , t he m et hod got quit e a lot of unint erest ing code added j ust because
of t aking care of t he st at e graph. An ugly if - st at em ent is very fragile t o changes in t he fut ure. Code
sim ilar t o t hat will be sprinkled everywhere in t he Order class. What we do is spread knowledge of
t he st at e graph in several different m et hods. This is a good exam ple of subt le but evil duplicat ion.
Even for sim ple exam ples like t his, we should reduce t he code duplicat ion and fragm ent at ion. Let 's
give it a t ry.
Proposal Two is j ust a slight variat ion. You can have a privat e m et hod called _ChangeState() , which
could, for exam ple, be called from AddOrderLine(). _ChangeState() could have a long swit ch
st at em ent , like t his:
if (newState == _currentState)
return; //Assume a transition to itself is not an error.
switch (_currentState)
{
case OrderState.NewOrder:
switch (newState)
{
case OrderState.Registered:
case OrderState.Cancelled:
_currentState = newState;
Break;
default:
throw new ApplicationException(...
break;
}
case OrderState.Registered:
switch (newState)
{
case OrderState.NewOrder:
case OrderState.Granted:
case OrderState.Cancelled:
_currentState = newState;
break;
default:
throw new ApplicationException(...
break;
}
...
//And so on...
}
}
I was quit e lazy in t he previous code and only showed t he st art of t he st ruct ure of t he huge swit ch
st at em ent , but I t hink it 's st ill pret t y obvious t hat t his is a good exam ple of sm elly code, especially if
you consider t hat t his exam ple was sim plified and didn't discuss all aspect s or all st at es t hat were
really needednot even close.
N ot e
As always, for som e sit uat ions t he exam ple j ust shown was good enough and t he " right "
solut ion. I j ust felt I had t o say t hat so as t o not im ply t hat t here is only one solut ion t o a
problem t hat is always right .
Also not e t hat I will discuss som e m ore about code sm ells in t he next chapt er.
OK, I 've been t here, done t hat in several proj ect s. I can't say I like t hat solut ion very m uch. I t seem s
fine at first , but when t he problem grows, t he solut ion get s t roublesom e. Let 's t ry out anot her one.
Solution Proposal Three
The t hird solut ion is based on a t able ( som e kind of configurat ion inform at ion) describing what should
happen at cert ain st im uli. So inst ead of describing t he st at e t ransform at ion in code as in proposals
one and t wo, t his t im e we describe t he t ransform at ions in a t able, Table 2- 1 .
New Or der
Regist er ed
New Or der
Cancelled
Regist er ed
New Or der
Regist er ed
Grant ed
Regist er ed
Cancelled
...
...
Cu r r e n t St a t e Allow e d N e w St a t e
Then your _ChangeState() m et hod can j ust check if t he new st at e t hat com es as a param et er is
accept able for when t he current st at e is NewOrder, for exam ple. For t he current st at e NewOrder,
only Regist ered and Cancelled are allowed as a new st at e.
New Or der
Regist er ( )
Regist er ed
New Or der
Cancel( )
Cancelled
Regist er ed
AddOrderLine( )
New Or der
Regist er ed
Grant ( )
Grant ed
Regist er ed
Cancel( )
Cancelled
...
...
Cu r r e n t St a t e M e t h od N e w St a t e
Now your _ChangeState() m et hod shouldn't t ake t he new st at e as a param et er, but rat her t he
m et hod nam e inst ead. Then _ChangeState() decides what t he new st at e should be by looking in t he
t able.
This is clean and sim ple. A big advant age here is t hat it 's very easy t o get an overview of t he
different possible st at e t ransform at ions. The m ain problem is probably t hat it 's hard t o deal wit h
cust om behavior depending upon t he current st at e and t hen t o go t o one st at e of several possible
st at es when a m et hod execut es. Sure, it 's no harder t han wit h proposal t wo, but it 's st ill not very
good. You could regist er inform at ion in t he t able about what delegat es ( a delegat e is like a st rongly
t yped funct ion point er) should be execut ed at cert ain t ransform at ions, and you could probably
ext end t hat idea t o solve t he ot her problem s as well, but I t hink t here is a risk t hat it get s a bit
m essy during debugging, for exam ple.
Do we have m ore ideas? Let 's apply som e knowledge reuse and t ry out t he Design Pat t ern called
St at e.
Figu r e 2 - 3 . St a t e pa t t e r n , ge n e r a l st r u ct u r e
The idea is t o encapsulat e t he different st at es as individual classes ( see ConcreteStateA and
ConcreteStateB) . Those concret e st at e classes inherit from an abst ract State class. Context has a
st at e inst ance as a field and calls Handle() of t he st at e inst ance when Context get s a Request() call.
Handle() has different im plem ent at ions for t he different st at e classes.
That 's t he general st ruct ure. Let 's see what t his could look like if we apply it t o t he problem at hand.
I n Figure 2- 4 , you find a UML diagram for t he specific exam ple.
N ot e
For t his exam ple, it m ight m ake sense t o add anot her abst ract class as t he base class for
NewOrder , Registered , and Granted . The new class would im plem ent AddOrderLine() and
Cancel() .
I n t he specific exam ple, t he Order class is t he Context from t he general st ruct ure. Again, Order has a
field of OrderState , alt hough t his t im e OrderState isn't an enum , but a class. For t he sake of
refact oring, your old t est s m ight expect an enum , and t hen you can keep t hat enum as well ( perhaps
as a propert y which im plem ent at ion inspect s what is t he current inst ance in t he st at e inherit ance
hierarchy) and t hereby not m ake changes t o t he ext ernal int erface.
A newly creat ed Order get s a new st at e inst ance of a NewOrder at inst ant iat ion and sends it self t o t he
const ruct or, like t his:
Not e t hat t he field is declared as int ernal. The reason for t his is so t hat t he st at e class can change t he
current st at e by it self, so Order delegat es t he st at e t ransform at ions t ot ally t o t he different st at e
classes. ( I could also let OrderState be an inner class of Order t o avoid t he need for internal .)
This t im e, t he Register() m et hod on Order is ext rem ely sim ple. I t could look like t his:
The Register() m et hod on NewOrder is also pret t y sim ple. At least it can focus on it s own st at e, and
t hat m akes t he code clean and clear. I t could look like t his:
Before changing t he st at e, t here was kind of a callback t o t he parent ( _parent._ Register() ) t elling
it t o do it s t hing before t he st at e was changed. ( Not e t hat t he " callback" went t o t he int ernal m et hod
_Register() and not t he public Register() .) This is j ust one exam ple of an opt ion, of course. Ot her
exam ples would be t o put t he code in t he OrderState base class or in t he NewOrder class it self. I t
should go wherever it 's best locat ed.
As you saw, if I want t o do t hings before or aft er t he st at e t ransform at ion, it 's sim ple and very well
encapsulat ed. I f I want t o disallow a cert ain t ransform at ion in t he NewOrder class, I j ust skip
im plem ent ing t hat m et hod and use t he im plem ent at ion of t he base class OrderState for t hat m et hod.
The im plem ent at ion of t he base class t hrows an except ion saying it was an illegal st at e
t ransform at ion, if t hat 's t he want ed behavior. Anot her t ypical default im plem ent at ion is t o do
not hing.
N ot e
I f you need m ore cont ext - aware except ions, you can of course im plem ent t he m et hods in
t he subclasses j ust as well, even if all t hey will do is raise except ions.
This also im plies t hat inst ead of using a base class for OrderState you could use an
int erface inst ead. I guess t hat if t he GoF book had been writ t en t oday, m any of t he
pat t erns would have used int erfaces inst ead of ( or at least t oget her wit h) abst ract base
classes. The St at e pat t ern isn't t he m ost t ypical exam ple of t his, but it st ill is a possible
exam ple.
More Comments
When using t he St at e pat t ern, we were act ually swapping a single field int o a bunch of separat e
classes. That doesn't sound like a very good idea at first , but what we t hen get is t he nice effect of
m oving t he behavior t o where it belongs and good alignm ent t o t he Single Responsibilit y Principle
( SRP) .
There are drawbacks, of course, and a t ypical one is t hat t he program can pot ent ially be flooded wit h
sm all classes when we use a solut ion such as St at e.
Which solut ion you prefer is indeed up for debat e, but I t hink t he St at e pat t ern is one t hat should be
seriously considered here. You m ight find t hat it solves your problem wit h t he least am ount of
duplicat ed code and wit h t he responsibilit y part it ioned out int o encapsulat ed and cohesive unit s, t he
concret e st at e classes. But wat ch out t he St at e pat t ern is also very easy t o overuse, as is every t ool.
Use it wisely!
That was an exam ple of a Design Pat t ern, a generic one. We'll com e back t o m ore Design Pat t erns of
anot her fam ily, but first a discussion about anot her cat egory of pat t erns.
Architectural Patterns
A com m on associat ion t o t he t erm " Archit ect ural Pat t erns" is t o t hink about som e of t he pat t erns
discussed in Buschm ann et al.'s Pat t ern- Orient ed Soft ware Archit ect ure [ POSA 1] . I n t hat book t here
are a couple pat t erns gat hered under t he cat egory called Archit ect ural Pat t erns. Exam ples of t he
pat t erns are Pipes and Filt ers and Reflect ion.
Pipes and Filt ers are about channeling dat a t hrough Pipes and processing t he st ream in Filt ers. Pipes
and Filt ers have been picked up by t he SOA com m unit y as a useful pat t ern for m essage- based
syst em s.
Reflect ion is built int o bot h Java and .NET, m aking it possible t o writ e program s t hat read from and
writ e t o obj ect s in a generic way by only using t he m et adat a of t he obj ect s ( not knowing anyt hing
about t he t ype of t he obj ect beforehand) .
I f Design Pat t erns is about refining subsyst em s or com ponent s, Archit ect ural Pat t erns is about t he
st ruct uring int o subsyst em s. To m ake it m ore concret e, let 's t ake a com m on exam ple, Layers [ POSA
1] .
An Example: Layers
Layers or layering is a basic principle when it com es t o archit ect ure, which m eans t o fact or out
responsibilit ies int o separat e cohesive unit s ( clust ers of classes) and define t he dependencies
bet ween t hose unit s. Most developers are reasonably fam iliar wit h t his.
Because it 's such a com m only used and well- underst ood pat t ern, we will j ust give a quick exam ple of
it here t o give us a feeling of t he pat t ern cat egory.
Problem
Assum e we have built a set of classes for a SalesOrder applicat ion, such as Customer, Order,
Product, and so on. Those classes encapsulat e t he m eaning t hey have for t he Dom ain, and also how
t hey are persist ed/ depersist ed and present ed. The current im plem ent at ion is t o persist t o t he file
syst em and t o present t he obj ect s as HTML snippet s.
Unfort unat ely, we now find out t hat we need t o be able t o consum e t he obj ect s as XML as well and t o
use a relat ional dat abase for persist ence.
The m ost com m on solut ion t o t his problem is probably t o fact or out som e of t he responsibilit ies of
t he classes. The new requirem ent s m ade it obvious t o us t hat t he classes were clearly breaking t he
SRP.
We t ry t o split t he classes so t hat t he responsibilit ies are cohesively dealt wit h from a t echnological
point of view.
Therefore, t he old classes will now only focus on t he dom ain m eaning ( let 's call t he layer Dom ain
layer) . The present at ion ( or rat her consum pt ion) responsibilit ies are dealt wit h by anot her set of
classes ( anot her layer called t he Consum er layer) , and t he persist ence responsibilit ies are dealt wit h
by yet anot her set of classes ( t he Persist ence layer) .
Three layers spont aneously felt like a t ypical solut ion here, one per responsibilit y cat egory. The t wo
new layers have t wo im plem ent at ions each for dealing wit h bot h t he old requirem ent s and t he new.
The dependencies bet ween t he layers are also defined, and in t his case we decided t hat t he
consum pt ion layer will depend on t he dom ain layer, and t he dom ain layer will depend on t he
persist ence layer. That way, t he Consum er layer is t ot ally unaware of t he Persist ence layer, which
was som et hing we decided was good in t his part icular proj ect .
We will get back t o t he subj ect of layering again in Chapt er 4, " A New Default Archit ect ure," and t hen
approach it a bit different ly.
We're not going t o discuss an exam ple about t he Dom ain Model pat t ern here and now because t he
whole book is about j ust t hat . I nst ead, we'll cont inue by focusing on anot her dim ension of t he
pat t erns, regarding dom ain- dependence or not . Next up are Design Pat t erns for specific t ypes of
applicat ions.
Design Patterns for Specific Types of Applications
Anot her set of Design Pat t erns isn't as generic as t hose discussed so far, but , for exam ple, pat t erns
for building ent erprise applicat ions.
Defining an ent erprise applicat ion is t ricky, but you can t hink of it as a large- scale inform at ion
syst em wit h m any users and/ or a lot of dat a.
The m ain book dealing wit h t he pat t erns in t his cat egory is Mart in Fowler's Pat t erns of Ent erprise
Applicat ion Archit ect ure [ Fowler PoEAA] .
The pat t erns here at first sight m ight not seem as cool or am azing as som e of t he Design Pat t erns,
but t hey are ext rem ely useful, cover a lot of ground, and cont ain a lot of experience and knowledge.
As I said, t hey are less generic t han t he ot her Design Pat t erns and focused j ust on large- scale
inform at ion syst em s.
They com e int o play for t he chosen st ruct ure of t he logic; for exam ple, t he Dom ain Model. The
pat t erns here aren't so m uch about how t he Dom ain Model it self ( or any of t he ot her m odels for
st ruct uring t he m ain logic) should be st ruct ured, but m ore about t he infrast ruct ure for support ing t he
Dom ain Model.
To m ake it m ore concret e, I 'd like t o discuss an exam ple, and I choose Query Obj ect s [ Fowler
PoEAA] .
There are several different solut ions from which t o choose in order t o navigat e t he Dom ain Model.
One solut ion is t o have a global root obj ect t hat has references t o root - like collect ions. I n t his case, a
cust om er collect ion would be an exam ple of one of t hese. So what t he developer does is t o st art wit h
t he global root obj ect and navigat e from t here t o t he cust om er collect ion, and t hen it erat e t he
collect ion unt il what is needed is found, or perhaps navigat e t o t he cust om er's sales orders if t hat 's
what 's of int erest .
A sim ilar paradigm is t hat all collect ions are global so you can direct ly access t he cust om er collect ion
and it erat e over it .
Bot h t hose paradigm s are easy t o underst and and sim ple t o use, but one drawback is t hat t hey are
lacking som ewhat from t he perspect ive of a dist ribut ed syst em . Assum e you have t he Dom ain Model
running at t he client ( each client has one Dom ain Model, or rat her a sm all subset of t he Dom ain
Model inst ances, and no shared Dom ain Model inst ances) and t he dat abase is running at a dat abase
server ( a pret t y com m on deploym ent m odel) . What should happen when you ask t he root obj ect t o
get t he cust om er collect ion of one m illion cust om ers? You can get all t he cust om ers back t o t he client
so t he client can it erat e over t he collect ion locally. Not so nice t o wait for t hat huge collect ion t o be
t ransm it t ed.
Anot her opt ion is t o add an applicat ion server t o t he pict ure and ask it t o only send over a collect ion
reference t o t he client side, and t hen m uch less dat a is t ransm it t ed, of course. On t he ot her hand,
t here will be an incredible am ount of net work calls when t he client is it erat ing t he list and asking for
t he next cust om er over t he net work one m illion t im es. ( I t will be even worse if t he cust om er
inst ances t hem selves aren't m arshaled by value but only by reference.) Yet anot her opt ion is t o page
t he cust om er collect ion so t he client perhaps get s 100 cust om ers from t he server at a t im e.
I knowall t hese solut ions have one problem in com m on; you don't oft en want t o look at all t he
cust om ers. You need a subset , in which case it 's t im e t o discuss t he next problem .
Problem
The problem is t hat t he users want a form where t hey can search for cust om ers flexibly. They want
t o be able t o ask for all cust om ers who
Have a nam e wit h " aa" in it . ( Hidden m arket ing for a Swedish car com pany.)
But on t he sam e form , t hey should also be able t o ask for j ust cust om ers in a cert ain part of Sweden.
Again, t he search form needs t o be pret t y flexible.
I 'm going t o discuss t hree different solut ion proposals, nam ely " filt ering wit hin Dom ain Model,"
" filt ering in dat abase wit h huge param et er list s," and " Query Obj ect s."
Let 's t ake a st ep back and adm it t hat we could use any of t he solut ions already discussed so t hat t he
collect ion is m at erialized som ewhere and t hen t he filt er is checked for every inst ance. All inst ances
m eet ing t he filt er crit eria are added t o a new collect ion, and t hat is t he result .
This is a pret t y sim ple solut ion, but pract ically unusable in m any real- world sit uat ions. You will wast e
space and t im e. Not only were t here one m illion cust om ers, but you also had t o m at erialize t he
orders for t he cust om ers. Phew, t hat solut ion is j ust im possible t o use and it 's even worse when you
scale up t he problem ....
Of course, t he conclusion here depends t o a large degree on t he execut ion plat form . Rem em ber what
I said about t he deploym ent m odela subset of t he Dom ain Model inst ances in each client , t he
dat abase at a dat abase server, no shared Dom ain Model inst ances.
I f inst ead t here was one shared set of Dom ain Model inst ances at an applicat ion server ( which has it s
own problem sm ore about t hat in lat er chapt ers) , t his m ight have been a suit able solut ion, but only
for server- side logic. For client s asking for a subset of t he shared Dom ain Model inst ances, t he client s
m ust express t heir crit eria som ehow.
Dat abases are norm ally good at st oring and querying, so let 's use t hem t o our advant age here. We
j ust need t o express what we want wit h a SQL st at em ent and t hen t ransform t he result int o inst ances
in our Dom ain Model.
N ot e
I t 's debat able whet her I can com bine t he t wo subselect s t arget ing Orders int o a single
subselect . As t he requirem ent was st at ed, I don't t hink so ( because t he m eaning would
change slight ly if I com bined t hem ) .
Here we j ust m at erialize t he inst ances t hat are of int erest t o us. However, we probably don't want
t he layer cont aining t he Dom ain Model t o have t o cont ain all t hat SQL code. What 's t he point of t he
Dom ain Model in t hat case? The consum er layer j ust get s t wo m odels t o deal wit h.
So we now have a new problem . How shall t he consum er layer express what it want s? Ah, t he
Dom ain Layer which is responsible for t he m apping bet ween t he dat abase and Dom ain Model can
provide t he consum er layer wit h a search m et hod. Proposal num ber t wo is t he following:
This probably solves t he requirem ent for t he first query, but not t he second. We need t o add a few
m ore param et ers like t his:
Do you see where t his is going? The param et er list quickly get s im pract ical because t here are
probably a whole bunch of ot her param et ers t hat are also needed. Sure, edit ors showing
placeholders for each param et er helps when calling t he m et hod, but using t he m et hod will st ill be
error- prone and im pract ical. And when anot her param et er is needed, you have t o go and change all
t he old calls, or at least provide a new overload.
Anot her problem is how t o express cert ain t hings in t hat pret t y powerless way of prim it ive dat at ypes
in a list of param et ers. A good exam ple of t hat is t he param et er called
mustHaveOrderedSomethingLastMonth . What about t he m ont h before t hat ? Or last year? Sure, we
could use t wo dat es inst ead as param et ers and m ove t he responsibilit y of defining t he int erval t o t he
consum er of t he m et hod, but what about when we only care about cust om ers in a cert ain t own?
What should t he dat e param et ers be t hen? I guess I could use m inim um and m axim um dat es t o
creat e t he biggest possible int erval, but it 's not ext rem ely int uit ive t hat t hat 's t he way t o express " all
dat es."
N ot e
Gregory Young com m ent ed on t he problem of how t o express presendence. Expressing t his
wit h a param et er list is t roublesom e: ( crit erion1 and crit erion2) or ( crit erion1 and
crit erion2)
I t hink we have quickly grown out of t his solut ion, t oo. I cam e t o t he sam e conclusion back in t he
VB6 days, so I used an array- based solut ion. The first colum n of t he array was t he fieldnam e ( such
as Cust om erNam e) , t he second colum n was t he operat or ( such as Like from an enum erat or) and t he
t hird colum n was t he crit erion such as " * aa* " . Each crit erion had one row in t he array.
That solut ion solved som e of t he problem s wit h t he param et er list , but it had it s own problem s. Just
because t here was a new possible crit erion added, I didn't have t o change any of t he old consum er
code. That was good, but it was pret t y powerless for advanced crit erion, so I st epped back and
exposed t he dat abase schem a, for exam ple, t o deal wit h t he crit erion " Have any orders wit h a t ot al
am ount larger t han one m illion?" I t hen used t he com plet e I N- clause as t he crit erion.
The array- based solut ion was a st ep in t he right direct ion, but it would have becom e a lit t le m ore
flexible wit h obj ect s inst ead. Unfort unat ely, it wasn't really possible t o writ e m arshal by value
com ponent s in VB6. There were solut ions t o t he problem , such as using a m ore flexible array
st ruct ure, but t he whole t hing is so m uch m ore nat ural in .NET. Over t o t he Query Obj ect pat t ern.
The idea of t he Query Obj ect pat t ern is t o encapsulat e t he crit eria in a Query inst ance and t hen send
t hat Query inst ance t o anot her layer where it is t ranslat ed int o t he required SQL. The UML diagram
for t he general solut ion could look like t hat shown in Figure 2- 5 .
Let 's com e up wit h a t ry for a Query Obj ect language for applying on t he problem . First t hough, let 's
assum e t hat t he Dom ain Model is as is shown in Figure 2- 6 .
Let 's see what it could look like our newly creat ed naïve query language in C# :
N ot e
The param et er t o t he Query const ruct or is not a t able nam e but a Dom ain Model class-
nam e. The sam e goes for t he param et ers t o AddCriterion(); I m ean it 's not t able colum ns,
but class fields/ propert ies. I n t hat case, propert y nam es or field nam es are used in t he
Dom ain Model.
Also not e t hat in t his specific exam ple, I didn't need a subquery for t he crit erion regarding
t he ReferencePersons because t he Dom ain Model was navigable from Customer t o
ReferencePerson. On t he ot her hand, subqueries were needed for t he Orders for t he
opposit e reason.
More Comments
I f you are SQL- lit erat e, your first im pression m ight be t hat t he SQL- version was m ore expressive,
easier t o read, and j ust bet t er. SQL is cert ainly a powerful query language, but rem em ber what we
want t o accom plish. We want t o be able t o work as m uch as possible wit h t he Dom ain Model ( wit hin
lim it s) and t hereby achieve a m ore m aint ainable solut ion. Also not e t hat t he C# code j ust shown was
needlessly t alkat ive. Lat er on in t he book we will discuss how t he synt ax could look by writ ing a t hin
layer on t op of a general query obj ect im plem ent at ion.
So what we gained was furt her t ransparence of our code wit h regard t o t he dat abase schem a.
Generally, I t hink t his is a good t hing. When we really need t o, we can always go out of t his lit t le
sandbox of ours t o st at e SQL queries wit h t he full power of t he dat abase and wit hout a lifeline.
Anot her t hing I 'd like t o point out is t hat creat ing a com pet ent Query Obj ect im plem ent at ion will
quickly becom e very com plex, so wat ch out t hat you don't t ake on t oo m uch work.
A nice lit t le side effect is t hat you can also use query obj ect s pret t y easily for local filt ering, such as
holding on t o a cached list of all product s. For t he developer consum ing t he Dom ain Model, he or she
j ust creat es a Query Obj ect as usual, but it is t hen used in a slight ly different m anner, wit hout
t ouching t he dat abase.
W a r n in g
I know, I know. Caching is j ust as cool and useful as it is dangerous. Wat ch out , it can
backfire. You have been warned.
Som e DDD- lit erat e readers would probably prefer t he Specificat ion pat t ern [ Evans DDD] as t he
solut ion t o t his problem . That provides a neat connect ion over t o t he t hird and final pat t ern cat egory
we are going t o focus on: Dom ain Pat t erns.
Domain Patterns
Dom ain Pat t erns have a very different focus from t he Design Pat t erns and t he Archit ect ural Pat t erns.
The focus is t ot ally on how t o st ruct ure t he Dom ain Model it self, how t o encapsulat e t he dom ain
knowledge in t he m odel, and how t o apply t he ubiquit ous language and not let t he infrast ruct ure
dist ract away from t he im port ant part s.
There is som e overlap wit h Design Pat t erns, such as t he Design Pat t ern called St rat egy, [ GoF Design
Pat t erns] which is considered t o be a Dom ain Pat t ern as well. The reason for t he overlap is t hat
pat t erns such as St rat egy are very good t ools for st ruct uring t he Dom ain Model.
As Design Pat t erns, t hey are t echnical and general. As Dom ain Pat t erns, t hey focus on t he very core
of t he Dom ain Model. They are about m aking t he Dom ain Model clearer, m ore expressive, and
purposeful, as well as let t ing t he knowledge gained of t he dom ain be apparent in t he Dom ain Model.
When I ended t he previous sect ion, I m ent ioned t hat t he Specificat ion pat t ern as a Dom ain Pat t ern is
an alt ernat ive t o Query Obj ect s pat t ern. I t hink t hat 's a good way of explaining how I see what
Dom ain Pat t erns are. Query Obj ect s is a t echnical pat t ern where t he consum er can define a query
wit h a synt ax based on obj ect s, for finding m ore or less any of t he obj ect s in t he Dom ain Model. The
Specificat ion pat t ern can be used for querying as well, but inst ead of using a generic query obj ect
and set t ing crit eria, one by one, a specificat ion is used as a concept t hat it self encapsulat es dom ain
knowledge and com m unicat es t he purpose.
For exam ple, for finding t he gold cust om ers, you can use bot h query obj ect s and specificat ions, but
t he solut ions will differ. Wit h Query Obj ect s, you will express crit eria about how you define gold
cust om ers. Wit h a Specificat ion, you will have a class t hat is perhaps called
GoldCustomerSpecification. The crit eria it self isn't revealed or duplicat ed in t hat case, but
encapsulat ed in t hat class wit h a well- describing nam e.
One source of Dom ain Pat t erns is [ Arlow/ Neust adt Archet ype Pat t erns] , but I have chosen a Dom ain
Pat t ern- exam ple from anot her good source, Eric Evans' book Dom ain Driven Design [ Evans DDD] .
The chosen exam ple pat t ern is called Fact ory.
N ot e
Pat t ern- aware readers m ight get confused because I t alk about t he Dom ain Pat t ern Fact ory
here and t he Design Pat t erns book [ GoF Design Pat t erns] also has som e Fact ory pat t erns.
Again, t he focus of Design Pat t erns is m ore on a t echnical level and t he focus of Dom ain
Pat t erns is on a sem ant ic Dom ain Model level.
They are also different regarding t he det ailed int ent s and t ypical im plem ent at ions. The
Fact ory pat t erns of GoF are called Fact ory Met hod and Abst ract Fact ory. Fact ory Met hod is
about deferring inst ant iat ion of t he " right " class t o subclasses. Abst ract Fact ory is about
creat ing fam ilies of dependent obj ect s.
The Fact ory pat t ern of DDD is st raight forward im plem ent at ion- wise and is only about
capt uring and encapsulat ing t he creat ion concept for cert ain classes.
An Example: Factory
Who said t hat t he soft ware indust ry is influenced by indust rialism ? I t 's debat able whet her it 's good,
but it is influenced. We t alk about engineering as a good principle for soft ware developm ent ; we t alk
about archit ect ure, product lines and so on and so fort h. Here is anot her such influence, t he Fact ory
pat t ern. But first , let 's st at e t he problem t hat goes wit h t his exam ple.
Problem
The problem t his t im e is t hat t he const ruct ion of an order is com plex. I t needs t o be done in t wo very
different flavors. The first is when a new order is creat ed t hat is unknown t o t he dat abase. The
second is when t he consum er asks for an old order t o be m at erialized int o t he Dom ain Model from
t he dat abase. I n bot h cases, t here needs t o be an order inst ance creat ed, but t he sim ilarit y ends
t here as far as t he const ruct ion goes.
Anot her part of t he problem is t hat an order should always have a cust om er; ot herwise, creat ing t he
order j ust doesn't m ake sense. Yet anot her part of t he problem is t hat we need t o be able t o creat e
new credit orders and repeat ed orders.
The sim plest solut ion t o t he problem is t o j ust use a public const ruct or like t his:
public Order()
Then, aft er having called t his const ruct or, t he consum er has t o set up t he propert ies of t he inst ance
t he way it should be t o be insert ed or by asking t he dat abase for t he values.
Unfort unat ely, t his is like opening a can of worm s. For exam ple, we m ight have dirt y t racking on
propert ies, and we probably don't want t he dirt y t racking t o signal an inst ance t hat was j ust
reconst it ut ed from persist ence as dirt y. Anot her problem is how t o set t he ident ificat ion, which is
probably not set t able at all. Reflect ion can solve bot h problem s ( at least if t he ident ifier isn't declared
as readonly ) , but is t hat som et hing t he Dom ain Model consum er developer should have t o care
about ? I definit ely don't t hink so. There are som e m ore esot eric solut ions we could explore, but I 'm
sure m ost of you would agree t hat a t ypical and obvious solut ion would be t o use param et erized
const ruct ors inst ead.
Because I have spent a lot of program m ing t im e in t he past a long t im e ago wit h VB6, I haven't been
spoiled by param et erized const ruct ors. Can you believe t hat not having param et erized const ruct ors?
I 'm act ually having a hard t im e believing it m yself.
Anyway, in C# and Java and so on, we do have t he possibilit y of param et erized const ruct ors, and
t hat is probably t he first solut ion t o consider in dealing wit h t he problem . So let 's use t hree public
const ruct ors of t he Order class:
The second const ruct or is for creat ing eit her a credit Order or a repet it ion of an old Order. This is
definit ely less clear t han I would like it t o be.
The last const ruct or is used when fet ching an old Order, but t he only t hing t hat reveals which
const ruct or t o use is t he param et er. This is not clear. Anot her problem ( especially wit h t he t hird
const ruct or) is t hat it 's considered bad pract ice t o have lot s of processing in t he const ruct or. A j um p
t o t he dat abase feels very bad.
According t o t he book Effect ive Java [ Bloch Effect ive Java] , t he first it em ( best pract ice) out of 57 is
t o consider providing st at ic Fact ory m et hods inst ead of const ruct ors. I t could look like t his:
A nice t hing about such a Fact ory m et hod is t hat it has a nam e, revealing it s int ent ion. For exam ple,
t he fift h m et hod is a lot clearer t han it s const ruct or count erpart from solut ion 1, const ruct or t hree,
right ? I act ually t hink t hat 's t he case for all t he previous Fact ory m et hods when com pared t o solut ion
1, and now I added t he requirem ent of reservat ions and repeat ing orders wit hout get t ing int o
const ruct ion problem s.
Bloch also discusses t hat st at ic Fact ory m et hods don't have t o creat e a new inst ance each t im e t hey
get involved, which m ight be big advant age. Anot her advant age, and a m ore t ypical one, is t hat t hey
can ret urn an inst ance of any subt ype of t heir ret urn t ype.
Are t here any drawbacks? I t hink t he m ain one is t hat I 'm probably violat ing t he SRP [ Mart in PPP]
when I have m y creat ional code in t he class it self. Evans' book [ Evans DDD] is a good rem inder of
t hat where he uses a m et aphor of a car engine. The car engine it self doesn't know how it is creat ed;
t hat 's not it s responsibilit y. I m agine how m uch m ore com plex t he engine would have t o be if it not
only had t o operat e but also had t o creat e it self first . This argum ent is especially valid in cases where
t he creat ional code is com plex.
Add t o t hat m et aphor t he elem ent t hat t he engine could also be fet ched from anot her locat ion, such
as from t he shelf of a local or a cent ral st ock; t hat is, an old inst ance should be reconst it ut ed by
fet ching it from t he dat abase and m at erializing it . This is t ot ally different from creat ing t he inst ance
in t he first place, bot h for a real, physical engine and for an Order inst ance in soft ware.
We are close t o t he pat t ern solut ion now. Let 's use a solut ion sim ilar t o t he second proposal, but
fact or out t he creat ional behavior int o a class of it s own, forget t ing about t he " fet ch from dat abase"
for now ( which is dealt wit h by anot her Dom ain Pat t ern called Reposit ory, which we will discuss a lot
in lat er chapt ers) .
The code could look like t his from a consum er perspect ive t o obt ain a ready- m ade new Order
inst ance:
anOrder = OrderFactory.Create(aCustomer);
aReservation = OrderFactory.CreateReservation(aCustomer);
aCredit = OrderFactory.CreateCredit(anOldOrder);
aRepeat = OrderFactory.CreateRepeat(anOldOrder);
This is not m uch harder for t he consum er t han it is using an ordinary const ruct or. I t 's a lit t le bit m ore
int rusive, but not m uch.
I n order for t he consum er t o get t o an old Order, t he consum er m ust t alk t o som et hing else ( not t he
Fact ory, but a Reposit ory) . That 's clearer and expressive, but it 's anot her st ory for lat er on.
To avoid t he inst ant iat ion of orders via t he const ruct or from ot her classes in t he Dom ain Model if t he
Fact ory code is in an ext ernal class is not possible, but you can m ake it a lit t le less of a problem by
m aking t he const ruct or int ernal, and hopefully because t he Fact ory is t here, t he Dom ain Model
developers t hem selves underst and t hat t hat 's t he way of inst ant iat ing t he class and not using t he
const ruct or of t he t arget class direct ly.
N ot e
Eric Evans com m ent ed on t he previous paragraph wit h t he following: " I hope som eday
languages will support concept s like t his. ( Just as t hey have const ruct ors now, perhaps
t hey will allow us t o declare fact ories, et c.) "
More Comments
First of all, please not e t hat som et im es a const ruct or is j ust what we want . For exam ple, t here m ight
not be any int erest ing hierarchy, t he client want s t o choose t he im plem ent at ion, t he const ruct ion is
very sim ple, and t he client will have access t o all propert ies. I t 's im port ant t o underst and not t o j ust
go on and creat e fact ories t o creat e each and every inst ance, but t o use fact ories where t hey help
you out and add clarit y t o and reveal t he int ent ion of t he Dom ain Model.
What is t ypical of t he Fact ory is t hat it set s up t he inst ance in a valid st at e. One t hing I have becom e
pret t y fond of doing is set t ing up t he sub- inst ances wit h Null Obj ect s [ Woolf Null Obj ect ] if t hat 's
appropriat e. Take an Order, for exam ple. Assum e t hat t he shipm ent of an Order is t aken care of by a
transporter.
At first , t he Order hasn't been shipped ( and in t his case we have not t hought m uch about shipm ent at
all) , so we can't give it any transporter obj ect , but inst ead of j ust leaving t he TRansporter propert y
as null, I set t he propert y t o t he em pt y ( " not chosen," perhaps) transporter inst ead. I n t his way, I
can always expect t o find a descript ion for t he TRansporter propert y like t his:
anOrder.Transporter.Description
I f TRansporter had been null, I would have needed t o check for t hat first . The Fact ory is a very handy
solut ion for t hings like t his. ( You could do t he sam e t hing in t he case of a const ruct or, but t here
m ight be m any places you need t o apply Null Obj ect s, and it m ight not be t rivial t o decide on what t o
use for Null Obj ect s if t here are opt ions. What I 'm get t ing at is t hat t he com plexit y of t he const ruct or
increases.)
You can, of course, have several different Fact ory m et hods and let t hem t ake m any param et ers so
you get good cont rol of t he creat ion from t he out side of t he Fact ory.
Using Fact ories can also hide infrast ruct ure requirem ent s t hat you can't avoid.
I t 's ext rem ely com m on t o hear about Fact ories and see t hem used in a less sem ant ic way, or at least
different ly so t hat all inst ances ( new or " old" ) are creat ed wit h Fact ories. I n COM for exam ple, every
class has t o have a class fact ory, as do m any fram eworks. Then it 's not t he Dom ain Pat t ern Fact ory
t hat is used: sim ilar in nam e and in t echnique, different in int ent ion.
Anot her exam ple is t hat you can ( indirect ly) let t he Fact ory go t o t he dat abase t o fet ch default
values. Again, it 's good pract ice t o not have m uch processing in const ruct ors, so t hey are not a good
place t o have logic like t hat .
N ot e
Now we have a problem . I t shouldn't be possible t o set som e propert ies from t he out side;
however, we need t o get t he values t here. This is done when a Fact ory set s default values
( and when a Reposit ory fet ches an old inst ance from t he dat abase) . Perhaps t his feels bad
t o you?
We'll get back t o t his lat er, but for now, rem em ber t hat t his is oft en a problem anyway
because reflect ion can be used for changing t he inner st at e, at least if t hat is allowed
according t o t he securit y set t ings.
My philosophy on t his is t hat you can't fully st op t he program m ers from doing evil when
consum ing t he Dom ain Model, but you should m ake it hard t o do st upid t hings by m ist ake,
and you need t o check t hat evil t hings haven't been done.
Overall, I t hink t he usage of t he Fact ory pat t ern clearly dem onst rat ed t hat som e inst ant iat ion
com plexit y was m oved from t he Order int o a concept of it s own. This also helped t he clarit y of t he
Dom ain Model t o som e degree. I t 's a good clue t hat t he inst ant iat ion logic is int erest ing and com plex.
Summary
This was a quick int roduct ion and m y at t em pt t o get you int erest ed in pat t erns. Hopefully it worked,
because I will use pat t erns as an im port ant t ool in t he following chapt ers.
Now it 's t im e t o dive int o how t o use TDD by discussing som e exam ples.
Chapter 3. TDD and Refactoring
A good exam ple is a powerful t hing; I t hink we are in agreem ent on t hat . One way t o describe Test -
Driven Developm ent ( TDD) is t o say t hat you use t est s or exam ples for specifying t he behavior.
Those exam ples will serve you over and over again for m any different purposes. They will serve you
during developm ent , for exam ple, for finding lacking or incorrect requirem ent s. When you refact or,
t he t est s will be a safet y net . Aft er developm ent t hey will serve you as qualit y docum ent at ion.
I n t his chapt er we will not j ust t alk about t est s as exam ples; we will discuss TDD it self wit h som e
exam ples. I j ust t hink t hat 's a good way of describing what it 's all about .
Aft er som e init ial discussion of TDD and t he st at e- based st yle, m y friend Claudio Perrone will discuss
som e t echniques for creat ing exam ples t he int eract ion- based way, writ ing t est s by using st ubs and
m ocks.
A key principle t hat is used during TDD is refact oring. Even refact oring is pret t y exam ple- cent ric. You
can t hink of it as writ ing a first exam ple of a piece of t he solut ion, t hen using refact oring t o refine
t hat exam ple unt il you're done. So you don't have t o com e up wit h a perfect design up front . That is
good news, because it is close t o im possible anyway.
Again, we will discuss refact oring wit h som e exam ples, of course.
The second st ep is t o writ e t he sim plest possible code t hat m akes t he t est pass.
Then you st art all over again, adding anot her t est .
I f we use xUnit lingo, t he first st ep should give you a red light / bar, and t he second st ep should give
you a green light / bar. ( Unfort unat ely, com pilat ion errors and refact oring don't have colors yet .)
I know, I know. There are an enorm ous num ber of good dem onst rat ion t ext s on how t o use TDD,
such as [ Beck TDD] , [ Ast els TDD] , [ Mart in PPP] . Anyway, I 'd like t o have a go at dem onst rat ing it
m yself. Rat her t han doing what is m ost com m on, I won't use a hom em ade t oy exam ple, but I 'll use
an exam ple from a real- world applicat ion of m ine.
A few years ago, I was asked by Dynapac t o writ e an applicat ion t hat t hey could bundle wit h a new
line of planers t hat t hey produced. The planers are used for rem oving old asphalt before paving out
new. Asphalt m illing is used t o rest ore t he surface of asphalt pavem ent t o a specified profile. Bum ps,
rut s, and ot her surface irregularit ies are rem oved, leaving a uniform , t ext ured surface.
The applicat ion would be used for calculat ing a num ber of different t hings, helping t o opt im ize t he
usage of t he planers. The applicat ion needed t o be able t o calculat e t he hardness of t he old asphalt ,
t he t im e needed t o plane a cert ain proj ect , t he t rucks needed t o keep m illing wit h t he m inim um cost ,
and lot s of ot her t hings.
I 'm going t o use t his real- world applicat ion t o dem onst rat e how TDD can be used so you get a feeling
for t he flow. I 'm going t o focus on calculat ing t he num ber of t rucks.
I t is im port ant t o have t he correct num ber of t rucks for t ransport ing t he old asphalt . I f you have t oo
few, t he planer will have t o st op every now and t hen or m ove slower. I f you have t oo m any, it 's a
wast e of t rucks and personnel. I n bot h cases, t he cost will increase for t he proj ect .
OK, let 's do t his t he TDD way. I 'll st art out by writ ing t he ident ified needed funct ionalit y in a t ext file
like t his:
Calculate millability
Calculate milling capacity
Calculate number of trucks needed
As I said, I 'm going t o focus on t he calculat ion for t he num ber of t rucks now, so I put a m arker in t he
file on t hat line so I know what I decided t o st art wit h. As soon as I ( or m ore likely t he cust om er)
com e up wit h anot her piece of funct ionalit y t hat I don't want t o work on right now, I add it t o t he file.
So t hat t ext file will help m e t o not forget about anyt hing, while st ill enabling m e t o focus on one
t hing at a t im e.
N ot e
Test s and refact orings could be writ t en t o t he sam e file, but I prefer not t o. I nst ead I writ e
t est s t agged wit h t he Ignore at t ribut e for t est s t hat I don't want t o focus on now.
Refact oring needs t hat I find, but I don't want t o deal wit h now, are probably not wort h
being done, or t hey will be found again and dealt wit h t hen.
The next t hing t o do is t o t hink about t est s for t he t ruck calculat ion. At first I t hought it was very
sim ple, but t he m ore I t hought about it , I found out it was act ually pret t y com plex.
So let 's st art out by adding a sim ple t est . Let t he t est check t hat when no input is given, zero t rucks
should be needed. First , I creat e a new proj ect t hat I call Tests. I add a class t hat I call
TRuckCalculationTests, and I do t he necessary preparat ions for m aking it a t est fixt ure according t o
NUnit , such as set t ing a reference t o nunit.framework, adding a using clause t o NUnit.Framework, and
decorat ing t he class wit h [TestFixture] . Then I writ e a first t est , which looks like t his:
[Test]
public void WillGetZeroAsResultWhenNoInputIsGiven()
{
TruckCalculation tc = new TruckCalculation();
Assert.AreEqual(0, tc.NeededNumberOfTrucks);
}
As a m at t er of fact , when writ ing t hat ext rem ely sim ple t est , I act ually m ade a couple of sm all design
decisions. First , I decided t hat I need a class called truckCalculation. Second, I decided t hat t hat
class should have a propert y called NeededNumberOfTrucks.
Of course, t he t est proj ect won't com pile yet because we haven't writ t en t he code t hat it t est s, so
let 's cont inue wit h adding t he " real" proj ect , so t o speak. I add anot her proj ect t hat I call
Dynapac.PlanPave.DomainModel . I n t hat proj ect I add a class like t his:
What is a bit irksom e is t hat I fake t he ret urn value t o - 1. The reason is t o force a failure for m y t est .
Rem em ber, we should always st art wit h an unsuccessful t est , and for t his specific t est j ust ret urning
zero would clearly not fail. I t should fail m eaningfully, but I can't com e up wit h a really m eaningful
failure and st ill st art out as sim ple ( neit her now nor when I wrot e t his in t he real proj ect ) , so t his will
have t o do.
I s t here anyt hing t o refact or? Well, I 'm pret t y happy wit h t he code so far. I t 's t he sim plest code I can
t hink of right now t hat sat isfies t he t est s ( oragaint he t est ) .
We have t aken a sm all st ep in t he right direct ion. We have st art ed working on t he new funct ionalit y
for calculat ing num ber of t rucks, and we have a first sim plebut goodlit t le t est .
Let 's t ake anot her sm all st ep. Again, we t ake t he st ep by let t ing t est s drive our progress. So we need
t o com e up wit h anot her t est . I n t he t est ing area, I need t o show bot h a rounded result and a m ore
exact result , at least t o one decim al. The rounded result m ust always be rounded up because it 's
hard t o creat e a half t ruck. ( I know what you are t hinking, but it 's not in t he cust om er requirem ent s
t o deal wit h a m ix of different - sized t rucks.) That 's a decent and necessary t est , but I don't feel like
dealing wit h it now. I want t o t ake a m ore int erest ing st ep, so I add t he rounding t est wit h t he Ignore
at t ribut e like t his:
I nst ead, I 'd like t o t ake a st ep wit h t he calculat ion. Heck, it can't be so hard t o calculat e t his. I have
t o t ake t ransport at ion dist ance int o account , as well as t ransport at ion speed, t ruck capacit y, m illing
capacit y, unloading t im e, loading t im e, and probably a couple of ot her t hings. Moving on and
sim plifying a bit , let 's say t hat I don't care about t ransport at ion for now, nor t he t im e for loading. I
won't even care about ot her fact ors t hat are as yet unknown t o m e. The only t hings I care about now
are m illing capacit y, t ruck capacit y and t im e for unloading. So t hings are sim ple enough for t he
m om ent . I can writ e a t est like t his:
[Test]
public void CanCalculateWhenOnlyCapacityIsDealtWith()
{
TruckCalculation tc = new TruckCalculation();
tc.MillingCapacity = 20;
tc.TruckCapacity = 5;
tc.UnloadingTime = 30;
Assert.AreEqual(2, tc.NeededNumberOfTrucks);
}
What I j ust did was t o assum e t he m illing capacit y was 20 t ons/ hour and each t ruck can deal wit h 5
t ons each t im e, which m eans 4 unloadings. I also assum ed t hat unloading t he t ruck t akes 30
m inut es, so each t ruck can only be used t wice in one hour. That should m ean t hat we need 2 t rucks,
so I t est for t hat .
N ot e
The calculat ion m ight seem a bit st range so far because t oo few fact ors are t aken int o
account and I j ust t ried t o get st art ed wit h it . The im port ant t hing here isn't t he calculat ion
it self, but t he process of how t o m ove forward wit h TDD, so please don't let t he calculat ion
it self dist ract you.
When I t ry t o com pile t he Tests proj ect , it fails because t he new t est expect s t hree new propert ies.
Let 's add t hose propert ies t o t he TRuckCalculation class. They could look like t his:
//TruckCalculation
public int TruckCapacity = 0;
public int MillingCapacity = 0;
public int UnloadingTime = 0;
Hm m m , t hat wasn't even propert ies, j ust public fields. We'll discuss t his lat er. Now we can build t he
solut ion, and hopefully we'll now get a red bar.
Yes, expect ed and want ed. We need t o m ake a change t o NeededNumberOfTrucks, t o m ake a real ( or,
at least , m ore real) calculat ion.
//TruckCalculation
public int NeededNumberOfTrucks
{
get
{
return MillingCapacity /
(TruckCapacity * 60 / UnloadingTime);
}
}
I now realize t hat t his was perhaps t oo big a leap t o t ake here, but I 'm feeling confident now.
Let 's build again and t hen re- execut e t he t est s. Green bar; oops...r e d. How can t hat be? Ah, it
wasn't t he last t est t hat was t he problem ; t hat t est runs successfully. I t 's t he old t est t hat now fails. I
get an except ion from it . Of course, t he first t est doesn't give any values t o t he truckCapacity and
UnloadingTime propert ies, so I get a division by zero. A silly m ist ake t o m ake, but I 'm act ually very
happy about t hat red bar. Even t hat t iny lit t le first t est helped m e by finding a bug j ust m inut es ( or
even seconds) aft er I creat ed t he bug, and t his ext rem ely short feedback loop is very powerful.
So we build, run t he t est s, and get a green bar. Goodanot her st ep in t he right direct ion, secured ( at
least t o a cert ain degree) wit h t est s.
Any refact orings? Well, I 'm pret t y sure several of you hat e m y usage of t he public fields. I used t o
hat e t hem m yself, but I have since changed m y m ind. As long as t he fields are bot h readable and
writ able and no int ercept ion is needed when reading or writ ing t he values, t he public fields are at
least as good as propert ies. The good t hing is t hat t hey are sim pler; t he bad t hing is if you need t o
int ercept when one of t he values is set . I will refact or t hat lat er, if and when necessary, and not
before.
N ot e
There is a difference bet ween public fields and public propert ies when it com es t o reflect ion,
and t hat m ight creat e problem s for you if you choose t o swit ch bet ween t hem .
A reviewer point ed out anot her difference t hat I didn't t hink about : t he fact t hat public
propert ies can't be used as ref argum ent s, but t hat 's possible wit h public fields.
This whole discussion is also language dependent . I n t he case of C# / VB.NET, a public field
and public propert y is used t he sam e way by t he consum er, but t hat 's not t he case wit h
C+ + and Java, for exam ple.
Anot her t hing I could refact or is t o add a [SetUp] m et hod t o t he t est class t hat inst ant iat es a
calculat ion m em ber on t he inst ance level. That 's right ; don't forget about your t est s when you t hink
about refact oring. Anyway, I can't say I feel com pelled t o do t hat change eit her, at least not right
now. I t would reduce duplicat ion a lit t le bit , but also m ake t he t est s slight ly less clear. I n t he case of
t est s, clarit y is oft en a higher priorit y.
Yet anot her t hing t hat I 'm not very happy about is t hat t he code for t he calculat ion it self is a bit
m essy. I t hink a bet t er solut ion would be t o t ake away what I t hink will be t he least com m on
sit uat ion of zero values in a guard. I n t his way, t he ordinary and real calculat ion will be clearer. This
change is not ext rem ely im port ant and is m ore a m at t er of personal t ast e, but I t hink it m akes t he
code a lit t le m ore readable. Anyway, let 's m ake t he refact oring called Replace Nest ed Condit ional
wit h Guard Clauses [ Fowler R] :
//TruckCalculation
public int NeededNumberOfTrucks
{
get
{
if (TruckCapacity == 0 || UnloadingTime == 0)
return 0;
return MillingCapacity /
(TruckCapacity * 60 / UnloadingTime);
}
}
N ot e
Just like pat t ern nam es, refact oring nam es can be used as a m eans of com m unicat ion
am ong developers.
Build t he t est s and t hen run t hem . We st ill see green bars, and t he code is clearer, but we can do
bet t er. I t hink it 's a good idea here t o use Consolidat e Condit ional Expression [ Fowler R] like t his:
//TruckCalculation
public int NeededNumberOfTrucks
{
get
{
if (_IsNotCalculatable())
return 0;
return MillingCapacity /
(TruckCapacity * 60 / UnloadingTime);
}
}
And while I 'm at it , t he form ula is a bit unclear. I reveal t he purpose bet t er if I change part of it int o
a propert y call inst ead by using Ext ract Met hod refact oring [ Fowler R] like t his:
return MillingCapacity /
_SingleTruckCapacityDuringOneHour;
That 's fine for now, but it 's t im e t o add anot her t est . However, I t hink t his lit t le int roduct ion t o
writ ing a new class for calculat ing t he needed num ber of t rucks was enough t o show t he flow of TDD.
Som e of you m ight dislike t hat you don't get help from int ellisense ( which helps you cut down on
t yping by " guessing" what you want t o writ e) when writ ing t est s first . I 'm fond of int ellisense t oo, but
in t his case I don't m iss it . Rem em ber, what we are t alking about here is t he int erface, and it could
be good t o writ e it t wice t o get an ext ra check.
Also not e t hat you should vary your speed depending upon how confident you are wit h t he code you
are writ ing at t he m om ent . I f it t urns out t hat you are t oo confident and t oo eager so t hat you get
int o hard problem s, you can slow down and writ e sm aller t est s and sm aller chunks t o get back t o
m oving forward.
Design Effects
During t he dem o I said t hat writ ing t he t est s was very m uch a design act ivit y. Here I have list ed
som e of t he effect s I have found when designing wit h TDD inst ead of det ailed up- front design:
M or e clie n t con t r ol
I used t o t hink t hat as m uch as possible should be hidden from t he out side regarding
configurat ion so t hat classes configure t hem selves. To use TDD, you need t o m ake it possible
for t he t est s t o set up t he inst ances t he way t hey need t hem . This is act ually a good t hing
because t he classes becom e m uch easier t o reuse. ( Of course, wat ch out so you don't open up
t he pot ent ial for m ist akes.)
M or e in t e r fa ce s/ fa ct or ie s
I n order t o m ake it possible ( or at least easier) t o use st ubs or m ock obj ect s, you will find t hat
you need t o gat her funct ionalit y via int erfaces so you can pass in t est obj ect s rat her t han t he
real obj ect s, which m ight be hard t o set up in t he t est environm ent . I f you com e from a COM
background, you will have learned t he hard way t hat working wit h int erfaces has m any ot her
m erit s.
N ot e
There will be m ore discussion about st ubs and m ocks lat er on in t he chapt er. For now, let 's
say t hat st ubs are " st and- ins" t hat are lit t le m ore t han em pt y int erfaces t hat provide
canned values creat ed for t he sake of being able t o develop and t est t he consum ers of t he
st ubs. Mocks are anot her kind of " st and- ins" for t est purposes t hat can be set up wit h
expect at ions of how t hey should be called, and aft erward t hose expect at ions can be
verified.
M or e su b- r e su lt s e x pose d
I n order t o be able t o m ove a t iny st ep at a t im e, you need t o expose sub- result s so t hat t hey
are t est able. ( I f I had cont inued t he dem o, you would have seen m e expose m ore sub- result s
for t he t ransport at ion and load t im e, for exam ple.) As long as t he sub- result s are j ust read only,
t his is not such a big deal. I t 's com m on t hat you will need t o expose sub- result s in t he user
int erface anyway. Just be careful t hat you don't expose t oo m uch of your algorit hm s. Balance
t his carefully against t he ordinary t arget of inform at ion hiding.
M or e t o t h e poin t
I f I had st art ed wit h det ailed up- front design for t he dem o exam ple, I 'm pret t y sure t hat I
would have invent ed a t ruck class holding ont o loads of propert ies for t rucks. Because I j ust
focused on what was needed t o m ake t he t est s run, I skipped t he t ruck class com plet ely. All I
needed t hat was closely t ruck- relat ed was a t ruck capacit y propert y, and I kept t hat propert y
direct ly on t he t ruck calculat ion class.
Le ss cou plin g
TDD yields less coupling. For inst ance, because UI is hard t o t est wit h aut om at ic t est s, t he UI
will m ore or less be forced not t o int erm ingle wit h t he Dom ain Model. The coupling is also
great ly reduced t hanks t o t he increased usage of int erfaces.
As I have already st at ed, t he design effect s are not t he only good t hings. There are loads of ot her
effect s, such as
When you use TDD, t he API has already been used once when t he t im e com es for your
consum er t o use it . Probably, t he consum er will find t hat t he API is bet t er and m ore st able t han
it would have been ot herwise.
Fu t u r e m a in t e n a n ce
Maint enance goes like a dream when you have ext ensive t est suit es. When you need t o m ake
changes, t he t est s will t ell you im m ediat ely if it breaks on consum ers.
I f you don't have ext ensive t est suit es when you need t o m ake changes, you can go ahead and
creat e t est s before m aking t he changes. I t 's not m uch fun, and you probably won't be able t o
creat e high- qualit y t est s long aft er t he code was writ t en, but it 's oft en a bet t er approach t han
j ust m aking t he changes and crossing your fingers. You t hen have t est s when it 's t im e for t he
next change, and t he next .
Despit e using TDD, bugs will appear in product ion code. When it happens and you are about t o
fix t he bug, t he process is very sim ilar t o t he ordinary TDD one. You st art by writ ing a t est t hat
exposes t he bug, and t hen writ e t he code t hat m akes t he t est s ( t he new and all t he old t est s)
execut e successfully. Finally, you refact or if necessary.
D ocu m e n t a t ion
The t est s you writ e are high- qualit y docum ent at ion. This is yet anot her good reason for writ ing
t hem in t he first place. Exam ples are really helpful in order t o underst and som et hing, and t he
t est s are exam ples bot h of what should work and what shouldn't .
Anot her way of t hinking about t he unit t est s is t hat you reveal your assum pt ions, and t hat goes
for t he ot her developers, t oo. I m ean, t hey reveal t heir assum pt ions about your class. I f t heir
t est s fail, it m ight be because your class isn't behaving as is expect ed, and t his is very valuable
inform at ion t o you.
A sm a r t e r com pile r
I n t he past I have t ried hard t o m ake t he com piler help m e by t elling m e when I do som et hing
wrong. Test s are t he next level up from t hat . The t est s are pret t y good at finding out what t he
com piler m isses. Anot her way of st at ing it is t hat t he com piler is great at finding synt ax
problem s, and t he t est s will find sem ant ic problem s.
I t 's even t he case t hat you probably will value t ype safet y a lit t le less when you are using TDD
because t est s will cat ch t ype m ist akes easily. That in it s t urn m eans t hat you can t ake
advant age of a m ore dynam ic st yle.
I f you follow t he ideas of TDD, you will also find t hat you don't need t o spend nearly as m uch
t im e wit h t he debugger as you would ot herwise have t o.
N ot e
Even so, t here m ight be sit uat ions where you need t o inspect t he values of variables, and
so on. You can use Console.WriteLine() calls, and you can run t he t est s wit hin t he
debugger. Personally I t hink it 's a sign of t oo big leaps or t oo few t est s when I get t he urge
t o use t hose t echniques.
Re u sa bilit y ch a n ce in ot h e r t e st s
The t est s you writ e during developm ent will also com e in handy for t he int egrat ion t est s. I n m y
experience, m any product ion t im e problem s are caused because of differences in t he product ion
environm ent com pared t o what is expect ed. I f you have an ext ensive set of t est s, you can use
t hem for checking t he deploym ent of t he finished applicat ion as well. You pay once, but reap
t he benefit s m any t im es over.
To sum m arize it all, t est - friendly design ( or t est abilit y) is a very im port ant design goal nowadays. I t 's
perhaps t he m ain fact or when you m ake design choices.
Problems
I have sounded like a salesm an for a while. However, t here are problem s t oo. Let 's have a look at t he
following:
UI
I t is hard t o use TDD for t he UI . TDD fit s easier and bet t er wit h t he Dom ain Model and t he core
logic, alt hough t his isn't necessarily a bad t hing. I t helps you be st rict in split t ing t he UI from
t he Dom ain Model, which is a basic design best pract ice ( so it should be done anyway, but TDD
st im ulat es it ) . Ensure you writ e very t hin UI and fact or out logic from t he form s.
Pe r sist e n t da t a
Dat abases do cause a t ricky problem wit h TDD because once you have writ t en t o t he dat abase
in one t est , t he dat abase is in anot her st at e when it 's t im e for t he next t est , and t his causes
t rouble wit h isolat ion. You could writ e your code t o set up t he dat abase t o a well- known st at e
bet ween each t est , but t hat adds t o t he t est er's burden and t he t est s will run m uch m ore
slowly.
You could also writ e t est s so t hat t hey aren't affect ed by t he changed st at e, which m ight reduce
t he power of t he t est s a bit . Yet anot her solut ion is t o use st ubs or m ock obj ect s t o sim ulat e t he
dat abase apart from during t he int egrat ion t est s when a backup of t he dat abase is rest ored
before t he t est s.
Yet anot her way is t o use t ransact ions purely for t he sake of t est ing. Of course, if your t est s
focus on t he t ransact ional sem ant ics, t his isn't a useful solut ion.
N ot e
We will discuss dat abase bound t est ing m ore in Chapt er 6, " Preparing for I nfrast ruct ure."
Fa lse se n se of se cu r it y
Just because you get a green bar doesn't m ean t hat you have zero bugsit j ust m eans t hat your
t est s haven't det ect ed any bugs. Make sure t hat TDD doesn't lead you int o a false sense of
securit y. Rem em ber t hat a green t est doesn't prove t he absence of bugs, only t hat t hat
part icular t est execut ed wit hout det ect ing a problem .
On t he ot her hand, j ust because your t est s aren't perfect doesn't m ean t hat you shouldn't use
t hem . They will st ill help you quit e a lot wit h im proving t he qualit y!
As m y friend Mat s Helander once said, t he value isn't in t he green, but in t he red!
TDD can be seen as a bot t om - up approach, and you m ust be aware t hat you m ight lose t he
overview from t im e t o t im e. I t 's definit ely a very good idea t o visualize your code from t im e t o
t im e as UML, for exam ple, so you get a bird's eye perspect ive. You will m ost cert ainly find
several refact orings t hat should be applied t o prepare your code for t he fut ure.
M or e code t o m a in t a in
The m aint enance aspect is a double- edged sword. The t est s are great for doing m aint enance
work, but you also have m ore code t o m aint ain.
I j ust said t hat TDD is hard t o apply for t he UI and dat abase, and t hat 's j ust one m ore reason why
t he Dom ain Model pat t ern shines because you can t ypically run m ore m eaningful t est s wit hout
t ouching t he dat abase and t he UI com pared t o when ot her logical st ruct ures have been used! That
said, we will discuss bot h dat abase t est ing and UI t est ing in lat er chapt ers.
Then aft er a while you will probably find t hat set t ing up som e t est s get s overly com plex and t oo
dependent on unint erest ing part sunint erest ing for t he t est it self at least . That 's a good sign t hat you
have reached t he next phase of TDD. My friend Claudio Perrone will t alk m ore about t hat in t he next
sect ion called m ocks and st ubs.
Mocks and Stubs
I said t hat we will t alk about dat abase t est ing lat er in t he book. I t 's act ually already t im e for t he first
incarnat ion of t hat . Here Claudio Perrone will discuss how you apply t he t echnique of st ubs and
m ocks in your t est ing. I n t he previous sect ion, I t alked about what is called st at e- based t est ing. Here
Claudio will focus on int eract ion- based t est ing.
To not run in advance, Claudio will use a classic approach for his dat abase- relat ed exam ples before
we really dive int o using t he Dom ain Model pat t ern in t he next chapt er.
Over t o Claudio.
By Claudio Perrone
A com m on approach for t est ing t he behavior of an obj ect is t o set it up wit h relevant cont ext
inform at ion, call one of it s m et hods, and writ e a few assert ions t o check t he ret urn value or t o verify
t hat t he m et hod changed t he st at e of t he environm ent as expect ed.
The following exam ple, which t est s t he SaveUser() m et hod of t he UserBC business com ponent ,
illust rat es t his approach:
Because t he UserBC business com ponent t akes a business ent it y and saves it t o t he dat abase, t he
t est checks it s behavior by creat ing t he ent it y, passing it as a param et er t o t he SaveUser() m et hod,
and verifying t hat t he ent it y is persist ed t o t he dat a st ore.
Declaration of Independence
A pot ent ial problem wit h t his t est ing st yle is t hat obj ect s very rarely operat e in isolat ion. Ot her
obj ect s t hat our obj ect under t est depends on oft en carry out part of t he work.
To illust rat e t his issue wit h our exam ple, we could im plem ent t he UserBC class as follows ( for
convenience, all except ion- handling code is om it t ed) :
I n t his case, UserBC delegat es t he user validat ion t o t he UserInfo business ent it y. I f one or m ore
business rules are broken, UserInfo will t hrow a cust om except ion cont aining a collect ion of
validat ion errors. UserBC also delegat es t he persist ence of t he business ent it y t o t he UserDao dat a
access obj ect t hat has responsibilit y for abst ract ing all dat abase im plem ent at ion det ails.
As IUserInfo is an explicit param et er of t he SaveUser() m et hod, we can argue t hat UserBC explicit ly
declares a dependency on t he IUserInfo int erface ( im plem ent ed by t he UserInfo class) . However,
t he dependency on UserDao is som ewhat hidden inside t he im plem ent at ion of t he UserBC class.
To com plicat e m at t ers furt her, dependencies are t ransit ive. I f UserBC depends on UserInfo and, for
exam ple, UserInfo needs a set of BusinessRule obj ect s t o validat e it s cont ent , UserBC depends on
BusinessRule. A bug in a BusinessRule obj ect could suddenly break our t est and several ot hers at t he
sam e t im e.
I ndeed, t he com plex logic handled by a Dom ain Model is oft en im plem ent ed t hrough a chain of
obj ect s t hat forward part of t he behavior t o ot her collaborat ing obj ect s unt il t he required result is
creat ed. Consequent ly, unit t est s t hat aim at verifying t he behavior of an obj ect wit h m any
dependencies m ight fail if one of t he obj ect s in t he chain has bugs. As a result , it is som et im es
difficult t o ident ify t he cause of an error, as t he t est s are essent ially sm all- scale int egrat ion t est s,
rat her t han " pure" unit t est s.
Are difficult t o set up or t est ( for exam ple, user int erface com ponent s or m essaging channels)
Are t oo slow ( such as dat a access layer com ponent s, service agent s, or dist ribut ed com ponent s)
Cont ain behavior t hat is difficult t o reproduce ( such as int erm it t ent net work connect ivit y or
concurrency issues)
Let 's go back t o our exam ple. I n t his case, we have t wo close collaborat ors in t he SaveUser()
m et hod UserInfo and UserDao. UserInfo is easy t o subst it ut e, as our t est sim ply needs t o provide an
obj ect t hat im plem ent s t he IUserInfo int erface and does not t hrow except ions when it s Validate()
m et hod is called ( unless, of course, we want t o t est t he behavior of t he SaveUser() m et hod when a
validat ion except ion occurs) .
UserDao is m uch m ore difficult t o replace because t he const ruct ion of t he obj ect is em bedded inside
t he UserBC class. We really want t o subst it ut e t his collaborat or, however, because it s access t o t he
dat abase will slow down t he execut ion of our t est s. Addit ionally, checking values in t he dat abase is
t im e consum ing and possibly of value only when t est ing UserDao in isolat ion or wit hin an int egrat ion
t est . One viable solut ion is t o ext ract t he int erface from UserDao and add a const ruct or t o t he UserBC
class t hat set s an explicit dependency on IUserDao .
The required code is very sim ple, wit h very low probabilit y of int roducing bugs. I n som e cases, you
m ay even consider writ ing it in addit ion t o t he exist ing const ruct or( s) for t est ing purposes only.
// Default constructor
public UserBC()
{
_daoUser = new UserDao();
}
if (user.IsNew)
_daoUser.Insert(user);
else
_daoUser.Update(user);
}
}
Now we can easily creat e a couple of st ubs t hat im plem ent IUserInfo and IUserDao . Their
im plem ent at ion is t rivial, so let 's exam ine UserDaoStub only.
First , our init ial t est was set t ing a couple of expect at ions about t he st at e of t he IUserInfo obj ect as a
result of calling t he SaveUser() m et hod. I f we m odify our t est so t hat it uses a UserDaoStub obj ect , we
will also need t o set up t he expect ed result by set t ing t he UserResult propert y before t he Insert()
m et hod is execut ed.
A second aspect t o consider is t hat t he dependency on t he dat abase is now com plet ely rem oved and
our init ial t est is now m uch fast er.
Because SaveUser() delegat es m ost of it s behavior, however, such a t est provides virt ually no value.
Act ually, on second t hought , I would also add t hat we are com m it t ing t he deadly ( but unfort unat ely
com m on) sin of put t ing assert ions on values ret urned from our st ubs. So we are effect ively t est ing
our st ubs rat her t han UserBC!
On t he ot her hand, it 's a different st ory if we want t o know how our UserBC class react s when t he
dat a access layer t hrows an except ion such as DalUnique-ConstraintExceptiona sit uat ion t hat could
occur if t he user login already exist s on t he dat abase.
//UserDaoStub
public void Insert(IUserInfo user)
{
if (ThrowDalUniqueConstraintExceptionOnInsert)
throw new DalUniqueConstraintException();
user.ID = UserResult.ID;
user.Name = UserResult.Name;
// etc
}
Assum e we'd like t he UserBC t o cat ch t he DalUniqueConstraintException and t hrow a proper business
except ion t o m aint ain t he abst ract ion of t he layers. The following t est illust rat es t his scenario:
As you m ight expect , t he t est is very fast , doesn't require access t o t he dat abase or ot her
collaborat ors, and allows us t o quickly verify t he funct ionalit y of t he class under t est in a condit ion
t hat is pot ent ially hard t o recreat e. Sim ulat ing ot her condit ions becom es a very sim ple exercise.
This brings us t o an im port ant lesson about st ubs. Using t est ing st ubs allow us t o isolat e t he code
under t est and t o observe how it react s t o t he ext ernal condit ions sim ulat ed by t he faked
collaborat ors.
To illust rat e what t his m eans, let 's creat e a t est t hat focuses on t he int eract ion of UserBC wit h t he
collaborat ing obj ect s. This t im e we will use a popular .NET m ock obj ect s fram ework called NMock
[ NMock] . A nice feat ure of t his open source fram ework is t hat it uses reflect ion t o generat e m ocks
dynam ically from exist ing classes or int erfaces at run t im e.
[Test]
public void TestUserBCSaveUserInteractsWell()
{
// (1 - Setup) Create mocks dynamically based on interface
DynamicMock mockUser =
new NMock.DynamicMock(typeof(IUserInfo));
DynamicMock mockUserDao =
new DynamicMock(typeof(IUserDao));
N ot e
NMock eit her produces a class t hat im plem ent s an int erface or generat es a subclass of a
real class. I n bot h cases, we t hen use polym orphism t o replace t he real class wit h an
inst ance of t he generat ed class. Alt hough really powerful, t his approach present s som e
not able lim it at ions. For exam ple, it is not possible t o creat e m ocks of sealed classes, and
m ocked m et hods m ust be m arked as virtual.
An int erest ing alt ernat ive t o NMock is a com m ercial fram ework called POCMock [ POCMock]
from Pret t y Obj ect s. I n t his case, m ocks are creat ed by replacing collaborat ors st at ically.
As you can see, t here is no need for assert ions in our t est because t hey are locat ed inside t he m ock
obj ect s and are designed t o ensure t hat t he m ocks are called as expect ed by t he code under t est . For
exam ple, calling Validate() t wice would im m ediat ely t hrow an except ion even before t he call t o
Verify() is m ade.
This exam ple leads us t o t he following observat ion: As m ock obj ect s verify whet her t hey are used
correct ly, t hey allow us t o obt ain a finer underst anding of how t he obj ect under t est int eract s wit h
t he collaborat ing obj ect s.
Design Implications
When I first learned about m ock obj ect s, I t hought t hat it was part icularly t ricky t o com e up wit h an
easy m echanism t o replace m y collaborat ors. The fundam ent al problem was t hat m y code was
coupled wit h t he concret e im plem ent at ion of t hose collaborat ors rat her t han t heir int erfaces. The
" aha! " m om ent cam e when I discovered t wo key m echanism s called Dependency I nj ect ion and
Service Locat or .
The first principle, Dependency I nj ect ion, suggest s t hat a class explicit ly declares t he int erfaces of it s
collaborat ors ( for exam ple, in t he const ruct or or as param et ers in a m et hod) but leaves t he
responsibilit y for t he creat ion of t heir concret e im plem ent at ion t o t he cont ainer. Because t he class is
not in cont rol of t he creat ion of it s collaborat ors anym ore, t his principle is also known as I nversion of
Cont r ol.
The second principle, Service Locat or, m eans t hat a class int ernally locat es it s concret e collaborat ors
t hrough t he dependency on anot her obj ect ( t he locat or) . A sim ple exam ple of a locat or could be a
fact ory obj ect t hat uses a configurat ion file t o load t he required collaborat ors dynam ically.
N ot e
There will be m uch m ore coverage about Dependency I nj ect ion, I nversion of Cont rol, and
Service Locat or in Chapt er 10, " Design Techniques t o Em brace."
Consequences
Mock obj ect s and st ubs perm it you t o furt her isolat e t he code t hat needs t o be t est ed. This is an
advant age, but can also be a lim it at ion, as t est s can occasionally hide int egrat ion problem s. While
t est s t end t o be quicker, t hey are oft en coupled t oo closely wit h t he syst em under t est .
Consequent ly, t hey t end t o becom e obsolet e as soon as a bet t er im plem ent at ion for t he syst em
under t est is found.
Refact oring act ivit ies aim ed at int roducing m ocks t end t o decouple obj ect s from a part icular
im plem ent at ion of t heir dependencies. Alt hough it is generally achievable t o creat e m ocks from
classes cont aining virt ual m et hods, it is usually recom m ended t o use int erfaces whenever possible.
As a result , it is not rare t o observe t hat syst em s designed t o be t est ed using m ock obj ect s cont ain a
significant num ber of int erfaces int roduced for t est ing purposes only.
Further Information
For a m ore in- dept h discussion of t he differences bet ween m ock obj ect s and st ubs ( and st at e- based
versus int eract ion- based t est ing) , see Mart in Fowler's " Mocks Aren't St ubs" [ Fowler Mocks Aren't
St ubs] .
Thanks Claudio! We are st rengt hened wit h yet anot her t ool; can we resist get t ing yet one m ore?
Next up is refact oring.
Refactoring
I m ent ioned refact oring previously as t he t hird st ep in t he general process of TDD, and I t hink I
should briefly explain t he t erm a bit m ore. Refact oring is about m aking sm all, well- known changes
st ep- by- st ep in order t o im prove t he design of exist ing code. That is, you m ake changes t o im prove
t he m aint ainabilit y of t he code wit hout changing it s observed behavior. Anot her way t o say it is t o
change how , not what .
The t erm " refact oring" has becom e som et hing of a buzzword; it 's m uch overused and also m isused.
For inst ance, inst ead of saying t hat we are going t o m ake loads of significant and ground- breaking
changes t o our code base, we say t hat we will refact or it . That 's not , however, t he cent ral m eaning of
t he t erm .
We t alked quit e a lot about what refact oring is and why you should use it in Chapt er 1. I n t his sect ion
about refact oring, we'll t ake a look at how it 's used. We will st art wit h som e basic refact orings for
rout ine cleaning. Then we'll t alk briefly about how product ivit y could gain from new t ooling support .
Finally, we'll refact or t o, t oward, or from pat t erns for prevent ing t he occurrence of m aint ainabilit y
issues.
return years;
}
else
return 0;
}
}
Smelly Code
I have t alked about sm elly code m any t im es already by now, and code sm ells will be t he
focus of our refact oring effort s for t he com ing pages. Therefore, I 'd like t o point out t hat
Mart in Fowler and Kent Beck present s a list of code sm ells in t he Refact or ing book
[ Fowler R] .
A t ypical exam ple, and also t he first one, is t he code sm ell called Duplicat ed Code.
Routine Cleanings
The class we j ust saw, Person, is a nice lit t le class t hat probably solves t he problem at hand.
Deducing from t he nat ure of t he class, t he requirem ent was t o t rack nam es and birt hdat es of cert ain
persons, who t heir children are and how old t hese people are. Again, let 's assum e t hat t he
requirem ent s are fulfilled. That 's a good t hing, but we have st art ed t o add t o our t echnical debt
because t he code is a bit m essy, and t hat 's where refact oring com es in. We'll clean up t he code wit h
a couple of exam ples which I have called " Rout ine Cleanings," each of which is based on Fowler's
work [ Fowler R] .
The t arget of t he first exam ple is t he Name- field. I t 's current ly a public st ring and t hat m ight be t oo
m uch for som e t o t ake. Let 's t ransform it from t his:
//Person
_name = name;
}
I said t hat t he requirem ent s were fulfilled before, didn't I ? Well, t hey were, kind of; it was possible t o
set t he Name and read it . However, t he requirem ent s could be fulfilled even m ore successfully. The
read- only aspect of t he Name field wasn't addressed before, but it is now.
Are we done, or could we do bet t er? Well, I t hink it could be even bet t er t o use a public readonly
field inst ead, like t his:
//Person
public readonly string Name;
public Person(string name)
{
Name = name;
}
I t hink t hat was even clearer, but unfort unat ely, t here are drawbacks as well. The one I 'm t hinking
about is t hat it 's not possible t o set t he Name via reflect ion, which is im port ant for m any t ools, such as
m any Obj ect Relat ional ( O/ R) Mappers. I n t his case, I need t he opt ion of set t ing t he Name via
reflect ion, so I decide t o go for t he get - based version inst ead.
That rem inds m e...does all m y consum er code st ill run? Aft er all, t he observable behavior of t he code
has act ually changed slight ly because I require t he Name t o get it s value via t he const ruct or. I get
com piler errors, so t hat 's sim ple t o sort out ; but are we done?
//Some consumer
public void SetNameByReflection()
{
Person p = new Person();
FieldInfo f = typeof(Person).GetField("Name",
BindingFlags.Instance | BindingFlags.Public);
f.SetValue(p, "Jimmy");
...
That snippet set s t he Name field via reflect ion ( you m ight wonder why, but t hat 's not im port ant here) .
This won't work any longer, but t he com piler won't det ect t he problem . Hopefully we have writ t en
aut om at ic t est s t hat will det ect t he problem .
So t he lesson learned is t hat refact oring requires aut om at ic t est s! As a m at t er of fact , refact oring and
TDD are sym biot ic. As I said at t he st art of t his chapt er, t he TDD m ant ra is Red- Green- Refact or, Red-
Green- Refact or....
( Well, refact oring doesn't require TDD; it requires aut om at ic t est s. On t he ot her hand, using TDD is a
great way of get t ing t hose aut om at ic t est s t o be writ t en at all.)
The second problem I 'd like t o address is t he public list of children, which looked like t his:
This solut ion m eans t hat t he consum er can add t o and delet e from t he list wit hout t he parent
knowing about it . ( To be fair, t hat 's not a violat ion t o any requirem ent s here, but I st ill dislike it .) I t 's
also possible t o add strings and ints inst ead of Person- inst ances. I t 's even t he case t hat t he
consum er can swap t he whole list .
A t ypical solut ion is t o creat e a t ype safe Children list class, wit h an Add() m et hod t hat only accept s
Person- inst ances. That addresses t he problem of lack of t ype safet y. I t could also address t he
problem of let t ing t he parent know about t he adds and delet es, but it won't address t he problem of
swapping t he whole list . That can be solved wit h Encapsulat e Field refact oring for t he list it self.
The problem wit h t his solut ion is t hat you have t o writ e som e dum m y code t hat you don't really want
t o have for get t ing t hat t ype safe list . I t 's cert ainly doable, but it 's not t he st yle I current ly prefer. I f
we t arget a plat form wit h generics ( such as .NET 2.0) , we can avoid t he lack of t ype safet y in a nicer
way.
That said, wit h or wit hout generics, I prefer t he st yle of Encapsulat e Collect ion refact oring. First , you
use Encapsulat e Field refact oring so t hat you get t he following code:
//Person
private IList _children = new ArrayList();
public IList Children
{
get {return _children;}
}
At least t he consum er can't swap t he whole list any longer, but t he consum er can st ill add what ever
he want s t o t he list and delet e it em s as well. Therefore, t he next st ep is t o hand out a wrapped list t o
t he consum er like t his:
Finally, we need t o give t he consum er a way of adding elem ent s, so I add an AddChild() m et hod t o
t he Person class like t his:
//Person
public void AddChild(Person child)
{
_children.Add(child);
}
Then we have t he t ype safet y as well, and t he parent knows about when new inst ances are added so
it can int ercept t hat act ion ( if it 's needed, whicht o be fairit act ually isn't in t his part icular exam ple) .
Unfort unat ely, t his has changed t he visible behavior of t he Person class, and t hat has t o be weighed
in as a fact or as t o whet her you can go ahead or not . I n t his case, m ost of t he needed consum er
changes aren't found by t he com piler. Luckily, we have som e aut om at ic t est s in place, st anding in
sort of as a second com piler layer, det ect ing t he problem . The t est t hat looked like t his helped out :
[Test]
public void CanCalculateNumberOfKids()
{
Person p = new Person("Stig");
p.Children.Add(new Person("Ulla"));
p.Children.Add(new Person("Inga"));
Assert.AreEqual(2, p.Children.Count);
}
N ot e
To be very clear, as you saw here, t he t est didn't point out t he real consum er code t hat
needed t o be changed. I t was j ust som e t est code of t he Person- class. Test s of t he
consum er are needed t o point out necessary changes of t he consum er code it self.
The p.Children.Add() lines are easily changed so t hat I get t his inst ead:
[Test]
public void CanCalculateNumberOfKids()
{
Person p = new Person("Stig");
p.AddChild(new Person("Ulla"));
p.AddChild(new Person("Inga"));
Assert.AreEqual(2, p.Children.Count);
}
I t 's kind of unfort unat e t hat t he IList has an Add() m et hod even t hough it has been wrapped as a
read- only list , but t est s easily cat ch t he problem . To solve t hat , I can change Children t o be an
ICollection inst ead.
I s t here any m ore t o do? We need t o do som et hing about t he HowOld() m et hod. I t 's not overly clear,
is it ?
Perhaps you have anot her, m uch bet t er solut ion t o t he problem at hand? Befor e t hinking about a
bet t er solut ion, I 'd like t o sim plify t he code, m aking it easier t o read and underst and. Refact oring is
in it self act ually a way of t rying t o underst and t he code. That 's a nice side effect , and t he bet t er we
underst and it , t he easier we can find sim plificat ions and bet t er solut ions.
//Person
public int HowOld()
{
if (BirthDate != DateTime.MinValue &&
BirthDate < DateTime.Now);
{
int years = DateTime.Now.Year - BirthDate.Year;
return years;
}
else
return 0
}
First , t here are t wo different sit uat ions t hat will ret urn 0. That 's not good. I prefer t o t hrow an
except ion in t he incorrect case.
Next , I 'd like t o t ake out t hat non- int uit ive logical expression by using t he Ext ract Met hod refact oring
t o get an explaining m et hod nam e inst ead. So we go from
if (_CorrectBirthDate())
Alm ost no m at t er what t he logical expression was, it s int ent ion in t he cont ext of t he HowOld() m et hod
is now m uch clearer.
Anot her st yle now com es t o m ind, t hat of Guard clauses, which m eans t hat I should t ake away t he
unusual, alm ost never happens sit uat ion first . I n t his way, I am let t ing go of t he else clause, and t he
code now reads like t his:
if (!_CorrectBirthDate())
throw new ArgumentException("Incorrect birthdate!");
if (_IncorrectBirthDate())
throw new ArgumentException("Incorrect birthdate!");
What 's left is t he calculat ion it self when we have t he unusual sit uat ion t aken care of. I t looks like
t his:
return years;
Yet again I use t he Ext ract Met hod refact oring, m oving t he calculat ion t o anot her privat e m et hod
called _NumberOfYears(). The com plet e HowOld() m et hod t hen looks like t his:
//Person
public int HowOld()
{
if (_IncorrectBirthDate())
throw new ArgumentException("Incorrect birthdate!");
return _NumberOfYears();
}
Sure, we could find m ore t o do ( for exam ple in t he newly creat ed privat e m et hod _NumberOfYears()
or fact oring out som e logic from t he class it self) , but you get t he m essage by now.
I t 's im port ant t o st ress t hat we should re- execut e t he t est s aft er each st ep t o confirm t hat we didn't
int roduce any errors, according t o t he t est s at least .
What we did, t hough, was t im e- consum ing and error prone. I f you use lot s of discipline, it is possible
t o deal wit h t he error proneness, but it 's st ill t im e- consum ing. Having t he concept s in place, but
finding out t hat t hey are t im e- consum ing t o apply is a perfect sit uat ion for using t he support of a
t ool, if you ask m e.
Cleaning Tool
There are several different refact oring t ools around. I f we focus on .NET, we have, for exam ple,
ReSharper [ ReSharper] and Refact or! [ Refact or! ] , which are add- ins t o Visual St udio .NET. I n t he
2005 edit ion of Visual St udio .NET, t here is also built - in refact oring support in t he I DE.
Those refact oring t ools m ake t he changes sim ilar t o what we j ust m ade in order t o help us becom e
m ore product ive. The value of t his should cert ainly not be underest im at ed. As a m at t er of fact , when
you get used t o a refact oring t ool, t here's no way you will want t o give it up!
The t ools not only help you m ake t he changes you want , t hey can also t ell you about when and what
changes need t o be m ade. I n t his way, t he t ools free you t o som e sm all degree from som e of t he
discipline of having t o t hink about refact oring by providing a visual rem inder.
N ot e
Do you rem em ber t hat I said t hat a failing t est is red and a t est t hat execut es successfully
is green, but t hat a need for refact oring doesn't have a color? As a m at t er of fact , t he
refact oring t ool ReSharper uses orange t o t ell you t hat refact oring is needed ( according t o
ReSharper, t hat is) . So before st art ing a new it erat ion, you should also see t o it t hat you
change t he orange int o green by cleaning up t he code before m oving on. Of course, t his
won't m ake it possible for you t o st op t hinking about what code is sm elly yourself; it 's j ust
a help.
When you see a developer in t he flow wit h a good refact oring t ool in his hands, t he speed at which he
m oves is j ust am azing, and wit hout creat ing bad code. I t 's rat her t he opposit e regarding t he code
qualit y!
So far we have m ost ly dealt wit h sim ple st uff. There's not hing wrong wit h t hat , of course, but from
t im e t o t im e you j ust aren't happy wit h t he code even aft er cleaning up t he sm all t hings. I t m ight
also be t hat you have a sit uat ion where t here is a st eady st ream of new problem s t hat needs t o be
cleaned up.
Perhaps you t hink t hat using pat t erns is t he nat ural solut ion t o t hat problem . The problem wit h
pat t erns is t hat t hey are t radit ionally used for up- front design, which oft en m eans t oo m uch
guesswork ( whereas refact oring, as we have discussed, is used lat er on during developm ent ) . Should
you choose pat t erns o r refact oring?
Before discussing t hat any furt her, I t hink a short exam ple of anot her pat t ern is in order. I 'd like t o
discuss t he Tem plat e Met hod pat t ern [ GoF Design Pat t erns] . The idea is t hat you define t he overall
algorit hm , or t em plat e m et hod, in a base class like t his:
VariationPoint();
_DoSomeMoreStuff();
Now t he subclasses can inherit from TotalBase and provide a cust om im plem ent at ion of t he
VariationPoint() m et hod. I t could look like t his:
The consum er code isn't aware of how t he algorit hm is creat ed. I t doesn't even know about t he base
class, only t he subclass. The consum er code could look like t his:
//Some consumer
TotalSub t = new TotalSub();
t.TotalAlgorithm();
Not e t hat you decide in t he base class if t he hook should be opt ional or m andat ory. I n t he previous
exam ple, I used a m andat ory one because I used abstract for t he VariationPoint() m et hod. Wit h
virtual, it would have been opt ional inst ead, such as when you want t o m ake it opt ional for
subclasses t o define a piece of t he t ot al t em plat e m et hod.
Let 's say we decide up front t o use Tem plat e Met hod, which t hen gives us t he problem of deciding
where we should m ake variat ions possible or forced. That 's a very t ough decision.
Nevert heless, pat t erns are ext rem ely useful, and we don't h av e t o choose; we can use bot h pat t erns
and refact oring. As a m at t er of fact , I t hink t hat 's t he way t o go. Refact oring t oward, t o, or from
pat t erns! This is what Kerievsky t alks about in his book Refact oring t o Pat t erns [ Kerievsky R2P] .
Let 's see t his in act ion wit h a fourt h exam ple, which will connect t o t he pat t ern we j ust t alked about .
Prevent Growing Problems Example One: Form Template Method
Let 's assum e t hat we have writ t en a bat ch m onit or in which we can hook in different program s. For a
program t o be a bat ch program , it has t o adj ust t o som e rules, and t hose are basically t o t ell t he
bat ch m onit or ( by som e cust om logging rout ines) when t he program st art s and finishes.
Aft er a while, we will probably have writ t en a couple of bat ch program s, and we will also have
decided t o reuse a base class for each bat ch program so t hat we don't have t o writ e t he log code
over and over again. An exam ple of t he Execute() m et hod in a subclass m ight look like t his:
_DoThis();
_DoThat();
base.LogEnd();
}
What is sm elly here? As you see, t he subclass is responsible for calling up t o t he base class at cert ain
point s in t he execut ion of t he Execute() m et hod. I t hink t hat 's t oo loose a cont ract for t he subclass;
t he developer of t he subclass has t o rem em ber t o add t hose calls and t o do it at t he right places.
Anot her t hing t hat sm ells here ( which is m ore obvious in a m ore realist ic exam ple where t here are
m any log spot s, such as aft er int roduct ion, aft er first phase, aft er second phase and so on) is t hat
wit hin t he core m et hod, t here's a lot of infrast ruct ure code, t hat is, t he log calls. Because of t hat , t he
calls t o t he int erest ing m et hods, such as _DoThis() and _DoThat(), aren't as obvious as t hey should
be.
As I see it , t his code snippet is crying out for Tem plat e Met hod. So let 's use t he refact oring called
Form Tem plat e Met hod [ Kerievsky R2P] .
The basic idea is t o not have a public Execute() in t he subclasses any longer, but t o m ove t hat
responsibilit y t o t he superclass. First let 's m ove t hat Execute() m et hod t o t he superclass. I t could
t hen look like t his:
DoTheWork();
_LogEnd();
}
The _LogStart() and _LogEnd() m et hods are now privat e inst ead of prot ect ed. The DoTheWork()
m et hod is defined in t he following way in order t o force t he subclasses t o im plem ent it :
This is pret t y m uch t he ot her way around. I nst ead of t he subclass calling up t o t he superclass, now
t he superclass calls down t o t he subclass. I f t he variat ion point s are good, t hen t his is a very
powerful solut ion, yet clean and sim ple! The subclass can t ot ally forget about t he infrast ruct ure ( such
as logging) and focus on t he int erest ing and specific st uff, which is t o im plem ent DoTheWork().
( Again, rem em ber t hat t his was a scaled- down version. I n t he real- world case t hat t his was based
on, t here were several m et hods t hat t he subclasses could im plem ent , not j ust one.)
Anot her problem where it is hard t o know whet her t o use t he solut ion up front or not is t he St at e
pat t ern [ GoF Design Pat t erns] . I t 's oft en a m at t er of over- design if you apply it from t he beginning.
I nst ead, it 's oft en bet t er t o wait unt il you know t hat it 's a good idea because you have t he problem .
But I t alked quit e a lot about t he St at e pat t ern in Chapt er 2, " A Head St art on Pat t erns," so I 'm sure
you have a good feeling for how t o approach it .
So we have discussed refact oring t o pat t erns a bit now. I m ent ioned refact oring from pat t erns as
well, so let 's t ake one such exam ple.
More and m ore oft en t he Singlet on pat t ern [ GoF Design Pat t erns] is considered a worst pract ice. The
reason for t hat is you creat e global inst ances, which are oft en a problem in t hem selves. Anot her
problem is t hat singlet ons oft en m ake t he t est s harder t o writ e ( rem em ber, t est abilit y is crucial) , and
t he int eract ion wit h t he singlet ons isn't very clear in t he code.
Let 's assum e you have a code snippet t hat goes like t his:
The refact oring called I nline Singlet on [ Kerievsky R2P] doesn't go " exact ly" like t his, but t his is a
variant .
I nst ead of let t ing t he DoSomething() m et hod call t he global variable ( t he singlet on it self) , t he
DoSomething() m et hod could ask for t he inst ance as a param et er.
Anot her t ypical solut ion is for DoSomething() t o expect t o find t he inst ance as a privat e m em ber t hat
has been inj ect ed at const ruct ion t im e or via a set t er before t he call t o DoSomething() is m ade. Then
DoSomething() goes like t his:
N ot e
To be fair, singlet ons can be used wit hout affect ing t est abilit y in t he previous code if t he
singlet on is inj ect ed by t he consum er. Then you can use a t est obj ect during t est ing, and
t he real singlet on during runt im e.
Problem s? Well, t he m ost apparent problem is t hat if you need t he value way down in t he call st ack,
t he param et er is sent a long way before it 's used. On t he ot her hand, it 's very clear where t he value
is used, and t his m ight be a sign of sm elly code in it self t hat m ight need som e refact oring. So
singlet ons m ight act ually hide sm elly code.
I t 's also t he case t hat Dependency I nj ect ion ( which will be discussed in Chapt er 10) will gracefully
reduce t he problem of t oo m any singlet ons.
Summary
As a sum m ary, I 'd like t o st ress t he point of TDD + Refact oring = = t rue. They are so very m uch in
sym biosis.
I n order t o be able t o use refact oring in a safe way, you m ust carry out ext ensive t est s. I f you don't ,
you will int roduce bugs and/ or you will priorit ize not m aking any changes sim ply for t he sake of
m aint ainabilit y, because t he risk of int roducing bugs is j ust t oo large. And when you st op m aking
changes because of m aint ainabilit y, your code has slowly st art ed t o degrade.
At t he sam e t im e, in order t o use TDD, you will have t o carefully guard your code and keep it clean
all t he t im e by applying refact oring. Also, isolat e your unit t est s wit h t he help of st ubs and m ocks. I f
you don't also guard t he t est code, t hat code has st art ed t o degrade.
TDD + Refact oring is a t ot ally different way of writ ing code com pared t o what m ost of us learned in
school. I f you give it a real t ry, it will t ot ally rock your world, and you won't go back.
Wit h t hese t ools on t he belt , we are ready for an archit ect ure discussion.
Part II: Applying DDD
I n t his part , it 's t im e t o apply DDD. We also prepare t he Dom ain Model for t he infrast ruct ure,
and focus on rules aspect s.
New t o whom , you m ight wonder. I t depends. When you describe Dom ain Model t o som e, t hey will
say " Yes? I sn't t hat how it 's always done?" At t he sam e t im e, anot her large group of developers will
say " Hm m m ... Will t hat work in realit y?"
No m at t er in which of t hose t wo groups you belong, we are j ust about t o st art a j ourney t oget her
exploring t he Dom ain Model, and especially how t o build it in t he spirit of Dom ain- Driven Design
( DDD) .
We will st art t he j ourney wit h a short discussion about Dom ain Models and DDD. To becom e m ore
concret e, we will discuss a list of requirem ent s of an exam ple applicat ion and sket ch possible
solut ions t o different feat ures. To get a bet t er feeling of t he requirem ent s, we will also use anot her
view and sket ch an init ial UI . The chapt er will end wit h a discussion about execut ion st yles for
Dom ain Models.
N ot e
Paul Gielens said t hat a warning is in place regarding t he word " Default " in t he nam e of t his
chapt er. The risk is t hat som e readers will get t he feeling t hat t his is t he way t o approach
all syst em s. Let m e st ress t hat t his is definit ely not t he case; t his book is not aim ing t o be a
t em plat e or som et hing like t hat . Absolut ely not ! I t 's in t he spirit of DDD t o let t he business
problem govern what your solut ion looks like!
When one says " Dom ain Model" in t he cont ext of archit ect ure, what is usually m eant is usage of t he
Dom ain Model pat t ern [ Fowler PoEAA] . I t 's like old school obj ect - orient at ion, in t hat you t ry t o m ap a
sim plified view ( or m ore correct ly st at ed, t he chosen abst ract ion) of t he realit y from your problem
dom ain as closely as possible wit h an obj ect - orient ed m odel. The final code will be very close t o t he
chosen abst ract ions. That goes for bot h st at e and behavior, as well as for possible navigat ion pat hs
and relat ionships bet ween obj ect s.
N ot e
Som eone ( unfort unat ely, I don't rem em ber who) called t he applicat ion of t he Dom ain Model
pat t ern in C# " program m ing C# as if it was Sm all- Talk." To som e, t hat m ight not sound
posit ive at first , but it was said and m eant as a very posit ive t hing.
The Dom ain Model is not t he silver bullet , but it cert ainly com es wit h several posit ive propert ies,
especially for large- scale and/ or com plex applicat ions t hat are long last ing. And as Mart in Fowler says
[ Fowler PoEAA] , if you st art using Dom ain Model for one proj ect , you will probably find yourself
want ing t o use it even for sm all, sim ple applicat ions lat er.
How to Recognize If an Application Will Be Long Lasting
Speaking of long- last ing applicat ions, I especially rem em ber one part icular applicat ion I
was asked t o build. A global dat a com m unicat ion service provider asked m e t o build a
prelim inary help desk applicat ion t o be used at t heir new office in Sweden. Tim e was
t ight t hey needed it t he next day so t hat t hey weren't sit t ing t here wit h paper and pen in
t heir high- t ech office when t he press cam e t o t he opening day. Because it was going t o
be exchanged for a com pany policy st andard applicat ion j ust a few weeks lat er, however,
t hey t old m e t hat building it well wasn't im port ant .
Yep, you guessed right . The quick- and- dirt y applicat ion I built was st ill being used in
product ion five years lat er. Sure, we im proved it a lot , but I couldn't convince t hem t o
change from t he plat form I st art ed using t o som et hing m ore suit able for a m ission-
crit ical applicat ion.
A Dom ain Model- focused design is m ore m aint ainable in t he long run because of it s increased clarit y
and an im plem ent at ion t hat is m ore t rue t o t he abst ract ions of t he dom ain. Anot her very im port ant
reason is t hat a powerful Dom ain Model is a good t ool for decreasing duplicat ion of logic. ( Those are
all propert ies of obj ect - orient at ion as well. I see Dom ain Model as a st yle where obj ect - orient at ion is
used in a pure way, pushing t he lim it s t o writ e m aint ainable code. Oh, and t o increase t est abilit y.)
When you hear t he words " Dom ain Model pat t ern" [ Fowler PoEAA] , it m ight m ean som et hing very
specific t o you, but of course t here are a lot of variat ions on how t o apply t hat pat t ern. Let 's call t he
variat ions different st yles.
As you already know from t he lengt hy discussion in Chapt er 1, DDD is several different t hings; for
exam ple, it is a set of pat t erns for helping out wit h st ruct uring t he Dom ain Model. We will get st art ed
in applying t hose t ools really soon.
But before focusing on t he det ails, I 'd like t o t ake a quick look at layering according t o DDD.
I n one way, I st ill st ress layering a lot . Because I 'm very m uch int o DDD, I t ry hard t o m ove
I nfrast ruct ure, such as persist ence, int o a layer of it s own, away from t he core Dom ain layer.
On t he ot her hand, I 'm m ore relaxed about layering and focus a lot of t he effort s on a single one: t he
Dom ain layer. I won't split t hat layer, t he Dom ain Model, int o finer layers; I let it be pret t y coarse-
grained. ( As a m at t er of fact , som e of t he DDD pat t erns com e in handy for som e of t he problem s I
previously used layering for.)
We have discussed t wo layers so far: I nfrast ruct ure and Dom ain. On t op of t hese t here m ight be an
Applicat ion layer providing som e coordinat ion, but it 's very t hin, only delegat ing t o t he Dom ain layer.
( See Service Layer pat t ern [ Fowler PoEAA] , which is like scenario classes, delegat ing all t he work t o
t he Dom ain Model.)
N ot e
Again, please don't aut om at ically do anyt hing regarding layering j ust because you read
about it in a book! You should challenge every decision!
I t hink t here are few t hings t o not e regarding how I use layering now com pared t o m y old st yle. First
of all, t he Applicat ion layer isn't m andat ory; it is only t here if it really adds value. Since m y Dom ain
layer is so m uch richer t han before, it 's oft en not int erest ing wit h t he Applicat ion layer.
Anot her difference is t hat inst ead of all calls going down, t he I nfrast ruct ure layer m ight " know" about
t he Dom ain layer and m ight creat e inst ances t here when reconst it ut ing from persist ence. The point is
t hat t he Dom ain Model should be oblivious of t he infrast ruct ure.
N ot e
I t is also im port ant t o not e we didn't t ake int o account part it ioning, or slicing t he pieces in
t he ot her dim ension com pared t o layering. This is im port ant for large applicat ions. We get
back t o t his in Chapt er 10, " Design Techniques t o Em brace."
I t 's t im e t o st art our j ourney and t o t ry out som e of t he concept s we have been discussing in t his and
earlier chapt ers, wit h a st rong focus on t he Dom ain layer. I t hink a good way of doing t hat is t o set
up an exam ple.
A First Sketch
To m ake it a bit m ore concret e, let 's use a list of problem s/ feat ures t o discuss how som e com m on
design problem s of an ordering applicat ion could be solved.
I know, I know. The answer t o how I would deal wit h t he feat ure list wit h m y current favorit e st yle of
a Dom ain Model depends on m any fact ors. As I said before, t alking about a " default archit ect ure" is
st range because t he archit ect ure m ust first and forem ost depend on t he problem at hand.
However, I st ill want t o discuss a possible solut ion here. I t will be very m uch a sket ched sum m ary,
wit h det ails following in lat er chapt ers. What I will be discussing here will be kind of a first rough
at t em pt , and I will leave it like t hat , let t ing t he design evolve in lat er chapt ers.
1 . List cust om ers by applying a flexible and com plex filt er.
The cust om er support st aff needs t o be able t o search for cust om ers in a very flexible m anner.
They need t o use wildcards on num erous fields such as nam e, locat ion, st reet address,
reference person, and so on. They also need t o be able t o search for cust om ers wit h orders of a
cert ain kind, wit h orders of a cert ain size, wit h orders for cert ain product s, and so on. What
we're t alking about here is a full- fledged search ut ilit y. The result is a list of cust om ers, each
wit h a cust om er num ber, cust om er nam e, and locat ion.
The t ot al value for each order should be visible in t he list , as should t he st at us of t he order,
t ype of order, order dat e, and nam e of reference person.
An order can have m any order lines, where each line describes a product and t he num ber of
t hat product t hat has been ordered.
I t 's alright t o use opt im ist ic concurrency cont rol. That is, it 's accept ed t hat when a user is
not ified aft er he or she has done som e work and t ries t o save, t here will be a conflict wit h a
previous save. Only conflict s t hat lead t o real inconsist encies should be considered conflict s. So
t he solut ion needs t o decide on t he versioning unit for cust om ers and for orders. ( This will
slight ly affect som e of t he ot her feat ures.)
The lim it is specific per cust om er. We define t he lim it when t he cust om er is added init ially, and
we can change t he lim it lat er on. I t 's considered an inconsist ency if we have unpaid orders of a
t ot al value of m ore t han t he lim it , but we allow t hat inconsist ency t o happen in one sit uat ion,
t hat is if a user decreases t he lim it . Then t he user t hat decreases t he lim it is not ified, but t he
save operat ion is allowed. However, an order cannot be added or changed so t hat t he lim it is
ex ceeded.
6 . An order m ay not have a t ot al value of m ore t han one m illion SEK ( SEK is t he Swedish
currency, and I 'm using it for t his exam ple) .
7 . Each order and cust om er should have a unique and user- friendly num ber.
8 . Before a new cust om er is considered accept able, his or her credit will be checked wit h a credit
inst it ut e.
That is, t he lim it discussed in st ep 5 t hat is defined for a cust om er will be checked t o see if it 's
reasonable.
9 . An order m ust have a cust om er; an order line m ust have an order.
There m ust not be any orders wit h an undefined cust om er. The sam e goes for order lines: t hey
m ust belong t o an order.
To be honest , I 'm not act ually sure t hat t his feat ure is necessary. I t m ight be alright if t he order
is creat ed first and t he order lines are added lat er, but I want t he rule for t his exam ple so t hat
we have a feat ure relat ed t o t ransact ional prot ect ion.
So we now have a nice, sim ple lit t le feat ure list t hat we can use for discussing solut ions from an
overview perspect ive.
N ot e
You m ight get t he feeling t hat t he feat ure list is a bit t oo dat a focused. I n som e cases, what
m ight seem dat a focused will in pract ice be solved wit h propert ies t hat have som e behavior
at t ached.
But t he im port ant t hing t o not e here is t hat what we want is t o apply t he Dom ain Model.
The m ain problem wit h t hat is how t o deal wit h dat a if we use a relat ional dat abase.
Therefore, it 's m ore im port ant t o focus a bit m ore on t he dat a t han norm al when it com es
t o obj ect - orient at ion.
Wit h t he problem s/ feat ures in place, it 's t im e t o discuss a possible solut ion for how t o deal wit h
t hem .
Dealing with Features One by One
What does all t his com e down t o? Let 's find out by exam ining how I would t ypically solve t he
problem s/ feat ures list ed earlier in t his chapt er. I will focus solely on t he Dom ain Model so t hat we
concent rat e on t he " right " t hings for now and t ry t o cat ch and form t he Ubiquit ous Language wit hout
get t ing dist ract ed by t he infrast ruct ure or ot her layers.
St ill, it can be good t o have som e idea about t he t echnical environm ent as well. We keep down t he
t echnical com plexit y and decide t hat t he cont ext is a Rich GUI applicat ion execut ing at t he client
deskt ops t oget her wit h t he Dom ain Model and a physical dat abase server wit h a relat ional dat abase,
all on one LAN.
N ot e
I 'm going t o m ent ion loads of pat t erns everywhere, but please not e t hat we will com e back
t o t hose in lat er chapt ers and t alk and show a lot about t hem t hen. ( See Appendix B.)
The first requirem ent is pret t y m uch about dat a and a piece of search behavior. First , let 's sket ch
what t he Customer class and surroundings ( wit hout t he Order for now) could look like ( see Figure 4-
2) .
As you see, I used a sim ple ( naïve) Customer class and let it be a com posit ion of Address and
ReferencePersons. I prefer t o not put t his kind of search behavior direct ly on t he Customer class it self,
so at t his point I only have dat a on t he classes shown in Figure 4- 2 .
N ot e
I could use t he Part y Archet ype pat t ern [ Arlow/ Neust adt Archet ype Pat t erns] inst ead or
ot her t ypes of role im plem ent at ions, but let 's use sim ple st ruct ures for now.
We could solve t he first requirem ent by using a Query Obj ect [ Fowler PoEAA] , which I t alked about in
Chapt er 2, " A Head St art on Pat t erns," but in pract ice I have found t hat it 's nice t o encapsulat e t he
use of Query Obj ect s a bit if possible. There are oft en a lot of t hings t o define regarding t he result of
queries t hat aren't j ust relat ed t o t he crit eria. I 'm t hinking about sort order, ot her hidden crit eria,
opt im izat ions, where t o send t he Query Obj ect for execut ion, and so on. I t herefore prefer t o use a
Reposit ory [ Evans DDD] for encapsulat ing t he query execut ion a bit . I t also cut s down in code
verbosit y for t he consum ers and increases t he explicit ness in t he program m ing API .
I n Chapt er 2, we discussed t he Fact ory pat t ern [ Evans DDD] and said it was about t he st art of t he
lifecycle of an inst ance. The Reposit ory t akes care of t he rest of t he lifecycle, aft er t he creat ion unt il
t he " deat h" of t he inst ance. For exam ple, t he Reposit ory will bridge bet ween t he dat abase and t he
Dom ain Model when you want t o get an inst ance t hat has been persist ed before. The Reposit ory will
t hen use t he infrast ruct ure t o fulfill it s t ask.
I could let t he m et hod on t he Reposit ory t ake a huge list of param et ers, one for each possible filt er
field. That is a sure sign of sm elly code, however: code t hat 's not going t o be very clear or easy t o
m aint ain. What 's m ore, a param et er of st ring t ype called " Nam e" is hard t o underst and for t he
Reposit ory regarding how t he param et er should be used, at least if t he st ring is em pt y. Does it m ean
t hat we are looking for cust om ers wit h em pt y nam es or t hat we don't care about t he nam es? Sure,
we can invent a m agic st ring t hat m eans t hat we are looking for cust om ers wit h em pt y nam es. Or
slight ly bet t er, we force t he user t o add an ast erisk if he or she isn't int erest ed in t he nam e. Anyway,
neit her is a very good solut ion. On t he ot her hand, going for a Query Obj ect [ Fowler PoEAA] ,
especially a dom ain- specific one, or t he Specificat ion pat t ern [ Evans DDD] is t o st art by going t oo
far, t oo quickly, don't you t hink? Let 's go for t he sim plest possible and only consider t wo of all
possible crit eria for now. See Figure 4- 3 for an exam ple of how t his could be done.
DDD and TDD are a great com binat ion. You get inst ant feedback, and t rying out t he m odel wit h t est
code is a great way of gaining insight . Wit h t hat said, I 'm not going t he TDD rout e here and now. I
will explain t he m odel sket ch wit h som e t iny t est s here, but only as a way of providing anot her view
of t he solut ion idea. I n t he next chapt er, we will t ake a st ep back and m ore t horoughly and t rue t o
TDD t ry out and develop t he m odel.
So t o fet ch all cust om ers in a cert ain t own ( Ronneby) , wit h at least one order wit h a value of > 1,000
SEK, t he following t est could be used:
[Test]
public void
CanGetCustomersInSpecificTownWithOrdersOfCertainSize()
{
int numberOfInstancesBefore = _repository.GetCustomers
("Ronneby", 1000).Count;
_CreateACustomerAndAnOrder("Ronneby", 20000);
Assert.AreEqual(numberOfInstancesBefore + 1
, _repository.GetCustomers ("Ronneby", 1000).Count);
}
As you saw in t he exam ple, t he Reposit ory m et hod GetCustomers() is used t o fet ch all t he cust om ers
t hat fulfill t he crit eria of t own and m inim um order size.
I could go for a bidirect ional relat ionship bet ween Customer and Order. That is, each Customer has a
list of Orders, and each Order has one Customer . But bidirect ionalit y cost s. I t cost s in com plexit y,
t ight coupling, and overhead. Therefore, I t hink it 's good enough t o be able t o get t o t he Orders for a
Customer via t he OrderRepository. This leads t o t he m odel shown in Figure 4- 4 .
[Test]
public void CanGetOrdersForCustomer()
{
Customer newCustomer = _CreateACustomerAndAnOrder
("Ronneby", 20000);
IList ordersForTheNewCustomer =
_repository.GetOrders(newCustomer);
Assert.AreEqual(1, ordersForTheNewCustomer.Count);
}
I could let t he Customer have an OrderList propert y and im plicit ly t alk t o t he Reposit ory, but I t hink
t he explicit ness is bet t er here. I also avoid coupling bet ween t he Customer and t he OrderRepository.
The t ot al value of each order is wort h a separat e m ent ion. I t 's probably t rickier t han first expect ed as
t he calculat ion needs all orderLines of t he order. Sure, t hat 's not t ricky, but it does alarm m e. I
know t his is prem at ure, but I can't help it ( because loading t he orderLines will be expensive when
you j ust want t o show a pret t y large list of orders for a cert ain customer , for exam ple) . I t hink one
helpful st rat egy is t hat if t he orderLines aren't loaded, a sim ple am ount field, which probably is
st ored in t he Orders t able, is used for t he TotalAmount propert y. I f orderLines are loaded, a com plet e
calculat ion is used inst ead for t he TotalAmount propert y.
This isn't som et hing we need t o t hink about right now. And no m at t er what , for consum ers, it 's as
sim ple as t his:
[Test]
public void CanGetTotalAmountForOrder()
{
Customer newCustomer = _CreateACustomerAndAnOrder
("Ronneby", 420);
Order newOrder = (Order)_repository.GetOrders
(newCustomer)[0];
Assert.AreEqual(420, newOrder.TotalAmount);
}
I n m y opinion, t he " right " way t o t hink about t his is t hat lines are t here because we work wit h an
Aggregat e and t he lines are an int im at e part of t he order. That m ight m ean t hat perform ance would
suffer in cert ain sit uat ions. I f so, we m ight have t o solve t his wit h t he Lazy Load pat t ern [ Fowler
PoEAA] ( used t o load list s from t he dat abase j ust in t im e, for exam ple) or a read- only, opt im ized
view.
But , as I said, t hat 's som et hing we should deal wit h when we have found out t hat t he sim ple and
direct solut ion isn't good enough.
Not e t hat I 'm considering a unidirect ional relat ionship here, t oo. I can probably live wit h sending bot h
an Orderline and it s Order if I know t hat I need bot h for a cert ain piece of logic. The risk of sending
an order t oget her wit h a line for anot her order is probably pret t y sm all.
[Test]
public void CanIterateOverOrderLines()
{
Customer newCustomer = _CreateACustomerAndAnOrder
("Ronneby", 420);
Also not e t he big difference in t he m odel shown in Figure 4- 5 com pared t o how a relat ional m odel
describing t he sam e t hing would look. I n t he relat ional m odel, t here would be a one- t o- m any
relat ionship from Product t o OrderLine and m any- t o- one, but so far we t hink t hat t he one- t o- m any
relat ionship isn't really int erest ing in t his part icular Dom ain Model.
Hm m m ...feat ure 4 is t ricky. I t hink a reasonable solut ion here is t hat Customer is on it s own, and
Order t oget her wit h OrderLines is a concurrency unit of it s own. That fit s in well wit h m aking it
possible t o use t he Dom ain Model for t he logic needed for feat ures next . I use t he pat t ern called
Aggregat e [ Evans DDD] for t his, which m eans t hat you decide what obj ect s belongs t o t he cert ain
clust ers of obj ect s t hat you t ypically work wit h as single unit s, loading t oget her ( by default , at least
for writ e scenarios) , evaluat ing rules for t oget her, and so on.
I t 's im port ant t o not e, t hough, t hat t he Aggregat e pat t ern isn't first and forem ost a t echnical pat t ern,
but rat her should be used where it adds m eaning t o t he m odel.
Figu r e 4 - 6 . Aggr e ga t e s
5. A Customer May Not Owe Us More Than a Certain Amount of Money
Feat ure 5 is also pret t y t ricky. The first solut ion t hat springs t o m ind is probably t o add a TotalCredit
propert y on t he Customer . But t his is problem at ic because it 's t hen a bit t oo t ransparent , so t hat t he
consum er sees no cost at calling t he propert y. I t 's also a consist ency issue. I 'm not even seeing t he
Customer Aggregat e as having t he Orders, so I don't expect t he unit t o be t he correct one for
assum ing consist ency handling direct ly in t he Dom ain Model, which is a good sign t hat I should look
for anot her solut ion.
I t hink I need a Service [ Evans DDD] in t he Dom ain Model t hat can t ell m e t he current t ot al credit for
a cust om er. You'll find t his described in Figure 4- 7
Figu r e 4 - 7 . TotalCreditService
[Test]
public void CanGetTotalCreditForCustomerExcludingCurrentOrder()
{
Customer newCustomer = _CreateACustomerAndAnOrder
("Ronneby", 22);
I t hink you can get a feeling about t he current idea of t he cooperat ion bet ween t he Order, t he
Customer , and service from Figure 4- 7 and t he previous snippet .
6. An Order May Not Have a Total Value of More Than One Million SEK
Because I est ablished wit h t he concurrency conflict det ect ion feat ure t hat an Order including it s
OrderLines is a concurrency conflict det ect ion unit of it s own or m ore concept uallyan Aggregat e, I
can deal wit h t his feat ure in t he Dom ain Model. An Aggregat e invariant is t hat t he Order value m ust
be one m illion SEK or less. No ot her user can int erfere, creat ing a problem regarding t his rule for a
cert ain order, because t hen I or t he ot her user will get a concurrency conflict inst ead. So I creat e an
IsOKAccordingToSize() m et hod on t he Order t hat can be called by t he consum er at will. See Figure 4-
8 for m ore inform at ion.
A sim ple t est for showing t he API could look like t his:
[Test]
public void CanCheckThatAnOrdersTotalSizeIsOK()
{
Customer newCustomer = _CreateACustomerAndAnOrder
("Ronneby", 2000000);
Assert.IsFalse(newOrder.IsOKAccordingToSize());
}
N ot e
I need t o consider if I should use t he Specificat ion pat t ern [ Evans DDD] for t his kind of rule
lat er on.
7. Each Order and Customer Should Have a Unique and User-friendly Number
As m uch as I dislike t his requirem ent from a developer's perspect ive, as im port ant and com m on it is
from t he user's perspect ive. I n t he first it erat ion, t his could be handled well enough by t he dat abase.
I n t he case of SQL Server, for exam ple, I 'll use I DENTI TYs. The Dom ain Model doesn't have t o do
anyt hing except refresh t he Ent it y aft er it has been insert ed int o t he t able in t he dat abase. Before
t hen, t he Dom ain Model should probably show 0 for t he OrderNumber and CustomerNumber ( see Figure
4 - 9) .
Hm m m ...I already regret t his sket ch a bit . This m eans t hat I allocat e an OrderNumber as soon as t he
Order is persist ed t he first t im e. I 'm not so sure t hat 's a good idea.
I 'm act ually int erm ingling t wo separat e concept s, nam ely t he I dent it y Field pat t ern [ Fowler PoEAA]
for coupling an inst ance t o a dat abase row ( by using t he prim ary key from t he dat abase row as a
value in t he obj ect ) and t he I D t hat has business m eaning. Som et im es t hey are t he sam e, but quit e
oft en t hey should be t wo different ident ifiers.
I t also feels st range t hat as soon as a cust om er is per sist ed it get s a user- friendly num ber kind of as
a m arker t hat it is OK. Shouldn't it rat her be when a cust om er is operat ional in t he syst em ( aft er
credit checks and perhaps m anual approval) ? I 'm sure we'll find a reason t o com e back t o t his again
in lat er chapt ers.
8. Before a New Customer Is Considered OK, His or Her Credit Will Be Checked with a
Credit Institute
So we need anot her Service [ Evans DDD] in t he Dom ain Model t hat encapsulat es how we
com m unicat e wit h t he credit inst it ut e. See Figure 4- 10 for how it could look.
Figu r e 4 - 1 0 . CreditService
Again, t he idea is a m at t er of cooperat ion bet ween an Ent it y ( Customer in t his case) and a Service for
let t ing t he Ent it y answer a quest ion. Let 's see how t he cooperat ion could be dealt wit h in a t est . ( Also
not e t hat t he real service will probably use t he OrganizationNumber of t he Customer , which is not t he
sam e as t he CustomerNumber, but t he official ident ificat ion provided by t he aut horit ies for regist ered
com panies.)
[Test]
public void CantSetTooHighCreditLimitForCustomer()
{
Customer newCustomer = _CreateACustomer("Ronneby');
newCustomer.CreditLimit = 1000;
Assert.IsFalse(newCustomer.HasOKCreditLimit);
}
N ot e
Gregory Young point ed t his out as a code sm ell. The problem is m ost likely t o be t hat t he
operat ion isn't at om ic. The value is first set ( and t herefore t he old value is overwrit t en) and
t hen checked ( if rem em bered) . Perhaps som et hing like Customer.RequestCreditLimit(1000)
would be a bet t er solut ion. We get back t o sim ilar discussions in Chapt er 7, " Let t he Rules
Rule."
Feat ure 9 is a com m on and reasonable requirem ent , and I t hink it 's sim ply and best dealt wit h by
referent ial int egrit y const raint s in t he dat abase. We can, and should, t est t his in t he Dom ain Model,
t oo. There's no point in sending t he Dom ain Model changes t o persist ence if it has obvious
incorrect ness like t his. But inst ead of checking for it , as t he first t ry I m ake it kind of m andat ory
t hanks t o an OrderFactory class as t he way of creat ing Orders, and while I 'm at it I deal wit h
OrderLines t he sam e way so an OrderLine m ust have Order and Product ( see Figure 4- 11) .
Let 's t ake a look at t he int eract ion bet ween t he different part s in a t est as usual.
[Test]
public void CanCreateOrderWithOrderLine()
{
Customer newCustomer = _CreateACustomer("Karlskrona");
Assert.AreEqual(1, newOrder.OrderLines);
}
Hm m m ... This feels quit e a bit like overdesign and not exact ly fluent and sm oot h, eit her. Let 's see
what we t hink about it when we really get going in t he next chapt er.
While we are discussing t he OrderFactory, I want t o m ent ion t hat I like t he idea of using Null Obj ect s
[ Woolf Null Obj ect ] for OrderType, Status, and ReferencePerson. ( That goes bot h for t he Dom ain
Model and act ually also for t he underlying relat ional dat abase.) The Null Obj ect pat t ern m eans t hat
inst ead of using null, you use an em pt y inst ance ( where em pt y m eans default values for t he
m em bers, such as string.Empty for t he strings) . That way you can always be sure t o be able t o
" follow t he dot s" like t his:
this.NoNulls.At.All.Here.Description
When it com es t o t he dat abase, you can cut down on out er j oins and use inner j oins m ore oft en
because foreign keys will at least point t o t he null sym bols and t he foreign key colum ns will be non-
nullable. To sum m arize, null obj ect s increase t he sim plicit y a lot and in unexpect ed ways as well.
As you saw in Figure 4- 11, I had also added a m et hod t o t he Order class, AddOrderLine(), for adding
OrderLines t o t he Order. That 's part of an im plem ent at ion of t he Encapsulat e Collect ion Refact oring
[ Fowler R] , which basically m eans t hat t he parent will prot ect all changes t o t he collect ion.
On t he ot her hand, t he dat abase is t he last out post , and I t hink t his rule fit s well t here, t oo.
Again, I see Order and it s OrderLines as an Aggregat e, and t he solut ion I plan t o use for t his feat ure
will be orient ed around t hat .
I will probably use an im plem ent at ion of t he Unit of Work pat t ern [ Fowler PoEAA] for keeping t rack of
t he inst ances t hat have been changed, which are new, and which are delet ed. Then t he Unit of Work
will coordinat e t hose changes and use one physical dat abase t ransact ion during persist ence.
As we specified, orders have an accept ance st at us ( see Figure 4- 12) . Therefore, I j ust add a m et hod
called Accept() . I leave t he decision about whet her or not t o int ernally use t he St at e pat t ern [ GoF
Design Pat t erns] for lat er. I t is bet t er t o m ake im plem ent at ion decisions like t his during refact oring.
[Test]
public void CanAcceptOrder()
{
Customer newCustomer = _CreateACustomer("Karlskrona");
Order newOrder = OrderFactory.CreateOrder(newCustomer);
Assert.IsFalse(newOrder.Status == OrderStatus.Accepted);
newOrder.Accept();
Assert.IsTrue(newOrder.Status == OrderStatus.Accepted);
}
What 's t hat ? Messy? OK, I agree, it is. We'll part it ion t he m odel bet t er when we dive int o t he det ails
furt her.
N ot e
The m odel shown in Figure 4- 13 and all t he m odel fragm ent s were creat ed up- front , and
t hey are bound t o be im proved a lot when I m ove on t o developing t he applicat ion.
Anot her not e is t hat I only showed t he core Dom ain Model and not t hings t hat are m ore
infrast ruct ure relat ed, such as t he m ent ioned Unit of Work [ Fowler PoEAA] . Of course, t hat
was t ot ally on purpose. We'll get back t o infrast ruct ure lat er in t he book. Now I 'm focusing
on t he Dom ain Model.
I said t hat t here are lot s of variat ions of how t he Dom ain Model pat t ern is used. To show you som e
ot her st yles, I asked a couple of friends of m ine t o describe t heir favorit e ways of applying Dom ain
Models. You'll find t hose in Appendix A.
To give us a bet t er feeling of t he requirem ent s, I 'd like t o t ake a look at t hem from yet anot her view
and sket ch a few form s for an upcom ing UI .
Making a First Attempt at Hooking the UI to the Domain
Model
I once st art ed describing a new archit ect ure from t he bot t om up. I m ean, I st art ed describing it from
t he dat abase. One of t he readers t old m e in no uncert ain t erm s t hat I should st art t alking about what
t he archit ect ure looked like from t he UI program m er's point of view. I f it wasn't good in t hat
perspect ive, t here was no point reading on. I decided t hat t hat way of t hinking had it s m erit s, so it 's
now t im e t o have a first look at t he Dom ain Model we j ust sket ched from a UI program m er's
viewpoint .
A Basic Goal
I want you t o consider whet her you t hink we are fulfilling one of m y basic goals, which is providing
" sim plicit y t o t he left " ( or " sim plicit y t o t he t op," depending upon how you visualize t he layers in a
layered archit ect ure) . What I m ean is providing a sim ple API for t he UI program m er so he or she can
easily see, breat he, and underst and t he m odel, and can focus on UI m at t ers and not have t o t hink
about com plex prot ocols for t he Dom ain Model.
Skipping dat a binding is not a basic goal, not at all, but I will skip dat a binding here in t he first
discussion about t he UI . Dat a binding won't be t he focus at all in t his book, but we'll t ouch som e
m ore on t hat in lat er chapt ers.
Add an order
Again, I won't use ordinary dat abinding right here, but j ust sim ple, direct code for hooking t he UI t o
t he Dom ain Model.
This is plain and sim ple. To m ake t his possible t o t est and show, we need t o writ e a funct ion t hat
could be called from Main() for faking a cust om er and som e orders.
The user will probably choose a cust om er from a cust om er list form , and we provide t he customer
inst ance t o t he const ruct or of t he form t o show det ails of a single customer ( let 's call t he form
CustomerForm) . The form st ores t he customer inst ance in a privat e field called ( _customer) .
//CustomerForm
private void _PaintCustomer()
{
//Get the data:
IList theOrders = _orderRepository.GetOrders(_customer);
Som et hing t hat is wort h point ing out is t hat I expect t he usage of Null Obj ect [ Woolf Null Obj ect ] in
t he previous code when I paint t he orders. Because of t hat , all orders will have a ReferencePerson
( an em pt y one) , even if it hasn't been decided yet , so I don't need any null checks. I n m y opinion,
t his is an exam ple of a det ail t hat shows how t o increase t he sim plicit y for t he UI program m er.
Having t o writ e t he code by hand for filling t he UI was a bit t edious. But looking back at it , isn't it
ext rem ely sim ple t o read so far? Sure, we are t rying out sim ple t hings, but st ill.
Add an Order
The ot her form exam ple is one for m aking it possible t o add an order. I 'm envisioning t hat you have
first select ed t he cust om er and t hen you get a form like t he one shown in Figure 4- 15.
To m ake t his happen, first an Order is inst ant iat ed, and t hen t he order is sent t o t he const ruct or of
t he form .
The code for _PaintOrder() could t hen look like t his:
//OrderForm._PaintOrder()
txtOrderNumber.Text = _ShowOrderNumber(_order.OrderNumber);
txtOrderDate.Text = _order.OrderDate.ToString();
//And so on, the code here is extremely similar in
//principle to the one shown above for _PaintCustomer().
To avoid having a zero value for txtOrderNumber, I used a helper ( _ShowOrderNumber() ) t hat perhaps
shows " New" inst ead of 0.
Again, t his sect ion was m ost ly t o give us a bet t er feeling about t he requirem ent s by t hinking about
t hem from anot her perspect ive, t he UI . From now on, we won't discuss m uch about UI - relat ed t hings
unt il we get t o Chapt er 11, " Focus on t he UI ."
Now let 's m ove on t o yet anot her view regarding t he requirem ent s.
Yet Another Dimension
So far in t his chapt er, I have m ost ly t alked about t he logical st ruct ure of t he Dom ain Model, which is
j ust one dim ension of t he pict ure, of course. There are ot hers. I 'd also like t o discuss different
execut ion st yles for a while. Let 's st art wit h t he deploym ent environm ent set up for t he feat ure list .
There, I said t hat we are creat ing a rich client ( WinForm s) applicat ion wit hout an Applicat ion Server.
I t could look sim ilar t o Figure 4- 16.
For t he sake of t he discussion here, let 's increase t he com plexit y quit e a bit for a m om ent and add a
requirem ent of an applicat ion server as shown in Figure 4- 17.
The first quest ion is on what t ier( s) should t he Dom ain Model execut e? Should it only execut e on t he
Applicat ion Server and t hen you give out dum b dat a st ruct ures, Dat a Transfer Obj ect s ( DTO) [ Fowler
PoEAA] t o t he Consum er t ier? Or should t he Dom ain Model only execut e on t he consum er side, and
you fill it by asking for DTOs from t he Applicat ion server? Or perhaps you want t he Dom ain Model t o
execut e on bot h t iers? Perhaps t wo different Dom ain Models?
N ot e
I t 's im port ant t o t hink about t he purpose of t he applicat ion server, t hat it 's really needed
and t hat you really need t o dist ribut e t he Dom ain Model. Rem em ber Fowler's First Law of
Dist ribut ed Obj ect Design: Don't dist ribut e your obj ect s! [ Fowler PoEAA]
Let 's assum e for a second t hat t he Dom ain Model should ( at least ) execut e at t he Applicat ion server.
Should it t hen be a shared Dom ain Model inst ant iat ion, so t hat t here is a single inst ance for
represent ing a single cust om er t o be used by all users? Or should it be one Dom ain Model
inst ant iat ion per user or per session so t hat t here are several inst ances represent ing a cert ain
cust om er at a cert ain point in t im e?
The t hird quest ion is, should t he Dom ain Model inst ant iat ion be st at eful bet ween calls, or should it go
away aft er each call?
Fourt h, should we t ry t o build up a com plet e Dom ain Model inst ant iat ion by fet ching as m uch dat a as
possible at each request , and never let go of inst ances?
We have lot s of quest ions and, as always, t he answers depend on t he sit uat ion. One problem wit h
t he discussion is t hat I haven't ( in a DDD- ish m anner) decided t oo m uch about t he infrast ruct ure.
Anyway, I 'd like t o say a few words about how I usually prefer t o deal wit h t his.
N ot e
What I m ean wit h t he t erm " Dom ain Model inst ant iat ion" is a set of inst ances of t he
Dom ain Model inst ead of it s classes. Of course, we are sharing t he classes bet ween users
m uch m ore oft en t han t he inst ances. Yet I t hink t his t erm adds clarit y t o t he discussion.
I t 's im port ant t o m ent ion, for com plex scenarios I 'm fond of Present at ion Model [ Fowler PoEAA2] as
t he UI - opt im ized view or version of t he Dom ain Model.
One of t he m ain problem s wit h a shared set of inst ant iat ed dom ain obj ect s occurs if it has t o execut e
in a dist ribut ed fashion, perhaps on t wo applicat ion servers in a " shared not hing" clust er. We t hen
have t he problem of dist ribut ed caching, and t hat 's a t ricky problem ( t o m ake an underst at em ent ) , at
least if you need real- t im e consist ency. I t is so t ricky t hat I have given up on it for now as far as
finding a general solut ion t hat can scale up well. However, for specific sit uat ions, we can find good
enough solut ions. Of course, if we have all Dom ain Model inst ances in m em ory, t here are probably
fewer sit uat ions where we need t o scale out , at least for efficiency reasons. St ill, if we do have t he
problem , it 's a t ough one t o solve in a good way.
N ot e
The t erm " shared not hing" clust er needs a short explanat ion. What I 'm aim ing at is t hat t he
applicat ion servers aren't sharing eit her CPU, disk, or m em ory. They are t ot ally
independent of each ot her, which is beneficial for scalabilit y.
To read m uch m ore about t his I recom m end Pfist er's I n Search of Clust ers [ Pfist er
Wolfpack] .
N ot e
There is an open source proj ect called Prevayler [ Prevayler] ( and t here are ot hers t hat are
sim ilar) t hat support s Dom ain Model inst ant iat ions t hat are st at eful, shared, and com plet e.
So t hat m eans m ore or less t hat t he Dom ain Model and t he dat abase are t he sam e t hing.
For t hat t o be possible, we need large am ount s of RAM, but t hat 's less of a problem t oday
because m em ory prices are falling, and 64- bit m achines are becom ing com m onplace.
The idea is t hat it writ es t o a sequent ial log file each t im e t here is a change t o t he
dat abase. I f t he power goes, t he Dom ain Model inst ant iat ion can com e back by reading an
im age creat ed at a cert ain point in t im e and reading t hrough t he log file. This is pret t y
sim ple and ext rem ely efficient execut ion- wise because all dat a is in m em ory.
What we have t hen is basically an obj ect dat abase, but a sim ple one because t here is no
need for fault ing or ot her such t hings. All inst ances are in m em ory all t he t im e, and t here is
no need for O/ R Mapping from / t o a relat ional dat abase, not even from / t o an obj ect
dat abase. There is j ust t he Dom ain Model inst ant iat ion.
OK, from now on in t his book I will leave t he added com plexit y because of t he applicat ion server and
j ust assum e t hat we work wit h t he rich client including t he Dom ain Model or a web applicat ion, which
again t alks direct ly t o t he Dom ain Model.
One reason for t his decision is t hat I t hink t he classic way of using applicat ion servers is in a way
disappearing, or at least changing. What 's t he driving force regarding t hat ? Perhaps SOA, but t hat 's
anot her st ory ( which we t alk a bit about again in Chapt er 10) .
Summary
I know, you want ed t he chapt er t o go on forever, but sadly it 's com e t o an end. We've covered a lot
of ground, discussed a " new" default archit ect ure based on Dom ain Models t o quit e an ext ent , and
also sket ched how it can be used for an exam ple. Now it 's t im e t o dig deeper int o t he Dom ain Model
and invest igat e it furt her and also m ake lot s of changes t o t he init ial sket ch discussed in t his chapt er.
Chapter 5. Moving Further with Domain-
Driven Design
Som e of you m ight be really eager by now and m ight be saying som et hing like " Com e on, let 's see
t he t ools and t ricks t hat will show us how t o im plem ent a Dom ain Model and it s surroundings."
Sorry, but t hat 's not how t o proceed. On t he cont rary, I want t o creat e t he Dom ain Model wit hout
t hinking about t he t ools and infrast ruct ure. That m eans good old OO t hat I used t o laugh about for
real- world applicat ions. As you know by now, I have since t hen changed m y m ind. I t 's pret t y m uch a
m at t er of design.
So far t he book has been pret t y general and abst ract wit h only sket ches of m odels. I t 's t im e t o
change t hat now. From here on I will t alk about how t he problem s could be solved in realit y.
I n t his chapt er, we will discuss how t o develop and refine t he Dom ain Model t hat was sket ched in t he
previous chapt er. We will m ove slowly by applying TDD when we let t he m odel evolve. Please be
prepared t hat t he discussion will be a bit " m oving around" and t he progress a bit slow. ( We will
change t his way of discussing t he developm ent by t he next chapt er.)
Let 's get st art ed wit h t he t hem e for t his chapt er; refining t he Dom ain Model.
Refining the Domain Model Through Simple TDD
Experimentation
Do you rem em ber t he very early sket ch we had when we left Chapt er 4, " A New Default
Archit ect ure" ? You'll find it again in Figure 5- 1 .
Figu r e 5 - 1 . Ea r ly sk e t ch fr om Ch a pt e r 4
I went a bit overboard, providing t oo m any det ails in t he sket ch which I norm ally wouldn't have.
Anyway, it 's bet t er now t han never t o really learn som e of t he det ails of t he requirem ent s. Let 's st art
im plem ent ing t his now in a TDD- ish m anner and see what issues we need t o address and resolve,
and by doing so we'll evolve t he m odel as we go.
I t ypically at t ack feat ure by feat ure, but considering t hat we t alked about som e UI sket ches in t he
last chapt er, I t hink I 'll st art by t rying t o m ake it possible t o support t hose UI sket ches and lat er on
sum m arize what feat ures we covered.
N ot e
The first few st eps are necessary t o properly creat e t he dom ain obj ect s. We m ust com plet e
t hese st eps before we can get t o t he int erest ing and crucial part , nam ely t est ing and
im plem ent ing t he logic t hat our m odel facilit at es.
I 'll get st art ed on writ ing a first t est for t his. I 'll t est so as t o m ake sure t hat I don't get null back
when I ask t he fact ory t o creat e a new order. Here goes:
[Test]
public void CanCreateOrder()
{
Order o = OrderFactory.CreateOrder(new Customer());
Assert.IsNotNull(o);
}
N ot e
You m ight wonder why I nam e m y t est s t he way I do? The early convent ion for nam ing
xUnit t est s was t o prefix t hem wit h " Test ," but t hat 's not necessary wit h NUnit , for
exam ple, because it will underst and t he at t ribut e Test inst ead. This m eans we are free t o
nam e t he t est s t he way we want . This also m eans we get t he t ech- t alk out of t he way and
can focus t he discussion on dom ain concept s and design.
I like nam ing t he t est s as st at em ent s of what t he t est s int end t o verify. That way, t he
collect ion of t est nam es becom es a list of what should be possible and what should not .
At first , t he t est looks ext rem ely sim ple. To m ake t he t est com pile, I need t o creat e an em pt y Order
class. That 's fine for now. Next , I need t o creat e an OrderFactory class wit h a single m et hod, but our
problem s st art cropping up already when writ ing t hat m et hod. One of t he rules defined in Chapt er 4
was t hat an Order always has t o have a cert ain Customer , and t his is solved by giving t hat
responsibilit y t o t he OrderFactory, giving t he Order a Customer at creat ion t im e. Therefore, t he
CreateOrder() m et hod of t he OrderFactory needs t o receive a Customer inst ance as a param et er
( which you can see in t he t est code) . No rocket science t here, but we have j ust st art ed working on
t he Order Aggregat e and we would like t o forget about everyt hing else right now.
The first solut ion t hat springs t o m ind ( which is also visible in t he t est I wrot e previously) would be t o
also j ust creat e an em pt y Customer class. Aft er all, I will need it really soon, and I 'm not going t o
int eract wit h it in t his t est , so t here isn't a lot of coupling added bet ween t he building bricksat least
not yet . On t he ot her hand, it feels like we are t ouching on t oo m any t hings in t his first lit t le t est .
That 's a t ypical sm ell, so let 's t ry t o avoid t hat if possible.
The second solut ion I t hought about would be t o m ock t he Customer and t hereby creat e looser
coupling bet ween t he Aggregat es, at least in t his t est . I cert ainly do like t he idea of m ocks, but it
feels a lit t le bit like overkill here. Aft er all, I 'm not going t o int eract wit h t he Customer at all; I j ust
need t he Customer m ore or less as a placeholder.
The t hird solut ion could be t o creat e an int erface called ICustomer ( or som et hing sim ilar, or let
Customer be an int erface) and t hen creat e a st ub im plem ent at ion of t he int erface. Again, t hat feels
like overkill right now, and what would t he purpose be when m oving forward? To be able t o swap
ICustomer im plem ent at ions? I s t hat really som et hing I expect ? No, I don't , so unt il proven wrong, I
decide t hat t his isn't t he solut ion I am going t o st art wit h.
The fourt h solut ion could be t o skip t he Customer param et er. I could do t hat t em porarily in order t o
get going and t hen change t he t est when I add t he Customer param et er lat er on. I could also decide
t hat I probably don't want gluing t he Order and t he Customer t oget her t o be a responsibilit y of t he
fact ory. Could it have been a prem at ure design decision t hat TDD revealed in a few seconds?
Not binding t he Order and Customer t oget her in t he fact ory would act ually add flexibilit y t o t he UI
design so t hat I don't first have t o st art wit h choosing t he cust om er. I nst ead, I could st art by let t ing
t he user fill in ot her inform at ion about t he new order and t hen ask t he user who t he cust om er is. On
t he ot her hand, flexibilit y som ewhere usually m eans com plexit y som ewhere else. For exam ple,
assum e prices are cust om er dependent ; what price should be used when I add OrderLines t o t he
Order wit hout a defined Customer ? What should happen lat er? I t 's cert ainly not im possible t o solve,
but we shouldn't int roduce com plexit y if we can avoid it .
Anot her drawback wit h t he fourt h solut ion is t hat t he Order I get back from t he fact ory isn't really in
a valid st at e. The rule was t hat every Order should have a Customer . Sure, t he order isn't persist ed in
t he fact ory, but it 's st ill not in a valid st at e. The consum er m ust do som et hing t o t ransform t he order
t o a valid st at e aft er t he fact ory has execut ed.
A fift h solut ion could be t o use object as t he t ype for t he param et er t o CreateOrder() , but t hat 's not
very purposeful, and it adds t o t he cast ing needs. The sam e goes if you invent som e generic
int erface t hat all your Dom ain Model classes should im plem ent , like IEntity, and t hen use t hat as a
param et er. What we are discussing now is using a sledgeham m er t o crack a nut .
You probably t hink t hat I 'm violat ing t he principles of TDD here by t hinking t oo m uch inst ead of
t rying it out wit h t est s, code, and refact oring. On t he ot her hand, during t he t im e it t akes you t o
writ e t he nam e of t he t est , lot s of ideas and t hought s ( and decisions) will flee t hrough your m ind
very fast and sem i- consciously. ( This, of course, depends on your experience wit h t he problem at
hand.)
Anyway, let 's not t hink t oo m uch and inst ead decide on one solut ion t o t ry out . I 'll grab t he first one.
Adding an em pt y Customer class wit h a public default const ruct or is act ually very quick and easy t o
do, so let 's do t hat . Now t he t est com piles, and I get a red bar because I only wrot e t he signat ure
and only ret urned null from t he CreateOrder() m et hod in OrderFactory.
I t 's t im e t o im plem ent CreateOrder() . The first t ry could look like t his:
//OrderFactory
public static Order CreateOrder(Customer customer)
{
return new Order();
}
For t hat t o com pile, I m ust have an accessible default const ruct or of t he Order. I t could be public,
but inst ead I decide t o let it be internal in order t o hinder t he consum er of t he Order class
inst ant iat ing it except via t he OrderFactory. Sure, t his isn't t he perfect prot ect ion, but at least direct
inst ant iat ion by m ist ake will only happen inside t he Dom ain Model, and t hat 's a st ep in t he right
direct ion in m y opinion.
Refact oring t im e? Well, what value does t he fact ory really add? Not anyt hing yet . I t j ust adds a bit of
com plexit y. I really should have at least st art ed wit hout t he fact ory, because it shouldn't be around if
it doesn't add value. Now I st ill t hink t here are quit e a lot of t hings it will deal wit h, such as
snapshot t ing t he customer , adding null obj ect s, creat ing different kinds of orders, and a few ot her
t hings.
But t he code so far j ust feels silly now wit h a fact ory, don't you t hink? I t m ight add value lat er on,
but now it 's less sim ple t han it could be. Let 's change it direct ly t o use t he sim plest possible
const ruct ion for t his: direct use of a const ruct or.
N ot e
I t feels st range t o refact or away from a fact ory. But it 's j ust a sign t hat I got carried away
and st art ed out wit h a t oo det ailed design from t he beginning.
Also wort h point ing out is t hat I had a CreateOrderLine() m et hod in t he sket ch in Chapt er
4, but life is sim pler wit hout it .
[Test]
public void CanCreateOrder()
{
Order o = new Order(new Customer());
Assert.IsNotNull(o);
}
Any ot her t est s t o writ e? Sure, what we have been discussing all along is how t o deal wit h t he
customer param et er. So in m y opinion an int erest ing t est would be t o check t hat a newly creat ed
order has a customer . I current ly don't have verificat ion of t hat . Let 's add a t est for doing so.
[Test]
public void CanCreateOrderWithCustomer()
{
Order o = new Order(new Customer());
Assert.IsNotNull(o.Customer);
}
This t est t ells m e t hat I need t o add a Customer field or propert y on t he Order. ( I t hink it will be
needed not only for m y t est , but also for som e of t he requirem ent s.)
I n order t o cut down t he com plexit y, I decide on a read- only propert y like t his in t he Order class:
//Order
public readonly Customer Customer;
I f t here is no way t o change t he Customer of t he Order, we can expect it t o be ever- present ( and
never- changing) , and t hat will sim plify t he ot her rules. I f you don't need t he flexibilit y...
Now everyt hing com piles and life is good, and we do get a red bar. That 's easily fixed by m odifying
t he const ruct or so it uses t he customer param et er. The const ruct or now looks like t his, and we get a
green bar:
//Order
public Order (Customer customer)
{
Customer = customer;
}
[Test]
public void OrderDateIsCurrentAfterCreation()
{
DateTime theTimeBefore = DateTime.Now.AddMilliseconds(-1);
The idea wit h t he t est is t o set up an int erval of spot s in t im e and t hen check t hat t he OrderDate is
wit hin t his int erval.
As usual, t his won't com pile. I need t o add a public OrderDate propert y. This t im e, I 'm using a privat e
field + a public get t er since I 'm going t o change t he OrderDate value lat er on in t he lifecycle. And t his
t im e, I let t he const ruct or of t he Order set t he OrderDate field wit hout adding anot her param et er t o
t he const ruct or. For clarit y, here's t he piece:
//Order
private DateTime _orderDate;
I st art ed t his sect ion wit h a diagram describing a subset of t he m odel in Figure 5- 2 . The m odel has
evolved slight ly, as shown in Figure 5- 3 where I visualize t he code.
N ot e
You m ight wonder why I draw figures by hand som et im es and wit h a UML t ool som et im es.
The reason is t hat I want ed t o illust rat e t hat upfront , I j ust sket ch quickly as a help wit h
t he t hought and com m unicat ion process. When I have im plem ent ed t he t hing, t hen I m ay
visualize t he im plem ent at ion wit h a UML t ool.
When you com pare Figure 5- 3 wit h Figure 5- 2 , t he visible differences aren't t hat big. I t 's act ually j ust
t hat I had t o im plem ent a first version of t he Customer class and t he relat ionship from Order t o
Customer . That 's not a real change t o t he m odel; only t o t he subset diagram .
N ot e
I also show t he const ruct or in Figure 5- 3 t o give a m ore det ailed view of how t he classes
work.
I t 's t im e for refact oring before m oving on t o t he next st ep. First , I want ed t he call t o t he const ruct or
of t he Order t o be m oved out t o t he [SetUp], but t hen I would have t o change t he last t est slight ly
regarding t he t im e int erval, and t hat would m ake it a lit t le less t o t he point . Moreover, t he t hree t est s
shown so far are j ust about t he creat ion, so I like having t he calls in t he t est m et hods t hem selves.
Let 's leave refact oring for t he t im e being and m ove on wit h refining t he Dom ain Model.
Second Task: The OrderRepository + OrderNumber
I n t he previous sect ion, we t alked about what t he OrderFactory could look like in order t o serve our
need t o creat e new Order inst ances from scrat ch, but t hen decided t o skip t he fact ory for now. I n m y
opinion, t he next problem nat urally is how t he OrderRepository should work out .
I n Chapt er 4, I discussed GetOrders() of t he OrderRepository. Right now, I t hink t he m ost im port ant ,
t ypical m et hod is GetOrder(), and t herefore I 'd like t o st art wit h t hat one and t he ident ifier of t he
Ent it y Order.
While we're t alking about it , what is OrderNumber? Well, t ypically an order has som e form of unique
ident ificat ion t hat could be used by hum ans for ident ifying one part icular order. One com m on
solut ion is t o j ust assign a new num ber t o each order from an ever- increasing sequence of num bers.
I n Figure 5- 4 , I show t he Order class again aft er m odificat ion and t he newly added m et hod in t he
OrderRepository class.
I know, I was supposed t o t alk about t he OrderRepository, but I t hink it is im port ant t o do som et hing
about t he OrderNumber first . Do we have t o give t he Order it s ident it y when it is creat ed? I t hink it 's
correct t o say t hat t he OrderNumber is 0 unt il t he order is saved ( m eaning t hat t he st at us is Ordered)
for t he first t im e. Unt il it is, we don't want t o wast e an OrderNumber on som et hing t hat j ust m ight
becom e a real order.
N ot e
This depends very m uch on t he requirem ent s ( whet her it 's good or bad) , but I get a
growing feeling t hat we are m ixing t wo different t hings here t he business ident ificat ion and
t he persist ence ident ificat ion. We'll com e back t o t hat in a lat er chapt er.
I also st rongly dislike t he coupling bet ween persist ence and business rules. I m ean t hat t he
m om ent t he order is persist ed, it 's also " Ordered." We'll leave t hat for now and com e back
t o it in Chapt er 7, " Let t he Rules Rule," when we focus on business rules.
So as usual we can t hen writ e a very sim ple t est like t his:
[Test]
public void OrderNumberIsZeroAfterCreation()
{
Order o = new Order(new Customer());
Assert.AreEqual(0, o.OrderNumber);
}
Guess what ? This won't com pile, so I add a new read- only propert y called OrderNumber t o t he Order
class and let it use a privat e _orderNumber field.
This way we dealt wit h OrderNumber from t he const ruct or perspect ive. I f t he OrderNumber propert y is
read- only, however, how can we give it t he value when using t he OrderRepository for finding and
reconst it ut ing an old Order? To m ake t he whole issue clear, let 's t ake a st ep back and writ e a t est
and a [Setup] m et hod ( aft er having declared OrderRepository wit h t he nam e _repository) :
[SetUp]
public void SetUp()
{
_repository = new OrderRepository();
}
[Test]
public void OrderNumberCantBeZeroAfterReconstitution()
{
int theOrderNumber = 42;
_FakeAnOrder(theOrderNumber);
Order o =
_repository.GetOrder(theOrderNumber));
Assert.AreEqual(theOrderNumber, o.OrderNumber);
}
As usual, t he whole t hing won't com pile. I don't have an OrderRepository class, so I writ e one wit h
j ust a signat ure for t he GetOrder() m et hod and no code. The t est code st ill won't com pile, so I have
t o st ub t he _FakeAnOrder() in t he t est class. I get a red bar.
I 'm j ust get t ing furt her and furt her away from t he problem I t hought I want ed t o focus on. To be
able t o writ e t he _FakeAnOrder() m et hod, I need t o m ake it possible for t he Reposit ory t o know about
an Order. I could go ahead and im plem ent a new m et hod in t he OrderRepository t hat is only t here
for support ing ot her t est s, but I t hink t his is a good sign of m y needing t o writ e anot her t est inst ead.
I need t o t est saving Orders, or at least m ake t he Reposit ory aware of Orders.
N ot e
I have t o adm it t hat I have quit e a lot of ideas about how t he saving should really happen,
but I 'll m ove on slowly here and writ e sim ple code t hat I will refact or a lot now. Please
don't get upset about t his; it 's not t he final solut ion.
As usual, it won't com pile. I need t o add t he AddOrder() m et hod t o t he OrderRepository. And as
usual, I j ust add t he signat ure, but t his is not enough t o get a red bar. As a m at t er of fact , t here is
no t est code at all in t he CanAddOrder() m et hod. The reason is t hat I 'm not keen on t he idea of let t ing
t he Reposit ory publish any m et hods for t he sole purpose of an ext ernal t est class for checking t he
inner st at e of t he Reposit ory. Sure, I could use t he GetOrder() m et hod, but t hen it 's t he chicken or
t he egg scenario. The im plem ent at ion of t his m et hod is far from even being st art ed yet .
I nst ead, I t ake a st ep back and add a privat e IList t o t he Reposit ory for holding on t o t he orders. I
don't publish anyt hing about t he IList t o t he out side; it 's very m uch an im plem ent at ion det ail, and I
already t hink I will have t o get rid of it really soon. I nst ead I use anot her assert ion, not a xUnit one,
but an assert ion from t he Diagnostics nam espace for checking what I t hink should be checked. What
t he Assert() does is check t hat t he st at em ent is t rue. I f not , t he developer will be not ified. The
AddOrder() m et hod could look like t his:
//OrderRepository
public void AddOrder(Order order)
{
int theNumberOfOrdersBefore = _theOrders.Count;
Trace.Assert(theNumberOfOrdersBefore
== _theOrders.Count - 1);
}
You should t hink t wice before using t he ordinary Diagnostics assert ions. One problem
wit h t hat is t hat it won't int egrat e well wit h NUnit . Anot her problem is t hat I can't
cust om ize it for how it should act in different sit uat ions like developm ent , cont inuous
int egrat ion, bet a t est ing, and during product ion. I discussed t his som e m ore in m y
earlier book [ Nilsson NED] .
You m ight also wonder why I didn't m ake sure t hat t he t est could be expressed
som ehow in a NUnit t est . I could expose t he necessary st at e t hat t he t est needs, but I
prefer not t o if I don't have t o. I f I did, it would m ake it harder t o refact or t he Reposit ory
class, andagainI 'm sure I need t o do t hat .
The t echnique I used earlier is t o som e ext ent inspired by Design By Cont ract by
Bert rand Meyer [ Meyer OOSC] . Even t hough it 's not form alized at all, t he assert ion
expresses what t he AddOrder() ensures, t hat is it s assurances for post - condit ions.
What could be t he pre- condit ions t hat t he AddOrder() requires? Perhaps t hat t he order
isn't known t o t he Reposit ory before? No, I dislike seeing t hat as an error. That
_theOrders isn't null? But t he m et hod would t hrow an except ion if it is. I t 's also t he case
t hat t he whole t hing about _theOrders is a very t em porary solut ion, as you will soon see.
Let 's leave t his alone for now.
So let 's creat e Mytrace.Assert(), which will j ust t hrow an except ion if it receives false as t he
param et er. That way, it at least int egrat es well wit h NUnit / Test driven.net .
Com pile, t est , and red bar. Good. So let 's swap t he TODO- com m ent for t he add call:
//OrderRepository
public void AddOrder(Order order)
{
int theNumberOfOrdersBefore +1 = _theOrders.Count;
_theOrders.Add(order);
MyTrace.Assert(theNumberOfOrdersBefore
== _theOrders.Count);
}
And we now have a green bar. We are writ ing som e st range code here and t here, but we are m oving
forward, and we are creat ing t est s t hat aren't weird at all along t he way, so let 's cont inue.
N ot e
I could have also worked wit h a m ock t o verify t hat t he Syst em Under Test ( SUT) worked
as expect ed, but you can probably envision how from Chapt er 3, " TDD and Refact oring," so
let 's m ove forward.
_repository.AddOrder(o);
}
Ouch, we are now experiencing anot her problem . Do you see it ? Yep, how can we get t he faked
OrderNumber int o t he order inst ance? The OrderNumber propert y was read- only ( which m akes sense) ,
so using t hat one won't work.
As a m at t er of fact , t his is a generic problem . I t can be expressed like t his: How can we from t he
out side ( such as in a Reposit ory) set values in inst ances t hat are being reconst it ut ed from
per sist ence?
There are several possible ways in which t o deal wit h t his problem . Let 's see what we can com e up
wit h.
We could have a specific const ruct or t hat could be used j ust for t his reconst it ut ion. I t could look like
t his:
//Order
public Order(int orderNumber, DateTime orderDate,
Customer customer)
I t works, but it 's not very clear t o consum ers of t he Order t hat t hey aren't supposed t o use t hat
const ruct or. Well, I could let it be int ernal, of course, t o lessen t he problem quit e a lot !
The int ent ion of t he const ruct or could becom e slight ly clearer if you use a st at ic nam ed m et hod as a
fact ory like t his:
//Order
public static Order ReconstituteFromPersistence(int orderNumber
, DateTime orderDate, Customer customer)
This not only m akes t he purpose of t he m et hod slight ly clearer, but also t he fact t hat t he consum er
should not m ess wit h t his m et hod. St ill, it 's possible for t he consum er t o use t he m et hod by m ist ake,
but againt hat could be dealt wit h by using an int ernal m et hod inst ead. I t 's also problem at ic when t he
class get s m ore real world- ish, when inst ead t here are perhaps 50 propert ies t hat should be set at
reconst it ut ion. I f t his is t he case, t he param et er list becam e unwieldy a long t im e ago.
Anot her opt ion is t o decide on a m et hod t hat t he Order class has t o im plem ent , and t ypically t his
m et hod should j ust be reachable via a specific int erface. Consequent ly, t here is m uch less of a risk
t hat t he consum er will m ess wit h t he m et hod by m ist ake. I f t he consum er want s t o do evil t hings, he
can, but t hat 's m ore or less always a problem . I f it 's possible t o set values in t he inst ance from t he
out side, t he consum er can do it t oo. That is act ually not necessarily a bad t hing. I nst ead you should
t ake a react ive approach and decide t hat t he possible usage didn't creat e a problem .
So what could t his look like? One approach could be t o have a m et hod like t his on t he Order:
//Order
public void SetFieldWhenReconstitutingFromPersistence
(int fieldKey, object value)
I t 's definit ely a bit m essy. Now we have t o set up a m ap of field keys, which m ust be m aint ained
from now on, bot h as t he m ap and as regards t he SetFieldWhenReconstitutingFromPersistence()
code it self.
A sim ilar solut ion ( st ill wit hout a nice m aint ainabilit y st ory) would be t o swap t he fieldKey param et er
for a fieldName param et er inst ead.
I could use reflect ion, but t here are pros and cons t o t his, as usual. The drawbacks are t hat reflect ion
is slow ( at least com pared t o ordinary access, but is it t oo slow?) , we can't close down privileges for
t he user, and we m ust know about t he int ernal st ruct ure such as field nam es from t he out side. ( The
last t hing could be dealt wit h in part by adding privat e propert ies t hat are only t here t o be used for
t he reflect ion or by set t ing up nam ing rules so t hat if t he propert y is called Name, t here should be a
privat e field called _name. I t m ight becom e slight ly m ore robust , but t he basic problem is st ill t here.)
The m ost im port ant advant age is t hat it 's not int rusive. You can creat e your Dom ain Model j ust t he
way you want it , wit hout having t o add infrast ruct ure- specific and obscure const ruct ions.
N ot e
Well, t here are sm all det ails, such as t hat Customer can't be readonly . We'll get back t o t his
in dept h in lat er chapt ers.
We could go for a com plet ely different solut ion: for exam ple, keeping t he values out side t he inst ance
all t he t im e in a " safe place" so t hat t he inst ance is j ust like a Proxy [ GoF Design Pat t erns] . I t really
is a t ot ally different solut ion, along wit h it s ups and downs. However, I really don't like m aking such
a big, specific decision right now. I t would also m ess up t he Dom ain Model classes wit h st uff t hat has
not hing t o do wit h t he dom ain. Let 's cont inue as sim ply as possible.
All t his has quit e a lot of infrast ruct ure flavor, hasn't it ? I 'd like t o post pone t he decision regarding
how t o set values from t he out side unt il lat er, when I st art t hinking about what infrast ruct ure t o use
for support ing m y Dom ain Model. On t he ot her hand, I need t o m ake som e sort of decision now in
order t o m ove on wit h t he t est s. What 's t he sim plest m echanism t hat could possibly work for now?
Unfort unat ely, t here is no really sim ple solut ion t hat I can com e up wit h now. That 's a good sign t hat
I should probably go back and ret hink t he whole t hing.
N ot e
I t 's pret t y ironic t hat we ended up in t his long discussion j ust because I st art ed t o work
wit h t he sem ant ics around OrderNumber. But we are here now, so let 's end t he discussion.
For now, I decide t o use reflect ion against t he privat e fields. I writ e a helper m et hod in t he
OrderRepository ( which probably should be fact ored out lat er) t hat looks like t his:
//OrderRepository
public static void SetFieldWhenReconstitutingFromPersistence
(object instance, string fieldName, object newValue)
{
Type t = instance.GetType();
System.Reflection.FieldInfo f = t.GetField(fieldName
, BindingFlags.Instance | BindingFlags.Public
| BindingFlags.NonPublic);
f.SetValue(instance, newValue);
}
At last , we can m ove on again. What a long discussion j ust because OrderNumber was read- only.
Rem em ber, however, t hat t his was act ually a generic discussion about how t o let t he Reposit ories set
values when reconst it ut ing inst ances from persist ence wit hout running int o problem s wit h read- only
propert ies and code in set t ers.
[Test]
public void OrderNumberCantBeZeroAfterReconstitution()
{
int theOrderNumber = 42;
_FakeAnOrder(theOrderNumber);
Order o =
_repository.GetOrder(theOrderNumber);
Assert.IsTrue(o.OrderNumber != 0);
}
I added t he Ignore at t ribut e before so t hat t he t est wouldn't be execut ed. Now I t ake away t he
Ignore at t ribut e, and I get a red bar.
Tim e t o change t he _FakeAnOrder(). I m ake sure t hat t he new order get s t he OrderNumber of 42, like
t his:
OrderRepository.SetFieldWhenReconstitutingFromPersistence
(o, "_orderNumber", orderNumber);
_repository.AddOrder(o);
}
St ill a red bar, but it 's due t o som et hing else t his t im e. I 'm afraid t hat I creat ed a sit uat ion for m yself
when t here were several reasons for red bars, which is not recom m ended. I t ook t oo big a leap in m y
TDD approach.
//OrderRepository
public Order GetOrder(int orderNumber)
{
foreach (Order o in _theOrders)
{
if (o.OrderNumber == orderNumber)
return o;
}
return null;
}
I know, it 's a naïve im plem ent at ion, but t hat 's j ust what I want right now. And guess what ? Green
bars.
So we are back on dry ground, but m y whole being is scream ing for refact oring t he
SetFieldWhenReconstitutingFromPersistence() m et hod. The SetFieldWhenReconstitutingFrom-
Persistence() m et hod j ust doesn't belong in t he OrderRepository. I creat e a RepositoryHelper class
for now and m ove t he SetFieldWhenReconstitutingFromPersistence() m et hod t here. St ill a green bar
aft er I changed t he call t o SetFieldWhenReconstitutingFromPersistence() .
Let 's have a look at how t he Dom ain Model diagram looks now. You'll find t he revised diagram in
Figure 5- 5 .
I have t he growing feeling t hat t he whole t hing isn't as good as I want it , but I can't put m y finger on
why. I 'm sure it will appear m ore clearly when I m ove on, so t hat 's what I 'd like t o do now. What 's
next on t he list ? Perhaps fet ching t he list of orders for a cert ain cust om er.
N ot e
Did you not ice how different t he m ult iplicit y in t he UML diagram in Figure 5- 6 is com pared
t o how it would be expressed in a dat abase diagram ? I f you com e from a dat abase
background, I t hink differences such as no navigable relat ionship from Customer t o Order
m ight surprise you, and t he m ult iplicit y is one t o one for t he relat ionship t hat is t here
because it is from Order t o Customer .
I t 's t im e for anot her t est . Again, I need t o fake Orders in t he OrderRepository for t he t est t o run.
Here goes:
[Test]
public void CanFindOrdersViaCustomer()
{
Customer c = new Customer();
_FakeAnOrder(42, c, _repository);
_FakeAnOrder(12, new Customer(), _repository);
_FakeAnOrder(3, c, _repository);
_FakeAnOrder(21, c, _repository);
_FakeAnOrder(1, new Customer(), _repository);
Assert.AreEqual(3, _repository.GetOrders(c).Count);
}
As you saw, I changed _FakeAnOrder() so it now also t akes Customer and OrderRepository as
param et ers. That 's a sim ple change, of course. Anot her pret t y sim ple t hing is needed for m aking t he
solut ion com pile and t hat is adding t he GetOrders() m et hod. I t could look like t his ( aft er you first
t ook t hat m andat ory t our of red, of course) :
//OrderRepository
public IList GetOrders(Customer customer)
{
IList theResult = new ArrayList();
I 'm not sure I really like t he previous code. I 'm t hinking about t he check for equalit y. Assum e t hat I
have t wo Customer inst ances ( not t wo variables point ing t o t he sam e inst ance, but t wo separat e
inst ances) , bot h wit h t he sam e CustomerNumber. Will t he call t o Equals() t hen ret urn t rue or false? I t
depends on whet her Equals() has been overridden or not and whet her or not t he overridden
im plem ent at ion uses t he CustomerNumber for deciding on equalit y.
N ot e
Readers t hat are fam iliar wit h t he concept of t he I dent it y Map pat t ern [ Fowler PoEAA] and
who see it as a m ust will probably wonder why we are having t his discussion at all. The
idea wit h I dent it y Map is t hat you will not have t wo separat e inst ances for a single
cust om er. The I dent it y Map will t ake care of t hat for you.
The language it self, C# for exam ple, won't t ake care of t his for you. But when we discuss
persist ence solut ions in Chapt er 8, " I nfrast ruct ure for Persist ence," and Chapt er 9, " Put t ing
NHibernat e int o Act ion," we'll cover t his. Unt il t hen, we are on our own.
I t is im port ant for us t o keep t rack of som e t hings in t he dom ain over t im e. No m at t er whet her a
cust om er changes nam e or address, it 's st ill t he sam e cust om er, and it 's som et hing we are int erest ed
in keeping t rack of. On t he ot her hand, if a cust om er's reference person changes, it is probably not
anyt hing we care t o keep t rack of. A cust om er is a t ypical exam ple of an Ent it y [ Evans DDD] . Again,
an Ent it y is som et hing we keep t rack of by ident it y rat her t han all it s values.
To t ake an ext rem e exam ple of som et hing t hat isn't an Ent it y, let 's t hink about t he int eger 42. I don't
care about t he ident it y of 42 at all; I only care about t he value. And when t he value changes, I no
longer t hink it 's t he 42 t hat has changedit 's a t ot ally new value wit h no connect ion t o t he old one.
Fort y- t wo is a Value Obj ect [ Evans DDD] and not an Ent it y.
I f we t ake t hat ext rem e exam ple over t o our dom ain, we m ight be able t o say t hat it isn't int erest ing
for us t o t rack ReferencePerson of a Customer by ident it y. I t 's only int erest ing for us t o t rack it by
value. We'll get back t o Value Obj ect s lat er on in t his chapt er.
N ot e
Of course, what should be t racked by ident it y and what should j ust be t hought of as values
is highly dependent on t he dom ain. Let 's t ake an exam ple. As I said above, I believe t hat
ReferencePerson in t his applicat ion can be dealt wit h as a Value Obj ect , but if t he
applicat ion is for, let 's say, a sales support applicat ion for salesm en, perhaps t hey see
ReferencePerson as an Ent it y inst ead.
RepositoryHelper.SetFieldWhenReconstitutingFromPersistence
(c, "_customerNumber", customerNumber);
return c;
}
N ot e
_FakeACustomer() should associat e t he cust om er wit h t he CustomerRepository ( or rat her t he
Unit of Work, when t hat com es in t o play) . Let 's skip t his for now because it won't affect t he
flow now.
Then I change t he t est CanFindOrdersViaCustomer(), so I use _FakeACustomer() inst ead of j ust calling
t he const ruct or of t he Customer direct ly. The code looks like t his aft er t he change.
[Test]
public void CanFindOrdersViaCustomer()
{
Customer c = _FakeACustomer(7);
_FakeAnOrder(42, c, _repository);
_FakeAnOrder(12, _FakeACustomer(1), _repository);
_FakeAnOrder(3, c, _repository);
_FakeAnOrder(21, c, _repository);
_FakeAnOrder(1, _FakeACustomer(2), _repository);
Assert.AreEqual(3, _repository.GetOrders(c).Count);
}
I t hink it is t im e t o sum up where we are wit h a figure. Since Figure 5- 6 , we have also added
CustomerNumber t o t he Customer class, as you can see here in Figure 5- 7 .
What have t he t est s bought us t hus far? Well for st art ers, we've used t he t est s as a m eans t o
discover and nail down t he behavior and specificat ion t hat we want t he Dom ain Model t o im plem ent .
By st art ing out wit h Fake/ naïve im plem ent at ion, we've been able t o concent rat e our energy on
invent ing t he API . We are also t rying hard t o com e up wit h, and playing wit h, t he Ubiquit ous
Language. Finally, our t est s have now given us a solid foundat ion in which we can t ransit ion t he code
from our naïve im plem ent at ion t o t he " real t hing."
I also believe we have respect ed t he event ual t arget wit h t he design choices. We have also creat ed
an abst ract ion layer in t he form of reposit ories so we can defer dealing wit h t he dat abase ( which is
wort h deferring) .
So, specifically what we have done was writ e a first fake version of t he OrderRepository...! We have
also given t he OrderRepository several different responsibilit ies. That m ight be t he reason for m y
uneasiness wit h t he design. I don't want t o focus on infrast ruct ure at all right nowI want t o post pone
it unt il lat er on. However, because I not iced t hat what I 'm current ly working on is infrast ruct ure
wit hin t he Dom ain Model, let 's wait wit h t he feat ure list for a while and consider som e refact oring t o
get a nicer solut ion wit h t he faking of t he OrderRepository.
N ot e
I 'm t rying t o use " st ub," " fake" and " m ock" wit h specific, explicit m eanings. Here's a quot e
from Ast els [ Ast els TDD] :
" St u bs: A class wit h m et hods t hat do not hing. They are sim ply t here t o allow t he syst em
t o com pile and run.
Fa k e s: A class wit h m et hods t hat ret urn a fixed value or values t hat can eit her be
hardcoded or set program m at ically.
M ock s: A class in which you can set expect at ions regarding what m et hods are called, wit h
which param et ers, how oft en, et c. You can also set ret urn values for various calling
sit uat ions. A m ock will also provide a way t o verify t hat t he expect at ions were m et ."
But t hat 's not t he only definit ion. I t 's discussed a lit t le different ly by Meszaros [ Meszaros
XUnit ] :
" A Te st St u b is an obj ect t hat is used by a t est t o replace a real com ponent on which t he
SUT depends so t hat t he t est can cont rol t he indirect input s of t he SUT. This allows t he t est
t o force t he SUT down pat hs it m ight not ot herwise exercise.
" A Fa k e Obj e ct is an obj ect t hat replaces t he funct ionalit y of t he real depended- on
com ponent in a t est for reasons ot her t han verificat ion of indirect input s and out put s.
Typically, it will im plem ent t he sam e or a subset of t he funct ionalit y of t he real depended-
on com ponent but in a m uch sim pler way.
" A M ock Obj e ct is an obj ect t hat is used by a t est t o replace a real com ponent on which
t he SUT depends so t hat t he t est can observe it s indirect out put s. Typically, t he Mock
Obj ect fakes t he im plem ent at ion by eit her ret urning hard- coded result s or result s t hat were
pre- loaded by t he t est ."
Perhaps an int erface like t he one shown in Figure 5- 8 is what I need for now.
I nst inct ively, I like t his a lot . I t m ight be because of m y COM herit age or because m any aut hors
( such as [ Szyperski Com ponent Soft ware] , [ Johnson J2EE Developm ent wit hout EJB] and [ Löwy
Program m ing .NET Com ponent s] ) clearly st at e t hat program m ing against int erfaces is preferable t o
program m ing against concret e classes.
St illand I have already t ouched on t hisI do have concret e classes ( Customer and Order) wit hin t he
signat ures of t he int erface. Again, I leave it like t his for now because I don't current ly see any value
in creat ing int erfaces for t hose classes.
Anot her t hing t hat com es t o m ind is t hat it m ight be nice t o creat e a m ore generic Reposit ory
int erface. I t could look like what is shown in Figure 5- 9 .
This m ight grow on m e, but right now I prefer t he m ore specific int erface in Figure 5- 8 , as it clearly
st at es exact ly what is needed. The generic IRepository requires m ore cast s when being used and
m ight be incorrect ly t rying t o gat her all upcom ing Reposit ories in one and t he sam e shape.
Anot her solut ion m ight be t o use generics in t he IRepository- int erface + a base class and t hereby at
least get t he t ype safet y ( and avoid code duplicat ion) and avoid ext ra t ype cast s. One problem t hen
is t hat I m ight add a Delete() m et hod t o t he Reposit ory, even t hough not all Reposit ories will need
it . And even wit h generics, t he GetListByParent(parent) is t roublesom e because what if an Ent it y
has several parent s? Well, it 's an early sket ch and t hat can be solved of course. But I can't help
t hinking t hat it 's bet t er t o let t he code " speak as clearly as possible for now" and skip generalizat ions
like t hat . I t 's j ust not feeling im port ant yet . As usual, no decisions are carved in st one. I can
challenge t he decisions again lat er on when I can m ore easily see what pieces can be generalized,
but for now, I 'll st ay wit h IOrderRepository.
I guess pure XPers would groan a lit t le bit at t he refact oring I j ust did. I act ually didn't have t o m ake
t hat change now; it was a change for preparing for t he fut ure, when I need a real Reposit ory inst ead
of t he faked one. OK, I can agree wit h t hat , but I can't help t hinking a lit t le bit about t he fut ure
( read: lat er chapt ers) when I will be hooking in infrast ruct ure.
I cross m y fingers t hat t his preparat ion will prove t o be good. I fell back int o old habit s of early
guessing.... On t he ot her hand, we are of course free t o choose our own balance and don't have t o
st ick t o XP dogm a!
I need t o ask t he infrast ruct ure t o deal wit h t he save funct ionalit y. The quest ion for now is if I want
t o st at e t he PersistAll() t o t he Reposit ory inst ance or t o som et hing at a higher level t hat m onit ors
inst ances for all t he Reposit ories. Again, I t hink I 'm drift ing away from t he Dom ain Model and int o
t he infrast ruct ure part . I 'm glad t he quest ion was raised, but part s of t he discussion will have t o wait
unt il t he next chapt er. There is a great deal t hat we need t o discuss as far as t hat is concerned. For
now, I 'm happy wit h AddOrder() as a way of let t ing t he Reposit ory know about t he inst ance. As far as
t he t est s t hat have been writ t en so far are concerned, it doesn't really m at t er t hat t he inst ance is
t ransient ( but prepared for being persist ed) and not persist ent at t hat point in t im e.
OK, I 'm as eager as you are t o get writ ing som e m ore t est s. What 's on t he list ? Well, I have dealt
wit h m ost of it in feat ure 2, " List t he orders when looking at a specific cust om er." What I haven't
dealt wit h t here is showing t he t ot al am ount for each order, t ype of order, and reference person.
Let 's t ake t hem one by one, st art ing wit h t ot al am ount for each order.
But t his is get t ing t o be t oo m uch for m e, t he " prem at ure opt im izer guy" t hat I am ( even t hough I 'm
t rying hard not t o be) . I nst ant iat ing all orderLines for each order for a customer j ust t o be able t o
show t he TotalAmount of t he orders set s off t he alarm bells. This m ight not be a problem depending
upon t he execut ion environm ent and chosen infrast ruct ure. On t he ot her hand, in t he case of a
dist ribut ed syst em , it is a problem , and pot ent ially a big one t hat can hurt t he dat abase server, t he
net work, and t he garbage collect or.
I m ust adm it I have t o force m yself not t o deal wit h t his opt im izat ion right away. I t 's sim ple t o fix it
direct ly, but it 's not really im port ant right now when I 'm crunching what t he Dom ain Model should
look like. I t 's m uch m ore im port ant right now t o design for sim plicit y and clarit y, and get back lat er
wit h a profiler t o see if it 's a real perform ance problem . So I st art wit h t he sim plest solut ion and can
t hen refact or t he TotalAmount propert y lat er on if t he perform ance charact erist ics aren't good
enough.
Ah, I m ade it ! I skipped an opt im izat ion now. And it feels so good for t he m om ent .
Let 's t ake a st ep back now t hat we have t hought a bit about t he TotalAmount. I t 's t im e t o writ e a t est
( bet t er lat e t han never) . I st art wit h t he sim plest possible one I can com e up wit h.
[Test]
public void EmptyOrderHasZeroForTotalAmount()
{
Order o = new Order(new Customer());
Assert.AreEqual(0, o.TotalAmount);
}
I t 's sim ple t o m ake t hat t est com pile. I j ust add a public read- only propert y called TotalAmount t o t he
Order class and let it ret urn - 1. I t com piles and I get red. I change it so t hat t he propert y ret urns 0
and I have a green bar.
I could leave t hat for now, but because I have t he cont ext set up for m e now, I cont inue a lit t le bit .
Here's anot her t est :
[Test]
public void OrderWithLinesHasTotalAmount()
{
Order o = new Order(new Customer());
o.AddOrderLine(ol);
Assert.AreEqual(104.00, o.TotalAmount);
}
Ouch, t here was a lot of design done in t hat single t est , and I now need t o creat e t wo classes and
new m et hods at old classes t o j ust m ake it com pile. I t hink I 'd bet t er com m ent out t hat t est for t he
m om ent and st art a lit t le m ore sim ply, focusing on t he OrderLine class.
First of all, I want t he OrderLine t o get t he price from t he chosen product as a default . Let 's writ e a
t est .
[Test]
public void OrderLineGetsDefaultPrice()
{
Product p = new Product("Chair", 52.00);
Assert.AreEqual(52.00, ol.Price);
}
Even t hat is a pret t y large j um p t hat requires som e code t o be writ t en, but I 'm feeling confident right
now, so let 's writ e a Product class. The second argum ent in t he const ruct or should be t he unit price.
The Product class should also have t wo read- only propert ies: Description and UnitPrice.
I also wrot e an OrderLine class wit h t wo m em bers: Product and Price. I t looks like t his:
The t est now com piles, but it 's red. I need t o change t he const ruct or so t hat I grab t he price from t he
Product and put it int o t he OrderLine it self. The const ruct or now looks like t his:
//OrderLine
public OrderLine(Product product)
{
_product = product;
Price = product.UnitPrice;
}
We are back t o green again. I writ e a t est proving t hat I can override t he default price in t he
OrderLine, but it 's not very int erest ing, so let 's leave it out here.
The next t est I 'd like t o writ e is a calculat ion of t he TotalAmount of one orderLine. The t est could be
like t his:
[Test]
public void OrderLineHasTotalAmount()
{
OrderLine ol = new OrderLine(new Product("Chair", 52.00));
ol.NumberOfUnits = 2;
Assert.AreEqual(104.00, ol.TotalAmount);
}
Two m ore design decisions t here. I need a NumberOfUnits field and a TotalAmount on t he OrderLine. I
let t he NumberOfUnits be a public field, and I writ e t he TotalAmount as a read only propert y ret urning
0. I t com piles, but is red. I t hen change t he TotalAmount int o t his:
//OrderLine
public decimal TotalAmount
{
get {return Price * NumberOfUnits;}
}
Green again.
Let 's have a look at what we j ust did. I n Figure 5- 10, you find a diagram wit h OrderLine and Product.
Figu r e 5 - 1 0 . OrderLine a n d Product
I t 's t im e t o go back t o t he t est I com m ent ed out before. You'll find it again here, but I m ade it a lit t le
bit " bigger" t his t im e, dealing wit h t wo OrderLines.
[Test]
public void OrderWithLinesHasTotalAmount()
{
Order o = new Order(new Customer());
I n order t o get t his t o com pile, I need t o add AddOrderLine() and TotalAmount t o Order. I let t he
read- only propert y TotalAmount j ust ret urn 0 for t he m om ent . And I set [Ignore] on
OrderWithLinesHasTotalAmount() t est . I nst ead, I writ e anot her t est t o focus on AddOrderLine(). That
t est could look like t his:
[Test]
public void CanAddOrderLine()
{
Order o = new Order(new Customer());
Assert.AreEqual(1, o.OrderLines.Count);
}
For t his t o com pile, I need t o add bot h AddOrderLine() and an OrderLines propert y t o t he Order.
Because t he t est will fail m eaningfully if eit her of t hem isn't working, I get st art ed by writ ing
OrderLines t he way I t hink I want it , but don't finish AddOrderLine(). You can find t he code here:
//Order
private IList _orderLines = new ArrayList();
I t com piles and is red. I add a line t o t he AddOrderLine() m et hod like t his:
//Order
public void AddOrderLine(OrderLine orderLine)
{
_orderLines.Add(orderLine);
}
//Order
public decimal TotalAmount
{
get
{
decimal theSum = 0;
foreach (OrderLine ol in _orderLines)
theSum += ol.TotalAmount;
return theSum;
}
}
Sim ple, st raight forward, and green. And did you not ice t hat I resist ed t he urge t o opt im ize it ? I j ust
wrot e it t he sim plest way I could t hink of, and I even alm ost did it wit hout groaning. Aft er all, I
current ly see t he Order and it s OrderLines as t he Aggregat e and t herefore as t he default load unit as
well.
The ot her problem is t hat t he const ruct or t akes a Customer as a param et er. That m eans t hat t he
Order m ight get int o t he persist ent obj ect graph direct ly, wit hout a call t o
IOrderRepository.AddOrder(), and t his m ight not be such a good idea. ( Well, it depends on your
infrast ruct ure as well, but it 's not obvious t hat t here is a boundary.) AddOrder() is t he way of saying
t hat t his order should get persist ed when it 's t im e for saving.
None of t hese problem s are at all hard t o deal wit h, but how do I com m unicat e t his clearly? I writ e a
t est , t o t ry out a proposal:
[Test]
public void OrderHasSnapshotOfRealCustomer()
{
Customer c = new Customer();
c.Name = "Volvo";
c.Name = "Saab";
Assert.AreEqual("Saab", c.Name);
Assert.AreEqual("Volvo", o.Customer.Name);
}
But I 'm not so sure about t his solut ion... Current ly, t he Customer is a pret t y sm all t ype, but it will
probably grow a lot . Even t hough it 's sm all now, is it really int erest ing t o keep t rack of what
reference people t he Customer had at t hat point in t im e?
I t hink creat ing anot her t ype wit h only t he propert ies t hat are int erest ing m ight be a good solut ion
here because it will also creat e an explicit boundary bet ween t he Aggregat es, but especially because
t hat 's what t he underlying m odel indicat es. Let 's creat e a CustomerSnapshot ( som ewhat inspired by
[ Fowler Snapshot ] regarding t he purpose, but different in im plem ent at ion) t hat only has t he
m inim um am ount of propert ies, and let it be a value obj ect . The t est only has t o be t ransform ed very
slight ly ( aft er I have correct ed t wo com pile errors: t he t ype for t he Customer propert y and t he
param et er t o t he const ruct or) :
[Test]
public void OrderHasSnapshotOfRealCustomer()
{
Customer c = new Customer();
c.Name = "Volvo";
c.Name = "Saab";
Assert.AreEqual("Saab", c.Name);
Assert.AreEqual("Volvo", o.Customer.Name);
}
Anot her t hing t o consider is whet her t he consum er or t he Order const ruct or is responsible for
creat ing t he snapshot . Previously, I let t he consum er be responsible. Let 's change t hat so t hat t he
const ruct or again t akes a Customer inst ance as t he param et er, as follows:
[Test]
public void OrderHasSnapshotOfRealCustomer()
{
Customer c = new Customer();
c.Name = "Volvo";
c.Name = "Saab";
Assert.AreEqual("Saab", c.Name);
Assert.AreEqual("Volvo", o.Customer.Name);
}
//Order
public Order(Customer customer)
{
Customer = customer.TakeSnapshot();
}
Anot her t hing t o consider is if it 's t he correct place in t im e t o t ake t he snapshot when t he cust om er
inst ance is creat ed. I sn't t hat t oo early? What if t he cust om er changes? Perhaps we should t ake t he
snapshot at a t ransit ion for when t he cust om er accept s t he order? Lot s of int erest ing and im port ant
quest ions, but I st art like t his now.
Let 's j ust conclude t his sect ion wit h an updat e of t he Customer . See Figure 5- 11.
I t 's refact oring t im e again, I t hink. Hm m m ...I 'm not t ot ally happy wit h t he fact t hat I send a Customer
inst ance t o GetOrders() when finding Orders. I t 's act ually j ust t he I D of t he cust om er t hat is
im port ant for t he funct ionalit y, and it feels a bit st range t o use a current cust om er for fet ching orders
wit h hist oric cust om er inform at ion. Anyway, I 'd like t o t hink about it som e m ore.
Anot her quest ion is what we should call t he propert y of t he Order for seeing t he hist oric cust om er
inform at ion of t hat order. Right now it 's called Order. Customer , but t hat says not hing about t he t im e
aspect of t he Customer inform at ion. Perhaps Order.CustomerSnapshot is bet t er. I t hink it is, I m ake
t hat change, and you can see t he new Order- class in Figure 5- 12.
Perhaps I should add t hat OrderFactory back again, add a m et hod t o it for CreateOrderLine(), and
let it t ake bot h a Product and an Order as param et er ( or at least an Order) . On t he ot her hand, it
feels good t o be able t o work wit h an OrderLine wit hout m aking it persist ent ( which will happen when
I add t he order line t o a persist ent order) . Let 's see if t his m ight need t o be changed lat er on, but
t his has raised anot her concern. I t hink I need t o discuss t he life cycle of an inst ance right here.
Then t he Product is t ransient . I t is not fet ched from t he dat abase as it has never becom e persist ent .
I f we want it t o becom e persist ent ( and st ored t o t he dat abase at next call t o PersistAll()) , we need
t o ask a Reposit ory for help by calling AddProduct(). Depending upon t he infrast ruct ure t hat is used,
t he Reposit ory m akes t he infrast ruct ure aware of t he product .
Then again, when I ask t he Reposit ory for help wit h reconst it ut ing an inst ance from t he dat abase,
t hat fet ched inst ance is persist ent when I get it . All changes I m ake t o it will be st ored at next
PersistAll().
But what about OrderLine? I didn't ask t he Reposit ory t o AddOrderLine(), but I did ask t he Aggregat e
root Order t o AddOrderLine(), and because of t hat t he order line is m ade persist ent , t oo. Wit hin
Aggregat es, I t hink t he persist ence aspect should be cascaded.
Let 's sum m arize what I t hink t he sem ant ics are for t he life cycle t hat I need in m y Dom ain Model.
They are shown in Table 5- 1.
Reposit ory.Get ( ) Persist ent in Dom ain Model ( and Dat abase)
Reposit ory.Delet e( inst ance) Transient ( and inst ance will get delet ed from
dat abase at x.Persist All)
N ot e
Evans t alks a lot about t his t oo... [ Evans DDD] . There is a splendid explanat ion for t his, so
be sure t o read it . The sam e goes for Jordan/ Russell [ Jordan/ Russell JDO] . JDO has m ore
com plex ( and flexible) sem ant ics, but of course I m ight discover lat er t hat t he sim ple
sem ant ics I sket ched previously are not enough.
Don't m ix t his up wit h how t he infrast ruct ure ( for exam ple NHibernat e) sees t he t ransient / persist ent .
What I t alk about here is t he way I want t he life cycle sem ant ics for m y Dom ain Model inst ances. I t 's
t hen up t o t he infrast ruct ure t o help m e wit h t he want ed sem ant ics behind t he scenes. This will be
discussed a lot m ore in lat er chapt ers.
Talking about t he infrast ruct ure, t he hawk- eyed reader m ight wonder what I m eant wit h
x.PersistAll() in Table 5- 1. I t ried t o sym bolize t hat unknown infrast ruct ure wit h x. Again, we can
forget about t hat for now.
Back t o feat ure 2, list ing orders for a cust om er. The next sub- feat ure was t hat an order m ust have
an ordert ype.
Type of Order
A sim ple solut ion here would be t o add an OrderType inst ance t o each Order, as shown in Figure 5- 14.
I 'm probably on t he wrong t rack here. Sure, I could im plem ent OrderType as a Value Obj ect , but
m uch is point ing in t he direct ion t hat an enum is good enough, and especially good enough for now,
so I define an OrderType enum and add such a field t o t he Order.
When we go for a Value Obj ect pat t ern [ Evans DDD] , it m ight feel obvious t hat we should use a
st ruct in .NET inst ead of a class, but t here are recom m endat ions for size regarding when t o use a
st ruct and when not t o, and you'll get m ore problem s wit h infrast ruct ure when it com es t o st ruct s.
I t 's also t he case t hat you will see m ore boxing when using st ruct s, so t he decision isn't clear- cut . I 'm
act ually leaning t o using classes, but m ost oft en I 'm m aking t hem im m ut able. I f you go t hat rout e,
you need t o use all t he values of t he class for when you are overriding t he Equals() .
This is what t he Equals() could look like for t he Value Obj ect ReferencePerson. ( Not e t hat I 'm
com paring all t he fields of t he Value Obj ect , unlike how I did it wit h t he Ent it y before. Also not e t hat ,
I dent it y Map or not , overriding Equals() for Value Obj ect s is needed.)
//ReferencePerson
public override bool Equals(object o)
{
if (o == null)
return false;
if (this.GetType() != o.GetType())
return false;
ReferencePerson other = (ReferencePerson) o;
if (! FirstName.Equals(other.FirstName))
return false;
if (! LastName.Equals(other.LastName))
return false;
return true;
}
N ot e
I ngem ar Lundberg com m ent ed on t he previous list ing wit h a m ore condensed version:
//ReferencePerson.Equals()
ReferencePerson other = o as ReferencePerson;
return other != null
&& this.GetType() == other.GetType()
&& FirstName.Equals(other.FirstName)
&& LastName.Equals(other.LastName);
So we have now writ t en som e of t he core funct ionalit y in t he Dom ain Model. I n Figure 5- 16, you can
see how t he developed Dom ain Model looks for t he m om ent .
But let 's end t he chapt er wit h a discussion about anot her st yle of API .
Fluent Interface
So far we have sket ched out a pret t y basic and prim it ive API for our Dom ain Model. Creat ing an
order wit h t wo products could look like t his ( assum ing we are already holding on t o a specific
customer ) :
I t hink it 's pret t y easy t o follow. But it 's a bit verbose and not as fluent as it could be. A sim ple way
of short ening it would be t o add numberOfUnits t o t he const ruct or of OrderLine, t aking it down t o
t hree st at em ent s, like t his:
newOrder.AddOrderLine(new OrderLine
(42, productRepository.GetProduct("ABC")));
newOrder.AddOrderLine(new OrderLine
(3, productRepository.GetProduct("XYZ")));
But it 's st ill not very fluent . Mart in Fowler's " Fluent I nt erface" [ Fowler Fluent I nt erface] is good
inspirat ion. Let 's see if we can sket ch t he API t o be a bit m ore fluent . Perhaps som et hing like t his:
I t 's bot h short er and clearer. I n m y sket ch, I kept t he first line because I t hink t hat is pret t y clear.
Then t he With() m et hod t akes t he numberOfUnits as param et er and a product ident ificat ion so t hat
With() int ernally can use t he productRepository for finding t he product. ( Let 's assum e for now t hat
With() can find t he productRepository at a well known place.)
With() also ret urns t he order, and t herefore we can chain several st at em ent s aft er each ot hers.
Let 's t ry out a variat ion. Assum e t hat we can't creat e t he whole order in one swoop, but want t o add
an orderLine as t he result from a user act ion. Then we m ight prefer som et hing like t his for adding an
orderLine:
newOrder.AddOrderLine("ABC").NumberOfUnits = 42;
This t im e AddOrderLine() ret urns t he orderLine and not t he order. We could t ake t hat furt her if we
want t o be able t o set m ore values of t he orderLine by changing NumberOfUnits int o a m et hod
inst ead t hat ret urns t he orderLine again, but you get t he point .
The im port ant t hing t o t ake away from t his sect ion is how m uch bet t er your API can becom e if you
play wit h it a bit .
Summary
So we spent t he whole chapt er discussing som e init ial part s of t he m odel, but wit h a fairly det ailed
discussion. As I see it , det ailed m odel discussions are best done wit h code and TDD inst ead of UML
sket ches, and t his chapt er followed t hat idea.
I t hink it 's a good idea t o sum m arize where we are in t he feat ure list before we leave t he chapt er. So
far we have dealt wit h feat ures 2, 3, 7 and 9. Not t hat m uch, but clear progress. And t he progress is
secured wit h quit e a lot of t est s. Good.
We'll cont inue t he work wit h refining t he Dom ain Model in Chapt er 7. The focus will shift a bit in t he
next chapt er. As you m ight have not iced, we sniffed on infrast ruct ure relat ed discussions several
t im es in t his chapt er, so let 's t ake on t hose problem s next by preparing for adding infrast ruct ure.
Chapter 6. Preparing for Infrastructure
I t 's t im e t o cont inue t he explorat ion of applying DDD t o our problem dom ain. There is no specific
next st ep, but you m ay be wondering when I will st art dealing wit h t he infrast ruct ure. For inst ance,
we haven't yet m ade it possible t o persist or depersist ( m at erialize or reconst it ut e) t he orders t o or
from a dat abase. As a m at t er of fact , we haven't even t hought about , let alone decided on, using a
dat abase.
This is int ent ional. We want t o delay m aking t his decision a bit longer, at least if we are feeling safe
and fam iliar wit h exist ing infrast ruct ural opt ions. I f t his is our first DDD- ish proj ect , t his m ight not be
t he case, of course, but let 's pret end.
The reason I want t o delay t he binding t o a relat ional dat abase is t hat in doing so we will focus on
t he Dom ain Model wit h as few dist ract ions as possible. Hey, I 'm an old dat abase guy, so it 's OK for
m e t o t alk about t he dat abase as a dist ract ion. I would never dare t o say t hat if I cam e from t he OO
side.
Seriously, I 'm not saying t hat t he dat abase int eract ion isn't im port ant ; on t he cont rary, I know t hat it
is im port ant . But st aying away from t he dat abase a bit longer m akes t rying out and exploring bot h
sm all and large m odel changes m ore product ive for us.
I t 's also m uch easier t o writ e t he t est s, because changes done in t est s won't be persist ent bet ween
execut ions. The t est execut ions t hem selves will also execut e m uch fast er, m aking it m uch m ore
m anageable for t he developers t o run t he t est s aft er each code change.
There are also problem s wit h t his approach. I have already said t hat we assum e we have good
cont rol of dealing wit h t he probable upcom ing dat abase int eract ion, so t his is not where t he problem
lies. I nst ead, t here's a good chance t hat you will want t o writ e som e UI prot ot ypes early on, not only
for your own sake as a way of challenging your Dom ain Model, but also as a way t o dialogue wit h t he
cust om er. I f t hese prot ot ypes have " live" dat a t hat t he user can int eract wit h, add t o, and so on,
t hey will be m ore useful t han what is com m on for early prot ot ypes.
As you m ight recall, we ended Chapt er 5, " A New Default Archit ect ure," wit h a prelim inary discussion
about adding early UI exam ples. Users will find t hese exam ples even m ore int erest ing t o t ry out if
t he dat a is also around aft er a rest art . ( Sure, t his can easily be done if you st art using t he planned
persist ence solut ion direct ly. However, we expect t hat t his will increase t he overhead during early
refact oring at t em pt s, so what we want is t o creat e an inexpensive " illusion." )
N ot e
Wat ch out so t hat your cust om er ( or your boss) doesn't t hink t hat t he whole applicat ion is
done aft er only having seen one or t wo prot ot ypes. Been t here, done t hat .
The second t hing I 'm aft er at t his point is t o be able t o writ e t est s for save scenarios here, again
wit hout dealing wit h a real dat abase. You m ight ask what t he point of t his is. Again, I 'd like t o focus
on t he m odel, t he sem ant ics " around" it , and so on.
I could cert ainly deal wit h t his problem on an individual basis in t he reposit ories, as I have done so
far, but I see value in having consist ency and j ust applying one solut ion t o all t he reposit ories. I also
want a solut ion t hat scales up t o early int egrat ion t est ing, and m ost im port ant ly I want t o writ e real
reposit ories now and not st upid, t em porary code t hat should be t hrown away!
So even t hough I st art ed out saying t hat it 's t oo early for infrast ruct ure, t his chapt er will deal wit h
pr epar at ion for t he infrast ruct ure, and in such a way t hat we won't have t o redo work when we add
infrast ruct ure. What we want is t o writ e infrast ruct ure- agnost ic code.
POCO as a Lifestyle
What I also j ust said bet ween t he lines is t hat I 'd really like t o t ry t o keep t he m ain asset of m y
applicat ions as free from infrast ruct ure- relat ed dist ract ions as possible. The Plain Old Java Obj ect
( POJO) and Plain Old CLR Obj ect ( POCO) m ovem ent st art ed out in Java land as a react ion against
J2EE and it s huge im plicat ions on applicat ions, such as how it increased com plexit y in everyt hing and
m ade TDD close t o im possible. Mart in Fowler, Rebecca Parsons, and Josh MacKenzie coined t he t erm
POJO for describing a class t hat was free from t he " dum b" code t hat is only needed by t he execut ion
environm ent . The classes should focus on t he business problem at hand. Not hing else should be in
t he classes in t he Dom ain Model.
N ot e
This m ovem ent is one of t he m ain inspirat ions for light weight cont ainers for Java, such as
Spring [ Johnson J2EE Developm ent wit hout EJB] .
I n .NET land it has t aken a while for Plain Old... t o receive any at t ent ion, but it is now known as
POCO.
POCO is a som ewhat est ablished t erm , but it 's not very specific regarding persist ence- relat ed
infrast ruct ure. When I discussed t his wit h Mart in Fowler he said t hat perhaps Persist ence I gnorance
( PI ) is a bet t er and clearer descript ion. I agree, so I 'll change t o t hat from now on in t his chapt er.
What are t hose dist ract ions? For inst ance, if you use a PI - based approach for persist ent obj ect s,
t here's no r equir em ent t o do any of t he following:
There is at least one m ore, and one t hat is so obvious t hat I forgot . You shouldn't have t o writ e
dat abase code such as calls t o st ored procedures in your Dom ain Model classes. But t hat was so
obvious t hat I didn't writ e specifically about it .
Wit h fram eworks, a very com m on requirem ent for support ing persist ence is t hat t hey require you t o
inherit from a cert ain base class provided by t he fram ework.
Well, it wasn't t oo bad, but it did carry som e sem ant ics and m echanism s t hat aren't opt im al for you.
For exam ple, you have used t he only inherit ance possibilit y you have for your Customer class because
.NET only has single inherit ance. I t 's cert ainly arguable whet her t his is a big problem or not , t hough,
because you can oft en design " around" it .
I t 's a worse problem if you have developed a Dom ain Model and now you would like t o m ake it
persist ent . The inherit ance requirem ent m ight very well require som e changes t o your Dom ain Model.
I t 's pret t y m uch t he sam e when you st art developing a Dom ain Model wit h TDD. You have t he
rest rict ion from t he beginning t hat you can't use inherit ance and have t o save t hat for t he
persist ence requirem ent .
Som et hing you should look out for is if t he inherit ance brings lot s of public funct ionalit y t o t he
subclass, which m ight m ake t he consum er of t he subclass have t o wade t hrough m et hods t hat aren't
int erest ing t o him .
I t 's also t he case t hat it 's not usually as clean as t he previous exam ple, but m ost of t he t im e
PersistentObjectBase forces you t o provide som e m et hod im plem ent at ions t o m et hods in
PersistentObjectBase, as in t he Tem plat e Met hod pat t ern [ GoF Design Pat t erns] . OK, t his is st ill not
a disast er, but it all adds up.
N ot e
This doesn't necessarily have t o be a requirem ent , but can be seen as a convenience
enabling you t o get m ost , if not all, of t he int erface im plem ent at ion t hat is required by t he
fram ework if t he fram ework is of t hat kind of st yle. We will discuss t his com m on
requirem ent in a lat er sect ion.
This is how it was done in t he Valhalla fram ework t hat Christ offer Skj oldborg and I
developed. But t o be honest , in t hat case t here was so m uch work t hat was t aken care of
by t he base class called EntityBase t hat im plem ent ing t he int erfaces wit h cust om code
inst ead of inherit ing from EntityBase was really j ust a t heoret ical opt ion.
Don't get m e wrong, I 'm not in any way against using fact ories. Nevert heless, I 'm not ecst at ic at
being forced t o use t hem when it 's not m y own sound decision. This m eans, for inst ance, t hat inst ead
of writ ing code like t his:
Customer c = (Customer)PersistentObjectFactory.CreateInstance
(typeof(Customer));
N ot e
I know, you t hink I did m y best t o be unfair by using ext rem ely long nam es, but t his isn't
really any bet t er, is it ?
Customer c = (Customer)POF.CI(typeof(Customer));
Again, it 's not a disast er, but it 's not opt im al in m ost cases. This code j ust looks a lot weirder t han
t he first inst ant iat ion code, doesn't it ? And what oft en happens is t hat code like t his increases t est ing
com plexit y.
Oft en one of t he reasons for t he m andat ory use of a provided fact ory is t hat you will consequent ly
get help wit h dirt y checking. So your Dom ain Model classes will get subclassed dynam ically, and in
t he subclass, a dirt y- flag ( or several) is m aint ained in t he propert ies. The fact ory m akes t his
t ransparent t o t he consum er so t hat it inst ant iat es t he subclass inst ead of t he class t he fact ory
consum er asks for. Unfort unat ely, for t his t o work you will also have t o m ake your propert ies virt ual,
and public fields can't be used ( t wo m ore sm all det ails t hat lessen t he PI - ness a lit t le) . ( Well, you can
use public fields, but t hey can't be " overridden" in t he generat ed subclass, and t hat 's a problem if t he
purpose of t he subclass is t o t ake care of dirt y t racking, for exam ple.)
N ot e
There are several different t echniques when using Aspect - Orient ed Program m ing ( AOP) in
.NET, where runt im e subclassing t hat we j ust discussed is probably t he m ost com m only
used. I 've always seen having t o declare your m em bers as virt ual for being able t o
int ercept ( or advice) as a drawback, but Roger Johansson point ed som et hing out t o m e.
Assum e you want t o m ake it im possible t o override a m em ber and t hereby avoid t he ext ra
work and responsibilit y of support ing subclassing. Then t hat decision should affect bot h
ordinary subclassing and subclassing t hat is used for reasons of AOP. And if you m ake t he
m em ber virt ual, you are prepared for having it redefined, again bot h by ordinary
subclassing and AOP- ish subclassing.
Anot her com m on problem solved t his way is t he need for Lazy Load, but I 'd like t o use t hat as an
exam ple for t he next sect ion.
I t 's not uncom m on t o have t o use special dat at ypes for t he collect ions in your Dom ain Model classes:
special as in " not t hose you would have used if you could have chosen freely."
The m ost com m on reason for t his requirem ent is probably for support ing Lazy Load, [ Fowler PoEAA] ,
or rat her im plicit Lazy Load, so t hat you don't have t o writ e code on your own for m aking it happen.
( Lazy Load m eans t hat dat a is fet ched j ust in t im e from t he dat abase.)
But t he specific dat at ypes could also bring you ot her funct ionalit y, such as special delet e handling so
t hat as soon as you delet e an inst ance from a collect ion t he inst ance will be regist ered wit h t he Unit
of Work [ Fowler PoEAA] for delet ion as well. ( Unit of Work is used for keeping t rack of what act ions
should be t aken against t he dat abase at t he end of t he current logical unit of work.)
N ot e
Did you not ice t hat I said t hat t he specific dat at ypes could bring you funct ionalit y? Yep, I
don't want t o sound overly negat ive about NPI ( Not - PI ) .
You could get help wit h bi- direct ionalit y so t hat you don't have t o code it on your own. This is yet
anot her exam ple of som et hing an AOP solut ion can t ake care of for you.
Yet anot her very regular requirem ent on Dom ain Model classes for being persist able is t hat t hey
im plem ent one or m ore infrast ruct ure- provided int erfaces.
This is nat urally a sm aller problem if t here is very lit t le code you have t o writ e in order t o im plem ent
t he int erface( s) and a bigger problem if t he opposit e is t rue.
One exam ple of int erface- based funct ionalit y could be t o m ake it possible t o fill t he inst ance wit h
values from t he dat abase wit hout hit t ing set t ers ( which m ight have specific code t hat you don't want
t o execut e during reconst it ut ion) .
Anot her com m on exam ple is t o provide int erfaces for opt im ized access t o t he st at e in t he inst ances.
Yet anot her way of providing values t hat reconst it ut e inst ances from t he dat abase is by requiring
specific const ruct ors, which are const ruct ors t hat have not hing at all t o do wit h t he business problem
at hand.
I t m ight also be t hat a default const ruct or is needed so t hat t he fram ework can inst ant iat e Dom ain
Model classes easily as t he result of a Get operat ion against t he dat abase. Again, it 's not a very
dram at ic problem , but a dist ract ion nonet heless.
Som e infrast ruct ure solut ions require your Dom ain Model classes t o provide specific fields, such as
Guid- based Id- fields or int - based Version- fields. ( Wit h Guid- based Id- fields, I m ean t hat t he Id- fields
are using Guids as t he dat at ype.) That sim plifies t he infrast ruct ure, but it m ight m ake your life as a
Dom ain Model- developer a bit harder. At least if it affect s your classes in a way you didn't want t o.
I have already m ent ioned t hat you m ight be forced t o use virt ual propert ies even if you don't really
want t o. I t m ight also be t hat you have t o avoid cert ain const ruct s, and a t ypical exam ple of t his is
read- only fields. Read- only ( as when t he keyword readonly is used) fields can't be set from t he
out side ( except wit h const ruct ors) , som et hing t hat is needed t o creat e 100% PI - Dom ain Model
classes.
Using a privat e field t oget her wit h a get - only propert y is pret t y close t o a read- only field, but not
exact ly t he sam e. I t could be argued t hat a read- only field is t he m ost int ent ion- revealing solut ion.
N ot e
Som et hing t hat has been discussed a lot is whet her .NET at t ribut es are a good or bad t hing
regarding decorat ing t he Dom ain Model wit h inform at ion about how t o persist t he Dom ain
Model.
My opinion is t hat such at t ribut es can be a good t hing and t hat t hey don't really decrease
t he PI level if t hey are seen as default inform at ion t hat can be overridden. I t hink t he m ain
problem is if t hey get t oo verbose t o dist ract t he reader of t he code.
PI or not PI?
PI or not PI of course it 's not t ot ally binary. There are som e gray areas as well, but for now let 's be
happy if we get a feeling for t he int ent ion of PI rat her t han how t o get t o 100% . Anyt hing ext rem e
incurs high cost s. We'll get back t o t his in Chapt er 9, " Put t ing NHibernat e int o Act ion," when we
discuss an infrast ruct ure solut ion.
N ot e
What is an exam ple of som et hing com plet ely binary in real life? Oh, one t hat I oft en rem ind
m y wife about is when she says " t hat wom an was very pregnant ."
Som et hing we haven't t ouched on yet is t hat it also depends on at what point in " t im e" we evaluat e
whet her we use PI or not .
This whole subj ect is charged wit h feelings because it 's cont roversial t o execut e som et hing ot her
t han what you wrot e yourself. The debugging experience m ight t urn int o a night m are!
N ot e
Mark Burhop com m ent ed as follows:
Hm m m ... This was t he original argum ent against C+ + from C program m ers in t he early
90s. " C+ + st icks in new code I didn't writ e." " C+ + hides what is really going on." I don't
know t hat t his argum ent holds m uch wat er anym ore.
I t 's also harder t o inj ect code at t he byt e level for .NET classes com pared t o Java. I t 's not support ed
by t he fram ework, so you're on your own, which m akes it a showst opper in m ost cases.
What is m ost oft en done inst ead is t o use som e alt ernat ive t echniques, such as t hose I m ent ioned
wit h runt im e- subclassing in com binat ion wit h a provided fact ory, but it 's not a big difference
com pared t o inj ect ed code. Let 's sum m arize wit h calling it em it t ing code.
I did m ent ion earlier in t his chapt er t hat speed is som et hing you will sacrifice for a high level of PI -
ness, at least for runt im e PI , because you are t hen direct ed t o use reflect ion, which is quit e
expensive. ( I f you t hink com pile- t im e PI is good enough, you don't need t o use reflect ion, but can go
for an AOP solut ion inst ead and you can get a bet t er perform ance st ory.)
You can easily prove wit h som e operat ion in a t ight loop t hat it is m agnit udes slower for reading
from / writ ing t o fields/ propert ies wit h reflect ion com pared t o calling t hem in t he ordinary way. Yet , is
t he cost t oo high? I t obviously depends on t he sit uat ion. You'll have t o run t est s t o see how it applies
t o your own case. Don't forget t hat a j um p t o t he dat abase is very expensive com pared t o a lot
you're doing in your Dom ain Model, yet at t he sam e t im e, you aren't com paring apples and apples
here. For inst ance, t he com parison m ight not be bet ween an ordinary read and a reflect ion- based
read.
Let 's t ake an exam ple t o give you a bet t er underst anding of t he whole t hing. One com m on operat ion
in a persist ence fram ework is deciding whet her or not an inst ance should be st ored t o t he dat abase
at t he end of a scenario. A com m on solut ion t o t his is t o let t he inst ance be responsible for signaling
IsDirty if it is t o be st ored. Or bet t er st ill, t he inst ance could also signal it self t o t he Unit of Work
when it get s dirt y so t hat t he Unit of Work will rem em ber t hat when it 's t im e t o st ore changes.
But ( you know t here had t o be a " but ," right ?) t hat requires som e abuse of PI , unless you have paid
wit h AOP.
N ot e
There are ot her drawbacks wit h t his solut ion, such as it won't not ice t he change if it 's done
via reflect ion and t herefore t he inst ance changes won't get st ored. This drawback was a bit
t wist ed, t hough.
An alt ernat ive solut ion is not t o signal anyt hing at all, but let t he infrast ruct ure rem em ber how t he
inst ances looked when fet ched from t he dat abase. Then at st ore t im e com pare how t he inst ances
look now t o how t hey looked when read from t he dat abase.
Do you see t hat it 's not j ust a com parison of one ordinary read t o one reflect ion- based read, but t hey
are t ot ally different approaches, wit h t ot ally different perform ance charact erist ics? To get a real
feeling for it , you can set up a com parison yourself. Fet ch one m illion inst ances from t he dat abase,
m odify one inst ance, and t hen m easure t he t im e difference for t he st ore operat ion in bot h cases. I
know, it was anot her t wist ed sit uat ion, but st ill som et hing t o t hink about .
Other Examples
That was som et hing about t he speed cost , but t hat 's not all t here is t o it . Anot her cost I point ed out
before was t hat you m ight get less funct ionalit y aut om at ically if you t ry hard t o use a high level of PI .
I 've already gone t hrough m any possible feat ures you could get for free if you abandon som e PI -
ness, such as aut om at ic bi- direct ional support and aut om at ic im plicit Lazy Load.
I t 's also t he case t hat t he dirt y t racking isn't j ust about perform ance. The consum er m ight be very
int erest ed as well in using t hat inform at ion when paint ing t he form sfor exam ple, t o know what
but t ons t o enable.
So as usual, t here's a t radeoff. I n t he case of PI versus non- PI , t he t radeoff is overhead and less
funct ionalit y versus dist ract ing code in t he core of your applicat ion t hat couples you t o a cert ain
infrast ruct ure and also m akes it harder t o do TDD. There are pros and cons. That 's reasonable, isn't
it ?
So t he conclusion t o all t his is t o be aware of t he t radeoffs and choose carefully. For inst ance, if you
get som et hing you need alongside a drawback you can live wit h, don't be t oo religious about it !
That said, I 'm current ly in t he pro- PI cam p, m ost ly because of how nice it is for TDD and how clean
and clear I can get m y Ent it ies and Value Obj ect s.
I also t hink t here's a huge difference when it com es t o your preferred approach. I f you like st art ing
from code, you'll probably like PI a great deal. I f you work in an int egrat ed t ool where you st art wit h
det ailed design in UML, for exam ple, and from t here generat e your Dom ain Model, PI is probably not
t hat im port ant for you at all.
But t here's m ore t o t he Dom ain Model t han Ent it ies and Value Obj ect s. What I 'm t hinking about are
t he Reposit ories. St rangely enough, very lit t le has been said as far as PI for t he Reposit ories goes.
For exam ple, t he Reposit ories need som et hing t o pull in order t o get t he infrast ruct ure t o work. This
m eans t hat t he assem bly wit h t he Reposit ories needs a reference t o an infrast ruct ure DLL. And t his
in it s t urn m eans t hat you have t o choose bet ween whet her you want t he Reposit ories in a separat e
DLL, separat e from t he Dom ain Model, or whet her you want t he Dom ain Model t o reference an
infrast ruct ure DLL ( but we will discuss a solut ion soon t hat will give you flexibilit y regarding t his) .
I t 's also t he case t hat when you want t o t est your Reposit ories, t hey are connect ed t o t he O/ R
Mapper and t he dat abase.
N ot e
Let 's for t he m om ent assum e t hat we will use an O/ R Mapper. We'll get back t o a m ore
t horough discussion about different opt ions wit hin a few chapt ers.
Suddenly t his provides you wit h a pret t y t ough t est ing experience com pared t o when you t est t he
Ent it ies and Value Obj ect s in isolat ion.
Of course, what you could do is m ock your O/ R Mapper. I haven't done t hat m yself, but it feels a bit
bad on t he " bang for t he bucks" rat ing. I t 's probably quit e a lot of work com pared t o t he ret urn.
I n previous chapt ers I haven't really shown any t est code t hat focused on t he Reposit ories at all.
Most of t he int erest ing t est s should use t he Dom ain Model. I f not , it m ight be a sign t hat your
Dom ain Model isn't as rich as it should be if you are going t o get t he m ost out of it .
That said, I did use Reposit ories in som e t est s, but really m ore as sm all int egrat ion t est s t o see t hat
t he cooperat ion bet ween t he consum er, t he Ent it ies, and t he Reposit ories worked out as planned. As
a m at t er of fact , t hat 's one of t he advant ages Reposit ories have com pared t o ot her approaches for
giving persist ence capabilit ies t o Dom ain Models, because it was easy t o writ e Fake versions of t he
Reposit ories. The problem was t hat I wrot e quit e a lot of dum b code t hat has t o be t ossed away lat er
on, or at least rewrit t en in anot her assem bly where t he Reposit ories aren't j ust Fake versions.
What also happened was t hat t he sem ant ics I got from t he Fake versions wasn't really " correct ." For
inst ance, don't you t hink t he following seem s st range?
[Test]
public void FakeRepositoryHaveIncorrectSemantics()
{
OrderRepository r1 = new OrderRepository();
OrderRepository r2 = new OrderRepository();
r1.Add(o);
x.PersistAll();
//This is fine:
Assert.IsNotNull(r1.GetOrder(o.Id));
//This is unexpected I think:
Assert.IsNull(r2.GetOrder(o.Id));
}
N ot e
As t he hawk- eyed reader saw, I decided t o change AddOrder() t o Add() since t he last
chapt er.
I 'm get t ing a bit ahead of m yself in t he previous code because we are going t o discuss save scenarios
short ly. Anyway, what I want ed t o show was t hat t he Fake versions of Reposit ories used so far don't
work as expect ed. Even t hough I t hought I had m ade all changes so far persist ent wit h PersistAll(),
only t he first Reposit ory inst ance could find t he order, not t he second Reposit ory inst ance. You m ight
wonder why I would like t o writ e code like t hat , and it 's a good quest ion, but it 's a pret t y big
m isbehavior in m y opinion.
What we could do inst ead is m ock each of t he Reposit ories, t o t est out t he cooperat ion wit h t he
Ent it ies, Reposit ories, and consum er. This is pret t y cheaply done, and it 's also a good way of t est ing
out t he consum er and t he Ent it ies. However, t he t est value for t he Reposit ories t hem selves isn't big,
of course. We are kind of back t o square one again, because what we want t hen is t o m ock out one
st ep furt her, t he O/ R Mapper ( if t hat 's what is used for dealing wit h persist ence) , and we have
already t alked about t hat .
Earlier Approach
So it 's good t o have Reposit ories in t he first place, especially when it com es t o t est abilit y. Therefore I
used t o swallow t he bit t er pill and deal wit h t his problem by creat ing an int erface for each Reposit ory
and t hen creat ing t wo im plem ent ing classes, one for Fake and one for real infrast ruct ure. I t could
look like t his. First , an int erface in t he Dom ain Model assem bly:
That m eans t hat t he Dom ain Model it self won't be affect ed by t he chosen infrast ruct ure when it
com es t o t he Reposit ories, which is nice if it doesn't cost anyt hing.
But it does cost . I t also m eans t hat I have t o writ e t wo Reposit ories for each Aggregat e root , and
wit h t ot ally different Reposit ory code in each case.
Furt her on, it m eans t hat t he product ion version of t he Reposit ories lives in anot her assem bly ( and
so do t he Fake Reposit ories) , even t hough I t hink Reposit ories are part of t he Dom ain Model it self.
" Two ext ra assem blies," you say, " That 's no big deal." But for a large applicat ion where t he Dom ain
Model is part it ioned int o several different assem blies, you'll learn t hat t ypically it doesn't m ean t wo
ext ra assem blies for t he Reposit ories, but rat her t he am ount of Dom ain Model assem blies m ult iplied
by t hree. That is because each Dom ain Model assem bly will have it s own Reposit ory assem blies.
Even t hough I t hink it 's a negat ive aspect , it 's not nearly as bad as m y having t he silly code in t he
Fake versions of t he Reposit ories. That feels j ust bad.
A Better Solution?
The solut ion I decided t o t ry out was creat ing an abst ract ion layer t hat I call NWorkspace [ Nilsson
NWorkspace] . I t 's a set of adapt er int erfaces, which I have writ t en im plem ent at ions for in t he form of
a Fake. The Fake is j ust t wo levels of hasht ables, one set of hasht ables for t he persist ent Ent it ies
( sim ulat ing a dat abase) and one set of hasht ables for t he Unit of Work and t he I dent it y Map. ( The
I dent it y Map keeps t rack of what ident it ies, t ypically prim ary keys, are current ly loaded.)
The ot her im plem ent at ion I have writ t en is for a specific O/ R Mapper.
N ot e
When I use t he nam e NWorkspace from now on, you should t hink about it as a " persist ence
abst ract ion layer." NWorkspace is j ust an exam ple and not im port ant in it self.
Thanks t o t hat abst ract ion layer, I can m ove t he Reposit ories back t o t he Dom ain Model, and I only
need one Reposit ory im plem ent at ion per Aggregat e root . The sam e Reposit ory can work bot h against
an O/ R Mapper and against a Fake t hat won't persist t o a dat abase but only hold in m em ory
hasht ables of t he inst ances, but wit h sim ilar sem ant ics as in t he O/ R Mapper- case. See Figure 6- 2 .
Anot her possibilit y t hat suddenly feels like it could be achieved easily ( for a sm all abst ract ion layer
API at least ) could be t o Mock t he infrast ruct ure inst ead of each of t he Reposit ories. As a m at t er of
fact , it won't be a m at t er of Mocking one infrast ruct ure- product , but all infrast ruct ure product s t hat
at one t im e will have adapt er im plem ent at ions for t he abst ract ion layer ( if t hat happens, t hat t here
will be ot her im plem ent at ions t han t hose t wo I wrot eit 's probably not t hat likely) . So m ore t o t he
point , what is t hen being Mocked is t he abst ract ion layer.
I t 's st ill a st ret ch t o t alk about PI Reposit ories, but wit h t his solut ion I can avoid a reference t o t he
infrast ruct ure in t he Dom ain Model. That said, in real- world applicat ions I have kept t he Reposit ories
in a separat e assem bly anyway. I t hink it clarifies t he coupling, and it also m akes som e hacks easier
t o achieve and t hen let t ing som e Reposit ory m et hods use raw SQL where t hat proves necessary ( by
using connect ion st rings as m arkers for whet her opt im ized code should be used or not ) .
However, inst ead of referring t o t he Persist ence Fram ework, I have t o refer t o t he NWorkspace DLL
wit h t he adapt er int erfaces, but t hat seem s t o be a big st ep in t he right direct ion. I t 's also t he case
t hat t here are lit t le or no dist ract ions in t he Reposit ories; t hey are pret t y " direct " ( t hat is, if you find
t he NWorkspace API in any way decent ) .
So inst ead of writ ing a set of Reposit ories wit h code against an infrast ruct ure vendor's API and
anot her set of Reposit ories wit h dum m y code, you writ e one set of Reposit ories against a ( naïve)
at t em pt for a st andard API .
N ot e
I 'm sorry for nagging, but I m ust say it again: I t 's t he concept I 'm aft er! My own
im plem ent at ion isn't im port ant at all.
Let 's find anot her t erm for describing t hose Reposit ories inst ead of calling t he PI Reposit ories. What
about single- set Reposit ories? OK, we have a t erm for now for describing when we build a single set
of Reposit ories t hat can be used bot h in Fake scenarios and in scenarios wit h a dat abase. What 's
probably m ore int erest ing t han nam ing t hose Reposit ories is seeing t hem in act ion.
To rem ind you what t he code in a Fake version of a Reposit ory could look like, here's a m et hod from
Chapt er 5:
OK, t hat 's not especially com plex, but rat her silly, code.
I f we assum e t hat t he OrderNumber is an I dent it y Field [ Fowler PoEAA] ( I dent it y Field m eans a field
t hat binds t he row in t he dat abase t o t he inst ance in t he Dom ain Model) of t he Order, t he code could
look like t his when we use t he abst ract ion layer ( _ws in t he following code is an inst ance of
IWorkspace, which in it s t urn is t he m ain int erface of t he abst ract ion layer) :
Pret t y sim ple and direct I t hink. Andagaint hat m et hod is done now, bot h for Fake and for when real
infrast ruct ure is used!
St ill, t here's a cost , of course. The m ost obvious cost for t he added abst ract ion layer is probably t he
t ranslat ion at runt im e t hat has t o be done for t he O/ R Mapper you're using. I n t heory, t he O/ R
Mapper could have a nat ive im plem ent at ion of t he abst ract ion layer, but for t hat t o happen som e
really popular such abst ract ion layer m ust be creat ed.
Then t here's a cost for building t he abst ract ion layer and t he adapt er for your specific O/ R Mapper.
That 's t he t ypical fram ework- relat ed problem . I t cost s a lot for building t he fram ework, but it can be
used m any t im es, if t he fram ework ever becom es useful.
Wit h som e luck, t here will be an adapt er im plem ent at ion for t he infrast ruct ure you are using and
t hen t he cost isn't yours, at least not t he fram ework- building cost . There's m ore, t hough. You have t o
learn not only t he infrast ruct ure of your choice, but also t he abst ract ion layer, and t hat can't be
neglect ed.
N ot e
I t was easier in t he past as you only had t o know a lit t le about Cobol and files. Now you
have t o be an expert on C# or Java, Relat ional Dat abases, SQL, O/ R Mappers, and so on,
and so fort h. I f som eone t ries t o m ake t he whole t hing sim pler by adding yet anot her layer,
t hat will t ip t he scales, especially for newcom ers.
Yet anot her cost is, of course, t hat t he abst ract ion layer will be kind of t he least com m on
denom inat or. You won't find all t he power t here t hat you can find in your infrast ruct ure of choice.
Sure, you can always bypass t he abst ract ion layer, but t hat com es wit h a cost of com plexit y and
ext ernal Reposit ory code, and so on. So it 's im port ant t o invest igat e whet her your needs could be
fulfilled wit h t he abst ract ion layer t o 30% , 60% , or 90% . I f it 's not a high percent age, it 's
quest ionable whet her it 's int erest ing at all.
Ok, let 's ret urn t o t he consum er for a while and focus on save funct ionalit y for a change.
Dealing with Save Scenarios
As I said at t he end of t he previous chapt er, I will m ove fast er from now on and not discuss all t he
st eps in m y t hought process. I nst ead it will be m ore like going direct ly t o t he decided solut ion. Not
decided as in " done," but decided as in " for now."
Wit h t hat said, I 'd st ill like t o discuss t est s, especially as a way of clarificat ion.
Now I 'd like t o discuss save scenarios from t he consum er's point of view. So here's a t est for showing
how t o save t wo new Customers:
[Test]
Public void CanSaveTwoCustomers()
{
int noOfCustomersBefore =
_GetNumberOfStoredCustomers();
Assert.AreEqual(noOfCustomersBefore,
_GetNumberOfStoredCustomers());
_ws.PersistAll();
Assert.AreEqual(noOfCustomersBefore + 2,
_GetNumberOfStoredCustomers());
}
At first glance, t he code j ust shown is pret t y sim ple, but it " hides" lot s of t hings we haven't discussed
before. First , it reveals what kind of consum er code I want t o be able t o writ e. I want t o be able t o do
a lot of st uff t o several different inst ances, and t hen persist all t he work wit h a single call such as
PersistAll(). ( The call t o _GetNumberOfStoredCustomers() goes t o t he persist ence engine t o check
t he num ber of persist ent cust om ers. I t 's not unt il aft er PersistAll() t hat t he num ber of persist ent
cust om ers has increased.)
A m issing piece of t he puzzle is t hat t he Reposit ory was fed wit h t he _ws at inst ant iat ion t im e. I n t his
way, I can cont rol t he Reposit ories t hat should part icipat e in t he sam e Unit of Work and t hose t hat
should be isolat ed in anot her Unit of Work.
Yet anot her t hing t hat m ight be int erest ing is t hat I ask t he Reposit ories for help ( t he Add() call) in
not ifying t he Unit of Work t hat t here is a new inst ance for persist ing at next PersistAll() call. I 'm
referring t o t he life cycle I want t o have for a persist ent inst ance ( I t ouched on t his in Chapt er 5, so I
won't repeat it here) .
What I t hink is wort h point ing out is t hat if I expect it t o be enough t o associat e t he Aggregat e root
wit h t he Unit of Work, t he inst ances t hat are part of t he Aggregat e and t hat t he Aggregat e root
reaches will get persist ed t o t he dat abase as well when we say PersistAll().
Again, Aggregat es assist us well; t hey provide a t ool for knowing t he size of graph t hat will be
persist ed because t he Aggregat e root is m arked for being persist ed. Again, Aggregat es m ake for
sim plificat ion.
N ot e
O/ R Mappers are oft en able t o be configured for how far t he reach of persist by reachabilit y
should go. But even when t hey are configured t hat way, t he Aggregat es are a very good
guide in m y opinion. What I m ean is t hat I use t he Aggregat es for det erm ining how far t he
reachabilit y should reach, when I do t he configurat ion.
Let 's t ake a closer look at t he reasoning behind t he decisions discussed so far.
So you can m ake lot s of changes t o t he Dom ain Model, collect t he inform at ion in t he Unit of Work,
and t hen ask t he Unit of Work t o save t he collect ed changes t o t he dat abase.
There are several st yles of Unit of Work t o use. The one I prefer is t o m ake it as t ransparent as
possible for t he consum er and t herefore t he only m essage needed is t o say Add() t o t he Reposit ory
( which in t urn will t alk t o t he Unit of Work) .
I f t he reconst it ut ion is done via t he Reposit ory, t he Unit of Work- im plem ent at ion can inj ect som e
obj ect t hat can collect inform at ion about changes. Ot herwise, t here can be a snapshot t aken at read
t im e t hat will be used t o cont rol t he changes by t he Unit of Work at persist t im e.
I also chose t o cont rol save or not save ( PersistAll()) out side of t he Reposit ories. I n t his part icular
exam ple, I could j ust as well have had PersistAll() direct ly on t he CustomerRepository , but I chose
not t o. Why? Why not let Reposit ories hide Unit of Work com plet ely? Well, I could, but I oft en find
t hat I want t o synchronize changes t o several Aggregat es ( and t herefore also t o several different
Reposit ories) in a single logical unit , and t hat 's t he reason. So code like t his is not only possible t o
writ e, but also very t ypical:
_ws.PersistAll();
But t hen I have t wo different Unit of Work inst ances and t wo I dent it y Maps ( it doesn't h av e t o be
t hat way, but let 's assum e it for t he sake of t he discussion) , which can give pret t y st range effect s if
we aren't very careful. Aft er all, all five lines in t he first exam ple were one scenario, and because of
t hat I find it m ost int uit ive and appropriat e t o t reat it like one scenario regarding how I deal wit h t he
Unit of Work and I dent it y Map as well. I m ean, t he scenario should j ust have one Unit of Work and
one I dent it y Map.
Anot her t hing t hat m ight be a problem is t hat when t he Reposit ory hid t he Unit of Work it probably
m eant t hat t here were t wo dat abase t ransact ions. That in t urn m eans t hat you m ight have t o prepare
t o add com pensat ing operat ions when t he out com e of a scenario isn't as expect ed. I n t he previous
case, it 's probably not t oo disast rous if t he Customer is added t o t he dat abase but not t he Order.
However, it can be a problem , depending upon your Aggregat e design.
That said, Aggregat es " should" be designed so t hat t hey are in a consist ent st at e at PersistAll()
t im e. But t he loose relat ionship bet ween Aggregat es doesn't t ypically live under such st rict
requirem ent s. That m ight m ake you like t he second solut ion. On t he ot her hand, t he second solut ion
would st ore t wo t ot ally unrelat ed customers in t he sam e PersistAll() if bot h of t hose customers were
associat ed t o t he Reposit ory. That is act ually less im port ant t han grouping a customer and it s orders
t oget her. Aggregat es are about obj ect s, not classes.
What speaks for t he solut ion in t he second exam ple is if one Aggregat e com es from one dat abase
and t he ot her Aggregat e is st ored in anot her dat abase at anot her dat abase server. Then it 's probably
easiest t o have t wo Unit of Work- inst ances anyway, one for each dat abase. So, solut ion t wo is
slight ly less coupled.
N ot e
I could even let Add() fulfill t he t ransact ion, but t hen I have different sem ant ics from t hose
I have discussed and expressed so far. I t would be crucial t o call Add() at t he right point in
t im e. This is less im port ant wit h t he solut ion I have chosen, as long as t he call is done
before PersistAll().
Wit h Add() fulfilling t he t ransact ion, it would also m ean t hat it 's cert ainly not a m at t er of
" gat her all changes and persist t hem all at PersistAll()," which again is very different
from m y current solut ion.
While we're at it , why not t hen encapsulat e t he whole t hing in t he Ent it y inst ead so t hat
you can writ e t he following code?
I t hink it 's m oving away from t he st yle I like. I t hink it breaks t he Single Responsibilit y
Principle ( SRP) [ Mart in PPP] , and it 's low PI - level. I t hink I 'm also m oving int o " m at t er of
t ast e" t errit ory.
I also have a problem wit h inconsist ency if one save goes well and ot hers do not . ( You could argue
t hat physical t ransact ion and Unit of Work don't h av e t o be t he sam e, but t hat increases com plexit y
in m y opinion. The way I see it is if you don't have t o do som et hing, you shouldn't .)
However, by using m y favorit e t echnique, t here's not hing t o st op m e from get t ing t he sam e effect s of
st oring one Aggregat e at a t im e if I really want t o by let t ing t he Reposit ories hide t he Unit of Work
and I dent it y Map. I t could t hen look like t his:
N ot e
For t he previous scenario, t he end result would be t he sam e wit h a single _ws , but t hat
depended on t he specific exam ple.
What I m ean is t hat I can have one Unit of Work/ I dent it y Map when I so wish, and several when I so
wish. I t hink t his is slight ly m ore flexible, which I like a lot , and t his is one m ore reason for m y
choice; nam ely t hat I current ly prefer t o see t he Unit of Work as som et hing belonging t o t he
consum er of t he Dom ain Model ( t hat is t he Applicat ion layer or t he present at ion layer) rat her t han
t he Dom ain Model it self.
I f we assum e t hat each Reposit ory has it s own I dent it y Map, it can get a bit m essy if t he sam e order
is referenced from t wo different Reposit ories, at least if you m ake changes t o t he sam e logical order
( but t wo different inst ances) in bot h Reposit ories.
As far as risks are concerned, what it boils down t o is which risk you prefer. The risk of com m it t ing
inst ances t hat you weren't done wit h because a PersistAll() call will deal wit h m ore inst ances t han
you expect ed? Or t he risk of forget t ing t o com m it a change because you'll have t o rem em ber what
Reposit ories t o ask t o do PersistAll().
I 'm not saying t hat it 's a solut ion wit hout problem s, but again, I prefer t he I dent it y Map and t he Unit
of Work t o belong t o t he scenario.
N ot e
Deciding on what program m ing m odel you want is up t o you, as usual. There are pros and
cons t o each.
I have m ent ioned Unit of Work and I dent it y Map t oget her over and over again. I t 's such a com m on
com binat ion, not only in m y t ext , but in product s as well. For exam ple, t here is Persist ence Manager
in JDO [ Jordan/ Russell JDO] and Session in Hibernat e [ Bauer/ King HiA] .
I t hought it m ight deserve a pat t ern, and I was t hinking about writ ing it up, but when I discussed it
wit h Mart in Fowler he not ified m e t hat he discusses t hat in [ Fowler PoEAA] when he t alks about
I dent it y Map and Unit of Work. That 's m ore t han enough, so I decided not t o repeat m ore about t hat .
OK, now t here's been a lot of t alk and no act ion. Let 's st art building t he Fake m echanism and see
where we end up.
Let's Build the Fake Mechanism
Let 's m ove on in an int erface- based way for a while, or at least for a st art . I have already t ouched on
a couple of t he m et hods, but let 's st art from t he beginning. A reduced version of t he int erface of t he
abst ract ion layer ( which I earlier in t he chapt er already called IWorkspace) could look like t his:
So far t he whole int erface is pret t y st raight forward. The first m et hod is called GetById() and is used
for reconst it ut ing an obj ect from t he dat abase. You say what t ype you expect and t he ident it y value
of t he obj ect .
The second m et hod, called MakePersistent(), is used for associat ing new inst ances wit h t he
IWorkspace inst ance so t hat t hey will be persist ed at next PersistAll(). Finally, PersistAll() is for
persist ing what is found in t he Unit of Work int o t he dat abase.
MakePersistent() isn't needed if you have read t he inst ance from t he dat abase wit h GetById(),
because t hen t he inst ance is already associat ed wit h t he Unit of Work.
So far I t hink you'll agree t hat t he API is ext rem ely sim ple, and I t hink it is very im port ant in order t o
keep com plexit y down in t his abst ract ion layer. OK, it 's not all t hat com pet ent yet , so we need t o add
m ore.
So m y goals are pret t y sim ilar t o t hose of declarat ive t ransact ions in COM+ , but I have chosen a
pret t y different API . I nst ead of set t ing at t ribut es on t he classes for describing whet her t hey require
t ransact ions or not , I will j ust say t hat PersistAll() int ernally does all it s work in an explicit
t ransact ion, even t hough you explicit ly didn't ask for it
I know t hat on t he face of it t his feels overly sim ple t o m any old- t im ers. That goes for m e as well,
because I believe t ransact ion handling is so im port ant t hat I like t o deal wit h it m anually. I f t he goal
is t o be able t o deal wit h som et hing like 90% of t he sit uat ions, however, I t hink PersistAll() could
very well use an explicit t ransact ion, and it 's as sim ple as t hat .
Again, it sounds way t oo sim plist ic, and of course t here are problem s. One t ypical problem is logging.
Assum e t hat you log t o t he dat abase server; you don't always want t he logging operat ion t o fail if t he
ordinary work fails. However, t hat 's sim ple t o deal wit h; you j ust use a separat e workspace inst ance
for t he logging. I f you want it t o use t he abst ract ion layer at all, t he logging will probably j ust be
im plem ent ed as a Service inst ead, which probably has not hing t o do wit h t he abst ract ion layer. As a
m at t er of fact , t here's a good chance t hat you will use a t hird- part y product for logging, or perhaps
som et hing like log4net [ Log4Net ] . I t 's not som et hing t hat will int erfere wit h or be dist urbed by t he
t ransact ion API of t he abst ract ion layer.
Anot her problem is t hat t here m ight well be a need for t he GetById() m et hod t o live in t he sam e
t ransact ion as t he upcom ing PersistAll(). That won't happen by default , but if you want t o force
t hat , you can call t he following m et hod before GetById():
To em phasize t his even m ore, t here is also an overload t o GetById() t o ask for an exclusive lock, but
t his com es wit h a warning t ag. Make sure you know what you're doing when you use t his! For
exam ple, t here should be no user int eract ion what soever aft er BeginReadTransaction() or read wit h
exclusive lock and before PersistAll().
But I digresswhat is im port ant for t he Fake? Because t he Fake only t arget s single- user scenarios, t he
t ransact ional sem ant ics aren't very im port ant , and for reasons of sim plicit y t hose will probably not be
dealt wit h at all. St ill, t he consum er code can be writ t en wit h t ransact ion- handling in m ind when t he
Fake is used, of course, so you don't have t o change t he code when it com es t o swapping t he Fake
for t he real infrast ruct ure.
I hear t he now very fright ened experienced developer exclaim , " Hey, what happened t o Rollback()?"
Well, t he way I see it , it 's not im port ant t o have rollback in t he API . I f PersistAll() is responsible for
com m it or rollback int ernally, what will happen t hen is t hat when t he consum er get s t he cont rol back
from PersistAll(), all changes or none have been persist ed. ( The consum er is not ified about a
rollback by an except ion.)
The except ion t o t his is when you are aft er BeginReadTransaction() and you t hen want t o cancel.
Then you call t he following m et hod:
void Clean()
I t will roll back t he ongoing t ransact ion and will also clean t he Unit of Work and t he I dent it y Map. I t 's
a good idea t o use Clean() aft er a failed t ransact ion because t here will be no at t em pt at all in
NWorkspace t o roll back t he changes in Dom ain Model inst ances. Sure, it depends upon what t he
problem wit h t he failed t ransact ion was, but t he sim ple answer is t o rest art .
Som e problem s can lead t o a ret ry wit hin PersistAll(). I n t he case of a deadlock, for exam ple,
PersistAll() can ret ry a couple of t im es before deciding it was a failure. This is yet anot her t hing
t hat sim plifies life for t he consum er program m er so t hat she can focus on what is im port ant t o her,
nam ely t o creat e a good user experience, not following lot s and lot s of prot ocols.
Now we have t alked a lot about t he funct ionalit y t hat is im port ant for NWorkspace, but not for t he
Fake version of NWorkspace. Let 's get back on t rack and focus for a while on t he Fake and it s
im plem ent at ion inst ead.
The fake im plem ent at ion uses t wo layers of I dent it y Maps. The first layer is pret t y sim ilar t o ordinary
I dent it y Maps in persist ence fram eworks, and it keeps t rack of all Ent it ies t hat you have read wit hin
t he current scenario. The second layer of I dent it y Maps is for sim ulat ing t he persist ent engine, so
here t he inst ances aren't kept on a scenario level, but on a global level ( t hat is, t he sam e set of
I dent it y Maps for all scenarios) .
So when you issue a call t o GetById(), if t he I D is found in t he I dent it y Map for t he request ed t ype,
t here won't be a roundt rip t o t he dat abase ( or in case of t he Fake, t here won't be a j um p t o t he
second layer of I dent it y Maps) . On t he ot her hand, if t he I D isn't found in t he first layer of I dent it y
Maps, it 's fet ched from t he second layer, copied t o t he first layer, and t hen ret urned t o t he
consum er.
The MakePersistent() is pret t y sim ple; t he inst ance is j ust associat ed wit h t he first layer of I dent it y
Maps. And when it 's t im e for PersistAll(), all inst ances in t he first layer are copied t o t he second
layer. Sim ple and clean.
This describes t he basic funct ionalit y. St ill, it m ight be int erest ing t o say a bit about what 's
t roublesom e, also. One exam ple is t hat I don't want t he Fake t o influence t he Dom ain Model in any
way at all. I f it does, we're back t o square one, adding infrast ruct ure- relat ed dist ract ions t o t he
Dom ain Model, or even worse, Fake- relat ed dist ract ions.
One exam ple of a problem is t hat I don't know which is t he I dent it y field( s) of a class. I n t he case of
t he real infrast ruct ure, it will probably know t hat by som e m et adat a. I could read t hat sam e
m et adat a in t he Fake t o find out , but t hen t he Fake m ust know how t o deal wit h ( t heoret ically)
several different m et adat a form at s, and I definit ely don't like t hat .
The sim plist ic solut ion I 've adopt ed is t o assum e a propert y ( or field) called Id. I f t he developer of
t he Dom ain Model has used anot her convent ion, it could be described t o t he Fake at inst ant iat ion of
t he FakeWorkspace .
Again, t his was m ore inform at ion t han you probably want ed now, but it leads us t o t he im port ant fact
t hat t here are addit ional t hings t hat you can/ need t o do in t he inst ant iat ion phase of t he Fake
com pared t o t he infrast ruct ure im plem ent at ions of NWorkspace.
To t ake anot her exam ple, you can read from file/ save t o file like t his:
//Do stuff...
((NWorkspaceFake.FakeWorkspace)ws).
PersistToFile("c:/temp/x.nworkspace");
We t alked quit e a lot about PI and t he Fake m echanism in a way t hat m ight lead you t o believe t hat
you m ust go for a PI - support ing infrast ruct ure lat er on if you choose t o use som et hing like t he Fake
m echanism now. This is not t he case at all. I t 's not even t rue t hat non- PI - support ing infrast ruct ure
m akes it harder for you t o use TDD. I t 's t radit ionally t he case, but not a m ust .
Speaking of TDD, has t he Fake affect ed our unit t est s m uch yet ?
Affecting the Unit Tests
Nope, cert ainly not all t est s will be affect ed. Most t est s should be writ t en wit h classes in t he Dom ain
Model in as isolat ed a way as possible, wit hout a single call t o Reposit ories. For inst ance, t hey should
be writ t en during developm ent of all t he logic t hat should t ypically be around in t he Dom ain Model
classes. Those t est s aren't affect ed at all.
The unit t est s t hat should deal wit h Reposit ories are affect ed, and in a posit ive way. I t m ight be
argued t hat t hese are m ore about int egrat ion t est ing, but it doesn't have t o be t hat way. Reposit ories
are unit s, t oo, and t herefore t est s on t hem are unit t est s.
And even when you do int egrat ion t est ing wit h Reposit ories involved, it 's nice t o be able t o writ e t he
t est s early and t o writ e t hem ( and t he Reposit ories) in a way so t hat it is possible t o use t hem when
you have infrast ruct ure in place as well.
I t hink a nice goal is t o get all t he t est s in good shape so t hat t hey can run bot h wit h t he Fake
m echanism and t he infrast ruct ure. That way you can execut e wit h t he Fake m echanism in daily work
( for reasons of execut ion t im e) and execut e wit h t he infrast ruct ure a couple of t im es a day and at t he
aut om at ic builds at check in.
You can also work quit e a long way wit hout infrast ruct ure in place. You m ust , of course, also t hink a
bit about persist ence, and especially for your first DDD proj ect s, it 's im port ant t o work it erat ively
from t he beginning. But when you get m ore experience, delaying t he addit ion of t he persist ence will
give you t he short est developm ent t im e in t ot al and t he cleanest code.
This also gives you t he possibilit y of anot her refact oring rhyt hm , wit h m ore inst ant feedback whet her
you like t he result or not . First , you get everyt hing t o work wit h t he Fake ( which is easier and fast er
t han get t ing t he whole t hing, including t he dat abase, t o t he right level) , and if you're happy t hen you
proceed t o get it all t o work wit h t he infrast ruct ure. I believe t he big win is t hat t his will encourage
you t o be keener t o do refact orings t hat would norm ally j ust be a pain, especially when you are
unsure about t he out com e. Now you can give t hem a t ry pret t y easily.
Of course, t rying t o avoid code duplicat ion is as im port ant for unit t est s as it is for t he " real" code.
( Well, at least close t o as im port ant . There's also a com pet ing st rive t o " show it all" inline.) Therefore
I only want t o writ e t he t est s once, but be able t o execut e t hem bot h for t he Fake and t he real
infrast ruct ure when in place. ( Please not e t hat t his only goes for som e of t he t est s of course. Most of
t he t est s aren't about t he Reposit ories at all so it 's im port ant t hat you part it ion your t est s for t his
aspect .)
One way of approaching t his is t o writ e a base class for each set of t est s t hat are Reposit ory-
affect ing. Then I use t he Tem plat e Met hod pat t ern for set t ing up an IWorkspace t he way I want . I t
could look like t his, t aking t he base class first :
[TestFixture]
public abstract class CustomerRepositoryTestsBase
{
private IWorkspace _ws;
private CustomerRepository _repository;
[SetUp]
public void SetUp()
{
_ws = _CreateWorkspace();
_repository = new CustomerRepository(_ws);
}
[TearDown]
public void TearDown()
{
_ws.Clean();
}
}
OK, t hat was t he plum bing for t he t est s relat ed t o Reposit ories, but what about t he t est s t hem selves?
Well, t here are several different st yles from which t o choose, but t he one I prefer is t o define as
m uch as possible in t he base class, while at t he sam e t im e m aking it possible t o decide in t he
subclass if a cert ain t est should be im plem ent ed or not at t he m om ent . I also want it t o be im possible
t o forget t o im plem ent a t est in t he subclass. Wit h t hose requirem ent s in place, m y favorit e st yle
looks like t his ( first , how a sim plified t est looks in t he base class) :
[Test]
public virtual void CanAddCustomer()
{
Customer c = new Customer();
c.Name = "Volvo";
c.Id = 42;
_repository.Add(c);
_ws.PersistAll();
_ws.Clean();
//Check
Customer c2 = _repository.GetById(c.Id);
Assert.AreEqual(c.Name, c2.Name);
//Clean up
_repository.Delete(c2);
_ws.PersistAll();
}
Not e t hat t he second level of I dent it y Maps isn't cleared when new FakeWork-space("") is done
because t he second level I dent it y Maps of t he Fake are static and t herefore not affect ed when t he
Fake inst ance is recreat ed. That 's j ust how it is wit h a dat abase, of course. Just because you open a
new connect ion doesn't m ean t he Customers t able is cleared.
So it 's a good t hing t hat t he Fake works in t his way, because t hen I will need t o clean up aft er t he
t est s wit h t he Fake j ust as I will when I 'm using t he t est s wit h a real dat abase, if t hat 's t he approach
I 'm choosing for m y dat abase t est ing.
Of course, IWorkspace m ust have Delete() funct ionalit y, which I haven't discussed yet , ot herwise it
won't be possible t o do t he cleaning up. As a m at t er of fact , in all it s sim plicit y t he Delete() is quit e
int erest ing because it requires an I dent it y Map of it s own for t he Fake in t he Unit of Work. I nst ances
t hat have been regist ered for delet ion will be held t here unt il PersistAll(), when t he delet ion is done
perm anent ly.
Unfort unat ely, it also int roduces a new problem . What should happen t o t he relat ionships for t he
delet ed obj ect ? That 's not sim ple. Again, m ore m et adat a is needed t o det erm ine how far t he delet e
should cascadem et adat a t hat is around for t he real infrast ruct ure, but not useful here. ( The
convent ion current ly used for t he Fake is t o not cascade.)
OK, back t o t he t est s. I n t he subclass, I t ypically have one of t hree choices when it com es t o t he
CanAddCustomer() t est . The first alt ernat ive is t o do not hing, in which case I 'm going t o run t he t est
as it 's defined in t he base class. This is hopefully what I want .
The second opt ion should be used if you aren't support ing a specific t est for t he specific subclass for
t he t im e being. Then it looks like t his in t he subclass:
This way, during t est execut ion it will be clearly signaled t hat it 's j ust a t em porary ignore.
Finally, if you " never" plan t o support t he t est in t he subclass, you can writ e it like t his in t he
subclass:
[Test]
public override void CanAddCustomer()
{
Console.WriteLine
("CanAddCustomer() isn't supported by Fake.");
}
OK, you st ill can forget a t est if you do your best . You'd have t o writ e code like t his, skipping t he
Test- at t ribut e:
There's a solut ion t o t his, but I find t he st yle I have shown you t o be a good balance of am ount of
code and t he risk of " forget t ing" t est s.
I know, t his wasn't YAGNI , because right now we don't have any im plem ent at ion ot her t han t he Fake
im plem ent at ion, but see t his j ust as a quick indicat or for what will happen lat er on.
N ot e
This st yle could j ust as well be used in t he case of m ult iple im plem ent at ions for each
Reposit ory.
For m any applicat ions, it m ight be close t o im possible t o deal wit h t he whole syst em in t his way,
especially lat er on in t he life cycle. For m any applicat ions, it 's perhaps only useful for early
developm ent t est ing and early dem os, but even so, if it helps wit h t his, it 's very nice. I f it works all
t he way, it 's even nicer.
I n real life, t he basics ( t here are always except ions) are t hat I 'm focusing on writ ing t he core of t he
t est s against t he Fake im plem ent at ion. I also writ e CRUD t est s against t he Fake im plem ent at ion, but
in t hose cases I also inherit t o t est s for using t he dat abase. That way, I t est out t he m apping det ails.
That said, no m at t er if you use som et hing like t he ideas of t he abst ract ion layer or not , you will
sooner or lat er run int o t he problem s of dat abase t est ing. I asked m y friend Philip Nelson t o writ e a
sect ion about it . Here goes.
Database Testing
By Philip Nelson
At som e point when you are working wit h DDD and all t he various flavors of aut om at ed t est ing, you
will probably run int o a desire t o run a t est t hat includes access t o a dat abase. When you first
encount er t his, it seem s like no problem at all. Creat e a t est dat abase, point your applicat ion at t he
t est dat abase, and st art t est ing.
Let 's focus m ore on aut om at ed t est ing, so let 's assum e you wrot e your first t est wit h JUnit or NUnit .
This t est j ust loaded a User dom ain obj ect from t he dat abase and verified t hat all t he propert ies were
set correct ly. You can run t his t est over and over again and it works every t im e. Now you writ e a t est
t o verify t hat you can updat e t he fields, and because you know you have a part icular obj ect in t he
dat abase, you updat e t hat .
The t est works, but you have int roduced a problem . The read t est no longer works because you have
j ust changed t he underlying dat a, and it no longer m at ches t he expect at ions of your first t est . OK,
t hat 's no problem ; t hese t est s shouldn't share t he sam e dat a, so you creat e a different User for t he
updat e t est . Now bot h t est s are independent of each ot her, and t his is im port ant : at all t im es you
need t o ensure t hat t here are no residual effect s bet ween t est s. Dat abase- backed t est s always have
precondit ions t hat you m ust m eet . Som ewhere in t he process of writ ing your t est s, you m ust account
for t he fact t hat you have t o reset t he dat abase t o m eet t he precondit ions t he t est expect s. More
det ails on t hat t o com e.
At som e point , you will have writ t en t est s for all t he basic User obj ect life cycle st at es, let 's say
creat e, read, updat e, and delet e ( CRUD) . I n your applicat ion, t here m ay very well be ot her dat abase-
backed operat ions. For exam ple, t he User obj ect m ay help enforce a policy of m axim um failed login
at t em pt s. As you t est t he updat ing of t he failed login at t em pt s and last login t im e fields, you realize
t hat your updat e act ually isn't working. The updat e t est didn't cat ch t he problem because t he
dat abase already had t he field set t o t he expect ed value. As t he sm art person you are, you figured
t his out very quickly. However, young Joe down t he hall has j ust spent four hours working on t he
problem . His coding skills aren't so m uch t he problem as m uch as his underst anding of how t he code
connect s t o t he dat abase and how t o isolat e t he dat a in t his t est from all t he ot her t est dat a he now
has. He j ust doesn't not ice t hat t he LastUpdateDate field is not reset bet ween t est s. Aft er all, t he code
is designed t o hide t he dat abase as an im plem ent at ion det ail, right ?
At t his point , you st art t o realize t hat j ust having separat e t est dat a for each t est is going t o be m ore
com plicat ed t han you want it t o be. You m ay or m ay not have underst ood as clearly as necessary
j ust how im port ant it was t o reset t he dat a bet ween t est s, but now you do. Fort unat ely, your xUnit
t est fram ework has j ust t he t hing for you. There is a set up and t eardown code block t hat is j ust m ade
for t his sort of t hing. But like m ost t hings in program m ing, t here is m ore t han one way t o do it , and
each has it s st rengt hs and weaknesses. You m ust underst and t he t radeoffs and det erm ine t he
balance t hat suit s you best .
Separat e t he t est ing of t he unit from t he t est ing of t he call t o t he dat abase.
One sim ple but slow approach is t o rest ore t he dat abase from backup before each t est . Wit h m any
dat abase syst em s, t his is not pract ical because of t he am ount of t im e it t akes. However, t here are
som e syst em s where it is possible. I f you are program m ing against a file- based dat abase, for
exam ple, you m ay only need t o close your connect ions and copy a file t o get back t o t he original
st at e. Anot her possibilit y is an in- m em ory dat abase, such as HSQL for Java, t hat can be rest ored
very quickly. Even if you are using a m ore st andard syst em like Oracle or SQL Server, if your design
for dat a access is flexible enough, you m ay be able t o swit ch t o an in- m em ory or file- based dat abase
for your t est s. This is especially t rue if you are using an O/ R Mapper t hat t akes t he responsibilit y of
building t he act ual SQL calls for you and knows m ult iple dialect s.
The proj ect DbUnit offers anot her way t o reset a dat abase before t he t est runs. Essent ially, it 's a
fram ework for JUnit t hat allows you t o define " dat a set s" t hat are loaded on clean t ables before each
t est run. Ruby on Rails has a sim ilar syst em t hat allows you t o describe your t est class dat a in t he
open YAML ( YAML Ain't Markup Language) form at and apply it during t est set up. These t ools can
work well, but you m ay st art running int o problem s as t hese dat abase insert s m ay be logged
operat ions t hat can be t oo slow. Anot her approach t hat could work for you is t o use bulk load ut ilit ies
t hat m ay not be as ext ensively logged. Here is how t his m ight work for SQL Server. First , use a
dat abase recovery opt ion on your t est dat abase of Sim ple Recovery. This elim inat es m ost logging
and im proves perform ance. Then, during t est design, do t he following:
I nsert dat a int o a t est dat abase t hat will only act as a source of clean dat a for your t est s
Call t ransact sql com m ands t hat export t he t est dat a t o files
Writ e t ransact sql com m ands t o do bulk insert of t he dat a in t hese files
Truncat e all your t ables. This is not a logged operat ion and can be very fast .
I ssue t he bulk copy com m ands creat ed earlier t o load t he t est dat a int o t he t est dat abase.
A variat ion of t his t echnique is t o set up your t est dat abase and load t he init ial t est dat a using norm al
dat a m anagem ent t echniques. Then, provided your dat abase support s such an operat ion, det ach t he
underlying dat a files from t he server. Make a copy of t hese files as t hese will be t he source of your
clean t est dat a. Then, writ e code t hat allows you t o
I n m any cases, t his operat ion is very fast and can be run in t he t est fixt ure set up or, if t he am ount of
dat a isn't t oo large, in t he t est set up it self.
Yet anot her variat ion support ed by som e of t he O/ R Mapping t ools is t o build t he dat abase schem a
from m apping inform at ion. Then you can use your Dom ain Model in t est set up t o populat e dat a as
needed for each t est suit e or possibly for each t est fixt ure.
What 's really great about t his t echnique is t hat your t est s can be blissfully unaware of what 's
happening underneat h t hem . This funct ionalit y has been packaged up in a proj ect called Xt Unit
[ Xt Unit ] and is an ext ension t o t he NUnit t est ing fram ework. This is by far t he sim plest approach t o
keeping your dat abase in prist ine shape. I t does com e wit h a price, t hough. Transact ions are by t heir
nat ure logged, which increases t he execut ion t im e. COM+ t ransact ions use t he Dist ribut ed
Transact ion Coordinat or, and dist ribut ed t ransact ions are slower t han local t ransact ions. The
com binat ion can be brut al t o t he execut ion speed of your t est suit e.
Nat urally, if you are t est ing t ransact ion sem ant ics t hem selves, you m ay have som e addit ional
problem s wit h t his t echnique. So depending on t he specifics of your proj ect , t his can be a really great
solut ion or a solut ion in need of a replacem ent as t he num ber of t est s grows. Fort unat ely, you would
not necessarily have t o rewrit e m uch code should t est speed becom e a problem because t he solut ion
is t ransparent t o t he t est . You will eit her be able t o live wit h it , or you will have t o adopt ot her
t echniques as your proj ect grows.
There is a downside, t hough. As soon as you m ake t he leap t o assum ing you know exact ly what dat a
will be affect ed by your t est , you have t ied yourself int o underst anding what not j ust t he code under
t est is doing wit h dat a, but also what addit ional code t he code under t est calls out t o. I t m ay get
changed wit hout you not icing it . Test s m ay break t hat are not an indicat ion of broken code. A bug
will get filed t hat m ay not be a bug at all but is m aint enance work j ust t he sam e.
I t is possible t o use t his t echnique successfully, but aft er m any years of t est writ ing, I have found
t his approach t o be t he m ost likely t o break wit hout good reason. You can m inim ize t his, t hough. I f
you m ock out t he classes your code under t est calls out t o, t hat code won't affect t he dat abase. This
is in spirit m uch closer t o what is m eant by a unit t est . Mocking is not useful if you are aut om at ing
syst em t est s where t he int eract ions bet ween real classes are exact ly what you want t o t est . At any
rat e, doing t his requires an archit ect ure decision t o allow for easy subst it ut ion of ext ernal classes by
t he t est ing fram ework. I f you are going t o do t hat , you have nat urally found yourself working t oward
t he final opt ion I am covering here.
I prefer t he approach of creat ing and running alt er script s against your dat abase. You could run t hese
script s im m ediat ely aft er your dat abase reset , but because all t hat dat abase st at e is cont ained in
your source cont rolled developm ent environm ent , it probably m akes sense t o develop t he script s and
use t hem t o m odify your t est environm ent . When your t est s pass, you check it all in and t hen have
t he script s aut om at ically set up t o run against your QA environm ent as needed.
I t 's even bet t er if t his happens on your build server because t he running of t he alt er script s is t hen
t est ed oft en before it 's applied t o your live syst em s. Of course, t hat assum es you regularly reset your
QA environm ent t o m at ch your live environm ent . I 'm sure t here are m any variat ions of t his process,
but t he m ost im port ant t hing is t o plan ahead t o ensure a reliable release of bot h code and dat abase
changes.
Separate the Testing of the Unit from the Testing of the Call to the
Database
Few t hings in t he Agile com m unit y's m ailing list s and forum s generat e m ore discussion t han t he
t est ing of code t hat int eract s wit h dat abases. Am ong t hose who are pract icing ( and st ill defining) t he
t echniques of TDD, it is a highly held value t hat all code can be t est ed independent ly as unit s as t hey
are writ t en. I n t he spirit of TDD, it wouldn't m ake sense t o writ e a t est for a class and st art out your
im plem ent at ion wit h a direct call t o a dat abase. I nst ead, t he call is delegat ed out t o a different obj ect
t hat abst ract s t he dat abase, which is replaced wit h a st ub or a m ock as you writ e t he t est . Then you
writ e t he code t hat act ually im plem ent s t he dat abase abst ract ion, and t est t hat it calls t he underlying
dat a access obj ect s correct ly. Finally, you would writ e a few t est s t hat t est t hat your infrast ruct ure
t hat connect s real dat abase calls t o your code works correct ly. As t he old saying goes, m ost
problem s in coding can be solved wit h anot her layer of indirect ion. As always, t he devil's in t he
det ails.
First , let 's clarify a few definit ions. A st ub is a replacem ent piece of code t hat does j ust enough t o not
cause problem s for t he caller and no m ore. A st ub for a dat abase call, such as a call t o a JDBC
Statement, would be accom plished by having a bare- bones class t hat im plem ent s t he Statement's
int erface and sim ply ret urns a ResultSet when called, possibly ignoring t he param et ers passed and
cert ainly not execut ing a dat abase call.
A m ock Statement would do all t hat and also allow t he set t ing of expect at ions. I 'll say m ore on t hat in
a m om ent . Like a st ub, t he t est would use t he m ock com m and inst ead of t he real com m and, but
when t he t est was com plet e, it would " ask" t he m ock com m and t o " verify" t hat it was called
correct ly. The expect at ions for a m ock Statement would be values for any param et ers t he call
needed, t he num ber of t im es t hat executeQuery was called, t he correct SQL t o be passed t o t he
st at em ent and so on. I n ot her words, you t ell t he m ock what t o expect . Then you ask it t o verify t hat
it did receive t hese expect at ions aft er t he t est is com plet e.
When you t hink about it , I t hink you have t o agree t hat a unit t est for a User class should not have t o
concern it self wit h what t he dat abase does. So long as t he class int eract s wit h t he dat abase
abst ract ion correct ly, we can assum e t he dat abase will do it s part correct ly or at least t hat t est s t o
your dat a access code will verify t hat fact for you. You j ust have t o verify t hat t he code correct ly
passes all t he fields t o t he dat abase access code, and you have done all you need t o do. I f only it
could always be t hat sim ple!
To t ake t his t o it s logical conclusion, you m ight end up writ ing m ock im plem ent at ions of m any of t he
classes in your code. You will have t o populat e t he m em bers and propert ies of t hose m ocks wit h at
least enough dat a t o sat isfy t he requirem ent s of your t est s. That 's a lot of code, and an argum ent
could be m ade t hat j ust having t o support t hat m uch code will m ake your code harder t o m aint ain.
Consider t his alt ernat ive. There are som e new fram eworks available in a variet y of languages t hat
allow you t o creat e m ock obj ect s from t he definit ions of real classes or int erfaces. These dynam ically
creat ed m ocks allow you t o set expect at ions, set expect ed ret urn values and do verificat ion wit hout
writ ing m uch code t o m ock t he class it self. Known collect ively as Dynam ic Mocks, t he t echnique
allows you t o sim ply pass in t he class t o m ock t o a fram ework and get back an obj ect t hat will
im plem ent it s int erface.
There are m any ot her sources of inform at ion on how t o m ock code, but m uch less on how t o
effect ively m ock dat abase access code. Dat a access code t ends t o have all t hese m oving part s t o
deal wit h: connect ions, com m and obj ect s, t ransact ions, result s, and param et ers. The dat a access
libraries t hem selves have driven t he creat ion of a wide variet y of dat a access helpers whose aim it is
t o sim plify t his code. I t seem s t hat none of t hese t ools, t he helpers, or t he underlying dat a access
libraries like JDBC or ADO.NET were writ t en wit h t est ing in m ind. While m any of t hese t ools offer
abst ract ions on t he dat a access, it t urns out t o be fairly t ricky work t o m ock all t hose m oving part s.
There is also t hat issue of having t o t est t he m apping of all t hose fields bet ween t he dat a access code
and rest of your classes. So here are som e pieces of advice t o help you t hrough it .
Test everyt hing you can wit hout act ually hit t ing your dat abase access code. The dat a access code
should do as lit t le as you can get away wit h. I n m ost cases, t his should be CRUD. I f you are able t o
t est all t he funct ionalit y of your classes wit hout hit t ing t he dat abase, you can writ e dat abase t est s
t hat only exercise t hese sim pler CRUD calls. Wit h t he aid of helper m et hods you m ay be able t o
verify t hat t he before and aft er set of fields m at ch your expect at ions by using reflect ion t o com pare
t he obj ect s rat her t han hand coding all t he propert y t est s. This can be especially helpful if you use an
O/ R Mapper, such as Hibernat e, where t he dat a access is very nicely hidden, but t he m apping file
it self needs t o be t est ed. I f all t he ot her funct ionalit y of t he class is verified wit hout t he dat abase hit ,
you oft en only need t o verify t hat t he class's CRUD m et hods and t he m apping are working correct ly.
Test t hat you have called t he dat a access code correct ly separat ely from t est ing t he dat abase code
it self. For exam ple, if you have a User class t hat saves via a UserRepository, or perhaps a Dat a
Access Layer in nTier t erm inology, all you need t o t est is t hat t he UserRepository is called correct ly
by your upper- level classes. Test s for t he UserRepository would t est t he CRUD funct ionalit y wit h t he
dat abase.
To t est cert ain t ypes of dat a access, t hese sim ple CRUD t est s m ay not be adequat e. For exam ple,
calls t o st ored procedures t hat aren't direct ly relat ed t o class persist ence fall in t his cat egory. At
som e point , you m ay need t o t est t hat t hese procedures are called correct ly, or in your t est you m ay
need dat a back from one of t hese calls for t he rest of your t est . Here are som e general t echniques t o
consider in t hose cases where you really are going t o m ock JDBC, ADO.NET, or som e ot her dat a
access library direct ly.
You m ust use fact ories t o creat e t he dat a access obj ect s and program against int erfaces rat her t han
concret e t ypes. Fram eworks m ay provide fact ories for you, as t he Microsoft Dat a Access Applicat ion
Block does in it s m ore recent versions. However, you also need t o be able t o use t hese fact ories t o
creat e m ock im plem ent at ions of t he dat a access classes, som et hing not support ed out of t he box by
m any fact ory fram eworks. I f you have a fact ory t hat can be configured by your t est code t o provide
m ocks, you can subst it ut e a m ock version of t hese dat a access classes. Then you can verify virt ually
any t ype of dat abase call. You st ill m ay need m ock im plem ent at ions of t hese classes, t hough. For
ADO.NET, t hese can be obt ained from a proj ect called .NET Mock Obj ect s [ MockObj ect s] . Versions for
ot her environm ent s m ay also be available. The only com binat ion of a fact ory- based fram ework t hat
can work wit h m ocks direct ly t hat I am aware of is t he SnapDAL fram ework [ SnapDAL] t hat builds on
.NET Mock Obj ect s t o supply m ock im plem ent at ions of t he ADO.NET generic classes and was built t o
fully support m ock obj ect s for t he ADO.NET generic int erfaces.
Whet her you can use t hese fram eworks or not depends on m any fact ors, but one way or anot her,
you will need your applicat ion t o support a fact ory t hat can ret urn a real or a m ock of your dat a
access classes. When you get t o a posit ion where you can creat e m ock inst ances of your dat a access
classes, you can now use som e or all of t he following t echniques t o t est :
The m ock ret urns result set s, act ing as a st ub for your code. The result set get s it s dat a from
t he t est code in st andard m ock obj ect st yle.
The m ock can ret urn t est dat a from files, such as XML files or spreadsheet s of accept ance t est
dat a provided by your business unit s.
The m ock can ret urn t est dat a from an alt ernat e dat abase or a m ore refined query t han t he real
query under t est .
I f you can subst it ut e a dat a access com m and, you can " record" t he dat a access and lat er " play
it back" from a m ock obj ect in your t est s because you would have access t o all t he param et ers
and t he ret urned result s.
Mocks can have expect at ions verified of im port ant t hings like t he connect ion being opened and
closed, t ransact ions com m it t ed or rolled back, except ions generat ed and caught , and dat a
readers read, and so on.
I hope t hese ideas can get you st art ed wit h an appreciat ion for t he m any possibilit ies t here are for
t est ing dat abase- connect ed code. The t ext was writ t en basically in order of com plexit y, wit h
dat abase reset t ing or t he rollback t echniques being t he easiest t o im plem ent . Fully separat ing out t he
dat a access code from t he rest of your code will always be a good m ove and will im prove your t est ing
success and t est speed. At t he m ost fine- grained level, allowing for m ock versions of your act ual
dat abase calls offers great flexibilit y in how you gat her, provide, and organize t est dat a. I f you are
working wit h legacy code t hat uses t he lower- level dat a access libraries of your language, you would
probably m ove t oward t his sort of approach. I f you are st art ing a new applicat ion, you can probably
st art wit h t he idea of sim ply reset t ing your dat abase bet ween t est s and enhance your t est st ruct ure
as t est speed begins t o affect your product ivit y.
Thanks, Phil! Now we are arm ed t o deal wit h t he problem of dat abase t est ing no m at t er what
approach we choose.
N ot e
Neeraj Gupt a com m ent ed on t his by saying, " You can use t he Flashback feat ure of Oracle
dat abase t o bring t he dat abase back t o t he previous st at e for t he t est ing."
We have com e quit e a long way, but t here is one very big piece of t he preparing for infrast ruct ure
puzzle t hat we haven't dealt wit h at all. How did I solve _GetNumberOfStoredCustomers?
Let 's t ake a st ep back and t ake anot her solut ion t hat is not query- based. Earlier, I showed you how
t o fet ch by ident it y in a Reposit ory wit h t he following code:
//OrderRepository
public Order GetOrder(int orderNumber)
{
return (Order)_ws.GetById(typeof(Order), orderNumber);
}
However, if OrderNumber isn't an ident it y, t he int erface of t he Reposit ory m et hod m ust clearly change
t o ret urn a list inst ead, because several orders can have ordernum ber 0 before t hey have reached a
cert ain st at e. But t hen what ? GetById() is useless now, because OrderNumber isn't an I dent it y ( and
let 's assum e it 's not unique because I said t he answer could be a list ) . I need a way t o get t o t he
second layer of I dent it y Maps of t he Fake for t he Orders. Let 's assum e I could do t hat wit h a
GetAll(Type typeOfResult) like t his:
//OrderRepository
public IList GetOrders(int orderNumber)
{
IList result = new ArrayList();
IList allOrders = _ws.GetAll(typeof(Order));
return result;
}
I t 's st ill pret t y silly code, and it 's definit ely not what you want t o writ e when you have infrast ruct ure
in place, at least not for real- world applicat ions.
//OrderRepository
public IList GetOrders(int orderNumber)
{
IQuery q = new Query(typeof(Order));
q.AddCriterion("OrderNumber", orderNumber);
return _ws.GetByQuery(q);
}
OK, t hat was pret t y st raight forward. You j ust creat e an IQuery inst ance by saying which t ype you
expect in t he result . Then you set t he crit eria you want for holding down t he size of t he result set as
m uch as possible, t ypically by processing t he query in t he dat abase ( or in t he Fake code, in t he case
of when you're using t he Fake im plem ent at ion) .
N ot e
We could pret t y easily m ake t he query int erface m ore fluent , but let 's st ay wit h t he m ost
basic we can com e up wit h for now.
That was what t o do when you want t o inst ant iat e part of t he Dom ain Model. Let 's get back t o t he
_GetNumberOfStoredCustomers() t hat we t alked about earlier. How could t hat code look wit h our
newly added querying t ool? Let 's assum e it calls t he Reposit ory and a m et hod like t he following:
//CustomerRepository
public int GetNumberOfStoredCustomers()
{
return _ws.GetByQuery(new Query(typeof(Customer))).Count;
}
I t works, but for product ion scenarios t hat solut ion would reduce every DBA t o t ears. At least it will if
t he result is a SELECT t hat fet ches all rows j ust so you can count how m any rows t here are. I t 's j ust
not accept able for m ost sit uat ions.
We need t o add som e m ore capabilit ies in t he querying API . Here's an exam ple where we have t he
possibilit y of ret urning sim ple t ypes, such as an int , com bined wit h an aggregat e query ( and t his
t im e aggregat e isn't referring t o t he DDD pat t ern Aggregat e, but , for exam ple, t o a SUM or AVG
query in SQL) :
//CustomerRepository
public int GetNumberOfStoredCustomers()
{
IQuery q = new Query(typeof(Customer),
new ResultField("CustomerNumber", Aggregate.Count));
return (int)_ws.GetByQuery(q)[0];
}
A bit raw and im m at ure, but I t hink t hat t his should give you an idea of how t he basic querying API
in NWorkspace is designed.
I t would be nice t o have a st andard querying language, wouldn't it ? Perhaps t he absence of one was
what m ade Obj ect Dat abases not really t ake off. Sure, t here was Obj ect Query Language ( OQL) , but
I t hink it cam e in pret t y lat e, and it was also a pret t y com plex st andard t o im plem ent . I t 's
com pet ent , but com plex. ( Well, it was probably a com binat ion of t hings t hat hindered Obj ect
Dat abases from becom ing m ainst ream ; isn't it always?) I 'll t alk m ore about Obj ect Dat abases in
Chapt er 8, " I nfrast ruct ure for Persist ence."
What I now want , t hough, is a querying st andard for persist ence fram eworks som et hing as
widespread as SQL, but for Dom ain Models. Unt il we have such a st andard, t he NWorkspace version
could bridge t he gap, for m e at least . I s t here a cost for t hat ? I s t here such a t hing as a free lunch?
Then t here's t he cost of loss of power because t he NWorkspace- API is sim plified, and com pet ent
infrast ruct ure solut ions have m ore t o offer and t hat is probably m uch worse. Yet anot her cost is t hat
t he API of NWorkspace it self is pret t y raw and perhaps not as nice as t he querying API of your
infrast ruct ure solut ion. OK, all t hose cost s sound fair, and if t here's a lot t o be gained, I can live wit h
t hem .
I left out one very im port ant det ail before about querying and t he I dent it y Map: bypassing t he cache
when querying or not .
I m ent ioned earlier t hat when you do a GetById(), if t hat operat ion m ust be fulfilled by going t o
persist ence, t he fet ched inst ance will be added t o t he I dent it y Map before being ret urned t o t he
consum er. That goes for GetByQuery() as well; t hat is, t he inst ances will be added t o t he I dent it y
Map.
However, t here's a big difference in t hat t he GetByQuery() won't invest igat e t he I dent it y Map before
hit t ing persist ence. The reason is part ly t hat we want t o use t he power of t he backend, but above all
t hat we don't know if we have all t he necessary inform at ion in t he I dent it y Map ( or cache if you will)
for fulfilling t he query. To find out if we have t hat , we need t o hit t he dat abase. This brings us t o
anot her problem . GetById() st art s wit h t he I dent it y Map; GetByQuery() does not . This is t ot ally
different behavior, and it act ually m eans t hat GetByQuery() bypasses t he cache, which is problem at ic.
I f you ask for t he new Customer Volvo t hat has been added t o t he I dent it y Map/ Unit of Work, but has
not been persist ed, it will be found if you ask by I D but not when you ask by nam e wit h a query.
Weird.
To t ell you t he t rut h, it was a painful decision, but I decided t o let GetByQuery() do an im plicit
PersistAll() by default before going t o t he dat abase. ( There's an override t o GetByQuery() t o avoid
t his, but again, it 's t he default t o im plicit ly call PersistAll().) I cam e t o t he conclusion t hat t his
default st yle is probably m ost in line wit h t he rest of NWorkspace and it s goal of sim plicit y and t he
lessened risk of errors. This is why I m ade som e sacrifices wit h t ransact ional sem ant ics. Som e m ight
argue t hat t his violat es t he principle of least am ount of surprise. But I t hink it depends on your
background, what is surprising in t his case.
The biggest drawback is definit ely t hat when doing GetByQuery(), you m ight get save- relat ed
except ions. What a painful decisionbut I need t o decide som et hing for now t o m ove on.
Do you rem em ber t he sim ple and unopt im ized version of t he _GetNumberOf-StoredCustomers()? I t 's
not j ust slowit m ight not work as expect ed when it looks like t his ( which goes for t he opt im ized
version as well:
The reason it won't work for m y purpose is t hat GetByQuery() will do t hat im plicit PersistAll().
I nst ead, an overload m ust be used like t his, where false is for t he implicitPersistAll param et er:
N ot e
And of course we could ( and should) use t he aggregat e version inst ead. The focus here was
how t o deal wit h im plicit PersistAll().
All t his affect s t he program m ing m odel t o a cert ain degree. First of all, you should definit ely t ry t o
adopt a st yle of working in blocks when it com es t o querying and changing for t he sam e workspace
inst ance. So when you have m ade changes, you should be happy about t hem before querying
because querying will m ake t he changes persist ent .
N ot e
You m ight be right . I m ight be responsible for fost ering a sloppy st yle of consum er
program m ers. They j ust code and it works, even t hough t hey forget about saving explicit ly
and so on.
An unexpect ed and unwant ed side effect is t hat you can get t ot ally different except ions from
GetByQuery() from what you expect because t he except ion m ight really com e from PersistAll().
Therefore, it 's definit ely a good idea t o do t he PersistAll() explicit ly in t he consum er code anyway.
And again, if you hat e t his behavior, t here's not hing t o st op you from using t he overload. ( Act ually,
wit h GetById() you could do it t he ot her way around, so t hat an overload goes t o t he dat abase
regardless, wit hout checking t he I dent it y Map.) "I don't care about m y own t ransient work; I want t o
know what 's in t he dat abase. "
That was a bit about how querying works in relat ion t o t he I dent it y Map. Next up is where t o host t he
quer ies.
I n Reposit ories
In Repositories
Probably t he m ost com m on place t o set up queries is in t he Reposit ories. Then t he queries becom e
t he t ool for fulfilling m et hod request s, such as GetCustomersByName() and GetUndeliveredOrders().
That is, t he consum er m ight send param et ers t o t he m et hods, but t hose are j ust ordinary t ypes and
not Query Obj ect s. The Query Obj ect s are t hen set up in accordance wit h t he m et hod and possible
param et er values.
In Consumers of Repositories
I n t he second case, t he queries are set up in t he consum ers of t he Reposit ories and sent t o t he
Reposit ories as param et ers. This is t ypically used in cases of highly flexible queries, such as when t he
user can choose t o fill in any fields in a large filt ering form . One such t ypical m et hod on a Reposit ory
could be nam ed GetCustomersByFilter(), and it t akes an IQuery as param et er.
Finally, it m ight be int erest ing t o set up t yped Query Obj ect s in t he Dom ain Model ( st ill queries t hat
im plem ent IQuery of NWorkspace) . The consum er st ill get s t he power of queries t o be used for
sending t o Reposit ories, for exam ple, but wit h a highly int uit ive and t ypesafe API . How t he API looks
is, of course, t ot ally up t o t he Dom ain Model developer.
//Consumer code
IQuery q = new Query(typeof(Customer));
q.AddCriterion("Name",
"Volvo");
//Consumer code
CustomerQuery q = new CustomerQuery();
q.Name.Eq("Volvo");
I n addit ion t o get t ing sim pler consum er code, t his also furt her encapsulat es t he Dom ain Model.
I t 's also about lessening t he flexibilit y, and t hat is very good. Don't m ake everyt hing possible.
Assum ing you like t he idea of Dom ain Model- host ed queries, which queries do we need and how
m any ?
Each of your Aggregat es is a t ypical candidat e for having Query Obj ect in t he Dom ain Model. Of
course, you could also go t he XP rout e of creat ing t hem when needed for t he first t im e, which is
probably bet t er.
Speaking of Aggregat es, I 'd like t o point out again t hat I see Aggregat es as t he default m echanism
for det erm ining how big t he loadgraphs should be.
N ot e
Wit h loadgraph, I m ean how far from t he t arget inst ance we should load inst ances. For
exam ple, when we ask for a cert ain order, should we also load it s customer or not ? What
about it s orderLines?
And when t he default isn't good enough perform ance- wise, we have lot s of room for perform ance
opt im izat ions. A t ypical exam ple is t o not load com plet e graphs when you need t o list inst ances, such
as Orders. I nst ead, you creat e a cut down t ype, perhaps called OrderSnapshot , wit h j ust t he fields
you need in your t ypical list sit uat ions. I t 's also t he case t hat t hose list s won't be int egrat ed wit h t he
Unit of Work and I dent it y Map, which probably is exact ly what you want , again because of
perform ance reasons ( or it m ight creat e problem sas always, it depends) .
An abst ract ion layer could support creat ing such list s so t hat your code will be agnost ic about t he
im plem ent at ion of t he abst ract ion layer at work. I t could look like t his:
For t his t o work, OrderSnapshot m ust have suit able const ruct or, like t his ( assum ing here t hat t he I ds
are im plem ent ed as Guids) :
//OrderSnapshot
public OrderSnapshot(Guid id, int orderNumber
, Guid customerId, string customerName)
N ot e
Get t ing t ype explosion is com m only referred t o as t he Achilles heel of O/ R Mappers, which I
provided an exam ple of earlier. I n m y experience, t he problem is t here, but not anyt hing
we can't deal wit h. First , you do t his only when you really have t o, so not all Aggregat e
root s in your m odel will have a snapshot class. Second, you can oft en get away wit h a
single snapshot class for several different list scenarios. The opt im izat ion effect of doing it
at all is oft en significant enough t hat you don't need t o go furt her.
Anot her com m on approach is t o use Lazy Load for t uning by loading som e of t he dat a j ust in t im e.
( We'll t alk m ore about t his in a lat er chapt er.)
And if t hat isn't powerful enough, you can writ e m anual SQL code and inst ant iat e t he snapshot t ype
on your own. Just be very clear t hat you are st art ing t o act ively use t he dat abase m odel as well at
t hat point in t im e.
Wit h all t his in place, you underst and t hat you have m any different possibilit ies for how
t o st ruct ure t he Reposit ories, but you m ight wonder how it 's done in real- world proj ect s.
I n t he m ost recent large proj ect of m ine ( which is in product ionit 's not a t oy proj ect ) , I
use a single set of Reposit ories, bot h for Fake execut ion and execut ion against t he
dat abase. There are a few opt im izat ions t hat use nat ive SQL, but I used a lit t le hack
t here so t hat if t he opt im ized m et hod finds an inj ect ed connect ion st ring, it calls out t o
anot her m et hod where I 'm t ot ally on m y own.
Ot herwise, t he un- opt im ized code will be used inst ead. That way, t he Fake will use t he
un- opt im ized version, and t he dat abase- relat ed code will t ypically use t he opt im ized
version.
Again, t his is only used in a handful of cases. Not ext rem ely nice and clean, but it works
fine for now.
Specifications as Queries
Yet anot her approach for querying is t o use t he Specificat ion pat t ern [ Evans DDD] ( encapsulat e
concept ual specificat ions for describing som et hing, such as what a cust om er t hat isn't allowed t o buy
m ore " looks like" ) . The concept get s a describing nam e and can be used again and again.
Using t his approach is sim ilar t o creat ing t ype safe Dom ain Model- specific queries, but it goes a st ep
furt her because it 's not generic querying t hat we are aft er, but very specific querying, based on
dom ain- specific concept s. This is one level higher t han t he query definit ions t hat live in t he Dom ain
Model, such as CustomerQuery . I nst ead of exposing generic propert ies t o filt er by, a specificat ion is a
concept wit h a very specific dom ain m eaning. A com m on exam ple is t he concept of a gold cust om er.
The specificat ion describes what is needed for a cust om er t o be a gold cust om er.
The code get s very clear and purposeful because t he concept s are caught and described as
Specificat ion classes.
Even t hose Specificat ion classes could very well spit out IQuery so t hat you can use t hem wit h
GetByQuery() of IWorkspace ( or equivalent ) if you like t he idea of an abst ract ion layer.
I haven't t hought about any m ore query languages for NWorkspace. But perhaps I can som eday t alk
som e people int o adding support for NWorkspace queries as out put from t heir queries. That way,
t heir queries ( such as som et hing like SQL, but for Dom ain Model) would be useful against t he
infrast ruct ure solut ions t hat have adapt er im plem ent at ions for NWorkspace.
I can't let go of t he idea t hat what querying language you want t o use is as m uch of a lifest yle choice
as is t he choice of program m ing language. Of course, it m ight depend even m ore on t he sit uat ion as
t o which query language we want t o use, if we can choose. That 's a nice way t o end t his subj ect for
now, I t hink ( m ore t o com e in Chapt er 8 and 9) . I t 's t im e t o m ove on.
Summary
So we have discussed what Persist ence I gnorance is and som e ideas of how t o keep t he
infrast ruct ure out of t he Dom ain Model classes, while at t he sam e t im e prepare for infrast ruct ure. We
also discussed dat abase t est ing, and a lot of at t ent ion was spent on an idea of int roducing an
abst ract ion layer.
I n t he next chapt er, we will change focus t o t he core of t he Dom ain Model again, t his t im e focusing
on rules. You will find t hat lot s of t he requirem ent s in t he list we set up in Chapt er 4 are about rules,
so t his is a near and dear t opic when Dom ain Models are discussed.
Chapter 7. Let the Rules Rule
I n t he last chapt er, we t ook a nice break and looked at som e infrast ruct ure preparat ions. Now we'll
ret urn t o t he core m odel for a chapt er. This chapt er is about rules.
The t opic of rules is a huge one. We will deal wit h part of it , focusing m ainly on validat ion rules. We
will do it by addressing t he requirem ent s defined in Chapt er 4, " A New Default Archit ect ure," and add
som e com m ent s where appropriat e.
Looking back at t he requirem ent s list in Chapt er 4 ( t he list will be repeat ed short ly) , we can clearly
see t hat t he m aj orit y of t he requirem ent s have som et hing t o do wit h rules. As I see it , t his is one
area where Dom ain Models really shine. We can go quit e a long way wit hout needing a rules engine.
As Evans says [ Evans DDD] , using several paradigm s at t he sam e t im e is problem at ic, so we are
doing ourselves a favor if we can avoid m ixing Dom ain Models wit h rules engines. ( To give you a
sense of how com plex it can be t o m ix paradigm s, t hat is why m ixing OO and Relat ional m odels is so
t ricky.)
I n m y last book [ Nilsson NED] , t here was a chapt er called " Business Rules" in which I provided a
bunch of exam ple problem s relat ed t o where t o locat e t he rule evaluat ion. For som e reason, alm ost
all t he exam ples ended up being checked in t he dat abase. Yet t hat was from m y dat abase era, and
now I 'm a Dom ain Model guy, so you will find t hat t his chapt er is t ot ally different . I s t hat for t he
bet t er? I definit ely t hink so, and I hope you will agree.
OK, where shall we st art ? How about som e cat egorizat ion of rules?
Categorization of Rules
I f we t ry t o cat egorize rules, we quickly find out t hat t here are m any dim ensions t o consider. For
exam ple, t here are at t ribut es such as t he following:
When t o execut e
Degree of com plexit y ( sim ple const raint s, spanning several fields, spanning several inst ances,
and so on)
I 'm sorry, but I won't be dealing wit h t his m uch ot her t han direct ing you t o som e ot her books on t he
subj ect , such as von Halle's book [ von Halle BRA] , t he one by Ross [ Ross BRB] , and Halpin's [ Halpin
I MRD] . You will find t hat t hese books are pret t y dat a- focused, but t hey are nevert heless highly
int er est ing.
Let 's t ry t o get st art ed from anot her angle. Let 's define som e principles and t hen get our hands dirt y.
Principles for Rules and Their Usage
I t hink t he word principle is very good because it 's not st rict . I t 's m uch easier t o com e up wit h
principles t han cat egories, probably because of t he built - in vagueness. St ill, principles are descript ive
regarding int ent ion. That 's exact ly what I need here and now.
And if you fail t o check in advance, t here is no m ercy, but you will learn ( react ively) t hat t here were
problem s via an except ion.
All is a " big" word, but we will t ry t o at least com e close. We should t ry t o avoid reaching t hose st at es
t hat won't be persist able.
I t 's also im port ant t o t hink about what error m eans here. An order m ight be considered t o be in error
if it 's t oo large. But unt il t he user t ries t o subm it t he order it 's not really an error, j ust a sit uat ion he
needs t o deal wit h before subm it t ing. And he should be able t o save t hat order before he subm it s it
so he can cont inue working on it lat er on, t o solve t he problem and subm it it t hen.
The product ivit y for consum ing rules will be addressed by m aking it possible t o fet ch m et adat a t o be
used for set t ing up t he UI . That will cut t he t im es you find problem s when you check because t he UI
has helped so t hat som e problem s j ust won't happen. ( Just wat ch out so you don't t rust t he UI t o be
all t hat is needed regarding rules checking.)
The product ivit y goal for defining rules m ight be reached wit h a sm all fram ework t hat let s you focus
on t he int erest ing part s of t he rules, and t he boilerplat e code will be dealt wit h for you.
I t hink t hat t he configurat ion aspect is part icularly useful when you build product s t hat will be used
by m any different cust om ers. I f you are building a syst em for a single cust om er, it 's probably of less
value.
I t hink t his principle helps anot her principle t hat could be called " Rules should be consist ent ." When
t he codebase reaches a cert ain size, t here is a risk t hat t he rules m ay int erfere or even cont radict
each ot her. Having t he rules t oget her and t oget her wit h t he st at e should help t o som e degree wit h
m anaging t he rulebase.
I n realit y, adding rules also creat es problem s wit h t est ing. You need t o set up inst ances t o correct
st at es. You can writ e t est helpers ( such as privat e m et hods in t he t est fixt ure) for dealing wit h t hat ,
but it 's st ill a hindrance.
The System Should Stop You from Getting into a Bad State
A good way of sim plifying how t o work wit h rules is t o avoid t he need for t hem when possible. One
way of doing t hat is, for exam ple, t o work wit h creat ion m et hods t hat will set up t he Dom ain Model
obj ect s in a valid st at e t hat can never be m ade invalid.
Starting to Create an API
We'll com e back t o t hese principles and evaluat e how we fulfilled t hem lat er in t he chapt er, but now
it 's t im e t o com e back down t o Eart h and t ake up som e of t he problem s out lined in Chapt er 4. I 'm
going t o st art wit h t he ext ernal API and see where we end up. I believe t hat will give a good,
pragm at ic feeling about t he whole t hing.
So t o rem ind you, t he problem s or request s out lined in Chapt er 4 were t he following:
1 . List cust om ers by applying a flexible and com plex filt er.
7 . Each order and cust om er should have a unique and user- friendly num ber.
8 . Before a new cust om er is considered OK, his or her credit will be checked wit h a credit inst it ut e.
9 . An order m ust have a cust om er; an order line m ust have an order.
Let 's t ake one of t he problem s; say, problem 6, " An order m ay not have a t ot al value of m ore t han
one m illion SEK."
How shall we approach t his problem ? There are several opt ions t o choose from .
You could creat e som et hing like a sim ple rule- checking engine where you can send your inst ances t o
be validat ed, or you could let t he inst ances t ake responsibilit y for t hat t hem selves. I like t he idea of
let t ing t he inst ances t ake responsibilit y for t hem selves as m uch as possible ( or at least as far as is
appropriat e) and t herefore prefer t he lat t er. Perhaps t his is a bit naïve, but also very sim ple in a
posit ive way.
[Test]
public void CantExceedMaxAmountForOrder()
{
Order o = new Order(new Customer());
Assert.IsFalse(o.IsValid);
}
What we did was t o add a propert y t o t he Order called IsValid. A pret t y com m on approach I t hink.
There are also som e obvious problem s, such as t he following:
What was t he problem ? We only know t hat t here was one, not what it was.
All we did was t o check if everyt hing was OK or not . We will com e back t o t he m ent ioned problem s,
but we have som et hing m ore basic t o deal wit h first . A m ore im port ant problem is t his quest ion:
I t hink t he reason for t he com m on approach of IsValid as som e kind of general, cat ch- all t est m ight
be because of t oo m uch focus on persist ence. I f we decouple persist ence from rules a bit and t ry t o
adhere t o t he principle of let t ing all st at es be savable, we m ight end up wit h anot her approach.
Then I t hink t he t ransit ions will be t he int erest ing t hing regarding rules. For exam ple, when an order
is in t he st at e of NewOrder, m ore or less everyt hing m ight be allowed. But when t he order should
t ransit ion t o t he Ordered st at e, t hat will only be allowed if cert ain rules are fulfilled.
So saving an order t hat is in t he st at e of NewOrder should be possible even if t he order isn't valid for
ent er Ordered st at e. Approaching rules t his way will focus rules on t he m odel m eaning and not let a
t echnicalit y, such as persist ed or not , affect t he m odel.
That said, t here is a realit y full of pract ical problem s, and we need t o deal wit h t hat well. So even if
we have t he int ent ion of focusing on t he m odel, we have t o be good cit izens regarding t he
infrast ruct ure also. Let 's see if t hinking about persist ed or not as a special st at e helps, but first I
t hink it 's im port ant t o discuss what could give us problem s regarding rules if we don't t hink enough
about t he infrast ruct ure.
Database Constraints
Even t hough you m ight choose t o focus on put t ing all your rules in t he Dom ain Model, you will st ill
probably end up wit h som e rules in t he dat abase. A t ypical reason for t his is efficiency. Som e rules
are m ost efficient ly checked in t he dat abase; t hat 's j ust how it is. You can probably design around
m ost of t hem , but t here will probably st ill be a couple of sit uat ions where t his is a fact of life.
Anot her reason is t hat you m ight not be able t o design a new dat abase, or you m ight not be able t o
design t he dat abase exact ly as you would like it , but you have t o adj ust t o a current dat abase
design. Yet anot her reason is t hat it 's oft en considered a good t hing t hat t he dat abase can t ake care
of it self, especially if several different syst em s are using t he sam e dat abase.
The im pedance m ism at ch bet ween obj ect - orient at ion and Relat ional dat abases t hat we discussed in
Chapt er 1, " Values t o Value," will also show up here. For exam ple, t he st rings in t he dat abase will
m ost likely have st at ic m ax lengt hs, such as VARCHAR(50). That a cert ain st ring isn't allowed t o be
longer t han t hat is kind of a generic rule, but it 's m ost ly relat ed t o persist ence. The t ransit ion t o
Persist ed st at e won't be allowed if t he st ring is t oo long.
So it 's probable t hat you will have t o deal wit h rules whose invalidit y won't be det ect ed unt il t he st at e
is persist ed t o t he dat abase. That in it s t urn represent s a couple of problem s.
First , parsing error inform at ion is t roublesom e, especially when you consider t hat a t ypical O/ R
Mapping solut ion oft en t ries t o be port able bet ween different dat abases. Or rat her, t he heart of t he
problem is t hat t he O/ R Mapper probably won't be able t o do t he m apping for you when it com es t o
errors and t ell you what field( s) caused t he problem in t he Dom ain Model; for exam ple, when t here's
a duplicat e key error.
Furt herm ore, t he error will com e at an inconvenient point in t im e. Your Dom ain Model has already
been changed, and it will probably be very hard for you t o recover from t he problem wit hout st art ing
all over again. I n fact , t he general rule is oft en t hat you should st art over inst ead of t rying t o do
som et hing sm art .
St ill, we do like t he idea of m aking it possible t o save our inst ances at any t im e. ( I n any case, we
have set up som e preferences even if we can't follow t hem t o 100% . The ext rem e is oft en ext rem ely
cost ly .)
As I see it , t ry t o design for as m uch proact ivit y as possible ( or as appropriat e) so t hat t he num ber of
except ions from t he dat abase will be ext rem ely few. For t hose t hat are st ill possible, be prepared t o
deal wit h t hem one by one in code, or be prepared t o roll back t he t ransact ion, t oss out t he Dom ain
Model changes, and st art all over again. A bit drast ic, but t hat 's t he way I see it . The key t o all t his is
design, so you m ake t he problem as sm all as possible.
OK, t hat was t he purely t echnical side of it ( t hat t he dat abase m ight show it s discom fort wit h us) . But
it 's not j ust a m at t er of t hat t he rules are infrast ruct ure- relat ed only or dom ain- relat ed only. There
are connect ions.
That principle is t he ideal. I n realit y, it will be hard not t o break cert ain rules during a m ult iple st ep
act ion. For exam ple, should you disallow t he change of t he nam e of a cust om er t o a nam e t hat t he
rule t hinks is t oo short ? Well, perhaps, but it m ight j ust prevent t he user from doing what he want s
t o do: nam ely delet ing t he old nam e and insert ing a new one inst ead.
I t 's possible t o deal wit h t his by having a m et hod called Rename(string newName) t hat t akes care of
t he work. During t he execut ion of t he m et hod, t he st at e of t he obj ect isn't correct , but we only
consider it a problem before and aft er t he m et hod execut ion.
N ot e
This is in line wit h invariant s according t o Design by Cont ract [ Meyer OOSC] . Such
invariant s are like assert ions t hat t he inst ance should abide by at all t im es, bot h before t he
m et hod execut ion and aft er. The only except ion is during t he m et hod execut ion.
Anot her approach is t o sim ply not set t he propert y unt il you've finished wit h t he change. Let 's see if I
can com e up wit h anot her exam ple. Assum e t hat t here are t wo fields, and eit her bot h field have t o
be set or neit her of t hem . Again, a m et hod would solve t he problem , but if you scale up t his problem
or consider t hat t he UI would prefer t o have t he propert ies exposed wit h set t ers, it 's clear t hat it 's
hard not t o get int o an inconsist ent st at e t here from t im e t o t im e.
Anot her quest ion m ight be if we should t rust t hat we didn't reach an invalid st at e? And if we against
all odds did reach an invalid st at e ( a really invalid one, such as an erroneous change when t he st at e
of t he order is Ordered) , should we allow t hat t o be st ored?
I t m ight be t hat t he dat abase won't allow us t o have t hat prot ect ion for som e error sit uat ions. But
even if you t ry hard t o let t he dat abase t ake care of it self regarding rules, you will probably let som e
t hings slip t hrough, and if you have m oved t o Dom ain Model- focused way of building applicat ions,
your dat abase is probably not as rigid when it com es t o self- prot ect ion. Aft er all, dom ain- focused
rules t hat are som ewhat advanced are m ost oft en m uch easier t o express in t he Dom ain Model t han
in a Relat ional dat abase, and you also want t o have t hem in t he Dom ain Model.
The quest ion is: can we t rust t he " environm ent " ? I m ean, can we t rust t hat we won't persist a st at e
t hat shouldn't be possible t o reach? For exam ple, can we expect t hat we don't have any bugs? Can
we expect t hat t he consum er isn't creat ive and won't use reflect ion for set t ing som e fields t o excit ing
values?
Assum e again an order t hat can be in t wo st at es, NewOrder and Ordered. We have only one dom ain-
relat ed t ransit ion rule: t he order m ay not be t oo large t o ent er Ordered. That gives us t he valid
com binat ions in Table 7- 1.
Ta ble 7 - 1 . Va lid
Com bin a t ion s of Or de r
St a t e s a n d Ru le
Ou t com e s
Or de r St a t e s Ru le
Ou t com e s
New Order Not t oo large
New Order Too large
Ordered Not t oo large
So far, it feels bot h sim ple and exact ly what we want . Let 's add t he dim ension of persist ed or not , as
shown in Table 7- 2.
Or de r St a t e s Ru le Pe r sist e d or
Ou t com e s N ot
New Order Not t oo large Not persist ed
New Order Not t oo large Persist ed
New Order Too large Not persist ed
New Order Too large Persist ed
Ordered Not t oo large Not persist ed
Ordered Not t oo large Persist ed
First , I 'd like t o point out t hat we expect t hat t he t ransit ions t o Ordered com bined wit h Too large will
not be possible.
Even m ore im port ant , if for som e reason it does happen, it 's an exam ple of a st at e t hat is in real
except ional error and t hat should not be savable.
N ot e
Your m ileage m ight vary regarding if you will check t he dom ain- relat ed t ransit ion rules at
persist t im e as well or not . I t m ight be considered a bit ext rem e in m any cases.
Requirements for a Basic Rules API Related to
Persistence
Now t hat we have decided on a specific cont ext for now, t hat of t he t ransit ion t o t he st at e of
persist ed, let 's st art t he discussion about an API regarding t hat . We will get back t o ot her ( and from
t he m odel's point of view, m ore int erest ing) st at e t ransit ion problem s, bot h general and specific,
aft erward.
N ot e
As usual, t he discussion here is really m ore about som e generic ideas t han t he API it self.
I 'm not t rying t o t ell you how you should creat e your int er- faces/ API s, I 'm j ust t rying t o
give m y t hought s on t he subj ect and hope t hat you m ay be prom pt ed t o find your own
solut ions.
I 'd like t o t ake a new code exam ple where we apply t he idea about being proact ive regarding not
persist ing except ional st at e errors and/ or problem s t hat will t hrow except ions from t he persist ence
engine.
I 'm going for t he lat t er: showing a sit uat ion when t he persist ence engine would t hrow an except ion.
( Again, t he form er problem should be hard t o get t o. I f everyt hing works as expect ed, t hat st at e
shouldn't be possible t o reach.)
Assum e t hat Order has Note, and Note is defined as VARCHAR(30) in t he dat abase. Depending on your
solut ion for persist ence, you m ight get an except ion when t rying t o save a long st ring, or you will
lose inform at ion silent ly. The im port ant t hing here is t hat I will proact ively cat ch t he problem . I t
could look like t his:
[Test]
public void CantExceedStringLengthWhenPersisting()
{
Order o = new Order(new Customer());
o.Note = "0123456789012345678901234567890";
Assert.IsFalse(o.IsValidRegardingPersistence);
}
Let 's set up a sim ple int erface for t he purpose of let t ing t he consum er ask an Aggregat e root if it 's in
a valid st at e or not for being persist ed. I t could look like t his:
public interface IValidatableRegardingPersistence
{
bool IsValidRegardingPersistence {get;}
}
So you let your classes t hat have persist ence- relat ed rules im plem ent t hat int erface. Norm ally t he
consum er only has t o ask t he Aggregat e [ Evans DDD] root if it 's valid or not t o be persist ed and t he
Aggregat e root will check it s children.
As you saw in t he code snippet , I chose t o let t he Dom ain Model classes t hem selves be
responsible for checking rules; considering how we like t o deal wit h persist ence ( from
t he " out side" ) , t hat m ight feel st range.
This m ight be som et hing t o t hink about , but for now I 'll st ick t o m y first idea here, part ly
because I t hink t he rules are at t he heart of t he Dom ain Model. The rules are not " j ust "
an infrast ruct ural aspect , as persist ence is.
What was t he problem ? We only know t hat t here was one, not what it was.
Let 's discuss t hose t hree problem s in t he cont ext of t he persist ence- relat ed rules.
Let 's add t o t he int erface for dealing wit h t his. I t could look like t his:
N ot e
As I see it , t he list of broken rules is an im plem ent at ion of t he Not ificat ion pat t ern [ Fowler
PoEAA2] .
One im port ant t hing m ent ioned wit h t hat pat t ern is t hat it 's not only errors t hat we need t o
be inform ed about , but warnings/ inform at ion as well. Anot her t hought t hat springs t o m ind
is t hat t he broken rules list I have t alked about is pret t y focused on Aggregat es, but we
can, of course, aggregat e ( pun not int ended) several such list s int o a single one in an
Applicat ion layer [ Evans DDD] , such as from several Aggregat e root inst ances.
Unfort unat ely, in t his case, t he t oo- long Note won't be possible t o save. That t ransit ion bet ween not
persist ed and persist ed, on t he ot her hand, is int erest ing here. But it won't be allowed. ( As I said, I
will get an except ion or t he st ring will be t runcat ed silent ly.)
The t ransit ion t o persist ed is a bit " special." We will get back t o t he problem of allowing incorrect
t ransit ions in t he cont ext of dom ain- relat ed rules short ly.
Again, t he consum er isn't following t he prot ocol, and t hat 's an except ional sit uat ion.
We got caught up in a specific t ransit ion problem : t ransit ion t o persist ed. I t 's t im e t o change focus
from infrast ruct ure- relat ed t ransit ions t o dom ain- relat ed for a while, but we will t ry t o m ove som e of
t he ideas wit h us, such as t hat it 's an except ion if t he consum er does not follow t he prot ocol.
Focus on Domain-Related Rules
Let 's work wit h t he rem aining feat ure requirem ent s from Chapt er 4, one by one. We st art ed out wit h
t he feat ure requirem ent num ber 6, which was called " An order m ay not have a t ot al value of m ore
t han one m illion SEK," but we got int errupt ed when we realized t hat t he cont ext was m issing from
t he sket ched API . Let 's see if we can t ransform t he t est a bit . I t looked like t his before:
[Test]
public void CantExceedMaxAmountForOrder()
{
Order o = new Order(new Customer());
OrderLine ol;
Assert.IsFalse(o.IsValid);
}
As you know by now, I t hink t here are several problem s wit h t his snippet . To follow t he ideas
discussed so far, we could add a t ransit ion m et hod t o Ordered st at e; for exam ple, t he m et hod could
be called OrderNow(). But I would st ill not be happy wit h t hat , because OrderNow() would m ost
probably t hrow an except ion before we get a chance t o check.
Again, I 'd like t o leave t he focus of what is persist ed and what is not for now. The int erest ing part
here is t hat when we t ry t o t ransit ion t o Ordered, we can't do t hat . Let 's reflect t hat wit h som e
changes t o t he t est .
[Test]
public void CantGoToOrderedStateWithExceededMaxAmount()
{
Order o = new Order(new Customer());
try
{
o.OrderNow();
Assert.Fail();
}
catch (ApplicationException ex) {}
}
I t 's im port ant t o consider whet her when we are in t he Ordered st at e if we will t hen check in
AddOrderLine() so t hat we aren't going t o break t he rule. I could let AddOrderLine() t ransit ion t he
order back t o NewOrder , if AddOrderLine() would be allowed at all. That avoids t he problem .
Anot her problem is t hat if one of t he OrderLines is changed when we are in Ordered, t hat m ight
break t he rule. A t ypical solut ion in t his case would be t o work wit h im m ut able OrderLines inst ead so
t hat t hey can't be changed. Let 's change t he t est t o reflect t hat .
[Test]
public void CantGoToOrderedStateWithExceededMaxAmount()
{
Order o = new Order(new Customer());
try
{
o.OrderNow();
Assert.Fail();
}
catch (ApplicationException ex) {}
}
N ot e
I could use t he ExpectedException at t ribut e of NUnit inst ead of t he TRy catch and
Assert.Fail() const ruct ion. That would m ake t he t est short er. The only advant age of t he
used const ruct ion is t hat I will check t hat t he expect ed except ion happens at t he
OrderNow() call, and t hat is act ually m ost oft en a sm all advant age.
When an OrderLine has been added, it can't be changed any longer, and for t his sim ple exam ple, t he
rule only has t o be checked in t he OrderNow() and AddOrderLine() m et hods now.
[Test]
public void CanHaveCustomerDependentMaxDebt()
{
Customer c = new Customer();
c.MaxAmountOfDebt = 10;
However, t hat will probably not work at all. Why not ? Well, t he order needs t o be able t o find t he
ot her orders of a cert ain st at e for t he cust om er at hand and what t ypically solves t hat is t he
OrderRepository.
N ot e
As you m ight recall, I chose t o go for a unidirect ional relat ionship bet ween Order and
Customer classes. That 's why I ask t he OrderRepository for help ( as one of several possible
st rat egies for sim ulat ing bidirect ionalit y) for going from Customer t o it s Orders.
We could deal wit h t hat by inj ect ing _orderRepository t o t he order in t he const ruct or like t his:
But was t his a good solut ion? As usual, t hat depends on t he part icular applicat ion. Let t ing t he Order
check t he current debt for t he Customer when it 's t im e for OrderNow() m ight be a bit lat e regarding
t he usabilit y aspect for t he user. Perhaps a bet t er solut ion would be t o ask what t he m axim um
am ount of a new order can be before creat ing t he order. Then t he user creat es t he new order, and
t he user can get feedback in t he UI when t he lim it is reached. This doesn't change t he API we j ust
saw, but it is m ore of a convenience.
Anot her problem wit h t he solut ion shown in t he code snippet is t hat t he _orderRepository is inj ect ed
in t he order inst ance. I f you reconst it ut e an order from persist ence and you do t hat by using an O/ R
Mapper, you're not in charge of t he creat ion of t he order inst ance. You could inj ect t he
_orderRepository in t he Reposit ory during reconst it ut ion, t hough, but it feels a lit t le bit like a hack
( consider, for exam ple, when you read a list of orders and t hen you have t o inj ect t he Reposit ory int o
each inst ance of t he list ) . Aft er having t hought about it , let 's t ry t o keep t he responsibilit y in t he
order for checking it self, but provide t he Reposit ory via a set t er inst ead or at t he t im e of t he check as
a param et er t o t he OrderNow() m et hod ( but t hat st rat egy has a t endency of not scaling well) .
N ot e
I t hink t his discussion point s out a weakness in at least som e OR Mappers: t hat you don't
cont rol t he inst ance creat ion during reconst it ut ion as m uch as you would like, especially
considering t he growing popularit y of Dependency I nj ect ion fram eworks, as we will discuss
in Chapt er 10, " Design Techniques t o Em brace."
I t hink t hat code is a no- no! A bet t er solut ion would be t o expose a m et hod on t he OrderRepository
wit h a m et hod called som et hing like CurrentDebtForCustomer(), t aking a Customer inst ance as
param et er.
N ot e
Wit h Reposit ory int erface design, it 's oft en a good idea t o provide overloads, such as
X(Customer) and X(Guid). I t is annoying having t o inst ant iat e a Customer j ust t o be able t o
call t he m et hod if you hold on t o t he I D of t he Customer .
I know what t he dat abase guys are t hinking right now. " What about real- t im e consist ency? Will t he
Reposit ory m et hod execut e wit h t he t ransact ion isolat ion level of serializable in an explicit t ransact ion
during save at least ?" Well, it is possible, but t here are problem s.
One problem is t hat t he O/ R Mapper you are using ( if we assum e for t he m om ent t hat an O/ R
Mapper is being usedm ore about t hat in lat er chapt ers) m ight not allow you t o t ake det ailed cont rol
of t he persist process regarding validat ion, locking, and so on. Anot her problem is t hat t he nat ure of
t he persist process m eans it m ight t ake som e t im e if you have lot s of dirt y inst ances t o be persist ed,
so t he lock t im e for all orders for t he cust om er m ight be pret t y long.
I t hink t hat in t his case it 's usually OK not t o expect real- t im e consist ency here, only som et hing
pret t y close t o real- t im e consist ency. I m ean, check t he sum of t he ot her orders j ust before saving
t his order, but do not span t he read wit h a high isolat ion level or not even do t he check wit hin t he
sam e t ransact ion.
I t hink t hat goes pret t y m uch hand in hand wit h what Evans says regarding Aggregat es [ Evans
DDD] . He says som et hing like st rive for real- t im e consist ency wit hin an Aggregat e, but not bet ween
Aggregat es. Consist ency problem s bet ween Aggregat es can be dealt wit h a lit t le lat er.
So if you find t he approach accept able ( again, we are t alking about a pret t y low risk here, for a
t ypical syst em at least ) , but you would like t o det ect t he problem , you could creat e som e bat ch
program t hat kicks in every now and t hen and checks for problem s like t his and report s back. Or why
not put a request on a queue at persist t im e t hat checks for problem s like t his regarding t he
part icular cust om er? I t 's such an unlikely problem , so why should any user have t o wait
synchronously for it t o be checked?
The fact t hat I t hink t he m et hod is at om ic signals t hat we should use a Service [ Evans DDD] inst ead
t o m ake t he whole t hing m ore explicit . The Service could check t he current debt and t herefore be
used proact ively by t he Order at good places in t im e. I t could also be used pret t y m uch react ively at
save t im e, and som e sort of request could be put on a queue and be used react ively aft er save. The
Service would probably use t he sam e Reposit ory m et hod as was j ust discussed, but t hat 's not
anyt hing t he caller needs t o know, of course.
What should it do react ively aft er t he save? Perhaps m ove t he order t o one of t wo st at es so t hat
when t he user st ores an order, it goes int o st at e NewOrder. Then t he Service kicks in and m oves t he
order t o st at e Accept ed or Denied, as shown in Figure 7- 1 .
Figu r e 7 - 1 . St a t e gr a ph
Aft er all t his ram bling I t hink we have t hree decent solut ions t o t he problem : one wit h pret t y t ight
coupling ( everyt hing being done in real t im e, possibly wit h high t ransact ion isolat ion level) , one wit h
less coupling ( but t hat is perhaps a bit m ore com plex because t here are m ore " m oving part s" ) , and
finally one where we don't do anyt hing ext ra beyond what was shown in t he t est ( but wit h a sm all
risk of inconsist ency t hat we will have t o t rack delayed) . Would one of t hese suit you?
OK, we t ouched upon using a Service for helping us out wit h a cost ly processing problem . Services in
t he Dom ain Model oft en arise from anot her necessit y as well.
Service-Serviced Validation
Com plet ely by coincidence, we do need such a rule t hat is by it s very nat ure service- based. I 'm
t hinking about feat ure 8, " Before a new cust om er is considered OK, his or her credit will be checked
wit h a credit inst it ut e."
We could very well call t hat credit inst it ut e service in t he Grant() m et hod, or we could use a solut ion
sim ilar t o t he one I j ust sket ched, let t ing our Service kick in aft er persist , t aking care of bot h calling
t he ext ernal service and m oving t he cust om er t o one of t wo st at es. One problem wit h t his approach
is t hat I 'm binding dom ain rules a bit t oo m uch t o persist ence.
Anot her big problem wit h t his approach of m oving som e funct ionalit y out of t he sandbox of t he
current Unit of Work/ I dent it y Map is t hat what you m ight have in your local cache will be out of sync
wit h t he dat abase because processing t akes place in t he aut onom ous Service. Of course, t hat 's t he
risk you always have wit h caching, if t he cache could be bypassed.
I f you know t hat t he cache will be invalidat ed because of an explicit Service call in real t im e, it 's
pret t y easy. Just kill t he cache. I t m ight be expensive t o recreat e it , t hough, or perhaps you even
know exact ly what needs t o be refreshed. On t he ot her hand, if you don't know when t he operat ion
t hat invalidat es t he cache will happen, you have t o t ake ext ra care and refresh t he cache as oft en as
possible. As I see it , all t his hint s at being aggressive wit h your cache m anagem ent and not let t ing
t he cache get t oo big and live for a long t im e, at least not for t he dat a t hat changes quit e frequent ly.
N ot e
When I t alk about cache here, I 'm m ost ly t hinking about t he I dent it y Map [ Fowler PoEAA] .
N ot e
Did you not ice how it all cam e t oget her? I t alked about OrderNow() before, and t hat m ight
have seem ed t o be kind of a t echnical solut ion t o t he problem of " always savable," but it
was core t o t he requirem ent s. And according t o t he requirem ent s, Accept() m ight m ake
m ore sense.
OK, " ridiculous" is t oo st rong a word, but if we assum e t hat t he rules for checking are j ust a couple of
sim ple const raint s wit hout t he cross Aggregat e border problem s, I would prefer t o apply t he principle
discussed earlier: t hat is, let t ing t he user m ake a proact ive check, and if t he result is posit ive, t he
st at e- changing m et hod will execut e successfully. A pict ure, I m ean code, says m ore t han a t housand
words:
[Test]
public void CanMakeStateTransitionSafely()
{
Order o = new Order(new Customer());
Assert.IsTrue(o.IsOKToAccept);
Checking t he IsOKToAccept propert y is opt ional, but not doing it and t hen calling Accept() at a t im e
when we shouldn't is except ional, and we will get an except ion. Except ions are for except ional
problem s; for " expect ed problem s" bool is fine.
We oft en don't j ust wonder if it will be OK or not , but we also want t o get a list of reasons why it 's
not OK. I n t hese cases, t he proact ive m et hod could ret urn a list of broken rules inst ead, som et hing
like t his:
[Test]
public void CanMakeStateTransitionSafely()
{
Order o = new Order(new Customer());
Assert.AreEqual(0, o.BrokenRulesIfAccept.Count);
//We can now safely do this without getting an exception...
o.Accept();
}
I prefer t o do t his on a case- by- case basis. There is no st andard int erface or anyt hing t o im plem ent ,
j ust a principle for int erface design. So t his is act ually j ust a prot ocol for m aking it possible t o be
proact ive regarding broken rules det ect ion.
The t ransact ion abst ract ion is a powerful one, and one t hat is underut ilized. An
alt ernat ive solut ion t o t he t ransit ion problem would be t o use t he t ransact ion abst ract ion
for t he Dom ain Model and validat ions as well. Then during t he t ransact ion, it wouldn't
m at t er if t he st at e wasn't correct ; only before and aft er would m at t er. For exam ple, t he
API could t hen look like t his:
//Some consumer...
DMTransaction dMTx = Something.StartTransaction();
c.Name = string.Empty;
c.Name = "Volvo";
dMTx.Commit();
I n t he code snippet , t he rules weren't checked unt il Commit() . As you underst and, t his
opens up a can of worm s t hat needs t o be dealt wit h, but it m ight be an int erest ing
solut ion for t he fut ure.
The solut ion becom es even m ore int erest ing if you consider t he new System.Transaction
nam espace of .NET 2.0. I n t he fut ure, we m ight get t ransact ional list classes, hash
t ables, and so on. I t get s even m ore int erest ing considering t ransact ions spanning bot h
t he Dom ain Model and t he dat abase. Again, loads of problem s, but int erest ing.
Obviously t here are lot s of variat ions t o t he problem of st at e t ransit ions. One such problem is
deciding when an act ion should be t aken as well. St ay t uned.
Business ID
The exam ple of a st at e t ransit ion t hat is paired wit h an act ion is feat ure 7 on t he feat ure list , " Each
order and cust om er should have a unique and user- friendly num ber."
A spont aneous solut ion t o t he problem is let t ing t he dat abase t ake care of t he problem wit h a built - in
m echanism , such as I DENTI TY does for MS SQL Server. But t here are problem s wit h t his approach.
First of all, you will have processing out side of your Dom ain Model, which com es at a cost . You will
need t o force a refresh of t he affect ed inst ance, which is not t oo hard but is som et hing t o keep t rack
of and m ight get a bit com plex.
Anot her problem is t hat t he value m ight com e t oo early, long before t he user has decided t o m ove on
wit h t he Order, when he st ill j ust considers it t o be in " perhaps" st at e. ( Obviously, t here are solut ions
t o t hat as well.)
Yet anot her problem is t hat O/ R Mappers will oft en cause you problem s if you also use t he IDENTITY
as a prim ary key. The sem ant ics for using a Guid as t he prim ary key, which requires less coupling t o
t he dat abase, are oft en a bit different .
N ot e
I n no way am I saying t hat you m ust use t he I DENTI TY ( as t he aut o increasing propert y is
called in SQL Server) colum n as a prim ary key j ust because you have such a colum n. You
can let it be an alt ernat e key only, but you m ight get t em pt ed from t im e t o t im e.
So what are t he alt ernat ives? There are several of t hem . Probably t he easiest and m ost direct one is
t o let t he Reposit ory have a m et hod for grabbing t he next free Id in som e way. I t could look
som et hing like t his ( assum ing t hat an Order shouldn't get an OrderNumber unt il it 's accept ed) :
//Order
public void Accept()
{
if (_status != OrderStatus.NewOrder)
throw new ApplicationException
("You can only call Accept() for NewOrder orders.");
_status = OrderStatus.Accepted;
_orderNumber = _orderRepository.GetNextOrderNumber();
}
N ot e
I nst ead of ApplicationException ( or a subclass) , it m ight be a good idea t o use
InvalidOperationException or a derivat ive.
Yet t his opens up a whole can of worm s, at least in syst em s t hat are som ewhat st ressed from t im e t o
t im e or if t he OrderNumber series is not allowed t o have holes in it . I t m eans t hat t he
GetNextOrderNumber() won't writ e changes t o t he dat abase, or at least it will not com m it t hem . This
m eans t hat you need an expensive lock wrapping t he Accept() call and t he following persist m et hod.
Yet anot her approach is t o use what will probably be t he next value and t hen be prepared for
duplicat es if som eone else already has used it .
I f you are prepared t o cat ch except ions during t he persist m et hod because of duplicat e key, what do
you do t hen? Well, you could call Accept() again, but t hen Accept() will t hrow an except ion t he way
it is current ly writ t en.
Perhaps it 's bet t er t o j ust ask for a new OrderNumber in t he code t rying t o recover from t he duplicat e
key except ion. That in it s t urn creat es anot her set of problem s, such as t alking t o t he dat abase
during t he persist m et hod or det ect ing which inst ance has t he problem in t he first place ( and for
which colum n if t here are several candidat e keys for t he inst ance) .
All t hese problem s can be avoided if you accept holes in t he num ber series and if t he m et hod for
grabbing t he next num ber also com m it s t he current m ax in a way sim ilar t o how I DENTI TY works in
SQL Server. I m ean, I DENTI TY allows holes, and it will wast e a value if you do a ROLLBACK.
To m ake it even clearer t hat t he GetNextOrderNumber() act ually m akes inst ant changes t o t he
dat abase and doesn't wait for t he next call t o t he persist m et hod, I t hink we should use a Service
inst ead. My Reposit ories don't m ake decisions for t hem selves when doing a com m it and such, but
Services do because Services should be aut onom ous and at om ic.
So wit h t hese changes in place, t he Accept() m et hod could now look like t his ( assum ing t hat an
IOrderNumberService has been inj ect ed t o _orderNumberService in t he order before t he call) :
//Order
public void Accept()
{
if (_status != OrderStatus.NewOrder)
throw new ApplicationException
("You can only call Accept() for NewOrder orders");
_status = OrderStatus.Accepted;
_orderNumber = _orderNumberService.GetNextOrderNumber();
}
Now t he risk of problem s during t he persist m et hod is reduced so m uch t hat it 's except ional if one
arises.
You'd be right if you t hink I avoided t he problem by accept ing holes in series ( which was act ually
even st at ed as OK wit h t he defined requirem ent s) , but som et im es t hat j ust isn't possible. I st rongly
dislike such series, but t here are st ill sit uat ions where you can't avoid t hem . Then what ? Well, I
guess I would go back t o square one. I f t hat wasn't enough, I would probably t urn t he whole
t ransit ion m et hod int o a Service inst ead, m oving t he order t o Accept ed st at us and set t ing an
ordernumber. This is not as pure or clean as doing t he work in t he Dom ain Model, but when realit y
calls, we should respond.
OK, so far we have discussed quit e a lot of different problem s t hat we have t o deal wit h when it
com es t o rules in t he Dom ain Model. There is one m ore t o look at before we m ove on.
Avoiding Problems
Feat ure 9, " An order m ust have a cust om er; an order line m ust have an order," is a great exam ple of
a rule t hat I 'd like t o not have as a rule at all if possible, but I 'd rat her force it in t he const ruct or
inst ead. Then t here's no need t o check for it .
Clean, sim ple, efficient . Just good. I know, I know, t his set s your alarm bells ringing. Of course t here
are problem s, t oo.
For exam ple, it 's possible t hat you'd like t o have an inst ance of an order wit hout first having t o
decide on t he cust om er because of t he UI design.
N ot e
This can be dealt wit h in t he UI , of course, in several different ways. St ill, it m ight not feel
good t o creat e a " problem " if we don't have t o.
Anot her problem is t hat t he creat ion code m ight get so com plex t hat it can t hrow except ions it self,
and t hen we are back int o t he problem s again wit h how t o expose broken rules, and so on. We also
said t hat except ions should be except ional, so it j ust doesn't feel right t o t oss except ions in t he
creat ion code for saying t hat t here was a broken rule.
There is one t hing t hat eases t he burden som ewhat . We could let t he feat ure request t alk about
persist ent inst ances and not t ransient inst ances. I 'm t hinking about OrderLine, for exam ple. I n m y
current design, OrderLine isn't an Aggregat e on it s own, but is one part of t he Order Aggregat e
inst ead. Therefore, t he only way t o m ake an OrderLine persist ent is t o associat e it t o an Order wit h
AddOrderLine(). Unt il t hen, I probably don't care t hat t he OrderLine doesn't have an Order. The
OrderLine can't be st ored, and t he persist m et hod won't t hrow an except ion eit her because of an
or phan OrderLine ( because t he persist m et hod won't know about it at all) .
Sure, it m ight be t he case t hat som e processing in t he OrderLine requires knowledge of t he Order,
but if not , I t hink t his is a fine solut ion.
N ot e
And right now I t hink it 's arguable whet her t he OrderLine needs t he knowledge of it s Order
at all. We can probably m ost oft en avoid t hat bidirect ionalit y t hat we will have ot herwise.
I don't know if you've not iced it , but I com e back t o one of t he DDD- pat t erns, t he Aggregat e, over
and over again. I 'd like t o t ake a break and t alk about t hat before m oving on.
I briefly t alked about rules aggregat ion earlier in t his chapt er, but let 's reit erat e and delve a lit t le bit
deeper.
When t he consum er of an Aggregat e root asks for broken rules regarding persist able or not , he
should receive broken rules from t he com plet e Aggregat e and not only t he root inst ance.
Also, t his way t he Aggregat e root has t o decide if t he ordinary rules of t he children should be used or
not . Cont ext is king.
I 'd like t o end t his short sect ion about Aggregat es wit h j ust a few words about feat ure 4.
Concurrency conflict det ect ion is im port ant . That feat ure could be t hought about as a kind of
business rule, but I 'd like t o t hink about it as a t echnical problem m ore t han a business problem . I t 's
also t he case t hat m ost O/ R Mappers have at least som e support for concurrency conflict det ect ion,
but I 'll leave t alking about t hat here and post pone it unt il Chapt er 8, " I nfrast ruct ure for Persist ence,"
and Chapt er 9, " Put t ing NHibernat e int o Act ion."
Let 's change focus a lit t le bit . Before we get int o discussing t he im plem ent at ion of t he API , let 's first
see if we should add anyt hing m ore.
Extending the API
We have t alked about t he rule API regarding persist ence- relat ed rules and how t o get inform at ion
about problem s wit h t hose. What m ore do we need of t he API ?
Well, depending on t he applicat ion we are building, we m ight really need loads of ot her rules- relat ed
t hings. I nspired by t he principles I st art ed t he chapt er wit h, one t hing t hat springs t o m ind is how
nice it would be t o be able t o check for rules very proact ively, especially when in t he UI . Anot her
im port ant t hing is t o be able t o add cust om ized rules, not only at com pile t im e but also at
deploym ent t im e. Let 's st art wit h a look at consum ing t he rules in t he UI .
The approach I 'm going t o use here is t o let t he classes expose m et adat a t hat can be used by t he UI
if it want s t o.
A sim ilar approach is t he one t aken wit h Web Services t hat expose an XSD Schem a, providing
requirem ent s on t he dat a. I 'm going for a slight ly different approach t o st art off, providing list s of
inst ances wit h sim ilar inform at ion.
N ot e
Mart in Fowler describes t he problem in som e det ail [ Fowler Fixed- Lengt hSt ring] . He
proposes a slight ly different approach where an obj ect for a st ring knows t he m axim um
lengt h on it s own, for exam ple.
Frequent ly, you want t he cust om er t o be able t o add his own specific rules, and let t ing him do t hat
isn't t oo hard if you creat e and expose a sim ple language for t he cust om er t o use t o add rules.
Refining the Implementation
So far we have been focusing on t he rules API from a consum er viewpoint . I t hink it would be
int erest ing t o writ e about som e ideas on how t o im plem ent t he rules as well. So let 's get under t he
hood of t he Order class and t ry out som e ideas.
Before we act ually st art " refining" we need t o com e up wit h a very sim ple solut ion t o t he problem so
t hat we have som et hing t o st art wit h.
A Naïve Implementation
Let 's see...first of all, we need a t est . We can reuse som et hing from before and change it a bit . The
CantExceedStringLengthWhenPersisting() t est will do. I t looked like t his:
[Test]
public void CantExceedStringLengthWhenPersisting()
{
Order o = new Order(new Customer());
o.Note = "0123456789012345678901234567890";
Assert.IsFalse(o.IsValidRegardingPersistence);
}
//Order
public bool IsValidRegardingPersistence
{
get
{
if (Note.Length > 30)
return false;
return true;
}
}
N ot e
Of course, I haven't forgot t en t he TDD m ant ra of red, green, refact or, red, green, refact or.
I j ust didn't want t o slow down your reading rhyt hm here.
OK, t hat works. Let 's t ake a copy of t he t est ( clipboard inherit ance) , change t he nam e, and expand it
a bit :
[Test]
public void TryingIdeasWithTheRulesAPI()
{
Order o = new Order(new Customer());
o.Note = "012345678901234567890123456789";
Assert.IsTrue(o.IsValidRegardingPersistence);
o.OrderDate = DateTime.Today.AddDays(1);
Assert.IsFalse(o.IsValidRegardingPersistence);
o.OrderDate = DateTime.Today;
Assert.IsTrue(o.IsValidRegardingPersistence);
o.Note += "012345";
Assert.IsFalse(o.IsValidRegardingPersistence);
}
As you saw, I added one m ore rule st at ing t hat t he OrderDate can't be a fut ure dat e, and for som e
reason ( not t oo m uch of a st ret ch) t hat rule was m andat ory regarding persist ence.
N ot e
To m ake t he OrderDate rule obviously and m andat ory connect ed t o infrast ruct ure, it
shouldn't be allowed t o be sm aller/ larger t han what your dat abase can st ore in a DATETIME
( if t here is such a difference for your dat abase) .
I n order t o get a green t est , we need t o change IsValidRegardingPersistence a lit t le bit , as follows:
//Order
public bool IsValidRegardingPersistence
{
get
{
if (Note.Length > 30)
return false;
return true;
}
}
I t hink t hat will do for now as far as rules com plexit y goes. Not t oo m uch, eh?
[Test]
public void TryingIdeasWithTheRulesAPI()
{
Order o = new Order(new Customer());
o.Note = "012345678901234567890123456789";
Assert.IsTrue(o.IsValidRegardingPersistence);
Assert.AreEqual(0, o.BrokenRulesRegardingPersistence.Count);
o.OrderDate = DateTime.Today.AddDays(1);
Assert.IsFalse(o.IsValidRegardingPersistence);
Assert.AreEqual(1, o.BrokenRulesRegardingPersistence.Count);
o.OrderDate = DateTime.Today;
Assert.IsTrue(o.IsValidRegardingPersistence);
Assert.AreEqual(0, o.BrokenRulesRegardingPersistence.Count);
o.Note += "012345";
Assert.IsFalse(o.IsValidRegardingPersistence);
Assert.AreEqual(1, o.BrokenRulesRegardingPersistence.Count);
}
//Order
public IList BrokenRulesRegardingPersistence
{
get
{
IList brokenRules = new ArrayList();
This is oft en not det ailed enough inform at ion about broken rules, but at least we have st art ed. What
feels worse right now is t hat I don't want t o express t he sam e rules in bot h t he
IsValidRegardingPersistence and t he BrokenRulesRegardingPersistence propert ies, so for now let 's
change IsValidRegardingPersistence t o an execut ion inefficient solut ion inst ead, which cut s down on
duplicat ion.
N ot e
This inefficiency regarding execut ion is oft en not m uch t o worry about if you put it in
relat ionship t o som e dat abase calls, for exam ple.
//Order
public bool IsValidRegardingPersistence
{
get {return BrokenRulesRegardingPersistence.Count == 0;}
}
OK, we have dealt wit h t he possibilit y of asking whet her t he inst ance is in a valid st at e for being
persist ed at any t im e and what t he current problem s are ( " dealt wit h" is an overst at em ent , but st ill) .
There is anot her prot ocol, t hough, and t hat relat es t o t ransit ions. Let 's deal wit h a t ransit ion and
m ake it possible t o get inform at ion about t he problem s. We will also deal wit h t he sit uat ions
react ively ( t hat is, we'll react if t he t ransit ion is at t em pt ed when t here are known problem s) .
Let 's say t hat a rule for being able t o Accept() an order is t hat t he Customer for t he order m ust be in
Accepted st at e. I t could go like t his:
[Test]
public void TryingTheAcceptTransitionWithTheRulesAPI()
{
Order o = new Order(new Customer());
Assert.IsFalse(o.IsOKToAccept);
o.Customer.Accept();
Assert.IsTrue(o.IsOKToAccept);
}
You should not e especially t hat for a new Order (NewOrder st at e) , it 's okay t o have a Customer t hat
isn't accept ed.
One m ore t hing I 'd like t o show, t hough, is t hat t he general rules for t he Order will be applied at t he
t ransit ions as well, so let 's add t hat t o t he t est :
[Test]
public void TryingTheAcceptTransitionWithTheRulesAPI()
{
Order o = new Order(new Customer());
Assert.IsFalse(o.IsOKToAccept);
o.Customer.Accept();
Assert.IsTrue(o.IsOKToAccept);
o.OrderDate = DateTime.Today.AddDays(1);
Assert.IsFalse(o.IsOKToAccept);
try
{
o.Accept();
Assert.Fail();
}
catch (ApplicationException ex) {}
}
N ot e
What also happens is t hat t he new Order as default for OrderDate is set t o DateTime.Today
in t he const ruct or. That 's why it is IsOKToAccept direct ly.
And while I was at it , I also showed what will happen if t he t ransit ion is t ried even t hough it shouldn't
work.
We need t o do som et hing in t he Order for t his. First , let 's do som et hing in IsOKToAccept.
//Order
public bool IsOKToAccept
{
get
{
if (Customer.Status != CustomerStatus.Accepted)
return false;
return IsValidRegardingPersistence;
}
}
As you saw, I first checked t he specific rules ( or rule in t his case) and t hen t he persist ence relat ed
rules, because I don't want t o m ove on wit h som et hing t hat won't be savable; t herefore, I want t o
point out problem s ( persist ence relat ed ones as well) as early as possible.
Again, I need t o change t his a bit if I also want a m et hod for t elling what broken rules t here will be if
I call t he Accept() , but t hat 's sim ple and not im port ant t o show right now.
The sam e goes for t he Accept() m et hod. I t 's pret t y sim ple and j ust needs t o check IsOKToAccept
before doing t he t ransit ion.
What m ight be a bit " t ricky," or at least not obvious, is t hat now t he rules for t he
IsValidRegardingPersistence j ust got a bit m ore com plex, because aft er we ent er t he Accepted
st at us of t he Order, we will have t o check t he sam e rules even in t he IsValidRegardingPersistence
propert y. We m oved t he real processing t o t he BrokenRulesRegardingPersistence propert y as you
saw before, so t hat is where you will see t he change:
//Order
public IList BrokenRulesRegardingPersistence
{
get
{
IList brokenRules = new ArrayList();
if (_OrderIsInThisStateOrBeyond(OrderStatus.Accepted))
_CollectBrokenRulesRegardingAccepted(brokenRules);
return brokenRules;
}
}
So in _CollectBrokenRulesRegardingAccepted() , t here will be a specific rule evaluat ion for ent ering
( or rat her, in t his case, being in) t he Accepted st at e.
N ot e
You m ay have not iced t hat I used t he Collect ing Param et er pat t ern [ Beck SBPP] for
_CollectBrokenRulesRegardingAccepted() . I sent in t he list of broken rules and asked t he
m et hod t o add m ore broken rules t o t he list if appropriat e.
To sum m arize all t his, I t hink you recognize plent y of sm ells and lack of funct ionalit y. For exam ple:
Ret urned inform at ion about broken rules is j ust strings, which isn't enough
We haven't addressed providing inform at ion about t he rules t hem selves t o be used by t he UI
I t 's t im e t o refine t his naïve im plem ent at ion a lit t le bit , wit hout showing t he it erat ions for get t ing
t here. Let 's reuse t he t est s and generalize t he im plem ent at ion a bit .
The com plex rules always have t o be coded by hand for each sit uat ion and are hard t o cust om ize by
adding inform at ion in a config file. Furt herm ore, it 's not im port ant t o provide inform at ion about t he
com plex rules t o generic form s. Those rules aren't m y t arget here. They aren't unint erest ing; on t he
cont rary, I want t o code t hem by hand. I f t hey fit int o t he big pict ure, t hat 's fine, but what I 'm t rying
t o say is it 's not im port ant t hat t hey are declared.
My t arget for what should be declared is t he sim ple rules: t hose t hat are unint erest ing t o writ e by
hand over and over again. Let 's give it a t ry.
N ot e
As always, wat ch out so you don't fall int o t he t rap of building fram eworks up front . I t 's
generally bet t er t o let t hem show t hem selves in your code and t hen you go from t here.
[ Fowler Harvest ed Fram ework]
My rule classes should im plem ent an int erface; let 's call it IRule:
IsValid is used t o check if t he rule is valid or not . The RuleId is used for m aking it possible t o
t ranslat e rules inform at ion and such. I t requires som e ext ra inform at ion, t ypically in t he form of long
const ant list s, but I 'll leave t hat t o t he reader.
The idea regarding ParticipatingLogicalFields is t hat t he consum er should be able t o m ark out t he
fields t hat are affect ing a cert ain broken rule.
And a rule class could look like t he following exam ple. This one is for checking t hat a dat e is wit hin a
cert ain range:
I also needed a base class ( RuleBase ) for generic funct ionalit y, such as reading values by reflect ion,
and for t aking away t he infrast ruct ure part of t he gam e from t he subclasses. All t hat is left for t he
subclasses is t he " int erest ing" code ( and som e const ruct orsI only showed one in t he previous
snippet ) .
N ot e
By t he way, fieldName can be eit her a field or a propert y.
I f you wonder what holder is, it 's t he Dom ain Model inst ance, such as an order inst ance,
t hat is using t he rule obj ect .
I t hink a figure would help here t o explain t he different pieces. See Figure 7- 2 .
Then we " only" have t o writ e classes, such as DateIsInRangeRule, for t he different needs t hat crop
up. I t 's a piece of highly reusable code t hat is being writ t en, but it will t ake som e effort .
You m ight be wondering why I want ed t o use reflect ion. " Want " isn't exact ly correct , but I want t he
posit ive effect of reflect ion. I m ean, I like t o be able t o define t he rule once, and t hen let it execut e
wit hout providing t he value t o check against explicit ly. I nst ead, I 'd provide t he field/ propert y t hat
has t he value. Let 's look at how it could be done.
N ot e
A possible opt im izat ion is t o only use reflect ion when really needed. For exam ple, when you
use reference t ypes, you don't have t o go via reflect ion t o get t he sam e effect . On t he ot her
hand, t hat does increase t he com plexit y a lit t le bit , so wat ch out carefully.
Gregory Young added t he following: " Anot her answer here m ight be t o use code generat ion
t o am ort ize t he reflect ions overhead."
Setting Up a List of Rules
We have one rule class so far. Let 's assum e a sim ilar one for MaxStringLengthRule as well. I t 's t im e
t o put t hem t o use. When using t hem in an Order class, it could look like t his:
//Order
private IList _persistenceRelatedRules = new ArrayList();
private DateTime _orderDate;
public string Note = string.Empty;
_persistenceRelatedRules.Add(new MaxStringLengthRule
(30, "Note", this));
N ot e
I 'm not put t ing any effort int o giving t he rules inst ances good ident ifiers. Therefore, I used
a const ruct or here where I 'm not providing t he values at all.
//Order
public IList BrokenRulesRegardingPersistence
{
get
{
IList brokenRules = new ArrayList();
RuleBase.CollectBrokenRules(brokenRules
, _persistenceRelatedRules);
if (_OrderIsInThisStateOrBeyond(OrderStatus.Accepted)
_CollectBrokenRulesRegardingAccepted(brokenRules);
return brokenRules;
}
}
N ot e
Do you rem em ber I said t hat t he list of broken rules is an im plem ent at ion of t he
Not ificat ion pat t ern [ Fowler PoEAA2] ? I st ill t hink it is, but I have m oved away slight ly.
Gregory Young described t he difference like t his: " The key difference is t hat t he act ual rule
( IRule) is exposed as opposed t o a surrogat e obj ect which sim ply says it has been broken
as is t he case wit h t he Not ificat ion pat t ern."
A good bonus, t hanks t o t he solut ion, is t hat we can easily writ e a RuleBase.IsValid() t hat we
provide wit h t he list of _persistenceRelatedRules as a param et er. That way we can increase t he
execut ion efficiency for t he IsValid propert y wit hout increasing t he am ount of code duplicat ion. I
m ean, t hat im plem ent at ion should j ust see if it finds any rule t hat is invalid. There is no need t o
collect a list of broken rules, no need t o go t hrough all t he rules even t hough t he first one is broken,
and so on.
Back t o t he basic flow. Let 's have a look at how CollectBrokenRules() in RuleBase could look:
//RuleBase
public static void CollectBrokenRules
(IList brokenRules, IList rulesToCheck)
{
foreach (IRule r in rulesToCheck)
if (! r.IsValid)
brokenRules.Add(r);
That was about t he persist ence relat ed rules; very st raight forward. But what about t he rules per
t ransit ion?
//Order
public IList BrokenRulesRegardingPersistence
{
get
{
IList brokenRules = new ArrayList();
RuleBase.CollectBrokenRules(brokenRules
, _persistenceRelatedRules);
if (_OrderIsInThisStateOrBeyond(OrderStatus.Accepted)
RuleBase.CollectBrokenRules(brokenRules,
_acceptedSpecificRules);
return brokenRules;
}
}
That way, m ost of t he work has m oved t o defining t he list of rules ( again, we can only go so far wit h
t his approach, but it is act ually quit e a long way) .
I now put all t he rules in one bucket ( or act ually several if t here are t ransit ion- based list s as well) : an
inst ance- based one. Wit h som e work, bot h of t he rules exam ples shown so far ( DateIsInRangeRule
and MaxStringLengthRule) could be changed t o a list of st at ic rules inst ead. I need t o change t he dat e
rule so t hat it will evaluat e what DateTime.Today is on it s own inst ead of get t ing it in t he const ruct or.
I could also provide relat ive dat es t o t he const ruct or as - 1 and 1 t o m ean one day before and one
day aft er t oday. I could also creat e som e funct ionalit y t hat will only let t he st at ic list live unt il it 's a
new day. Of course, you should st rive t o m ove t he rules t o static list s inst ead, if possible. That will
pot ent ially reduce t he overhead a lot . Wit h t hat said, it 's not affect ing t he principle m uch, if at all.
Let 's m ove on inst ead of looking m ore int o t hose det ails regarding scope.
An API Improvement
My friend I ngem ar Lundberg point ed out t hat it felt a bit st range t o use a propert y for
BrokenRulesRegardingPersistence, and Christ ian Crowhurst suggest ed t hat it would be bet t er t o let a
m et hod use a collect ing param et er and ret urn a bool. Som et hing like t his:
Do you rem em ber IsOKToAccept and BrokenRulesIfAccept? This idea will reduce t he size of t he API
and not split t he check and t he det ailed error inform at ion int o t wo separat e pieces. Those t wo pieces
could very well be rewrit t en int o one m et hod like t his:
The consum er code will be slight ly affect ed. I nst ead of t his:
//Some consumer...
if (! o.IsOKToAccept)
_Show(o.BrokenRulesIfAccept);
//Some consumer...
IList brokenRules = new ArrayList();
if (! o.CheckOKToAccept(brokenRules))
_Show(brokenRules);
Regarding t he collect ing param et er brokenRules, if it 's not init ialized ( null) when CheckOKToAccept()
st ar t s, CheckOKToAccept() can ignore it and only ret urn t he bool. That 's at least one approach, but an
overload t o CheckOKToAccept() wit hout a param et er feels m ore int ent ion revealing. ( I t 's not really a
split int o t wo m et hods, but j ust a chaining from one of t he overloads t o t he ot her. I t 's also t he case
t hat even if t he bool is TRue, t he ret urned list can have warnings for exam ple.)
An addit ional consequence is t hat it st eers a consum er away from execut ing rule checking code
t wice, once for t he IsOKToAccept and again for t he BrokenRulesIfAccept. For exam ple, it is unlikely
t hat t he client will writ e t he following code:
//Some consumer...
if (! o.CheckOKToAccept())
{
IList brokenRules = new ArrayList();
o.CheckOKToAccept(brokenRules);
_Show(brokenRules);
}
I like t his.
Customization
There are loads of ways t o achieve cust om izat ion of a Dom ain Model; for exam ple, you could let
different cust om ers who are using your applicat ion add som e behavior of t heir own. One appealing
solut ion is t o use t he Decorat or pat t ern [ GoF Design Pat t erns] , while anot her is t o provide inherit ance
hooks and configurable creat ion code.
Yet anot her, and pret t y sim plist ic, t echnique is t o m ake it possible t o define t he rules, or at least add
specific rule inst ances, by describing t hem in t he form of configurat ion files.
Wit h t he current solut ion draft , we have m ost of it in place. What we need is a way of adding rules,
so let 's sket ch a new int erface called ICustomRules:
interface ICustomRules
{
void AddCustomRule(IRule r);
}
I n t his first draft , I j ust assum e t hat we can add persist ence relat ed rules and t hat t hey go t o t he
inst ance- based list of rules. That can ( and should) be refined if you need t o.
N ot e
Talking about needing t o add rule inst ances t o st at ic list s rem inds m e of an old wish of
m ine. I 'd like t o be able t o define st at ic int erfaces as well. Why not ?
Now you can add m ore rules during inst ant iat ion of Dom ain Model classes, but as I saidinst ant iat ion
get s a bit m essy, and you should probably use a Fact ory of som e sort .
The good news is t hat t he cust om izat ion we j ust t alked about works seam - lessly wit h t he possibilit y
of dragging out inform at ion about t he rules, which com es in very handy for creat ing t he form s.
interface IValidatableRegardingPersistence
{
bool IsValidRegardingPersistence {get;}
IList BrokenRulesRegardingPersistence {get;}
IList PersistenceRelatedRules {get;}
}
Then it 's up t o t he consum er t o do som et hing int erest ing wit h t he rules she finds. There will probably
be som e rules t hat are easily used by t he UI when new form s are shown, such as fields t hat are
required, cert ain value ranges, lengt hs of st rings and so on.
Concept ually, I like t he solut ion. Som et hing like t his should be useful for a great num ber of proj ect s.
But I can't help feeling t hat it is st ill a bit sm elly, especially regarding t he t ransit ion- specific rules, at
least if t he scale of t he problem increases.
You can also work wit h several levels in t he inherit ance hierarchy regarding t he different st at es; for
exam ple, if an inst ance- based rule definit ion is t he sam e for several of t he st at es.
I t hink applying t he Specificat ion pat t ern [ Evans DDD] is oft en a good idea for com plex rules.
What we t ry t o achieve when using Specificat ions is t o express im port ant dom ain concept s in code.
The com m on t hem e wit h DDD is t o be concept - focused. ( The focus is on dom ain concept s inst ead of
j ust t echnical concept s. For exam ple, num eric int ervals and st ring lengt hs are m ore of t echnical
concept s m ost oft en.)
For exam ple, t here m ight be a Specificat ion class called ReadyToInvoiceSpecification wit h a m et hod
like t his:
//Customer
public IList OrdersToInvoice(ReadyToInvoiceSpecification
specification)
{
IList orders = _orderRepository.GetOrders(this);
IList result = new ArrayList();
foreach (Order o in orders)
{
if (specification.Test(o))
result.Add(o);
}
return result;
}
As always, it 's cont ext - dependent whet her a cert ain design is recom m ended or is even possible, but
m y focus here was j ust t o provide you wit h a sim ple exam ple t hat shows how t he concept could be
applied and t hat t he code is very clear and yet highly flexible. ( Rem em ber, t he Specificat ion
param et er had been configured before being sent in.)
Again, t he rules for what m akes an order invoicable are encapsulat ed in t he Specificat ion, not spread
out in several m et hods.
N ot e
A very nice feat ure of a Specificat ion im plem ent at ion is if you can let it be evaluat ed in t he
dat abase as well, so t hat it can be used for concept - focused querying.
The problem wit h t he Specificat ion approach as I see it is how t o m ake it easy for t he UI t o
aut om at ically do sm art t hings beforehand inst ead of let t ing t he rule break. On t he ot her hand, I can
oft en live wit h t hat problem , especially if Specificat ions are used for som ewhat m ore advanced
problem s t hat are hard t o be proact ive about anyway. On t he ot her hand, if a Specificat ion is using a
concept sim ilar t o IRule, t he part s of t he Specificat ion could be used as usual regarding proact ivit y
for aut om at ically set t ing up t he UI .
I also m ust point out how nice com plex rules t hat are encapsulat ed as Specificat ions are when it
com es t o unit t est ing. I t 's very easy t o t est t he Specificat ions separat ely.
Binding to the Persistence Abstraction
I n t he previous chapt er, I t alked about how t o prepare for t he persist ence infrast ruct ure by working
wit h an abst ract ion layer t hat I called NWorkspace ( which is j ust an exam ple of such an abst ract ion
of course) . As you m ight have guessed, it has som e support for validat ion as well, because t he
react ive nat ure needs t o be dealt wit h when we m ake calls t o PersistAll().
Of course, I don't want t he persist ence abst ract ion t o expect a cert ain int erface t o be im plem ent ed
on t he Aggregat e root s.
The IWorkspace im plem ent at ion t alks t o t he IValidator im plem ent at ion, and t he IValidator
im plem ent at ion t hen decides what int erfaces t o look for on t he ent it ies. I n m y case, t he IValidator
im plem ent at ion looks for IValidatableRegardingPersistence im plem ent at ions and knows what t o do
wit h t he IValidatableRegardingPersistence im plem ent at ion in order t o t hrow an except ion during
PersistAll(), if necessary. To m ake t his a bit m ore concret e, see Figure 7- 3 .
Just as wit h t he dat abase it self, t he IValidator is react ive, but it react s at a st ep earlier t han t he
dat abase and it oft en react s on slight ly m ore com plex and dom ain focused rules.
To m ake t est ing easier, I also have an im plem ent at ion of IValidator t hat is called
ValidatorThatDoesNothing. I m ean for it t o be used for unit t est s when you don't want t o have t he
validat ion t o int erfere. Then you inj ect ValidatorThatDoesNothing t o t he IWorkspace im plem ent at ion
inst ead of t he one looking for IValidatableRegardingPersistence inst ances. I t t ook 30 seconds t o
writ e, and I t hink t hat 's a decent invest m ent com pared t o how useful it is.
I n m y im plem ent at ion, I prefer t o check t he rules in real- t im e; t hat is, when som eone want s t o
know. As I 've m ent ioned, I like t he idea of using Services for dealing wit h problem s relat ed t o what
can't be done at t he validat ion spot .
One alt ernat ive solut ion is t o updat e t he list of broken rules aft er each change t o a propert y so t hat it
is pre- calculat ed when it is needed. Depending on your call pat t erns, it could eit her be m ore or less
efficient t han m y way of doing it .
N ot e
Gregory Young point ed out t hat wit h t he m et adat a on t he rules m ent ioned earlier ( what
fields affect what rules) , one can be very efficient about rechecking rules and always having
current validat ion.
A problem is t hat it requires som e help wit h dirt y t racking, or you will have t o writ e loads of code
yourself in your set t ers ( unless you apply AOP for dealing wit h t he crosscut t ing concern of course) .
You will also have t o use propert ies inst ead of public fields, even if public fields would ot herwise do
very well.
N ot e
This st yle is used in t he CSLA.NET- fram ework [ Lhot ka BO] , which also has support for
som et hing I haven't t ouched upon: m ult i- st ep undo.
Anot her solut ion is t o hold on t o a flag called IsValidated t hat is set t o t rue each t im e you reproduce
t he list of broken rules and set t o false aft er each change. At t he validat ion spot for t he persist -
pipeline, you expect t he IsValidated t o be t rue, or you t hrow an except ion. That affect s t he
program m ing m odel slight ly because it m akes t he IsValidRegardingPersistence call or
BrokenRulesRegardingPersistence call m andat ory. The ot her drawback ( if you consider t he
m andat ory call a drawback, and I t hink I do) is t hat you have sim ilar problem s wit h t he dirt y t racking
as I j ust m ent ioned.
Anyway, it 's good t o have a couple of different approaches prepared in case you find problem s wit h
your first choice.
I f you find t hat you put a lot of energy int o defining loads of sim ple rules by hand, such as m axim um
st ring lengt hs, you should consider set t ing up t hose rules dynam ically inst ead by reading m et adat a
som ewhere. For exam ple, you have t he inform at ion in t he dat abase, but using t hat m ight be a bit
t roublesom e depending on your m apping solut ion. An alt ernat ive m ight be t he m et adat a m apping
dat a it self. Perhaps you'll find t he source for several rules t here.
Anyway, t he im port ant part of t he idea is t o read t he dat a from som ewhere when you st art up t he
applicat ion, set up t he rules dynam ically, and t hen you are done.
Of course, as wit h all t he ot her ideas in t his chapt er, t his isn't t he answer t o every problem . I t is j ust
one m ore t ool for solving t he big puzzle.
Generics and Anonymous Methods to the Rescue
I f you are using an environm ent t hat support s generics ( such as .NET 2.0) , you can of course apply
generics t o t he solut ion proposals discussed previously and gain slight ly in explicit ness, t ype safet y,
and perform ance. That goes, by t he way, for m ost of t he chapt ers discussed so far.
Not a dram at ic im provem ent or som et hing we can't live wit hout ( as is shown t hroughout t he book) ,
but an im provem ent t hat will affect ( again posit ively) m any places in your code.
Anot her t echnique I have not had in t he environm ent s I 've been working in m ost of t he t im e is
anonym ous m et hods ( sim ilar t o blocks or closures as it 's called in ot her languages) .
The idea is t o be able t o send a block of code as a param et er t o a m et hod, but t he block of code can
use variables t hat are in scope of t he m et hod t hat received t he block.
Som e people have discussed it as a way of im plem ent ing Specificat ions wit hout creat ing new classes,
alt hough I t hink t hat m eans t hat you will lose som e of t he explicit ness and clarit y wit h t he
Specificat ions nam ing, which is a powerful feat ure of Specificat ions. I nst ead, I current ly t hink of
anonym ous m et hods m ore as a good t echnique for providing variat ions t o reusable asset s. For
exam ple, you can inj ect part of t he im plem ent at ion of a m et hod at will. I t 's a different way of
t hinking about cust om izabilit y.
Just t o give you a t ast e of t he whole t hing if you are new t o t he t echnique, let 's com bine generics
and anonym ous m et hods t o a snippet we discussed previously and see if it can be im proved. Do you
rem em ber t he loop for seeing if a Customer needs t o be invoiced? I t looked like t his:
//Customer
public IList OrdersToInvoice(ReadyToInvoiceSpecification
specification)
{
IList orders = _orderRepository.GetOrders(this);
IList result = new ArrayList();
foreach (Order o in orders)
{
if (specification.Test(o))
result.Add(o);
}
return result;
}
Here it is again in a slight ly m odified version:
//Customer
public List<Order>OrdersToInvoice(Predicate<Order>
readyToInvoicePredicate)
{
List<Order> orders = _orderRepository.GetOrders(this);
return orders.FindAll(readyToInvoicePredicate);
}
This t im e, t he param et er is a predicat e for if an Order can be invoiced or not . The call provides an
anonym ous m et hod as t he param et er. The call could be like t his, assum ing a very sim ple algorit hm
at t his point in t im e:
That " Specificat ion" or predicat e is sent t o t he FindAll() m et hod of t he generic List for filt ering out
orders t hat can be invoiced.
At t he t im e of t his writ ing, it 's st ill early for m e regarding bot h generics and anonym ous m et hods,
but I 'm sure t hey will m ake a huge difference regarding how I design in t he foreseeable fut ure. I 'm
not j ust t alking about t iny t hings as in t he exam ples above, but m ore like a m ind shift .
But at t he sam e t im e, t hey are j ust som e m ore t ools for t he t oolbox; t hey won't change everyt hing,
of course.
What Others Have Done
I have occasionally t ouched on what ot hers have done and writ t en about in t his respect , and before
we end I 'd like t o t ouch on t wo m ore sources.
The first is St ream lined Obj ect Modeling [ Nicola et al. SOM] , which has a t horough discussion bot h
about different rules and st rat egies for design and im plem ent at ion of t he sam e, all in obj ect - orient ed
cont ext .
The second is Ent erprise Pat t erns and MDA [ Arlow/ Neust adt Archet ype Pat t erns] , which discusses
archet ype pat t erns for how t o organize rules. I t hink you will find t hat m any of t he ideas t here are
useful for m oving on from here.
Summary
All t hese years and t his t opic st ill feels a bit im m at ure and wit h no obvious solut ions. That said, we
have t ouched on several ideas for how t o deal wit h rules, som e t ypical and som e a lit t le m ore
at ypical.
We discussed quit e a lot about rule obj ect s as an im plem ent at ion t echnique, but we have also
t ouched on ot her variant s. As always, no solut ion is t he best for all sit uat ions. For exam ple, t he rule
obj ect s I sket ched were probably m ost appropriat e for pret t y sim ple rules and if you have m any
rules.
The m aj or t akeaways in t his chapt er were probably t hat you should t ry t o decouple persist ence and
t he dom ain- relat ed rules as m uch as possible. ( St ill, t here are connect ions for som e of t he rules.)
Working wit h different st at es is a very powerful solut ion for get t ing close t o t he " all st at es should be
savable" goal. Finally, rem em ber t hat t he rules are very cont ext - connect ed, and t ry t o focus on t he
m odel m eaning of t he rules.
I n t his chapt er, we have dealt wit h m any of t he feat ure request s defined in Chapt er 4, but now we
will m ove on t o t he needed infrast ruct ure, wit h a focus on persist ence support .
Part III: Applying PoEaa
I n t his part , we put several of t he pat t erns in Fowler's Pat t erns of Ent erprise Applicat ion
Ar chit ect ur e [ Fowler PoEAA] int o cont ext by discussing what we need from t he infrast ruct ure for
providing persist ence support t o our dom ain m odel. We will look at how t hose requirem ent s are
fulfilled by an exam ple t ool.
I m port ant t o not e is t hat we will do t his because we h av e t o, not because we want t o. That 's not t he
sam e t hing as saying it 's not im port ant . I t 's j ust t hat we want t o put as m uch of our effort s as
possible on t he dom ain problem s.
But before we st art discussing t he infrast ruct ure, t he obvious quest ion is what infrast ruct ure is
needed? As a m at t er of fact , a great deal of infrast ruct ure is needed, such as infrast ruct ure for
Present at ion ( which m ight be a st ret ch t o call t hat infrast ruct ure)
Logging
And so on, and so fort h. I guess it m ight be m y background as a dat abase guy t hat m akes m e see it
t his way, but I t hink persist ence is t he m ost obvious and int erest ing infrast ruct ure. At least t his is
what we will be focusing on in t he upcom ing chapt ers.
As we define t he needed infrast ruct ure for persist ence, we will also m ake sm all changes t o t he
current Dom ain Model design here and t here in order t o m ake it fit t he t ypical choice of persist ence
infrast ruct ure bet t er.
N ot e
A design approach t hat does not use it erat ions is very dangerous. Let 's assum e t hat you
are responsible for not hing but t he Dom ain Model and t he persist ence. Even so, you should
work a lit t le on t he Dom ain Model, choose and t ry t he persist ence infrast ruct ure, work on
t he Dom ain Model, check t he persist ence infrast ruct ure, and so on. This is especially how
you should proceed wit h your first couple of DDD proj ect s, but is always a good idea t o
som e ext ent .
Let m e also clarify t hat I t ot ally underst and t hat t he UI , for exam ple, is ext rem ely
im port ant and t hat it m ight be considered an insult t o t alk about it j ust as " m echanics." Of
course I ( and t he users) ext rem ely value a usable UI . I t 's also frequent ly t he case t hat
m uch of t he t ot al proj ect t im e is spent on t he UI . Wit h t hat said, our focus here is t he
Dom ain Model. Discussing good UI design is not t he purpose of t his book ( alt hough t here is
som e coverage in Chapt er 11, " Focus on t he UI " ) .
We have decided t o focus on persist ence infrast ruct ure. The next quest ion t hen is what requirem ent s
do we have on t he persist ence infrast ruct ure for being a persist ence infrast ruct ure t hat enables us t o
focus on t he dom ain?
Requirements on the Persistence Infrastructure
Let 's repeat again t hat I want t he infrast ruct ure t o st ay out of t he way of t he Dom ain Model as m uch
as possible so t hat I can focus on creat ing a powerful Dom ain Model for solving t he business problem
wit hout having m ore dist ract ions t han are necessary. For exam ple, I believe t hat I should be able t o
work wit h as high a level of Persist ence I gnorance ( PI ) as possible, so t hat 's a requirem ent of t he
infrast ruct ure.
At t he sam e t im e, it 's also im port ant not t o put t oo m uch responsibilit y on t he consum er of t he
Dom ain Model. I want t o provide t he consum er wit h a very sim ple API so t hat t he consum er
program m er can focus on what is im port ant t o him : creat ing a good experience for consum er users.
I have already defined cert ain desirable feat ures for t he life cycle of t he persist ent ent it ies in Chapt er
5, " Moving Furt her wit h Dom ain- Driven Design," but let 's repeat it again here in Table 8- 1.
Anot her way of t hinking about t he requirem ent s of t he persist ence infrast ruct ure is t o look at t he
non- funct ional requirem ent s I have. Typical exam ples are scalabilit y, securit y, and m aint ainabilit y.
Of course, t his varies widely, not only concerning t he requirem ent s, but also because a cert ain
persist ence fram ework can som et im es fail and som et im es succeed for t he sam e m ix of non-
funct ional requirem ent s. The reason for t his is t hat t he success or failure depends on t he t ype of
applicat ion, t he usage pat t erns, and so on. I have t o leave it up t o t he reader t o define her own m ix
of non- funct ional requirem ent s and t o check whet her a cert ain persist ence fram ework can fulfill t he
requirem ent s by carrying out careful t est s. Just rem em ber t hat if your appet it e for non- funct ional
requirem ent s becom es t oo big, it will cost you a lot som ewhere else.
N ot e
Most oft en it 's very hard t o get t he cust om er t o express any non- funct ional requirem ent s at
all. I f you succeed, t he risk is t hat he will want everyt hing t o 100% , and t hat 's when it 's
good t o rem em ber t he cost side of it .
For furt her discussion of non- funct ional requirem ent s, see [ POSA 1] , [ Fowler PoEAA] or
[ Nilsson NED] .
As you m ay have not iced, I didn't m ent ion it as a requirem ent on t he persist ence fram ework t o be
able t o have a net work bet ween t he consum er and t he Dom ain Model. Building it is very possible, as
we did in Valhalla [ Valhalla] . However, it 's probably bet t er t o t hink along t he lines of explicit
boundary where net works are involved and design t he crossing borders in a service- orient ed way.
This is why I seldom see t he need for t he short cut t hat rem ot ing represent s.
So, we have defined requirem ent s t o fulfill for t he Dom ain Model's sake, and we have defined how t o
use t he API for t he persist ence fram ework.
Wit h t he requirem ent s now in place, let 's get going and m ake som e choices about t he infrast ruct ure.
First is t he locat ion for t he persist ent dat a.
Where to Store Data
Assum e we st art wit h a clean sheet of paper; how would we like t o st ore t he dat a? We have at least
four choices:
RAM
File syst em
N ot e
I realize t hat t his m ay be a case of apples and oranges because it is a t wo- part problem :
what t o st ore ( Obj ect s, Hierarchies, such as XML, or Tables) and where t o st ore it : ( RAM,
File syst em , Obj ect dat abase, or Relat ional dat abase) . But t hat 's not wit hout problem s,
eit her. Aft er t hinking t hrough it a couple of t im es, I t hink m y original way of describing it is
good enough, so let 's m ove on.
RAM
St oring t he dat a in RAM isn't necessarily as silly as it m ight first sound. What I 'm t hinking about is
seeing t he Dom ain Model as t he dat abase it self while at t he sam e t im e keeping persist ent st orage of
all changes as a log on disk so t hat t he Dom ain Model can be re- creat ed in case of a syst em crash.
The beaut y is t hat you avoid m apping from t he Dom ain Model ont o som et hing else. The Dom ain
Model is persist ent by it self.
You could also st ore hierarchies in m em ory, wit h XML docum ent s as a t ypical exam ple. Then you do
get som e im pedance m ism at ch because you are using t wo m odels and need t o t ransform bet ween
t hem . On t he ot her hand, you do get som e funct ionalit y for free, such as querying if you find XPat h
and XQuery t o be good languages for t hat .
No m at t er what you " st ore" in RAM, one problem is t he size of RAM. I f you have 2 GB of RAM in your
m achine left over when t he syst em and ot her applicat ions have t aken t heir part , your dat abase
shouldn't be larger t han 2 GB or perform ance will suffer.
On t he ot her hand, 64- bit servers are becom ing m ore and m ore com m on, and RAM prices are
dropping all t he t im e. For a m aj orit y of applicat ions, t he current as well as t he next generat ion of
hardware is oft en enough, at least when considering t he possible m axim um size of t he dat abase.
Anot her problem is t hat it t akes t im e t o recreat e t he Dom ain Model aft er a syst em crash, because
working t hrough a huge log will t ake t im e. The problem is m inim ized if t he RAM- based solut ion t akes
snapshot s t o disk every now and t hen of t he current Dom ain Model. But t he problem is st ill t here,
and t aking snapshot s m ight be a problem in it self because it will bring t he syst em on it s knees and
m ight cause periods of wait st at e for ot her request s when t he snapshot is t aken.
N ot e
Gregory Young point ed out t hat t o m ake t he issue of snapshot s sm aller, cont ext boundaries
can be used wit hin t he dom ain and t hey can be snapshot t ed separat ely.
One of t he worst problem s wit h t his approach com es in m aking changes t o t he schem a. What you'll
have t o do is serialize t he obj ect s t o disk, and t hen deserialize t hem int o t he Dom ain Model again
wit h t he new schem a, which is a t edious t ask. Working wit h XML inst ead of pure classes helps wit h
t his problem .
Anot her big problem is t hat of t ransact ions. Fulfilling At om icit y, Consist ency, I solat ion and Durabilit y
( ACI D) is not easily done wit hout hurt ing scalabilit y a lot . First , inst ead of using t he " t ry and see"
approach in t his case it 's bet t er t o prepare for a t ransact ion as m uch as possible in order t o
invest igat e whet her t he t ask is likely t o succeed. ( " I need t o do t his; will t hat get m e int o t rouble?" )
Of course, t his won't solve t he whole problem , but at least it will reduce it . I t 's good t o be proact ive
here, especially considering t hat you have very good efficiency because t here are probably no
process boundaries or net work involved.
N ot e
This depends on t he t opology. I f you consum e t he Dom ain Model ( and t herefore t he
" dat abase" in t his case) from anot her m achine, t here are process boundaries and net works
t o cross.
Again, being proact ive didn't provide any t ransact ional sem ant ics, it j ust m ade a rollback less likely.
One approach I 've heard about requires a RAM t wice t he size of t he Dom ain Model if t ransact ions are
needed so t hat t he changes can be done in t he copy of t he Dom ain Model. I f all changes are
successful, t hey are redone in t he ordinary Dom ain Model. Meanwhile, t he Dom ain Model is
inherent ly single- user. Keep in m ind t hat operat ions are usually ext rem ely fast , and yet t his does not
seem scalable t o m e. I also consider it t o be a sign of im m at urit y, so expect bet t er solut ions t o t his
lat er on. At t he t im e of t his writ ing, t here are light weight t ransact ion m anagers in t he works or being
int roduced, which m ight be a good solut ion t o t he problem .
One m ore problem is t hat t here is no obvious choice for a query language. There are som e open
source alt ernat ives, but again, t his feels a bit im m at ure at t he m om ent . This problem get s bigger
when you consider report ing and t he need for ad- hoc querying done by end users and not j ust
querying from wit hin t he applicat ion. For exam ple, t ypical report writ er t ools for end users are pret t y
useless in t his case.
N ot e
I f possible, report ing should be done on a dedicat ed server and dedicat ed dat abase
anyway, so t his m ight be less of a problem t han what was first ant icipat ed. On t he ot her
hand, in realit y t here is oft en at least a grey zone of what are report s and what are list s for
support ing t he daily t ransact ional work, so t o speak. And voilá, t he problem is back.
Yet anot her problem is t hat navigat ion in t he Dom ain Model is t ypically based on t raversing list s.
There m ight not be built - in support for indexing. Sure, you can use hash t ables here and t here, but
t hey only solve part of t he problem . You can, of course, add an in- m em ory indexing solut ion if you
need it . On t he ot her hand, you should not e t hat t his cert ainly won't be a problem as early on as it is
for disk- based solut ions.
Finally, as I 've already said a couple of t im es, I consider t his approach t o be a bit im m at ure, but very
int erest ing and prom ising for t he fut ure, at least in cert ain sit uat ions.
File System
Anot her solut ion is t o use t he file syst em inst ead of RAM. What t o persist is t he sam e as wit h RAM,
nam ely t he Dom ain Model obj ect s or XML. As a m at t er of fact , t his solut ion could be very close t o t he
RAM solut ion. I t could be t he sam e if t he dat abase is sm all, and it m ight " only" spill out t o disk when
t he RAM is filled t o a cert ain level.
This approach has sim ilar problem s t o t he previous one, except t hat t he size of RAM isn't as m uch of
a lim it ing fact or in t his case. On t he ot her hand, t he perform ance charact erist ics will probably be less
im pressive.
I believe t hat it m ight be pret t y appealing t o writ e your own solut ion for persist ing t he Dom ain Model
( or XML docum ent s also) , but as always when you decide t o roll your own infrast ruct ure, you have t o
be prepared for a lot of work. I know t hat not hing is m ore inspiring t o a developer t han hearing t hat
" it 's t oo hard" or " t oo com plex," so if t hey haven't already done so, now j ust about everybody will be
writ ing t heir own file syst em - based solut ion, right ? Just be prepared for it t o be decept ively sim ple at
first , but t he devil is in t he det ails, and t he com plexit y increases as you m ove forward.
I f you do decide t o build a Dom ain Model t hat could spill out t o disk when persist ing, what you
act ually creat e is quit e like an obj ect dat abase. ( Perhaps t hat gives a bet t er sense of t he am ount of
work and com plexit y.)
Object Database
Hist orically, t here have been m any different st yles of obj ect dat abases, but t he com m on denom inat or
was t hat t hey t ried t o avoid t he t ransform at ion bet ween obj ect s and som e ot her st orage form at . This
was done for m ore or less t he sam e reasons as I have been t alking about when want ing t o delay
adding infrast ruct ure t o t he Dom ain Model, as well as for perform ance reasons.
N ot e
The num ber of st yles increases even m ore if we also consider t he hybrids, such as obj ect -
relat ional dat abases, but I t hink t hose hybrids have m ost oft en com e from a relat ional
background and st yle rat her t han from t he obj ect - orient ed side.
As it t urned out , t he num ber of dist ract ions was not zero. I n fact , you could say t hat t he im pedance
m ism at ch was st ill t here, but com pared t o bridging t he gap bet ween obj ect s and a relat ional
dat abase, using obj ect dat abases was pret t y clean.
So far, t he problem s wit h obj ect dat abases have been as follows:
Lack of st andards
Mat urit y
Repor t ing
N ot e
My evil friend Mart in Rosén- Lidholm point ed out t hat m any of t he sam e argum ent s act ually
could be used against DDD and O/ R Mapping com pared t o dat a- orient ed solut ions in a
.NET- world, considering Microsoft 's applicat ion blocks, papers, guidelines, and so on.
I 'll pret end I didn't hear t hat . And a focus on t he dom ain will probably becom e m ore and
m ore popular for Microsoft 's guidance as well, which Mart in t ot ally agrees wit h.
I 'm cert ainly no expert on obj ect dat abases. I 've played wit h a couple of t hem over t he years, and
t hat 's about t he ext ent of it . For m ore inform at ion, m y favorit e books on t he subj ect are [ Cat t ell
ODM] and [ Connolly/ Begg DB Syst em s] .
There was a t im e, around 1994, when I t hought obj ect dat abases were t aking over as t he de fact o
st andard. But I based t hat idea on purely t echnical charact erist ics, and life isn't as sim ple as t hat .
Obj ect dat abases were prom ising a decade ago. They are used very m uch in cert ain sit uat ions t oday,
but above all, t hey are st ill j ust prom ising. As I see it t oday, t he de fact o st andard is st ill relat ional
dat abases.
Relational Database
As I said, t he de fact o solut ion for st oring dat a in applicat ions is t o use a relat ional dat abase, and t his
is t he case even if you work wit h a Dom ain Model.
St oring t he dat a in a relat ional dat abase m eans t hat t he dat a is st ored in t abular form at , where
everyt hing is dat a, including t he relat ionships. This has proved t o be a sim ple and yet effect ive
( enough) solut ion in m any applicat ions. But no solut ion is wit hout problem s, and in t his case when
we want t o persist a Dom ain Model in a relat ional dat abase, t he problem is t he im pedance m ism at ch.
However, I t alked about t hat at lengt h in Chapt er 1, " Values t o Value," so I won't repeat it here.
I f we go t his rout e, t he m ost com m on solut ion is t o use an im plem ent at ion of t he Dat a Mapper
pat t ern [ Fowler PoEAA] . The purpose of t he Dat a Mapper pat t ern is t o bridge t he gap bet ween t he
Dom ain Model and t he persist ent represent at ion, t o shuffle t he dat a bot h ways. We'll com e back t o
t hat pat t ern in a few m inut es.
Choosing what st orage solut ion t o use isn't obvious. St ill, we have t o m ake a choice.
Before choosing and m oving forward, I 'd like t o t hink about a couple of ot her quest ions.
The Dom ain Model excels in a sit uat ion where t here are several resource m anagers because it can
com plet ely hide t his com plexit y from t he consum ers if desired. But we should also be clear t hat t he
presence of m ult iple resource m anagers adds t o t he com plexit y of m apping t he Dom ain Model t o it s
persist ence. I n order t o m ake t hings sim pler in t he discussion, I 'll only assum e one resource
m anager here.
Other Factors
I n realit y, we rarely st art wit h a clean sheet of paper. There are fact ors t hat color our decision, such
as what we know ourselves. A good way of becom ing efficient is t o work wit h t echnology t hat you
know.
Ot her t ypical fact ors t hat com e int o play, apart from t he raw t echnology fact ors t hat we t alked about
earlier and t hat didn't prove a clear winner, are what syst em s t he cust om er has invest ed in ( bought
and t rained t he st aff in) .
Mat urit y in solut ions is also a very influent ial fact or when it com es t o t he dat a. Losing dat a vit al t o
t he business processes j ust isn't an opt ion, so cust om ers are oft en picky if you choose what t hey
t hink is an unproven solut ion.
I t act ually m akes m e want t o add som e requirem ent s t o t he list of our requirem ent s on t he
persist ence infrast ruct ure:
Dealing carefully wit h t he relat ional dat abase. ( St icking as closely as possible t o how we would
program it m anually.)
St rong querying support . ( Which is, t o a large degree, what t he previous bullet was about .)
Support for concurrency collision det ect ion.
Support for advanced m apping, such as different inherit ance st rat egies ( even if I will probably
be careful using " inherit ance" in t he dat abase) and fine- grained t ypes in t he Dom ain Model.
As I said, what is t hen needed is an im plem ent at ion of t he Dat a Mapper pat t ern. The quest ion is how
t o im plem ent t hat pat t ern.
Approach
There are cert ainly m any different ways of dealing wit h t he Dat a Mapper pat t ern, but I t hink t he
m ost t ypical are t he following:
N ot e
I t hink a sent ence about each of t he pat t erns m ent ioned previously is in order. The Unit of
Work pat t ern [ Fowler PoEAA] is about capt uring inform at ion about changes t hat are done t o
t he Dom ain Model during a logical unit of work. That inform at ion can t hen be used t o affect
t he persist ent represent at ion.
The I dent it y Map pat t ern [ Fowler PoEAA] is about keeping no m ore t han one inst ance for
each ent it y in t he session. I t 's like an ident it y- based cache. This is vit al for bridging t he
im pedance m ism at ch. When you work wit h obj ect s, you want t o be able t o use t he built - in
obj ect ident it y, t he address t o t he obj ect .
Finally, t he Lazy Load pat t ern [ Fowler PoEAA] is about loading subgraphs j ust in t im e.
Unit of Work and I dent it y Map are needed, according t o t he requirem ent s we set up. That also goes
for querying. Lazy Load m ight not be needed t hough. I t can be solved pret t y easily on your own if
you need it occasionally. Wit h t hat said, it 's nice if we get support for in case we do need it .
So it seem s as if t here is som e work t o do. And t hose were j ust a couple of exam ples. There is m ore,
m uch m ore t o it .
I f you decide t o st ick t o t he requirem ent s I defined, you will find t hat you are about t o build a specific
and ( hopefully) sim plified O/ R Mapper if you go for cust om m anual code. That m eans t hat we have
kind of left t his cat egorizat ion and m oved t o t he t hird one. Let 's ignore t hat for now and j ust assum e
t hat we will be t rying really hard t o live wit hout Unit of Work, I dent it y Map, Lazy Load, dynam ic and
flexible querying, and so on.
First , you have t o decide how everyt hing should work in det ail. And when all t hat work has been
done, you have t o apply it t o your com plet e Dom ain Model. This is very t edious, t im e- consum ing,
and prone t o errors. Even worse, t he problem will hit you again each t im e you m ake changes t o t he
Dom ain Model from now on.
This approach has t he sam e problem s as cust om m anual code, plus com plexit ies wit h t he code
generat ion it self, of course. The up side is t hat t he product ivit y will be m uch bet t er when t he design
it self is m at ure.
Anot her com m on problem wit h code generat ion- based solut ions is t hat of source code cont rol. A
sm all change t o t he Dom ain Model will usually force you t o check out ( if you use a t ool for source
code cont rol t hat requires a checkout before m aking changes) all t he classes t hat deal wit h t he Dat a
Mapping and regenerat e t hem all. I t could be worse, but it 's st ill inconvenient .
There are m ore problem s, such as adding loads of unint erest ing code t o t he code base, code t hat
isn't t o be read by any hum ans, only t he com piler.
A com m on problem is t hat t he generat ed code is oft en t ight ly coupled t o a specific dat abase product .
Even if t hat 's solvable wit h an abst ract ion layer, t he problem is st ill t here if you need t o support
different dat abase schem as. Then you need t o keep one generat ed code base per schem a. This is
also a viable opt ion for different dat abase product s, even t hough it 's not a very sm oot h solut ion.
Anot her problem is t hat you will probably have fewer possibilit ies for runt im e t uning. Take how t he
opt im izer of a relat ional dat abase works as a com parison. Only " what " is decided st at ically, " how" is
decided at runt im e, and t herefore " how" can change depending upon t he sit uat ion. I don't see t his as
a big problem for m ost applicat ions at t he m om ent , t hough. Moreover, if you com pare a specific
scenario wit h t he sam e approaches for generat ed code and reflect ive code, it is oft en possible t o
squeeze out bet t er perform ance from generat ed st at ic code t han from reflect ive code.
Perhaps a worse problem is t hat of new generat or versions. I have t he gut feeling t hat it 's hard t o
get a new version of a generat or int o product ion because it will have t o re- generat e all t he code.
Also, if t he dat abase schem a changes, it 's not possible t o m ake changes at runt im e wit hout a
recom pile. But t his is som et hing t hat 's rarely recom m ended anyway. These sort s of changes should
involve t he developers.
The code generat ion being of roundt rip st yle or forward only is a pret t y big difference. I f it is
roundt rip st yle, your changes t o t he generat ed code will be preserved, while in t he case of forward
only st yle, you should never change t he generat ed code because changes will be lost at next
generat ion.
Let 's end on an up not e. Debugging m ight be easier wit h a solut ion based on code generat ion t han
based on m et adat a m apping. All t he code is " t here," but t he code m ight be hard t o underst and, and
t here is a lot of it .
Oft en t he cat alyst for want ing t o look furt her is t he lack of dynam ics, such as when it com es t o
querying. And I also said t hat if we decide t o im plem ent dynam ic querying, Unit of Work, I dent it y
Map, and so on, I t hink we should t ake a good look at t he next cat egory: t he O/ R Mapper.
The m ost t ypical im plem ent at ion is probably t hat of O/ R Mappers. I will use t he t erm O/ R Mapper as
a product fam ily t hat t akes care of Met adat a m apping.
N ot e
My friend Mat s Helander describes O/ R Mapping as Tai Chi.
Tai Chi is com posed of t wo halves. The first half is about learning t o elevat e and lower t he
arm s slowly, in harm ony wit h t he breat hing. The second half is everyt hing else. This isn't a
j oke. No m at t er how good you get at Tai Chi, you are " expect ed" or recom m ended t o
cont inue t o spend as m uch t im e on t he first m ove as on all t he ot her m oves t oget her.
O/ R Mapping is also com posed of t wo halves. The first is about shuffling dat a bet ween
obj ect s in m em ory and rows in t he dat abase and back. The ot her half is everyt hing else.
As you can probably guess by now, m ost O/ R Mappers have built - in support for Unit of Work, I dent it y
Map, Lazy Load, and Querying.
But t here's no solut ion wit hout problem s. A com m on com plaint against O/ R Mappers is t hat t hey are
incapable of creat ing really good SQL code. Let 's have a look at som e exam ples t hat are oft en
brought up. First is UPDATE wit h t he WHERE clause. Look at t he following exam ple:
UPDATE Inventory
SET Balance = Balance 1
WHERE Id = 42 AND Balance >= 1
This m eans t hat I only want t o change t he balance if t here are product s in st ock. Ot herwise, I do not
want t o change t he balance. This is usually not support ed direct ly by O/ R Mappers. I nst ead, t he
approach t hat O/ R Mappers would t ake here is t o read t he Inventory row wit h an opt im ist ic lock,
m ake t he change, and writ e it back ( hoping for t he best t hat t here was no concurrency except ion) .
To clarify, here's an exam ple of t he opt im ist ic approach ( in t his case as a SQL bat ch, but not e t hat
we aren't holding on t o any locks because t here is no explicit t ransact ion, so t his exem plifies t he
scenario) :
UPDATE Inventory
SET Balance = @newBalance
WHERE Id = 42 AND Balance = @oldBalance
--If @@ROWCOUNT now is 0, then the update failed!
Alt ernat ively, it would read t he Inventory row wit h a pessim ist ic lock, m ake t he change, and writ e it
back. Bot h approaches would cause scalabilit y t o suffer.
Anot her com plaint about O/ R Mappers is t hat t hey are oft en ineffect ive for updat ing large num bers of
rows. The approach for updat ing all product s via an O/ R Mapper will probably be t o read all product s
int o a list , loop t he list , and updat e t he product s one by one. I f t hat could have been done wit h a
single UPDATE st at em ent inst ead, t he t hroughput would have been t rem endously bet t er.
Yet anot her com plaint is t hat it 's hard t o balance t he am ount t o read. Eit her t oo lit t le is read and
t here will t herefore be lot s of roundt rips when lazy loading, or m ore is read t han is necessary. Type
explosion is a com m on result from t his, defining several variat ions of t he t ype definit ions.
But we can look at it t he ot her way around as well. Can a person writ e all code ext rem ely well and be
consist ent ? And are all t he developers on t he t eam as good as t he best one? Even if t hat 's t he case,
should we use person hours for t his if we get good enough perform ance wit h an aut om at ic approach?
N ot e
To be fair, t he point j ust m ade is also valid for code generat ion.
We found som e pros and som e cons. I like t hat , because it m akes m e feel t hat I underst and ( t o som e
degree) t he t echnology t hat is being discussed.
Choosing Again
I s t his an easy choice? Of course not , but in m y experience t he approach t hat best fulfills t he
requirem ent s we decided on t oget her is t he O/ R Mapper. I nt ellect ually, it feels like a decent approach
for m any sit uat ions, but it 's not wit hout problem s.
I f we are in YAGNI - m ood, I t hink O/ R Mappers m ake sense because we can solve t he problem in a
sim ple way ( hopefully wit hout adding dist ract ions t o t he Dom ain Model) and st and st rong for t he
fut ure. And when t he perform ance isn't good enough, t hese ( hopefully rare) cases can be dealt wit h
by cust om code. This is probably a very efficient way of dealing wit h t he problem , at least as long as
not all t he problem s are perform ance problem s, but t hat 's hardly t he case.
To be clear, everyt hing I 'm about t o discuss is applicable even in t he case of cust om code ( except for
m apping st yle) . That also goes for t he pat t erns descript ion. But in order t o becom e m ore concret e,
we will be t hinking about O/ R Mappers from now on.
The first classificat ion is about t he st yle of Dom ain Model t hat is support ed.
I nher it ance
Persistent Ignorant
Persist ent I gnorant m eans t hat you m ake no changes at all t o t he Dom ain Model in order t o m ake it
persist able. Of course, t here's a scale here, and it 's not a m at t er of being com plet ely black or whit e.
For exam ple, reflect ion- based approaches set som e requirem ent s. AOP- based approaches set ot her
requirem ent s.
Inheritance
A com m on approach hist orically is t o require t he Dom ain Model classes t o inherit from a super class
provided by t he Persist ence Fram ework.
Interface Implementation
Finally, anot her com m on approach hist orically is t o require t he Dom ain Model classes t o im plem ent
one or m ore int erfaces provided from t he Persist ence Fram ework.
This was j ust one aspect showing how you m ight have t o adapt your Dom ain Model t o fit t he
persist ence fram ework. Loads of ot her t hings m ight have t o be done regarding Versioning and Lazy
Load, for exam ple, but we'll com e back t o t hat lat er in t he chapt er.
Mapper Style
Met adat a- based m appings are oft en im plem ent ed in t wo different ways:
As t he sharp- eyed reader will have not iced, I j ust m ent ioned code generat ion again, t his t im e in t he
cont ext of O/ R Mappers. However, t here's one im port ant difference. Now t he code generat ion is
done, t ypically j ust before com pilat ion, by reading m et adat a and spit t ing out t he m apping code. Of
course, code generat ion of cust om code could be done in a sim ilar way, but t he m ain difference is
t hat t he appet it e regarding what t o support varies. This definit ion is not ext rem ely dist inct , but it 's a
st art .
Fram ework/ reflect ive m eans t hat t here is no source code generat ed before com pilat ion t im e for t he
m apping work. I nst ead, t he m apping is dealt wit h by reading m et adat a at runt im e.
N ot e
As you probably suspect , t hings are even fuzzier. For exam ple, how should we cat egorize
st at ic AOP? I t ry t o keep t he descript ion and cat egorizat ion sim ple and clean.
I t 's also im port ant t o not e t hat code generat ion and fram ework don't have t o be m ut ually
exclusive.
Starting Point
When you are working wit h a cert ain O/ R Mapper, you can oft en choose one or m ore st art ing point s
from t he following list :
By st art ing point I m ean what you focus on when you st art building your applicat ion. Of course, it 's
beneficial if t he O/ R Mapper support s several st art ing point s because t here's t hen a great er chance
you can use it for t he different sit uat ions in which you will find yourself.
As you know by now, I prefer t o st art working from t he Dom ain Model; however, you can't always
have t hat and m ay have t o st art from t he dat abase schem a inst ead or at least keep a close eye on
t he dat abase schem a. You m ay also have t o st art working from t he m apping inform at ion inst ead,
describing t he classes' relat ionships t o t ables in a UML- like diagram m ing t ool, for exam ple.
I f you prefer st art ing from t he Dom ain Model, but t he persist ence fram ework t hat you want t o t ry out
doesn't support t hat , you can work around t he problem by seeing t he UML Edit or or Dat abase Design
as a way of writ ing your Dom ain Model. I t 's a bit awkward, t hough. And TDD, for exam ple, won't be
as nat ural t o apply.
Even t hough t he st art ing point m ight be t he dat abase, t his doesn't have t o im ply t hat it
is forced by t he persist ent fram ework or t hat t he designer prefers t o work in t his way. I t
can also be t hat you have a legacy dat abase t hat m ust be used.
Be prepared for it t o be m uch harder t o go t hat rout e wit h an O/ R Mapper ( unless it 's
specialized for t hat ) , especially if you aren't allowed t o change t he design of t he
dat abase at all. Oft en it 's at least allowed t o add views, colum ns, and t ables t o t he
dat abase even if you aren't allowed t o change exist ing colum ns. That can help! ( Changes
t hat exist ing apps aren't affect ed by are pret t y likely t o be allowed, but wat ch out
because t he exist ing apps m ight not be t he m ost robust around.)
I t 's especially t roublesom e if t he legacy dat abase design isn't in great shape, which can
happen if t he applicat ion has been in product ion for a couple of years.
Som et hing else about t his point is how do you m ove furt her when you are " done" wit h t he first one
( such as t he Dom ain Model) ? Does t he chosen O/ R Mapper provide any help wit h creat ing t he ot her
t wo part s t o any ext ent ? For exam ple, you have t he Dom ain Model, and now you need t he dat abase
and m et adat a. Can you get t hat aut om at ically? I t 's not as t hough t his is a show- st opper if it 's not
support ed; you can oft en creat e such basic t ools on your own pret t y easily. But it 's an advant age if
t hat has been t aken care of for you.
So let 's now assum e t hat we have t he Dom ain Model, dat abase, and m apping inform at ion in place.
Let 's discuss what t he API will look like.
API Focus
The API focus com es in t wo alt ernat ives:
This is st ret ching t hings, because from t he st art t he whole purpose of O/ R Mappers was t o let
developers work wit h obj ect s inst ead of t ables. Therefore, for t ypical O/ R Mappers, t he API focus is
always Dom ain Model. ( An exam ple of an API t hat is m ore focused on relat ional t ables is t hat of t he
Recordset pat t ern, im plem ent ed wit h DataTable in .NET.)
Anot her very im port ant aspect of t he API , and one t hat isn't t he sam e for every O/ R Mapper, is
querying.
I believe it 's fit t ing t o explain each of t hese a lit t le bit m ore.
String-Based, SQL-ish
By t his I m ean query languages t hat look quit e sim ilar t o SQL, but work wit h classes in t he Dom ain
Model inst ead of t he t ables in t he dat abase. Som e queries, especially advanced ones, are very well
expressed in a language like t his. On t he ot her hand, t he t ypical drawback is t he lack of t ype safet y.
I t 's im port ant t o not e, t hough, t hat t his way of st at ing queries isn't necessarily st ring- based at t he
im plem ent at ion level, only at t he API level.
Query Object-Based
The second t ypical query language is t o use obj ect s t o represent queries, following t he Query Obj ect
pat t ern [ Fowler PoEAA] . Sim ple queries are oft en bet t er expressed in t his approach, it 's possible t o
have t ype safet y, and t he developer doesn't have t o know m uch about querying sem ant ics in order t o
be efficient . The problem , t hough, is t hat com plex queries m ight require lot s of code t o express, and
t he code quickly get s hard t o read.
Raw SQL
Yet anot her nice solut ion t o have for rare cases is t o be able t o express t he query in SQL, but t o
receive t he result as Dom ain Model inst ances. Of course, t hat has t he problem of m aking your code
dat abase- coupled, but if you can't find anot her solut ion, it 's great t o at least have t he opt ion. This is
very handy when you need t o opt im ize. And if you need t o get ent it ies as t he result and t he SQL-
int egrat ion can t ake care of t hat for you, it will cut down on t he code am ount you have t o writ e.
Of course we should be allowed t o j um p out t o SQL wit hout receiving t he result as Dom ain Model
inst ances as well.
Which Approach?
As I see it , ideally t he t ool should support several approaches. This is because som et im es st ring-
based expressions are best , while for ot her sit uat ions query obj ect - based expressions are m ost
suit able.
The querying st yle in it self is only part of t he st ory. Anot her im port ant aspect is how com pet ent t he
querying solut ion is. That is part of t he next t opic.
Aggr e ga t e s
A very basic feat ure of SQL is t he capabilit y t o do t hings like SELECT SUM(x) , MIN(y), MAX(z).
When you work wit h a Dom ain Model focus, it m ight be slight ly less com m on t hat you need
t hose aggregat es, but t hey are st ill very useful and som et im es necessary.
Or de r in g
I t m ight prove m ost efficient t o order t he result set in t he dat abase wit hout having t o do t he
ordering in t he Dom ain Model.
Gr ou p By
Som et hing else you can do when you work wit h SQL is t o use GROUP BY . I t 's especially com m on
for ad- hoc queries and report ing, but is st ill occasionally useful in Dom ain Model- focused
applicat ions.
Sca la r qu e r ie s
I t 's not necessarily t he case t hat you always want t o fet ch com plet e inst ances back. Som et im es
it 's j ust field values, perhaps som e from one class and som e from anot her.
I t 's also very nice if t here are ot her ways t o m ove funct ionalit y t o t he dat abase, funct ionalit y t hat fit s
best in t he dat abase, t ypically dat a- int ensive operat ions. What I 'm t hinking about here is usually t he
capabilit y t o call st ored procedures, but it could also include ot her cust om ways of m oving
funct ionalit y, such as user- defined funct ions.
The m ain problem wit h t his is t hat we m ight lose port abilit y of t he applicat ion and t he dat abase
design. But if we use t his as an opt im izat ion t echnique, used only when really necessary, t he problem
is m inim ized.
The ot her big problem is t hat if we j um p out of t he sandbox, we are on our own, but t hat 's not all.
We m ust also t ake care t o do what it t akes for t he int egrat ion wit h t he sandbox. I t m ight be t hat we
have t o purge t he I dent it y Map aft er we have called a st ored procedure. Nobody can decide t hat for
us; we have t o j udge it on our own.
N ot e
I t hink t his is a good exam ple of what Joel Spolsky t alks about in his art icle " The Law of
Leaky Abst ract ions" [ Spolsky Leaky Abst ract ions] . Abst ract ions are great , but you have t o
know a lot about what 's happening behind t he scenes as well.
I t hink t hat 's t he way t o t hink about and use O/ R Mappers. You shouldn't expect t hem t o
hide everyt hing. You have t o know what 's going on behind t he abst ract ion. See t he O/ R
Mapper as a t ool t hat helps you wit h a t edious t ask t hat you could do m anually, but
pract ically don't want t o.
Other Functionality
That was a whole range of feat ures, but t here's m ore; for exam ple,
W h a t ba ck e n ds a r e su ppor t e d?
I t m ight be a nice feat ure for you if t he part icular O/ R Mapper support s several different
backends so t hat you aren't j ust t ied t o one, such as Oracle or SQL Server.
N ot j u st a n O/ R M a ppe r
Many product s t hat are O/ R Mappers are also m uch m ore t han t hat . For inst ance, t hey m ight
help you out wit h dat a binding ( t o bind cont rols in your UI t o your obj ect s wit hout any cust om
code) , wit h business rules, or wit h bi- direct ionalit y m anagem ent .
Adva n ce d ca ch in g
Advanced caching isn't necessarily im port ant t o you, but if you do need it , it 's nice if it is
support ed by t he chosen product . Wit h advanced caching, I 'm not j ust t hinking about t he cache
in t he form of t he I dent it y Map, but also a cache t hat is used for querying. I m ean t hat when
you query for cert ain cust om ers, for exam ple, t hat query m ight execut e against t he second-
level cache inst ead of t ouching t he dat abase.
Exam ples of t his feat ure include how well you can cont rol t ransact ions regarding isolat ion
levels, lessen t he deadlock risk by avoiding escalat ions from read locks t o writ e locks, and
whet her dist ribut ed t ransact ions are support ed. Pret t y disparat e t hings, but t hey m ight be
pret t y im port ant , no quest ion about t hat .
Also int erest ing in t his cont ext is what t echnique is used for t ransact ion cont rol. Typical opt ions
are m anual cont rol, int ercept ion- based, and hiding t he whole t hing wit h a persist ence m anager.
Ope n sou r ce
Pros and cons when it com es t o open source versus com m ercial product s are not in t he scope of
t his book. St ill, it 's a fact or t o t ake int o considerat ion when you're about t o choose O/ R Mapper.
Ve r sion ( ge n e r a t ion )
And last on t he list , it 's im port ant t o consider what generat ion t he O/ R Mapper is. That m ight
say som et hing about what m at urit y t o expect .
Keep st ored in your head som ewhere t hat " less is som et im es m ore." I t m ight be t hat t he bigger t he
product 's focus, t he less t he product is focused on det ails. I t doesn't have t o be t hat way, of course; I
j ust want t o point out t hat it 's not as easy t o j udge what product is best j ust by count ing feat ures.
Let 's have a look at t he classificat ion from a t ot ally different angle.
Another Classification: Infrastructure Patterns
I n t his second part of t he classificat ion, I will use som e of t he PoEAA pat t erns [ Fowler PoEAA] , som e
of which are focused on infrast ruct ure.
Again, t his descript ion can be used even if you decide t o go t he cust om rout e. Who knows, perhaps
t his descript ion will help one or t wo readers avoid creat ing t heir own cust om solut ions and inst ead
choose one of t he exist ing solut ions. I t hink t his is usually a good idea because it 's so m uch work
building your own full- fledged solut ion. Been t here, t ried t hat .
At t ribut es ( annot at ions m ight be a clearer t erm ; for exam ple, [MyAttribute] in C# )
Source code
As usual, each one com es wit h it s own cat ch. For inst ance, XML docum ent s suffer from XML hell. For
m ost developers, XML isn't a very product ive form at t o work wit h. I t 's oft en said t hat XML isn't for
people but for parsers, but it 's st ill t he case t hat t ools aren't up t o par here, so we oft en find
ourselves sit t ing t here edit ing huge XML docum ent s.
Anot her problem wit h t he XML docum ent s is t hat t hey are ext ernal t o t he Dom ain Model source code,
so it 's easy for t hem t o get out of synch wit h each ot her. And m any I DEs lack an underst anding of
t he sem ant ics of t he XML docum ent s, and t herefore refact oring won't work seam lessly.
At t ribut es are used for decorat ing t he Dom ain Model, so t he risk of get t ing out of synch wit h t he
Dom ain Model is som ewhat sm aller. A bigger problem in t his case is t hat t he Dom ain Model is slight ly
m ore coupled t o t he dat abase. I f you want t o use your Dom ain Model wit h t wo different dat abases,
t here is a great er risk t hat you'll have t o have t wo different versions of t he source code for t he
Dom ain Model if you use at t ribut es t han if you use som e ext ernal t ype of m et adat a. This m ight not
be a huge problem , but it can be. I t 's also harder t o get an overview of t he m apping in t his case, but
t ooling can help.
I t is debat able whet her providing t he m apping inform at ion in source code is a cat egory of it s own.
I t 's act ually j ust anot her docum ent form at . Anyway, I t hought having j ust t wo cat egories was a bit
cheap. The dist inct ion I 'm aft er here is t hat t he source code describes t he m apping inform at ion in a
procedural way rat her t han a declarat ive way. I also see t his opt ion as som et hing com ing bet ween
XML docum ent s and At t ribut es. The m et adat a is in t he source code and com piled, but it 's writ t en in a
way t hat you get it as an overview. To som e t his m eans " nice C# code inst ead of ugly XML." I can't
say t hat I t ot ally disagree. St ill, t his is an esot eric opt ion, not com m only used.
And as usual, it doesn't have t o be " one and only one." For exam ple, perhaps t he inform at ion is
provided as at t ribut es but can be overridden by XML inform at ion.
Are you wondering what t o describe in m et adat a? I t 's t he relat ionship bet ween t he Dom ain Model
and t he dat abase, but t o becom e concret e, we need an exam ple. We could t ake I dent it y Fields as an
exam ple.
Identity Field
An I dent it y Field [ Fowler PoEAA] of an ent it y holds on t o t he value of t he Prim ary Key of t he
underlying t able in t he dat abase. That 's how t he relat ionship bet ween t he ent it y inst ance and t he
t able row is handled.
When it com es t o new ent it ies, t he values for I dent it y Fields can be generat ed in at least four
different layers:
Consum er
Dat abase
O/ R Mapper
The first t wo are very sim ilar from t he O/ R Mapper's perspect ive. As t he O/ R Mapper sees it , t he
value is provided and out of t he cont rol of t he O/ R Mapper. The O/ R Mapper j ust has t o hope t hat t he
Consum er or Dom ain Model follows t he prot ocol. I f I m ay choose, I prefer t he Dom ain Model t o t he
Consum er . A problem here is for O/ R Mappers t hat use t he I dent it y Field value t o j udge if an inst ance
is new and should be insert ed or updat ed.
N ot e
This is a good exam ple of let t ing one t hing have t wo responsibilit ies. I t 's sim ple and it looks
good at first , but problem s are wait ing around t he corner.
The t hird opt ion is pret t y com m on, but it com es wit h som e sem ant ic problem s. I t m eans t hat t he
dat abase uses som et hing like I DENTI TY ( SQL Server) or Sequence ( Oracle) for set t ing t he value of
t he prim ary key when t he ent it y is persist ed. The problem is t hat t his is pret t y lat e in t he life cycle,
and t here can be problem s wit h t he set s where you have added t he Ent it y when t he ident it y value
changes.
Finally, t he O/ R Mapper it self can t ake care of t he generat ion of t he values of t he I dent it y Fields, and
t hat 's t he m ost convenient solut ion, at least for t he O/ R Mapper.
So what all t his com es down t o is t hat it m ight be a good idea t o keep t wo ident it ies around for
ent it ies. One is a nat ural ident it y, let 's call it Business I dent it y, t hat can get it s value at different
t im es in t he life cycle, not necessarily from t he very st art ( not all ent it ies have such an ident it y,
t hough) . I t 's also com m on t o have m ore t han one such ident ificat ion per class.
The second is t he I dent it y Field, which is m ore of a Persist ence I D or Dat abase I D. I f we com pare
t his wit h Relat ional dat abase t erm s, we get Table 8- 2.
Ta ble 8 - 2 . D om a in M ode l
Te r m s by Re la t ion a l
D a t a ba se Te r m s
D om a in Re la t ion a l D a t a ba se
M od e l
Business I D Alt ernat e Key
I dent it y Field Prim ary Key
This is act ually som et hing I need t o apply as an im plem ent at ion det ail in m y current Dom ain Model.
For exam ple, t he OrderNumber of Order is a Business I D rat her t han an I dent it y Field. That 's very
apparent in t he Equals() / HashCode() im plem ent at ions, which creat es problem s for set s, for exam ple.
Therefore, I also add Id fields whose values are generat ed by t he O/ R Mapper when t he newly
creat ed ent it y inst ance is associat ed wit h it s reposit ory. Aft er t hat , t he value won't change ever
again. I use Guid for t hose Id fields, as shown in t he diagram in Figure 8- 1 .
N ot e
The OrderNumber and CustomerNumber are st ill around. Also not e t hat t he reposit ories will
change slight ly because of t his. There will be new overloads for GetOrder() and
GetCustomer() .
This was a change t hat was very m uch needed for t he infrast ruct ure and is t herefore a t ypical
exam ple of a dist ract ion. I t was not anyt hing I did for t he sole purpose of j ust one specific O/ R
Mapper, but rat her as a sim plificat ion for m ore or less all O/ R Mappers.
N ot e
I t 's ironic. When we built Valhalla, we decided t hat using Guids should be com pulsory. We
weren't alt oget her happy wit h t hat decision because it put a " m ust " on t he developer, and
it was on our list for fut ure changes. Now when I 'm using ot her persist ence fram eworks,
I 'm free t o choose. Nevert heless, I st ill t hink it 's oft en a good idea t o use a Guid as t he
I dent it y Field.
Let 's get back t o t he m et adat a wit h anot her exam ple of what it cont ains.
Unlike t he I dent it y Fields, t his isn't about copied values in t he Dom ain Model. I nst ead, it 's j ust a
m et adat a t hing.
There are a variet y of relat ionships t hat can be used, and t he ones t hat are support ed by t he O/ R
Mappers can differ quit e a lot . To m y experience, m ost of t he t im e you will only use relat ively few
t ypes of relat ionships, but when you need som et hing m ore esot eric, you are glad if you find support
for it .
Embedded Value
One very im port ant way of bridging t he I m pedance Mism at ch is t he possibilit y of having coarse-
grained t ables and fine- grained classes in t he Dom ain Model. That 's where t he Em bedded Value
pat t ern [ Fowler PoEAA] com es in.
I t m eans t hat you should be able t o st ore a cust om er in a single Customers t able in t he dat abase, but
work wit h t he cust om er as a Customer obj ect and an Address obj ect in t he Dom ain Model. ( This
exam ple was very sim plist ic; in realit y, t he difference is oft en very large.)
I n t he sim plest form ( let 's call it level one) , you are able t o j ust describe t he relat ionship bet ween t he
Em bedded Value and t he colum ns in t he dat abase t able. Level t wo is where you m ight have t o writ e
assist ing code t hat helps out wit h t he t ranslat ion for advanced cases.
Inheritance Solutions
I nherit ance hierarchies in t he Dom ain Model don't have a perfect m at ch in t he relat ional dat abase
because inherit ance isn't a relat ional dat abase concept ( at least not before SQL: 1999, which few
dat abase product s support at t he t im e of t his writ ing) . Furt herm ore, inherit ance in t he Dom ain Model
is probably less com m only used t han m any would expect . That said, when you need t o use it , you
should be able t o support it wit h t he O/ R Mapper.
There are t hree different t ype solut ions t o t he problem . They are Single Table I nherit ance, Class
Table I nherit ance, and Concret e Table I nherit ance [ Fowler PoEAA] . I have chosen t o group t hem
t oget her because t hey are j ust different solut ions t o t he sam e problem .
The m ain difference is regarding how m any t ables are used for st oring an inherit ance hierarchy.
Assum e Person as base class and Student and Teacher as subclasses. Then t he different pat t erns will
lead t o t he following t ypical t ables, as shown in Table 8- 3. From t here you can probably easily
deduce what colum ns will go where.
Ta ble 8 - 3 . Pa t t e r n s for Pe r sist e n ce of
I n h e r it a n ce H ie r a r ch ie s a n d W h a t Ta ble s
Ar e N e e de d
Pa t t e r n Ta ble s in t h e D a t a ba se
Single Table I nherit ance People
I f t he O/ R Mapper only support s one of t hose, your flexibilit y in t he dat abase design has decreased
com pared t o if you had all t hree from which t o choose. You have t o decide whet her t hat 's im port ant
or not .
Identity Map
I n m y early at t em pt s t o creat e an O/ R Mapper, I first t hought I could skip t he I dent it y Map, but I
cam e t o t he conclusion t hat it get s t oo com plex and t here is t oo m uch responsibilit y for t he consum er
pr ogr am m er .
On t he ot her hand, a lot also depends on your Dom ain Model design. I f you never have relat ionships
bet ween ent it ies in different Aggregat es, t he need for t he I dent it y Map decreases. So DDD ideas,
such as sim plificat ion and decoupling wit hin t he Dom ain Model, m ake it easier t o live life wit hout an
I dent it y Map. That said, I st ill t hink it 's useful t o have an act ive I dent it y Map.
N ot e
I f you t hink about O/ R Mapping as a work horse t hat goes bet ween dat abase and obj ect ,
t he I dent it y Map m ight not be im port ant . But t hat 's not what we are t alking about here,
because t hen we would need t o do m ore work. Here we'd like t o j ust support t he Dom ain
Model wit h as sim ple ( or rat her as good) a solut ion as possible.
The I dent it y Map can be used for ot her t hings as well and not only for cont rolling t he obj ect graph
t he consum er knows about . For inst ance, it can be used for dealing wit h building M: N relat ionships of
obj ect s in t he Dom ain Model when reading from t he dat abase.
N ot e
M: N describes t he relat ionship regarding cardinalit y/ m ult iplicit y bet ween obj ect s by saying
it is m any- t o- m any. For exam ple, a house has m any people st aying t here, and at t he sam e
t im e every person can own several houses.
I t 's also oft en considered a cache for perform ance reasons, but as you know, I 'm not overly cache-
friendly, so I see t he I dent it y Map as a convenience for t he program m ing m odel rat her t han as a
m eans t o im prove perform ance.
Different O/ R Mappers differ regarding what " session" level you can/ m ust have t he I dent it y Map for.
I t can be m achine, a process, and/ or a session.
Anot her pat t ern oft en goes hand in hand wit h t he I dent it y Map. I 'm t hinking about Unit of Work.
Unit of Work
Most O/ R Mappers use, or at least have support for, t he Unit of Work pat t ern. The m ain difference is
really how t ransparent t he Unit of Work is for t he consum er. Where t he O/ R Mapper is of " runt im e-
Persist ence I gnorant " st yle, t he consum er m ight have t o t alk t o t he Unit of Work explicit ly for
regist ering a new inst ance t o be insert ed at next persist . Ot her O/ R Mappers are m ore t ransparent ,
but t hen you probably will have t o inst ant iat e wit h a fact ory supplied by t he O/ R Mapper. There are
pros and cons t o t hese approaches.
The " session" level m ight also differ for t he Unit of Work, at least in t heory, j ust as I said for t he
I dent it y Map.
I nst ead, as t he default st rat egy for m y Aggregat es, I use load eagerly. Or aggressively, or greedily,
or span loading, or pre- load, or what ever you like t o call it . I will from now on call it Eager Load.
Eager Load is pret t y m uch t he opposit e of Lazy Load; you load t he com plet e graph im m ediat ely
inst ead of delaying loading part s of t he graph unt il lat er.
As I see it , Eager Load goes hand in hand wit h Aggregat es [ Evans DDD] , at least as t he default
solut ion.
N ot e
To som e I m ight have put t oo m uch em phasis on Aggregat es when it com es t o reading
scenarios. I have been using Aggregat es as t he default load schem e and opt im ized when I
have found t he need for it .
Aft er all, Aggregat es are m ost im port ant for writ e scenarios. When seeing it t hat way,
adding a need for som et hing like a GetForWrite() t o t he prot ocol before m aking changes t o
an Aggregat e inst ance m ight m ake sense. The GetForWrite() would load everyt hing from
t he Aggregat e, possibly wit h read consist ency.
I f you do have a concept t hat is spanning m any inst ances and you want t o t reat it as a unit ,
Aggregat es is t he t hing, and it has im plicat ions.
I also t hink t he read- only/ writ able dist inct ion is oft en som et hing nice for users, who have t o
act ively choose t o m ove int o writ e m ode. Anot her good t hing about it is t hat t he user won't
st art m aking changes t o an already st ale obj ect when opt im ist ic concurrency cont rol is
used, which m eans t hat t he risk of collisions becom es sm aller. This approach also
t ranslat es nicely t o pessim ist ic concurrency cont rol schem es.
There are m any different im plem ent at ion variant s for Eager Load. I t 's oft en solved wit h OUTER JOINs
in SQL, and t he result set is t hen broken down t o t he graph. The ot her m ost com m on solut ion is t o
bat ch several SELECT st at em ent s aft er each ot her.
A com pet ent O/ R Mapper should support bot h Lazy Load and different Eager Load st rat egies, which
goes bot h for list s and single inst ances. I t m ay even apply for Lazy Loading groups of fields of a
single inst ance, even if I don't consider t hat crucial. Such a group of at t ribut es could always be
fact ored out int o a Value Obj ect inst ead, which would m ake a lot of sense in m ost sit uat ions. And
t hen we are back t o Lazy Load/ Eager Load of inst ances again.
Controlling Concurrency
As I 've said several t im es already, t he Aggregat e pat t ern is a good t ool for cont rolling concurrency.
Thanks t o it , I get t he unit I want t o use and work wit h as a single whole. Yet t hat 's not t he com plet e
solut ion. I also need t o avoid collisions or det ect whet her collisions have occurred so t hat we don't
get inconsist ent dat a ( and especially not wit hout being not ified) .
Coa r se - Gr a in e d Lock
I nst ead of locking on t he inst ance level, t his pat t ern suggest s locking a m ore coarse- grained
unit . We can, for exam ple, use it on t he Aggregat e root level, t hereby im plicit ly locking all t he
part s of t he Aggregat e.
This rem inds m e t hat I now want t o add som e versioning inform at ion t o t he Dom ain Model as a way
of st at ing where we need t o deal wit h cont rolling concurrency, for dealing wit h feat ure 4,
" Concurrency conflict det ect ion is im port ant ." I t hink m y Aggregat e root s should get a Version field
t o support Opt im ist ic Offline Lock. I t 's not an aut om at ic act ion. I nst ead, you add it where you need
it . You'll find t he change in Figure 8- 2 .
But t he whole discussion was pret t y abst ract . Som e exam ples would help m ake it m ore concret e.
That 's t he int ent ion of t he next chapt er. There we will use NHibernat e for t he exam ples.
Chapter 9. Putting NHibernate into Action
This chapt er is different from m ost of t he ot her chapt ers in t he book. I nst ead of being som ewhat
abst ract , t his one will be pret t y m uch hands- on. What we will do here is apply what was discussed in
Chapt er 8, " I nfrast ruct ure for Persist ence," by using NHibernat e [ NHibernat e] as an exam ple of a
Persist ence fram ework.
This chapt er st art s wit h an int roduct ion t o NHibernat e, including how t o get st art ed, how t o deal wit h
t he m apping, and what t he API looks like.
Then we will posit ion NHibernat e regarding t he classificat ions discussed in Chapt er 8, and we'll also
t ake a look at how NHibernat e im plem ent s t he infrast ruct ure pat t erns discussed in t he previous
chapt er.
This chapt er ends wit h a discussion of how NHibernat e fit s in t he big pict ure of DDD.
Why NHibernate?
You m ight wonder why I chose NHibernat e. Well, it 's not because NHibernat e is necessarily t he best
solut ion available. What is t he best car? That 's a silly quest ion, right ? I t 's always t he st andard
answer: " I t depends."
These are m y m ot ivat ions for choosing NHibernat e for t his chapt er:
Ja va h e r it a ge
NHibernat e is a port of t he popular Hibernat e [ Hibernat e] ; t herefore, m any people know it , and
t here are a great deal of books and lot s of ot her resources available for it . Furt herm ore, Obj ect
Relat ional Mapping is pret t y m at ure in Java- land, cont rary t o .NET- land.
Ope n sou r ce
NHibernat e is open source, and t hat m akes it very approachable and easy t o t ry.
I n no way is t his chapt er int ended t o be an exhaust ive guide t o NHibernat e. The purpose is j ust t o
m ake t he discussions in Chapt er 8 less abst ract . I will also avoid get t ing int o enum erat ing feat ure
aft er feat ure; t hat 's not very int erest ing, and t hat aspect of t his book wouldn't be current for m ore
t han a few weeks aft er writ ing t his chapt er.
A possible effect , alt hough not one of m y m ain int ent ions, m ight be t hat t he chapt er could easily be
writ t en for any ot her Persist ence Fram ework as well, t herefore m aking it a lit t le easier t o com pare
different solut ions. Let 's see if t hat happens. ( Hopefully t here will t hen be a separat e sect ion ent it led
" What else should have been included in t he com parison?" .)
I will also not be discussing NHibernat e in t he cont ext of an abst ract ion layer, such as NWorkspace
[ Nilsson Workspace] . The focus here will be on NHibernat e it self and it s API .
As I said, NHibernat e is a port from t he very popular O/ R Mapper in Java- land called Hibernat e,
originally creat ed by Gavin King [ Bauer/ King HiA] . The port is based on version 2.1 of Hibernat e,
which is considered a pret t y old version, but t he port doesn't st rict ly j ust m ove t he code base for t hat
part icular Hibernat e version. I nst ead, feat ures from lat er versions of Hibernat e as well as ot her
feat ures have been added here and t here.
NHibernat e ( and Hibernat e) is open source. As I writ e, NHibernat e is released as version 1.0. You can
download it from here: [ NHibernat e] .
The proof of t he pudding is in t he eat ing, so let 's see how NHibernat e is used.
Preparations
Let 's assum e you have a Dom ain Model and you now want t o writ e som e consum er code against t he
Dom ain Model.
N ot e
One m ore requirem ent is t hat you want t o m ake t he Dom ain Model persist ent . Therefore,
you also have a dat abase product , but don't t hink about t he dat abase schem a for t he
m om ent .
First , you need t o set a reference in t he consum er t o t he NHibernat e fram ework ( nam ely
nhibernat e.dll) . That wasn't t oo hard.
Then you need t o configure t he usage of NHibernat e in t he consum er of t he Dom ain Model. You can
eit her do t hat in code or in a .config file. Typically a .config file is used, so let 's assum e t hat . Som e
t hings t hat are configured can be what t he dat abase product in quest ion is, t he connect ion st ring t o
t he dat abase, and logging. You will find lot s of exam ples of .config files t o copy and past e from at t he
NHibernat e sit e, so I won't go int o det ail here, but I 'll j ust t ake it for grant ed t hat you have a suit able
.config file in place.
What you t hen t ry t o do j ust once per applicat ion execut ion is t o set up a SessionFactory. The reason
for not creat ing several is t hat t he cost is fairly high. The SessionFactory will analyze all m et adat a
and build up m em ory- based st ruct ures for t hat . As you m ight guess from it s nam e, t he
SessionFactory is t hen used for inst ant iat ing new inst ances t hat im plem ent ISession .
ISession is t he st ring t o pull in order t o get work done against t he dat abase and is also t he int erface
t hat you will int eract wit h all t he t im e from t he consum er perspect ive.
Next , it 's nice if you can use a helper for t he ISession m anagem ent . This can be done wit h different
levels of sophist icat ion, but here a sim ple at t em pt would be good enough for our purpose. I f we
assum e t hat our Dom ain Model is called ADDDP.Ordering.DomainModel, a sim plified helper called
NHConfig could look like t his:
static NHConfig()
{
Configuration config = new Configuration();
config.AddAssembly("ADDDP.Ordering.DomainModel");
_sessionFactory = config.BuildSessionFactory();
}
}
Making m ore assum pt ions, we are now working wit h a rich client applicat ion; t herefore, we t hink it 's
enough t o have a single ISession inst ance. At least , let 's st art t hat way. Then t he following code
m ight be suit able for t he st art of t he applicat ion, or perhaps for a single form :
_session = NHConfig.GetSessionFactory().OpenSession();
_session.Disconnect();
So when you want t o get an ISession t o act on, you can use t he following lit t le snippet over and over
again:
_session.Reconnect();
//Do stuff...
_session.Disconnect();
And finally, when t he applicat ion t erm inat es ( or t he form is closed, depending upon your chosen
st rat egy) , you close t he ISession like t his:
_session.Close();
N ot e
One ISession per form or one per applicat ion are j ust t wo of several possible st rat egies.
OK, t hat was all good fun, but it was com plet ely useless considering what we accom plished in t he
dat abase. Opening and closing ISessions is not enough, and we need t o persist changes t o t he
dat abase as well. For t hat t o be possible, we need t o m ake som e m ore preparat ions.
So far, we haven't creat ed a schem a in t he dat abase, so we are pret t y free t o work as we like. The
only t hing we have is t he Dom ain Model. We can use t ools for creat ing t he m apping inform at ion
and/ or t he dat abase schem a, but t he only t hing t hat is im port ant for t his int roduct ion is showing
what a m apping file could look like, given a cert ain Dom ain Model Ent it y and dat abase t able. Let 's
pick a sim ple Ent it y from our Dom ain Model. I t hink Customer fit s t he requirem ent s pret t y well. You
find t he Ent it y and it s Value Obj ect s [ Evans DDD] in Figure 9- 1 .
I n t he dat abase, bot h t he Customer and t he Address are probably st ored in a single t able. The DDL for
t hose t wo classes could look like t his:
N ot e
I t felt st range writ ing t hat piece regarding t he Town and Country at least . I would probably
fact or t hem out in a real sit uat ion, but t hat 's not im port ant for t his discussion.
The Reference Persons t able is m issing from t he DDL above, but you can probably deduce it
from Figure 9- 1 .
Then t he m issing piece, which is t he int erest ing piece here, is t he m apping file.
N ot e
Again, please not e t hat I never said you had t o creat e t he dat abase t able before t he
m apping file. The order of how you work is up t o you.
I f I can choose, I prefer t o st art wit h t he Dom ain Model, t hen writ e t he m apping files, and
from t hat aut om at ically generat e t he dat abase from t he m apping inform at ion. To
accom plish t hat , you can use t he following snippet :
I n m y experience, I oft en want t o add som e m ore const raint s t o t he dat abase, on t op of
what can be described in t he m apping file, and I do t hat by writ ing som e cust om code. A bit
raw, but it solves t he problem .
Wit h t hat in place, I can regenerat e t he developm ent dat abase as oft en as I like, even
before every t est execut ion ( if it 's not becom ing t oo slow) .
Let 's t ake it piece by piece. First , you need t o describe t he docum ent , som et hing like t his for
Customer.hbm.xml:
I provided t he namespace and assembly t ags here, so t he rest of t he m apping inform at ion can be
expressed less verbosely because t hat inform at ion won't have t o be repeat ed.
N ot e
I f you want t he m et adat a t o be wit hin t he assem bly, don't forget t o set t he propert y of t he
XML file t o be an Em bedded Resource.
Then you describe t he nam e of t he class for t he Ent it y and t he nam e of t he t able. For exam ple, like
t his:
Then you describe t he I dent it y Field [ Fowler PoEAA] , not only t he nam e in t he class and t he t able ( in
t he upcom ing exam ple t he propert y nam e and t he colum n nam e are t he sam e, so t he column t ag
isn't needed) , but also t he st rat egy t hat is used for creat ing a new value. I t could look like t his:
I n t his specific exam ple, a guid is generat ed by NHibernat e when a new inst ance is associat ed wit h
t he ISession .
Then t he sim ple propert ies are m apped, such as Name, like t his:
Norm ally NHibernat e can underst and what t ype t o use for t he propert ies by invest igat ing t he class by
reflect ion, but in t he case of st rings, I provide a specific type t o get VARCHAR inst ead of NVARCHAR if I
aut om at ically generat e t he schem a from t he m apping inform at ion. The length is also used for
generat ing DDL from t he m apping inform at ion, but because I like m oving along t hat rout e, I t ake t he
ext ra work of adding t hat inform at ion.
N ot e
I nform at ion like t his is also very useful for your cust om validat ion.
NHibernat e also m akes it possible t o m ap not only propert ies, but fields as well. As a m at t er of fact ,
Customer.Name isn't a propert y ( which NHibernat e considers t he default and t herefore doesn't have t o
be expressed) but a public field, so I need t o add an access- t ag like t his t o get it all correct ly:
And it works for all accessor t ypes, even privat e, so you are pret t y free t o choose a st rat egy. For
exam ple, you oft en expose som et hing slight ly different in your propert y get t o what is st ored, or you
do som e int ercept ion on get / set . I n t hese cases, you need t o m ap, for exam ple, t he privat e field
inst ead.
<property name="_customerNumber"
access="field" not-null="true" />
Assum ing t hat you do m ap privat e fields, it 's a good idea t o use nam ing rules. This is so your query
code doesn't have t o be writ t en t o use t he nam e of t he privat e fields ( for exam ple, _customerNumber) ,
but rat her ordinary, nice propert y nam es ( like CustomerNumber) . I t could look like t his:
<property name="CustomerNumber"
access="field.camelcase-underscore" not-null="true" />
N ot e
Sure, t here are pit falls here ( as always) , but I usually find it good enough t o m ap privat e
fields inst ead of int roducing separat e privat e propert ies purely for t he aspect of persist ence.
I f it works, fine. I f not , I can always change it when/ if t he need arises.
This is t he t opic of a heat ed debat e, t hough. Many prefer t o m ap t o persist ency- specific
privat e propert ies inst ead.
Finally, ( well, it could be done before t he sim ple propert ies j ust as wellit j ust happened t o be like t his
here) we need t o describe how t he used Value Obj ect is m apped t o t he single Customers t able. I t
could look like t his in t he m apping file for Customer ( t he Address class won't have any m apping
inform at ion of it s own because it 's a Value Obj ect and not an Ent it y) :
<property name="PostalCode"
access="field.camelcase-underscore"
type="AnsiString" length="10" not-null="true" />
<property name="LastName"
access="field.camelcase-underscore" not-null="true"/>
</composite-element>
</bag>
Let 's t ake anot her exam ple. I n earlier chapt ers I sket ched t hat OrderLine should be a Value Obj ect . I f
so, t he m apping in t he Order regarding OrderLine m ight look sim ilar t o what was j ust shown.
But it 's not t oo m uch of a t wist t o lat er on find out t hat t he OrderLine m ight have a list of it s own,
such as a list of not es. I f so, t hat 's a good reason for t ransform ing OrderLine int o an Ent it y inst ead.
That is, it 's t ransform ed t o an Ent it y for t echnical and infrast ruct ural reasons rat her t han concept ual.
We have t o be pragm at ic. I f so, t he m apping inform at ion in Order changes t o t his inst ead ( and
OrderLine will have m apping inform at ion of it s own) :
For t he sake of t he exam ple, let 's also assum e t hat we want t he OrderLine t o have a field point ing
back t o t he Order ( despit e what I have said earlier about t rying t o use bidirect ionalit y sparingly) . So
in t he OrderLine XML file t hat was added when OrderLine was t ransform ed t o an Ent it y, t here is now
a m any- t o- one sect ion like t his:
<many-to-one
name="Order"
access="field.camelcase-underscore"
class="Order"
column="OrderId" />
An im port ant point here is t hat you are on your own regarding t he bidirect ionalit y. So in t he
AddOrderLine() m et hod of Order, it could now look like t his:
//Order
public void AddOrderLine(OrderLine ol)
{
_orderLines.Add(ol);
ol.Order = this;
}
Finally, t his also m eans t hat OrderLine will have an I dent it y Field of it s own, whet her it 's used or not
in t he Dom ain Model.
I f you fill in t he open sect ions in t he files, we are ready t o m ake t he consum er code m uch m ore
int er est ing.
CRUD-C: Create
To creat e a new inst ance ( or row) in t he dat abase, you j ust inst ant iat e a new Customer , set it s
propert ies, and call t he m et hods you want . When you're ready t o save it , you use t he snippet we
t alked about before for reconnect ing an ISession . Then you associat e t he inst ance wit h t he ISession ,
and you t hen call Flush() on t he ISession t o st ore all changes.
//A consumer
Customer c = new Customer();
c.Name = "Volvo";
_session.Reconnect();
_session.Save(c);
_session.Flush();
_session.Disconnect();
I n t his case, I was specific and t old t he ISession t hat it should lead t o an INSERT ( because I called
Save()) . I could have called SaveOrUpdate() inst ead, and t hen NHibernat e would have decided on it s
own whet her it should be an INSERT or an UPDATE. The inform at ion used in t hat case is t he value of
t he I dent it y Field, and it 's com pared t o what you indicat ed for unsaved-value in t he m apping file
( " 00000000-0000-0000-0000-000000000000" in t he case of Guids) . I f t he I dent it y Field m at ches t he
unsaved-value , it 's t im e for an INSERT; ot herwise, it would be an UPDATE.
I t is also im port ant point ing out t hat t he INSERT is delayed and won't happen when you say Save(),
but rat her when you say Flush(). The reason for t his is t hat you should be able t o m ake m any
changes in t he consum er and t hen get t hem all persist ed t oget her and as lat e as possible.
Did we succeed in writ ing t o t he dat abase? The easiest way t o check t hat is t o read t he inst ance
back, so let 's do t hat .
The second exam ple is t o read one inst ance ( row in t he dat abase) by it s I dent it y Field. From now on,
let 's assum e t hat we use t he ordinary reconnect / disconnect snippet and j ust focus on t he specific
code inst ead.
As usual, you t alk t o t he ISession inst ance. You call Load()/ Get() and say what t ype you are looking
for and it s I dent it y Field value. I t could go like t his:
Customer c = (Customer)_session.Load(typeof(Customer), theId);
But beware. This didn't necessarily prove anyt hing if you didn't close t he ISession since t he last
Flush(), because t he ISession will provide you wit h t he inst ance from t he I dent it y Map [ Fowler
PoEAA] when you call Load()/ Get() inst ead of going t o t he dat abase. What you can do t o force a
dat abase j um p ( inst ead of opening a new ISession ) is t o call Evict() on t he inst ance by saying t hat
you don't want t he I dent it y Map t o keep t rack of t he inst ance any longer. I t could look like t his:
_session.Evict(customer);
That was good, but what if you don't know t he ident it y value? Perhaps you only know part of t he
nam e of t he cust om er and want t o fet ch all inst ances t hat m at ch t hat nam e pat t ern. This t akes us
over t o t he next exam ple, t hat of read m any.
There are t wo specific languages for querying in NHibernat e. But we are going t o use Hibernat e
Query Language ( HQL) for t his exam ple. I t 's pret t y sim ilar t o SQL, yet different . I n order t o fet ch all
cust om ers wit h a nam e t hat st art s wit h " Vol" , t he code could look like t his:
//A consumer
string hql = "select from Customer where Name like 'Vol%'";
IList result = _session.CreateQuery(hql).List();
So in t he result, you will get a list of customers wit h nam es t hat st art wit h " Vol" , j ust as you
expect ed.
Norm ally, you wouldn't writ e code as st at ic as t his and would use param et erizat ion inst ead. But
again, I j ust want t o show very sim ple code here in order t o give you a quick feeling of how it could
be done.
CRUD-U: Update
We found lot s of inst ances wit h nam es st art ing wit h " Vol" . We saw t hat we needed t o m ake som e
changes t o one of t hem . We m ade t he changes t o t he propert ies of t hat inst ance, and we are now
ready t o persist t he changes. Again, we can use SaveOrUpdate(), but here we know t hat it 's a
quest ion of an UPDATE, so we use Update() like t his inst ead ( cont inuing from t he previous snippet ) :
As a m at t er of fact , because we found t he inst ance via a read, we didn't have t o m ake t he Update()
call at all. The inst ance was already associat ed wit h t he ISession and so it would have been t aken
care of anyway at Flush() t im e.
CRUD-D: Delete
One of t he found inst ances was wrong, so it should be delet ed. That could be done like t his:
//A consumer
Customer c3 = (Customer) result[1];
_session.Delete(c3);
_session.Flush();
Transactions
Before we leave t he API exam ple, I t hink it 's im port ant t o have a look at how t ransact ions can be
cont rolled when NHibernat e is used, because t ransact ions are used a great deal.
I f you are used t o ot her ways of m anual t ransact ion cont rol, it 's easy t o underst and how it 's done
wit h NHibernat e as well. What you do is grab an ITransaction inst ance, which you can t hen use t o
m ake eit her a Commit() or Rollback() ( Commit() will by default aut om at ically do a Flush()) . The
com plet e snippet could look like t his:
//A consumer
ITransaction tx = _session.BeginTransaction();
try
{
tx.Commit();
}
catch (Exception ex)
{
tx.Rollback();
...
N ot e
Suddenly I used except ion handling in t he code snippet . The reason is t hat Rollback()
m akes m ost sense t hen. Of course, except ion handling should be used for t he ot her
snippet s as well, but here in t he book it would m ost ly be a dist ract ion.
I t hink t hat finishes an ext rem ely short int roduct ion. See t he NHibernat e sit e [ NHibernat e] for m uch
m ore inform at ion on how t o get st art ed.
We now m ove on t o posit ioning t he chosen exam ple of a Persist ence Fram ework wit h t he st ruct ure
t hat was present ed in Chapt er 8. First , let 's t ake a look at t he overall requirem ent s.
Requirements of the Persistence Infrastructure
As I said, before we go int o t he det ails, I t hink it 's fit t ing t o discuss t he overview requirem ent s t hat
were defined in Chapt er 8. I 'm t hinking about Persist ent I gnorant ( PI ) level, support ed life cycle, and
dat abase t reat m ent .
Anot her exam ple of such a price is t hat NHibernat e won't help by t elling you whet her or not your
inst ances are dirt y by using an IsDirty propert y or som et hing sim ilar. ( NHibernat e will decide which
inst ances should be persist ed at persist t im e, but t hat 's not what I 'm referring t o here.)
These are j ust t wo exam ples of t he high level of PI com ing at a price. Anot her such cost is
perform ance, which m ight becom e problem at ic because of t he high PI .
There are also som e t hings t hat you have t o do wit h your Dom ain Model classes in order t o m ake it
possible for t hem t o becom e persist ed by NHibernat e at all. Here are som e t ypical exam ples:
The m ost int ent ion revealing const ruct ion if you need a read- only propert y in a class is t o use
t he readonly keyword, but t hen NHibernat e can't set t he field by reflect ion. Therefore, it has t o
be convert ed t o privat e field + a public get propert y.
So even if you don't need one in your Dom ain Model, you have t o have a const ruct or wit hout
any param et ers. The const ruct or can be int ernal and even privat e, but you st ill need t o add it .
I oft en don't see t hat as a very bad t hing anyway. I m ean, I like t o use I List , for exam ple,
inst ead of a CustomerList class. Generics, of course, is also very good.
( Unfort unat ely, at t he t im e of writ ing, generics isn't well support ed by NHibernat e, so you have
t o go t hrough som e j um ps here and t here.)
Norm ally, you would give I dent it y Fields default values, such as Guid.NewGuid(), but t hat 's not a
good idea if it 's possible t o avoid it when you use NHibernat e because NHibernat e uses t he
I dent it y Field values t o det erm ine if it should be an UPDATE or INSERT. I f you provide a default
value ( unless you set it t o unsaved-value , of course) , NHibernat e will always expect UPDATE if
you don't explicit ly provide guidance. ( You can also use t he version t ag for signaling
INSERT/ UPDATE.)
This isn't t oo bad, but t here are st ill som e t hings t hat lower t he PI level. To be honest , I don't know
how t o avoid t he problem when using t he readonly st at em ent , so I guess it won't be any bet t er in
ot her solut ions unless t hey m anipulat e your code.
Certain Desirable Features for the Life Cycle of the Persistent Entities
I n Chapt er 5, " Moving Furt her wit h Dom ain- Driven Design," ( and it 's repeat ed in Chapt er 8) I t alked
about t he sim ple life cycle I needed t o support for m y Dom ain Model inst ances. The sum m ary is
repeat ed here again in Table 9- 1.
This is easily m apped t o NHibernat e and is t herefore easily support ed. Let 's add one m ore colum n for
m apping Table 9- 1 t o NHibernat e. Then it looks as in Table 9- 2:
As you saw in Table 9- 2, I added one m ore row about how t o free t he I dent it y Map/ Unit of Work of
an inst ance ( or all inst ances) . That wasn't som et hing I envisioned before t hat I would need, but in
realit y I run int o sit uat ions when t his is needed, such as when " m oving" inst ances bet ween sessions.
Let 's conclude by st at ing t hat t here's not m uch m ore t o say about t his right now.
N ot e
There are loads of det ails, of course, but we are st aying at a bird's eye view here.
I know, you t hink I was t hinking t oo m uch about NHibernat e when I wrot e t hat sect ion in Chapt er 5,
don't you? That m ay be so, but you will find t hat m ost ot her O/ R Mappers support t his as well.
I f t he previous requirem ent ( t he life cycle) was " easy," t his one is m uch harder and will vary quit e a
lot bet ween different O/ R Mappers.
I t 's easy t o be crit ical about how NHibernat e deals wit h t he dat abase in cert ain sit uat ions and t hink
t hat you could do bet t er m anually. I have said over and over again t hat I t hink it m akes sense not t o
opt im ize every call t o t he dat abase because it m ost oft en doesn't m at t er m uch anyway. I nst ead, you
can always go t o t he code and opt im ize t he places where it really is needed. St ill, t he requirem ent is
set because I don't want t o opt im ize at all m ore t han is necessary, and when I opt im ize I don't want
t o have t o go t o ordinary SQL m ore t han is absolut ely necessary.
N ot e
I hope t his didn't sound like " avoid SQL at any price" or " use only O/ R Mappers t hat are
ext rem ely funct ion- rich."
SQL is great , and I like using it when t hat 's t he best solut ion.
So what are t he problem areas t o look out for regarding NHibernat e? An obvious one I t hink is t hat
when we m ove processing out from t he dat abase, for exam ple, we avoid having logic in st ored
procedures ( and act ually avoid st ored procedures alt oget her) . This is int ent ional because we want t o
achieve a bet t er m aint enance st ory by having all t he logic in t he Dom ain Model and it s nearby
surroundings. ( And again, when we really have t o, we can opt im ize t he rare places wit h st ored
procedures.)
Anot her t ypical exam ple of a problem area is when we do processing t hat is norm ally set - based, such
as increasing a colum n value of all inst ances of a cert ain class ( for exam ple, set t ing t he Price of all
product s t o Price = Price * 1.1) . Doing t hat in SQL is perfect ly norm al and recom m ended. Wit h
NHibernat e, t he set s will be single row set s regarding how it 's processed against t he dat abase. This
can also be a good t hing, because t he validat ion rules are m ost oft en inst ance- based, and we want
t hem t o be processed for large updat es, t oo. However, t he cost m ight be t oo high.
A t hird problem is t hat t he consum er of t he Dom ain Model probably doesn't care about t he dat abase
at all. He or she m ight creat e a huge load on t he back- end wit hout realizing it or act ually be alm ost
incapable of realizing it . That 's one drawback t o t he nice isolat ion and abst ract ion t he Dom ain Model
provides.
A fourt h problem is t hat of select ive updat es if a cert ain crit erion is m et , such as
A fift h is t he " reading way t oo m uch" problem when t oo m any com plex t ypes are read even t hough
j ust a t iny am ount of inform at ion is really needed. This is especially com m on if you haven't used a
som ewhat careful Aggregat e design and haven't used Lazy Load.
Yet anot her classic problem is t hat of n+ 1 select s. Assum e you fet ch all Orders in t he dat abase and
t hat OrderLines are Lazy Loaded. Then you t ouch each Order and it s OrderLines. Then t here will be a
new SELECT issued for each Order's OrderLines. I f you don't use Lazy Load, t he problem will be
sm aller, but t hen you run t he risk of get t ing int o t he problem j ust m ent ioned of fet ching t oo m uch in
som e scenarios.
Neit her of t hese exam ples is specific t o NHibernat e, but t hey are pret t y norm al for O/ R Mappers. An
exam ple of a problem t hat I t hink is m ore relat ed t o NHibernat e is t hat of IDENTITY or sequences.
Using such an I dent it y Field leads t o earlier INSERTs t o t he dat abase t han what you probably expect .
All in all, it 's m y opinion t hat NHibernat e does a good j ob of fulfilling t hose overview requirem ent s,
especially if you are happy wit h t he nat ure of how O/ R Mappers t ypically work and t he t radeoffs t hat
are involved!
Classification
OK, I have int roduced NHibernat e, and we have had a general look at how it deals wit h t he
requirem ent s. We are now ready t o invest igat e NHibernat e furt her, and t his t im e wit h t he help of t he
disposit ion used in Chapt er 8. But inst ead of discussing t he alt ernat ives in an abst ract way, I will now
posit ion NHibernat e as being an exam ple of t he alt ernat ives t o each cat egory and also discuss how
t he solut ion looks in a lit t le bit m ore det ail.
First up is t he Dom ain Model st yle t hat NHibernat e expect s us t o use. We have already t ouched upon
t his t opic, but let 's say a few m ore words about it .
PI
I nher it ance
Life isn't black and whit e, but in t his case I t hink t he choice is easy. The way I see it , NHibernat e
gives us a high level of PI . You don't have t o inherit from cert ain base classes, and you don't have t o
im plem ent cert ain int erfaces. You don't even have t o reference any NHibernat e assem blies in your
Dom ain Model.
Mapper Style
When it com es t o Mapper st yle, I said t hat Met adat a- based m appings are oft en exem plified in t wo
different ways:
Again, it 's pret t y easy t o posit ion NHibernat e because it 's a t ypical exam ple of a Fram ework/ reflect ive
solut ion. Sure, t here is som e code generat ion support in NHibernat e, but t hat is t ypically used when
generat ing one of t he t hree part s of t he Dom ain Model, Met adat a or dat abase schem a by looking at
one ( or t wo) of t he ot her part s. For exam ple, assum e you have t he m et adat afrom t hat you can
creat e dat abase schem a. That 's not what I m eant by code generat ion as t he m apper st yle. The
m apper st yle is defined by how t he m apping is done at runt im e, and for t hat , NHibernat e doesn't use
code generat ion.
One except ion t o t he rule is when we look at what is done t o support Lazy Load [ Fowler PoEAA] .
Then at runt im e NHibernat e will swap, for exam ple, your used list class for som e proxy inst ead. I n
order for t his t o work, you have t o expose t he list as an int erface and not as a concret e class.
N ot e
Not e t hat I didn't m ent ion t he usage of int erfaces as a m eans of lowering PI level earlier in
t he chapt er. The reason for t his decision was t hat Lazy Loading is a feat ure and not
som et hing you have t o use.
The opinion on t hat varies, but as I see it , Lazy Loading is an opt im izat ion t echnique and
not som et hing you have t o use all t he t im e.
I s it good or bad t hat NHibernat e is using t he Fram ework/ reflect ive approach? I really believe t hat it
is m ost ly a good t hing when it com es t o O/ R Mappers.
Starting Point
When you are working wit h a cert ain O/ R Mapper, you can oft en choose one or m ore st art ing point s
from t he following list :
NHibernat e allows you t o st art wit h any of t hese, and it 's not j ust a hack, but it 's support ed by
design. Wit h t hat said, if you have t o st art from a legacy dat abase schem a t hat you aren't allowed t o
change, having a look at som et hing like iBATI S [ iBATI S] m ight be a good idea.
API Focus
The API focus com es in one of t wo alt ernat ives:
Tables
But I said t hat t his doesn't really apply when it com es t o t he m ost com m on O/ R Mappers because
t heir m ain purpose is t o provide a Dom ain Model view of t he world while using a Relat ional dat abase
for t he persist ence. So t he answer here is easy. NHibernat e uses t he Dom ain Model as t he API focus.
NHibernat e has im plem ent at ions for bot h of t hese st yles, called HQL and Crit eria obj ect s in
NHibernat e. I have already given an exam ple of what an HQL query could look like when searching
for all Customers whose nam es st art wit h " Vol" . I f I want t o express t he sam e t hing wit h Crit eria
obj ect s, it could look like t his:
//A consumer
IList result = _session.CreateCriteria(typeof(Customer))
.Add(Expression.Like("Name", "Vol%"))
.List();
I n t he previous snippet , you also saw an exam ple of chaining of several m et hod calls. I t works
because Add() ret urns an ICriteria j ust as CreateCriteria(). This helps t o m ake t he usage of
crit eria queries slight ly m ore readable.
N ot e
I n t his chapt er, I 'm j ust t ouching briefly on how different t hings are accom plished wit h
NHibernat e, but in no ot her case is m y briefness so apparent as when it com es t o t he huge
t opic of querying. Please refer t o [ Bauer/ King HiA] for m ore inform at ion.
I n Chapt er 8, I also m ent ioned t hat it 's good t o have t he possibilit y t o go over t o raw SQL as a last
resort , t ypically t o solve perform ance problem s, and you can do t hat wit h NHibernat e. Bot h variant s
are support ed so t hat you can get Ent it ies back and you can get t o t he raw connect ion and do
what ever you want t o.
NHibernat e also provides som et hing in bet ween t he ordinary query m echanism s and raw SQL t hat
t hey call report queries ( also som et im es called flat t ening queries) . I t can look like t his in act ion:
//A consumer
string hql = "select new CustomerSnapshot(c.Id, c.Name) " +
"from Customer c";
IList result = _session.CreateQuery(hql).List();
So here t he result won't have Customer inst ances, but CustomerSnapshot inst ances. For it t o work, you
need t o provide a m at ching const ruct or on t he Value Obj ect ( CustomerSnapshot in t he previous case)
and t o m ent ion CustomerSnapshot in a m apping file via an import direct ive like t his:
Not e t hat CustomerSnapshot j ust holds on t o flat dat a ( t ypically read- only) according t o NHibernat e.
I dent it ies won't be t racked in t he I dent it y Map, and no changes will be t racked in t he Unit of Work.
Talking about querying, t hat 's act ually exact ly what t he next cat egory is about as well.
Advanced Database Support
The exam ples I provided in Chapt er 8 for " advanced dat abase support " ( not advanced for a dat abase
guy, but perhaps for an obj ect guy) follow:
Aggregat es
Ordering
Group by
Scalar queries
All four of t hese are support ed by bot h HQL and Crit eria obj ect s in NHibernat e. Let 's t ake an exam ple
of each, beginning wit h an aggregat e query finding t he num ber of inst ances of Customer . I n HQL, it
could look like t his:
//A consumer
string hql = "select count(*) from Customer";
int numberOfCustomers =
(int)_session.CreateQuery(hql).UniqueResult();
N ot e
Again, not e t hat it 's not t able nam es but classes t hat are used in HQL.
The second exam ple, t o order t he result set in t he dat abase so t hat it doesn't have t o be done in t he
Dom ain Model ( which m ight oft en be a good t hing) , could look like t his in HQL. I n t his case we are
ordering t he fet ch operat ion of all customers by Name.
Group by is m ost ly used for report ing purposes, but you could st ill use it in your applicat ion. Here I 'm
grouping on Name and count ing how m any inst ances for each nam e ( a bit t wist ed, but it shows t he
synt ax) :
//A consumer
string hql =
"select c.Name, count(*) from Customer c group by c.Name";
IList result = _session.CreateQuery(hql).List();
Finally, an exam ple of a scalar query could be t o only fet ch t he Name of t he Customers whose nam es
st art wit h " Vol" ( which by now you'll recognize as m y favorit e crit erion) , but as a m at t er of fact you
j ust saw anot her exam ple when I execut ed t he group by query earlier. To get t o t he values in t he
result , t he IList called result cont ains a list of object arrays. Here's a snippet for cont inuing from
t he previous exam ple, list ing t he nam es and t he num ber of inst ances for each nam e:
Scalar queries are especially useful in sit uat ions where you find it t oo expensive t o fet ch com plet e
Customer inst ances but want a m ore light weight result , and you don't want t o define a class.
Of course, t he result won't be t ypesafe in t his case, but you could use a variat ion, nam ely t he one I
t alked about earlier in t his chapt er called report query ( or a flat t ening query) .
An alt ernat ive is t o provide m apping variat ions, but t hen I t hink it 's an even bigger t hing you have
done. That is obviously violat ing t he Aggregat es because you are m aking it possible t o updat e t he
inst ances wit hout m aking it m andat ory t o load t he com plet e Aggregat es. Warning bells should go off.
Let 's end t his sect ion wit h som et hing t hat m ight be " obvious" t o you if you com e from an obj ect
background, but m ight look like m agic if you com e from an SQL background.
The query it self was very sim ple, but not e t hat dat a is fet ched from t wo t ables, and t here is no
m ent ion about t hat in t he from clause ( t hat is, t here is no j oin) . Of course, t he m apping inform at ion
is used t o det erm ine what needs t o be done at execut ion t im e wit h t he HQL query.
Other Functionality
Finally, we have a m ix of ot her funct ionalit y t o check for NHibernat e.
W h a t ba ck e n ds a r e su ppor t e d?
This is a t ypical exam ple of som et hing t hat could becom e a long and t edious feat ure
enum erat ion, so I won't go int o det ail here. Let 's j ust say t hat NHibernat e support s several
different dat abases ( m ost of t he m aj or com m ercial and open source dat abases) . Check t he sit e
[ NHibernat e] for current inform at ion. You can also writ e your own plugin if you m iss t he
dat abase you need t o work wit h.
N ot j u st a n O/ R M a ppe r
NHibernat e is pret t y focused on being an O/ R Mapper and not hing else. The philosophy is t o do
one t hing and do it well.
N ot e
Of course, NHibernat e does ot her t hings as well, but t hose ot her t hings are j ust not t he
focus. And t hey are not t oo m any or t oo big eit her.
Adva n ce d ca ch in g
Advanced caching is one area where NHibernat e isn't really up t o par when com pared t o
Hibernat e, but I t hink it 's rapidly becom ing bet t er. On t he ot her hand, t o m e t hat 's not usually a
big deal. There are m any problem s wit h second- level caching, so t hat opt ion is oft en ruled out .
Support for m anual t ransact ion cont rol is pret t y good in NHibernat e. There are sit uat ions where
you m ight be t aken by surprise if you don't wat ch out ( for inst ance, when you execut e a query
in t he m iddle of a t ransact ion, NHibernat e will t hen Flush() changes t o t he dat abase before
execut ing t he query) . That 's a t radeoff bet ween querying not going " t hrough" t he cache or
ordinary t ransact ion cont rol. The good news is t hat it 's cont rollable by your code.
To bind t his t o Chapt er 8, t he t ypical way of dealing wit h t ransact ions in NHibernat e is " m anual
cont rol."
N ot e
On t op of t hat , you can also build som et hing t hat uses any of t he m ore aut om at ic
approaches m ent ioned in Chapt er 8.
Ope n sou r ce
As I 've said already, NHibernat e is an open source proj ect , so you can invest igat e t he source
code and even build your own branch.
Ve r sion ( ge n e r a t ion )
I t 's hard t o decide what version NHibernat e is in. At t he t im e of writ ing, it 's called version 1 by
t he t eam building it , but at t he sam e t im e, I would say t hat t he qualit y is higher t han wit h
t ypical first versions. NHibernat e is also a port from Hibernat e, which is second generat ion or
act ually t hird now, but t hat 's not reflect ed in NHibernat e. Anyway, let 's call it generat ion 1.
Let 's have a look at how NHibernat e posit ions it self in t he classificat ions from a t ot ally different
angle: t he infrast ruct ure pat t erns angle.
Another Classification: Infrastructure Patterns
Wit hout furt her ado, let 's get st art ed wit h t ype of m et adat a.
At t ribut es
Source code
This cat egory was sim ple regarding NHibernat e because it s m et adat a is t ypically XML docum ent s.
You can describe t he m et adat a in source code as well in t he works, but t hat 's not t he m ainst ream
t hing t o do at all.
There are at t ribut e- based approaches as well, but t hey generat e m et adat a as XML docum ent s.
Identity Field
I have already t ouched on t he m at t er of how you deal wit h I dent it y Fields in NHibernat e, but I 'd like
t o go a lit t le deeper. Earlier I showed how t o m ap an I dent it y Field t hat is of t he Guid t ype. Let 's t ake
a look at t he Product Ent it y, which has an int for t he I dent it y Field, and t he value is generat ed wit h
an IDENTITY ( aut o increm ent ing colum n) in t he dat abase. I t could t hen look like t his:
As I said in Chapt er 8 , when it com es t o new ent it ies, t he values for I dent it y Fields can be generat ed
in at least four different layers:
Consum er
Dat abase
O/ R Mapper
I n t he case of t he guid, you can generat e it in all t he layers, but it 's recom m ended t hat you do it in
t he O/ R Mapper. I n t he exam ple wit h IDENTITY j ust shown, t he value is generat ed in t he dat abase,
and t hat act ually affect s t he program m ing m odel a lot . First , t here will be a dat abase j um p earlier
t han you expect . Second, t here m ight be an INSERT j ust t o grab t he IDENTITY value. Bot h exam ples
are som et hing I consider t o be problem s, and t herefore I don't like t o use IDENTITY s m ore t han is
necessary.
As a m at t er of fact , Guid s are oft en a very nice solut ion. But perhaps som e of you have read m y
art icle about a possible cost of INSERT s when you use Guid s as prim ary keys [ Nilsson COMB] . The
problem is t hat t he INSERT t hroughput m ight be m any t im es lower for t ables wit h Guid s for prim ary
keys t han if you use int s. That 's not a problem you will t ypically get , but it m ight com e and bit e you
if you have very large t ables and a high INSERT load. I suggest ed a solut ion t o t he problem in t he
art icle I called " COMB." I t 's basically a Guid , but kind of a sequent ial one. I was very surprised t o see
t hat NHibernat e added support for COMB in a specific alpha version. To use t he COMB generat or, t he
m et adat a could look like t his ( t he only difference is t hat generat or is guid.comb and not j ust guid ) :
I t is easiest for you if you let NHibernat e generat e t he Guids for you, but t hat 's not always possible,
of course. Som et im es you m ust use assigned I dent it y Fields inst ead, which m akes it quit e a bit
harder. For exam ple, you can't let NHibernat e det erm ine using UPDATE or INSERT by looking at
unsaved-value . I nst ead, you will t ypically t ell NHibernat e what t o do wit h explicit calls t o Save() or
Update() inst ead of SaveOrUpdate() .
N ot e
As I said earlier in t his chapt er, you can use t he version t ag +unsaved-value t ag for helping
you out when you prefer t o set t he I dent it y Field values on your own.
These were j ust a few exam ples of st rat egies for I dent it y Fields. NHibernat e support s m any m ore.
You can also plug in your own st rat egies quit e easily.
Wit hout going int o det ails, I would say t hat NHibernat e has st rong support for m any relat ionship
st yles t hat will solve m ost of your needs in t hat area. I t 's not very easy, t hough, t o learn t o use all
variat ions effect ively, but you can go a long way wit h a few basic ones.
On t he ot her hand, what is pret t y easy is using t he Em bedded Value pat t ern [ Fowler PoEAA] wit h
NHibernat e.
Embedded Value
NHibernat e uses t he word component ( as if t hat word didn't have enough different m eanings) for
describing an Em bedded Value. Let 's repeat again what it could look like in t he m apping file t o
describe t hat a Customer has an Address :
<property name="PostalCode"
access="field.camelcase-underscore"
type="AnsiString" length="10" not-null="true" />
Not e t hat t he Customers t able cont ains all colum ns, but t he Customer class has j ust an Address field.
When t hat is in place, using t he Em bedded Value from t he consum er is very easy t o underst and. I t
could look like t his, for exam ple:
Console.WriteLine(aCustomer.Address.Street);
Som et hing t o t hink about , however, is whet her t he Value Obj ect Address should be im m ut able or not .
I would probably choose im m ut able in t his part icular exam ple, but it 's not always an easy choice.
I f you decide t o use m ut able, you could writ e t he code like t his inst ead of inst ant iat ing a new Address
:
N ot e
I f you have an Em bedded Value t hat should be used in m any ot her classes, it could be a
good idea t o im plem ent IUserType so t hat you don't have t o describe t he m apping over and
over again. That 's also t he case if t he st orage is different from t he t ype t o expose. The
t ranslat ion is t hen done by t he IUserType im plem ent at ion.
Consequent ly, one downside is t hat t he Dom ain Model will have t o refer t o nhibernat e.dll,
or you will have t o have t he specific code in a separat e assem bly and inherit t he basic
Dom ain Model class inst ead.
I t ry t o avoid t his if possible. When t he ordinary approach for Em bedded Value can be used,
everyt hing is j ust fine. For t ricky cases, it 's oft en possible t o do t he t ranslat ion m anually
inst ead in propert y get / set from / t o privat e fields and t hen m ap t hose privat e fields t o t he
dat abase.
A t ypical exam ple of when I avoid a cert ain const ruct or deal wit h it wit h cust om get / set
code is when it com es t o applying t he t ypesafe enum pat t ern [ Bloch Effect ive Java] ( for
exam ple, for adding behavior t o enum s) . First , I t hink t wice if I can't j ust live wit h an
ordinary C# enum . Second choice is cust om get / set code so I don't have t o deal wit h
IUserType . I t feels like a quit e big solut ion for a t iny t hing.
To end t his not e, j ust one m ore t hing: Don't exaggerat e your t ries t o avoid a reference t o
nhibernat e.dll in your Dom ain Model. I f t he benefit is bigger t han t he cost ...
Inheritance Solutions
NHibernat e support s all t hree different inherit ance solut ions, nam ely Single Table I nherit ance, Class
Table I nherit ance, and Concret e Table I nherit ance [ Fowler PoEAA] . I f we assum e t hat Customer and
Vendor inherit s from Company , t he m apping inform at ion could look like t his:
Then, som et hing like t he following is needed for each subclass, where t he specifics are described
( t hat is, t he m apping inform at ion t hat isn't for t he Company class) :
From t hat you underst and t hat t he only variat ion in each case is a single specific field,
CustomerNumber and VendorNumber . I n t his case, we will have j ust a single Companies t able, and it
would look like t his ( m eaning t hat we used Single Table I nherit ance here) :
That m eans t hat for Vendors , CustomerNumber will be NULL , and vice versa. The Type colum n will have
t he value " Customer " or " Vendor " ( or norm ally som e sm aller sym bols) .
N ot e
I know, som e of you are feeling so uncom fort able regarding t his exam ple because you
prefer t o use som et hing like t he Part y archet ype inst ead [ Arlow/ Neust adt Archet ype
Pat t erns] . Or at least you prefer not such an overuse of inherit ance, if t he only variat ion
was a single field and not hing else.
My int ent ion was j ust t o show an obvious and clear exam ple.
And as you would probably expect , when t he inherit ance m apping is in place, t he consum er code can
forget about how t he inherit ance hierarchy is act ually st ored and focus on how t o use t he inherit ance
hierarchy inst ead.
Identity Map
NHibernat e uses an I dent it y Map on an ISession level. You can easily see t his if you read an inst ance
by Id wit h Load() , m ake a change t o t he row direct ly in t he dat abase, and t hen read t he inst ance
again wit h Load() ( wit h t he sam e ISession inst ance) . You won't see t he change because NHibernat e
didn't roundt rip t o t he dat abase aft er t he first Load() , but inst ead t he inst ance was grabbed from t he
I dent it y Map.
NHibernat e also uses t he I dent it y Map when it com es t o querying; not for finding inst ances, but for
placing t he I dent it ies in t he Map t o support fut ure Load() calls from t he I dent it y Map.
I f you'd like t o force an inst ance away from t he I dent it y Map, you can call Evict() on t he ISession ,
or Clear() t o clear t he I dent it y Map from all inst ances, or of course Close() t he ISession .
Unit of Work
I t probably won't com e as a surprise t o learn t hat NHibernat e uses t he Unit of Work pat t ern [ Fowler
PoEAA] as well, and again it 's dealt wit h in t he ISession . That said, t he im plem ent at ion is pret t y
different from t he m ost t ypical one. I nst ead of regist ering what has happened wit h t he Unit of Work,
NHibernat e t akes a snapshot of t he inst ances when t hey are read from t he dat abase. At flush t im e,
t he inst ances known by ISession are com pared t o t he snapshot s t o creat e a Unit of Work at t hat
point in t im e.
To be clear, in a way delet es are regist ered and so are not ificat ions of new inst ances wit h, for
exam ple, SaveOrUpdate() .
As always, t here are pros and cons t o t his solut ion, and one obvious drawback is when t here are
m any inst ances t o invest igat e, only t o find t hat j ust one should be flushed. That 's one reason for why
Hibernat e ( t hat 's right , Hibernat e, not N Hibernat e, at least not at t he t im e of t his writ ing) 3 has
been changed regarding t his.
Now t he OrderLines of an Order are lazily loaded when t he OrderLines are needed for t he first t im e.
I n order for t his t o work, however, you m ust have a connect ed ISession .
I f you don't use t he lazy="true" declarat ion in t he m et adat a, you will effect ively get Eager Load
inst ead. NHibernat e support s several different approaches for Eager Load, such as OUTER JOIN and
sev er al SELECT st at em ent s bat ched aft er each ot her.
What m ight be im port ant is t hat when you do Eager Load wit h several SELECT st at em ent s, you m ight
get read inconsist ency ( which m ight be a bigger problem in t he case of Lazy Load) in t his case, t oo.
This can be avoided wit h explicit t ransact ion cont rol and by increasing t he Transact ion I solat ion Level
t o serializable [ Nilsson NED] , but it 's rarely a serious problem , so I won't go int o det ails here.
You can also cont rol in code whet her you want Eager/ Lazy Load. That 's som et hing you can do when
you use querying, but we are sat isfied wit h t he discussion about querying we've had already in t his
chapt er.
Controlling Concurrency
Finally, we need support for cont rolling concurrency. Fowler [ Fowler PoEAA] describes t he following
solut ions t o t he problem :
I m plicit Lock
NHibernat e deals wit h Opt im ist ic Offline Lock if you add a <version> t ag t o t he ent it ies, like t his:
Then, if t he row in t he dat abase has anot her value of t he version colum n com pared t o what you
expect it t o be at persist t im e, som eone else has updat ed t he row, and t here's a conflict in
concurrency ( and you'll get a StaleObjectStateException ) .
You'll have t o deal wit h t he ot her t hree m echanism s yourself. NHibernat e doesn't support t hem out of
t he box.
To use a cust om IInterceptor im plem ent at ion, you provide it as a param et er when inst ant iat ing
ISession like t his:
//A consumer
_session = NHConfig.GetSessionFactory()
.OpenSession(new MyCustomInterceptorImpl());
Just wat ch out t hat you can't do everyt hing in t he validat ion code when using t his approach; for
exam ple, you can't call out by using t he sam e ISession inst ance, which m ight creat e a problem here
and t here, but we have t ouched on som e st rat egies t hat can be used for dealing wit h t his problem in
Chapt er 7 , so I won't repeat t hose here.
NHibernate and DDD
I bet som e of you are scream ing for som e exam ples t hat put all t his about NHibernat e int o t he
cont ext of DDD. I 'd like t o end t he chapt er wit h exact ly t hat .
Again, I 'm not going t o use an abst ract ion layer like NWorkspace here; st ill, what I describe here
could be used for ot her O/ R Mappers as well ( and it would be sim plified if you do use an abst ract ion
layer) .
Not e t hat t he Dom ain Model doesn't have a dependency t o NHibernat e now. St ill, t he Dom ain Model
can use t he Reposit ories if needed. One approach is t hat t he Reposit ories are im plem ent ing
int erfaces t hat are in t he Dom ain Model. Then t hose int erface im plem ent at ions ( reposit ories) are
inj ect ed in t he Dom ain Model inst ances at suit able spot s.
can be t ransform ed int o t he following code if a reposit ory t akes care of som e of t he work ( not m uch
in t his sim ple case, but som e) :
Customer c = customerRepository.GetCustomer(theId);
That snippet assum ed t hat t he customerRepository was inst ant iat ed t his way:
//A consumer
ICustomerRepository customerRepository =
new CustomerRepository(_session);
So from t hat point and forward, t he reposit ory would have an ISession t o use for t alking t o t he
backend.
//A consumer
customerRepository.Add(customer);
orderRepository.Add(order);
_session.BeginTransaction().Commit();
Think about it t he ot her way around. I m ean, we have a reposit ory and now we want t o fill it wit h
real code. Assum e t hat you decide t o writ e m anual code t here. The API for t he reposit ory consum er
can be t he sam e t hing wit h ot her im plem ent at ions, of course, but inst ead of t he following line:
Then you need t o inst ant iat e t he customer inst ance and shuffle all t he values from t he result set row
t o t he inst ance.
Sure, we can all do t hat . I t 's not t he com plexit y t hat is t he problem ; it 's t hat t his m ost oft en is an
unint erest ing piece of work. And t here is a lot m ore t o it . For exam ple, t he customer also had a list of
ReferencePersons t hat should be reconst it ut ed at t he sam e t im e and a whole bunch of ot her t hings as
well.
When we are done wit h t hat code, every single change t o t he schem a or Dom ain Model will lead t o
m ore t edious work for us. Rem em ber, t his was a single get operat ion of a single obj ect .
I f we inst ead use an O/ R Mapper, changes are oft en dealt wit h by m aking a few changes t o t he
m apping inform at ion and t hat 's it . I believe I 'm m uch m ore efficient dealing wit h changes when I
don't hand code t he unint erest ing persist ence code.
That t hought can be seen in a larger perspect ive also, because if I know t hat changes won't be t oo
expensive, I 'm m uch m ore inclined t o do refact orings t han in t he opposit e case!
Let 's end t his sect ion wit h a short st ory from a recent proj ect . I t hink changes in t hat proj ect t hat
only affect t he pieces ( t he Dom ain Model and t he dat abase schem a) t hat are dealt wit h by t he O/ R
Mapper are probably done a m agnit ude cheaper com pared t o t he changes t hat affect t he persist ence
code t hat we have hand t uned! ( That said, don't forget t hat O/ R Mappers are of course not t he silver
bullet eit her. There are pros and cons.)
Summary
By applying an O/ R Mapper such as NHibernat e, t he design and code we st art ed sket ching out in
Chapt er 4, " A New Default Archit ect ure," and forward can be followed pret t y closely and non-
int rusively. NHibernat e let s us build our Dom ain Model in a PI m anner.
I see t his fam ily of t ools ( t he O/ R Mappers) as enablers for m aking it possible t o focus on DDD, but
at t he sam e t im e t hey need t o provide openings for us t o handcraft pieces of t he persist ence code
when needed.
Of course, it 's not j ust gold and green forest s. For exam ple, I would really like t o see awareness of
DDD from O/ R Mappers like NHibernat e, which would sim plify t he whole t hing and lead t o even bet t er
end result s. St ill, applying NHibernat e as part of your infrast ruct ure, I t hink, is a big st ep in t he right
dir ect ion.
So, what 's next ? The last part of t he book, Part I V, " What 's Next ?" is what 's next .
The first chapt er of t hat part st art s wit h a discussion about larger cont ext s, having several m odels at
play. Aft er t hat t here is a focus on int erest ing design t echniques for now and t he fut ure. Those are
Service- Orient ed Archit ect ure ( SOA) , I nversion of Cont rol/ Dependency I nj ect ion ( I oC/ DI ) and Aspect
Orient ed Program m ing ( AOP) .
Part IV: What's Next?
I n t his part , t here is a focus on ot her design t echniques t o keep an eye on and st art using. The
ot her focus is on how t o deal wit h t he present at ion layer when it com es t o bridging t hat gap t o
t he Dom ain Model and how t o deal wit h developer t est ing of t he UI . This part is alm ost
exclusively writ t en by guest aut hors.
We have now spent quit e a lot of t im e discussing and applying t he basics of DDD. We have writ t en
m any unit t est s, designed our Dom ain Model carefully, and m ade t he Dom ain Model persist ent wit h
an O/ R Mapper. What 's left ?
A st ory about a well- known indust ry leader in a m ult inat ional com pany goes like t his. He held a
m eet ing aft er t he com pany's profit s, qualit y, and so on were bet t er t han ever before and said
som et hing like: " Now I want all of us t o spend one m inut e t hinking how good we are..." A m inut e
lat er he recom m enced, t aking up problem s, crit icizing, and so on. I t was business as usual.
Aft er we have t hought nice t hought s about ourselves for a m inut e, what do we need t o focus on
now?
Of course, t here are dozens of t hings t o consider. First of all, we are by no m eans done wit h even t he
basics of t he Dom ain Model, let alone t he det ails. But we have st art ed out nicely, and we are also in
good shape for t aking on problem s such as perform ance charact erist ics, concurrency issues, securit y,
and so on. I will act ually leave all t his as an exercise for you, t he reader, because I hope your
appet it e has been whet t ed so you are forced t o give it a t ry on your own if you haven't before.
I nst ead, in t his Chapt er I will st art wit h a short discussion about how you can scale up t he DDD
principles used so far, m ost ly by focusing on t he Bounded Cont ext pat t ern [ Evans DDD] . Aft er t hat
we will discuss t hree different design t echniques t hat I t hink are wort h looking at t oday. They are
Service Orient at ion, I nversion of Cont rol/ Dependency I nj ect ion, and Aspect Orient at ion.
I asked a couple of m y friends t o writ e about t hose design t echniques, and we have t heir
cont ribut ions here, but I penned t he first sect ion in t his chapt er m yself. Over t o " Cont ext is King."
Context Is King
I t hink it 's pret t y com m on not t o give enough t hought t o how im port ant t he cont ext is. For exam ple,
when t he GoF pat t erns [ GoF Design Pat t erns] are discussed and used by developers wit hout prior
experience of t hese pat t erns, it is t ypical t o forget t hat t here is a cont ext for when t he pat t erns are
suit able.
A good idea/ solut ion/ anyt hing, but in t he wrong cont ext it isn't necessarily any bet t er t han a bad
count erpart . That 's j ust t he way it is.
Let 's t ake a st ep back before we focus m ore on t he specific cont ext - relat ed concept of t his sect ion.
First , here's a word on layers and part it ions.
To m ake t his m ore concret e wit h an exam ple, t wo t ypical layers are t he UI and t he Dom ain Model.
Two possible part it ions m ight be t he subsyst em for regist ering orders and t he subsyst em for
adm inist ering user com plaint s. Bot h part it ions m ight have a UI and a Dom ain Model.
Today, j ust as it was back t hen, I t hink layering has received m uch m ore focus t han part it ions.
Layering has been a very im port ant way of providing " separat ion of concerns." You probably have a
firm grasp of what t he idea is: t o live by t he principle of Single Responsibilit y ( SRP) [ Mart in PPP] .
I n a way, t his alm ost t ot al focus on layering is changing. I t hink layering has relaxed a bit wit h DDD,
at least com pared t o t he rigorous layering I used in t he past [ Nilsson NED] . ( Well, we are st ill very
focused on fact oring out t he infrast ruct ure from t he Dom ain Model.)
N ot e
We discussed layering according t o DDD in Chapt er 4, " A New Default Archit ect ure."
At t he sam e t im e, t here is an increasing underst anding of how you can't creat e one single huge
Dom ain Model, or at least t hat it 's oft en t oo com plex, cost ly, or inefficient t o go t hat rout e in large-
scale sit uat ions. I also t hink Service Orient at ion ( SO) is a driving force when it com es t o t he
increased int erest in part it ioning. The whole problem sim ply becom es m ore evident .
Because of t he increased int erest in part it ioning, t he int erest in layering m ight lessen. I t 's j ust not as
im port ant or beneficial wit h a rigorous layering design for a t iny part it ion.
Let 's have a closer look at t he reasons for part it ioning.
But again, organizat ional reasons are im port ant for part it ioning, such as because one t eam t akes
care of t his and anot her t eam t akes care of t hat . This is t ot ally in line wit h a discussion I had wit h
som e colleagues about m ot ivat ions for layering. None of t hem t hought t hat layering was good t o use
for organizing a t eam . That 's som et hing I 've done from t im e t o t im e, and ( t o m y m ind) wit h success.
What I t hink t hey all really m eant was t hat it 's a bet t er idea t o organize t he t eam around part it ions
inst ead. And t hen t he layering is less st ressed inside each part it ion. We will, of course, st ill see t hat
different people have different m ain int erest s and expert ise, and we shouldn't fight t hat . We should
j ust not creat e a large depart m ent of UI developers t hat builds t he UI for all applicat ions, anot her
depart m ent of Dom ain Model developers, and yet one m ore depart m ent of dat abase developers. Out
of t hose t wo dim ensions ( if you have t o choose) , t he m ost im port ant is t he dom ain problem s t hat
should be solved, not what t echnologies t o use. Rem em ber t hat when organizing t he t eam also.
What also m at t ers regarding whet her you need part it ioning or not is t he size of t he developm ent
effort . For a t iny syst em , one part it ion m ight be all t hat is needed; for a large syst em , a good
part it ion design m ight be ext rem ely im port ant t o succeed.
To sum m arize t his, I t hink t hat first it 's a m at t er of part it ions, and t hen inside t hose part it ions it 's a
quest ion of layers, not t he opposit e.
Let 's see if we can couple t his t o DDD, which brings m e t o t alking a lit t le about t he Bounded Cont ext
pat t ern [ Evans DDD] .
Bounded Context
A com m on quest ion is " How should we deal wit h com plexit y?" And j ust as com m on an answer is
" divide and conquer." Use of hierarchies is one way of dividing and conquering.
DDD is pret t y m uch about hierarchies. One ext rem ely useful t ool t hat I 've been em phasizing a lot is
t he Aggregat e pat t ern, which is a pret t y coarse- grained unit . Ent it ies is anot her unit , and Value
Obj ect s is yet anot her ( all found and discussed at lengt h in [ Evans DDD] ) .
I f we go in t he opposit e direct ion, " up" from Aggregat es, we will find t hat Bounded Cont ext s isn't t he
sam e as aggregat es, but rat her t he sam e as subsyst em s or sub- m odels.
The basic idea wit h Bounded Cont ext is t o be very explicit about in what cont ext t he m odel applies.
You should also be very st rict about t he m odel and it s concept s wit hin t he Bounded Cont ext ; what is
out side doesn't really m at t er t hat m uch.
From a narrow perspect ive, a good reason for t he division int o several Bounded Cont ext s is t o be
able t o t hink about all t he det ails wit hin one m odel and t o be able t o keep it pure. At t he sam e t im e,
from a wider perspect ive we can t hink about " large" abst ract ions t hat are easy t o grasp and t hink
about in overview t erm s.
A st rong advant age of t he Aggregat e is it s boundary. I t sim plifies life, decreases coupling, and m akes
connect ions m ore explicit . Again we find advant ages of a boundary, t his t im e on a higher level wit h
t he Bounded Cont ext .
N ot e
Alt hough I see great value in boundaries, t here are also cost s. You m ight int roduce a lot of
overhead when it com es t o com m unicat ion and perform ance. As usual, keep it sim ple and
add com plexit y when you gain m ore t han t he cost .
I f we bind t his t o t he exam ple I used in t he previous chapt ers, t hat of t he sales order, t here m ight be
one bounded cont ext for ordering and anot her for shipping. This is not how I st art ed t o t alk about it
in m y lit t le exam ple, but in a real- world, large scale sit uat ion it m ight m ake sense from a
t echnological st andpoint , and different part s of t he organizat ion m ight very well be dealing wit h each
of t hose business processes, which m ight be a good reason for t he split .
Bounded Cont ext s m ight also help preserve t he Ubiquit ous Language from becom ing un- crisp and
having loose definit ions. I nst ead what you will get are several Ubiquit ous Languages, one per
Bounded Cont ext , which is part ly a bad buy. But on t he ot her hand, each of t hese will be m ore
powerful and exact . Rat her t wo good, t han one bad.
When you find out t hat what you t hought was a single m odel has st art ed t o have concept s wit h
different m eanings and t hat t he Ubiquit ous Language isn't as clear and crisp as before, t hat can very
well be a sign t hat it has act ually becom e t wo m odels. I nst ead of fight ing it , it can oft en be wise t o
prom ot e t his evolut ion and define t wo different Bounded Cont ext s.
I t 's t im e t o shift focus and t alk about anot her reason for part it ioning of Dom ain Models.
This book is not about int egrat ion or m essaging, but m erely about archit ect ure and design for one
service or one applicat ion. But we relax t he focus of t he book for a sect ion and have a look at an
int roduct ion t o Service Orient ed Archit ect ure ( SOA) t hat Udi Dahan has writ t en.
An Introduction to SOA
By Udi Dahan
Bot h DDD and SOA are relat ively new concept s, t he first being quit e well- defined, and t he second
less so. While t here are t hose who claim t hat SOA has been around since t he early CORBA days,
never has t here been such broad vendor and indust ry buy- in for " j ust an archit ect ure."
Chunky int erfaces, also known as coarse- grained int erfaces, cause m ore work t o be perform ed in a
single call t han fine- grained int erfaces, which require m ult iple calls t o perform t he sam e am ount of
work. The explicit coordinat ion and resource- locking t hat needs t o t ake place over fine- grained
int erfaces is t ot ally encapsulat ed in a single chunky call. This result s in client code t hat is less
coupled t o t he server code im plem ent at ion.
I n fact , t he evolut ion of dist ribut ed syst em s archit ect ure has been punct uat ed by t he int roduct ion of
new ideas and t he sobering effect s of realit yperform ance. Despit e t he fact t hat Moore's law has held
over t he years, and apparent ly will cont inue t o hold, t he world of large- scale syst em s developm ent
cont inues t o be preoccupied wit h perform ance. However, it is not so m uch perform ance as a st at ic
m easure t hat is int erest ing, but rat her scalabilit y, t he dynam ic m easure of perform ance over varying
loads, t hat archit ect s st rive t o m axim ize.
SOA is t he next st ep on t he ladder of archit ect ural evolut ion t hat will enable new syst em s t o be built ,
and older syst em s t o be ut ilized, in scalable solut ions.
N ot e
Not e t hat " schem a" doesn't necessarily dict at e XML, but rat her t he set of m essages t hat
flow bet ween services.
While XML, and SOAP by ext ension, are not prerequisit es of SOA, t he ext ensibilit y of XML
m akes t he versioning of schem a m uch easier.
What Is a Service?
Besides being bot h t he unit of design and t he unit of deploym ent , services are surprisingly ill- defined
for t he size of t he buzz surrounding SOA. I nst ead of defining what a service is, m ost of t he lit erat ure
describes propert ies of services. One such exam ple is t he four t enet s of Service Orient at ion:
While t hese propert ies do indeed drive t he design of scalable services ( and will be discussed in m ore
det ail lat er) , t hey apparent ly provide lit t le guidance on t he design of dist ribut ed syst em s. Archit ect s
j ust beginning t o em ploy service- orient ed t echniques t o t heir designs have no inform at ion about
which elem ent s should be grouped t oget her int o services, how t o recognize and define service
boundaries, and how t hese services are t o be im plem ent ed using classic OO pat t erns. On t op of t hat ,
t he t echnologies surrounding t he " pure" archit ect ural aspect s of SOA cont inue t o be in a st at e of flux,
and t he various vendor offerings appear t o be lit t le m ore t han repackaging of current product s. I s it
any wonder t hat SOA is already being dism issed as hype?
By t aking int o account t hat com m unicat ion wit h a service is based on m essage exchanges, we find
t hat services are com posed of different t ypes of elem ent s and not j ust " com ponent s" or " obj ect s." I n
order t o expose funct ionalit y, services use a m essage schem a. This schem a is com posed of several
elem ent s: t he m ost basic include t he " dat a t ypes" ( like Customer ) t hat define ent it ies, t he m essages
t hat define what operat ions can be perform ed ( not necessarily on a per- ent it y basis) , and t he service
cont ract t hat defines int eract ions wit h t he defined m essages ( a Cust om erChangeRequest will result in
a Cust om erChangeReply, for inst ance) . I t is quit e clear t hat a m essage schem a is neit her an obj ect
nor a com ponent , yet it is a necessary part of a service.
Anot her part of services t hat is oft en overlooked is t he service host . A service would not be able t o
provide funct ionalit y wit hout having som e kind of execut ing environm ent in which t o run. Web
services using HTTP will likely have eit her I I S, Apache, WebSphere or som e ot her Web server as t heir
host . Ot her services m ay be host ed by COM+ , a Windows Service, or even som et hing as sim ple as a
console applicat ion. Alt hough t he indust ry has been m oving t oward t ransport - independent services,
cert ain host im plem ent at ion det ails ( like prot ocol) do affect services in significant ways. HTTP and
ot her TCP- based prot ocols are all connect ion- orient ed. I n dist ribut ed syst em s where elem ent s m ay
fail, reboot , or sim ply respond slowly, connect ion- orient ed prot ocols can cause perform ance t o suffer
unt il t im e- out s occur. Connect ionless prot ocols ( like UDP) cause ot her problem st here are no built - in
m echanism s t o recognize t hat a m essage did not arrive at it s dest inat ion. I f anyt hing, t he necessary
part of any service is it s host .
Beyond t hese at ypical elem ent s, services will indeed be com posed of com ponent s and/ or obj ect s.
Yet , not j ust any com posit ion will m eet t he guidance prescribed by t he 4 SOA t enet s. A t horough
discussion of t heir m eaning is in order.
N ot e
The t erm " t ransact ion" was originally used t o describe a way of working wit h relat ional
dat abases and t he four propert ies of t ransact ions were given t he acronym ACI D: At om ic,
Consist ent , I solat ed, Durable. A com m on im plem ent at ion for dat abases t o fulfill t hese
requirem ent s, t he relevant rows, pages, and t ables were locked wit hin t he scope of a
t ransact ion.
The t hird t enet ( schem a, not class) seem s t o be t alking about int eroperabilit y, t hat t o com m unicat e
bet ween services, we use XML on t he wiret he so- called lowest com m on denom inat or. However, at it s
m ost basic level, t his t enet is t alking about separat ion of concerns. The class t hat im plem ent s t he
desired behavior is decoupled from t he ext ernal client s t hat " call it ." This is quit e different from Java
RMI , COM, or .NET rem ot ing, where client - code m ust reference server t ypes. When using schem a, an
explicit m apping needs t o be perform ed bet ween ext ernal m essage form at s and int ernal class
invocat ions. This enables us t o change t he int ernal im plem ent at ion of a service, going so far as t o
change which class or int erface is invoked wit hout affect ing ext ernal client s.
There is an even deeper m eaning t o t he t hird t enet , and it is versioning. While t ypes can form
hierarchies such t hat one t ype is a kind of anot her t ype, hist ory has proven versioning t ypes t o be
horrendously difficult DLL hell com es t o m ind. One of t he goals of versioning a service is t o avoid
having t o updat e client - code already deployed. This goes so far as t o say t hat t he deployed client s
will cont inue com m unicat ing wit h t he sam e endpoint s as before. The benefit inherent in schem as t hat
is absent in t ypes is t hat schem as can be com pat ible, even t hough t hey are different . This is where
t he ext ensibilit y of XML is im port ant .
For exam ple, aft er deploying version 1 of our service and client , we would like t o roll out version 2 of
t he service so t hat we can deploy several new client s ( version 2) t hat require m ore advanced
funct ionalit y from t he service. Obviously, we wouldn't want t o break exist ing client s by such a
change, nor would we want t o have t o upgrade t hem . I n order for t his t o be possible, version 2 of t he
service's schem a needs t o be com pat ible wit h version 1, a t ask m ore difficult and less developer-
friendly when com m unicat ing wit hout schem a. I m agine having t o t ack on t o t he end of each m et hod
signat ure som et hing like " params object[] extraData" .
The fourt h propert y of services in SOA ( com pat ibilit y is based on policy) furt her reinforces t he first
t wo point st he service decides whet her or not it will respond t o a given request and adds anot her
dim ension; m et adat a is t ransferred as a part of t he request . This m et adat a is called policy. I n m ost
present at ions given, policy is described using exam ples such as encrypt ion or aut hent icat ion
capabilit ies. The idea is based on a separat ion of concerns; t he schem a t hat defines t he logical
com m unicat ion is independent of t he encrypt ion policy. I f you have inform at ion you'd like t o pass
bet ween services wit hout expressing it in your schem a, policy is one way t o do it .
I n fact , SOA and OO operat e on different levels. OO deals wit h t he design and code of a single
deploym ent unit while SOA deals wit h a solut ion com prised of m ult iple deploym ent unit s. SOA does
not suggest new or alt ernat e ways of designing or coding t he int ernal logic of a given applicat ion or
service. There is no reason SOA and OO should not be cooperat ive t echnologies. The quest ion t hat
SOA does bring t o t he t able when developing OO applicat ions is how t hese applicat ions will accept
and respond t o m essages com ing from sources ot her t han t he user, and even in parallel t o user
act ivit y. The fact t hat a given applicat ion can receive request s and, at t he sam e t im e, issue it s own
request s t o ot her services brings us t o t he conclusion t hat int eract ions no longer follow t he classic
" client - server" pat t ern.
However, as syst em s grew and becam e m ore int erconnect ed, t he N- Tier concept blurred as
applicat ion servers began t o m ake request s from ot her applicat ion servers act ing as t heir client s. The
inherent ordering found in t he t iered archit ect ures wasn't being seen in pract ice. Finally, client - side
soft ware was beginning t o receive event s asynchronously from it s servers, in essence responding t o
request ssom et hing t hat it wasn't explicit ly designed for.
Beyond t he SOA t heory t hat st at es t hat client soft ware should also be designed as a service, t here is
a real need for client code t o be able t o receive m essages. Consider t he case where an act ion on t he
server t akes a very long t im e t o com plet e, longer t han t he t im e- out durat ion for HTTP, possibly even
days. This is not at all unusual for operat ions t hat require hum an int ervent ion. While t he client m ay
poll t he server for com plet ion, t his places undue load on t he server, requiring a background t ask on
t he client . I f we were t o use t hat sam e background t ask t o list en for m essages not ifying about work
com plet ion, we could relieve t he server of t his load. This solut ion is bot h feasible wit h t oday's
t echnology and sim ple t o im plem ent .
I n t his m anner, t he client m ay receive any num ber of t ypes of m essages, effect ively becom ing a
service. I n fact , t hese m essage exchanges could bet t er be described as conversat ions bet ween an
init iat or and a t arget t han request s/ response pairs bet ween client and server. There are no inherent
const raint s as t o which services can init iat e a conversat ion and which can respond.
Because t he init iat or no longer requires a synchronous response, t he t arget service is now free t o
perform t he processing at t he t im e m ost beneficial t o it . Should t he t arget service be under heavy
load, it could schedule t he processing of new m essages for a lat er t im e. I n ot her words, we are able
t o perform pro- gram m at ic load balancing over t im e. For inst ance, we can writ e code t hat t akes int o
account t he nat ure of t he request when scheduling it for fut ure processing.
I n t he previous synchronous request - response paradigm , t he init iat or was only capable of receiving
t he response from t he t arget . Now t hat t he init iat or is list ening for a response, t he const raint t hat
only t he t arget service can ret urn t he response is lift ed. The t arget service can now offload ret urning
responses t o ot her services.
The advant ages of using one- way asynchronous m essage- exchange pat t erns are num erous. Bot h t he
flexibilit y of t he solut ion and it s scalabilit y are increased. These benefit s obviously have a cost
at t ached t o t hem , but we will lat er see t hat t he cost is not t hat great .
How SOA Improves Scalability
By using one- way asynchronous m essaging, a service is able t o m oderat e load by queuing request s.
This result s in services t hat do not degrade in perform ance under increasing load because no
perform ance- draining resources ( like t hreads) are acquired. By keeping resource ut ilizat ion near
const ant at any load above t hat giving m axim um perform ance, services developed using one- way
asynchronous m essaging achieve bet t er perform ance charact erist ics, as shown in Figure 10- 1.
Not e t hat while under sm all loads, t he t im e t o process a single m essage t his way m ay well be great er
t han when using classic RPC. This is secondary t o t he great er t hroughput achieved under heavy load.
First , a request arrives at our service, is placed int o a queue, and t hen handled. I n order t o handle
t he request , inform at ion needs t o be ret rieved from t hree ot her services. Aft er request s are
dispat ched t o t he ot her services, t he st at e of processing t he original request ( pending responses 1,
2, and 3) is saved ( see Figure 10- 3) .
Should anot her request arrive before processing of t he previous request is com plet e, it would have
no im pact on t he processing of t he original request . I t could begin it s own processing and send
request s t o any num ber of ot her services in t he sam e m anner. We can int erleave t he processing of
m ult iple request s wit h t he sam e resources ( see Figure 10- 5) .
When t he response from service # 3 arrives, it is handled in t he sam e way as t he response from
service # 2. Because not all necessary responses have been received, again no response will be sent
t o t he init iat or of t he original request ( see Figure 10- 6) .
Finally, only when t he response from service # 1 arrives for m essage handling can t he processing of
t he original request be com plet ed. Aft er updat ing t he st at e of t he original request in t he st ore, t he
service now knows t hat all responses have arrived and t hat t he response can be sent t o t he init iat or
( see Figure 10- 7) .
Alt hough we've t aken int o account t hat services m ay t ake som e t im e t o respond t o our request s, t he
issue t hat we haven't dealt wit h yet is when no response is going t o ret urn. The current design does
not solve t his problem because it specifically circum vent s t im e- out s inherent in connect ion- orient ed
pr ot ocols.
When t he t im e wait ing for a response expires, what should be done? This is anot her area in t he
design where dom ain logic is required. The quest ions t hat need t o be answered by t he dom ain logic
are varied and include t he following:
I n t he int eract ion diagram shown in Figure 10- 8, we can see t hat t he code t hat handles t im eout s is
not only separat ed from t he m essage- handling code, but is separat ed in t im e as well. Bot h request
and failure handling logic are encapsulat ed.
Figu r e 1 0 - 8 . Applyin g a t im e ou t w a t ch e r
Scaling Services
We've already seen t he increased scalabilit y SOA provides by ut ilizing one- way asynchronous
m essaging. However, can services designed t his way efficient ly m ake use of increasing num bers of
processors on t he sam e box? What about increasing num bers of servers?
Let 's first look at t he m essage handling. The m essage handling t hread/ process is st at elessfor each
request , it finds t he appropriat e st at e in t he st ore and processes t he result accordingly. Therefore,
we can increase t he num ber of concurrent m essage handlers wit hout harm ing correct ness. Because
each of t he m essage handlers is independent of ot hers, t here will be no need for in- m em ory locking
or for a given m essage handler t o wait ( unless it has no m essages t o process) .
For a single box wit h m ult iple processors, t his m eans t hat we can increase t he num ber of m essage
handlers and increase t hroughput . For m ult iple servers, we could place t he m essage receipt , queue,
and st ore on a single server while placing m ore m essage handlers on each addit ional server.
The ult im at e advant age of t he scale- out scenario described is t hat it enables addit ion of m ore servers
at runt im e. By m onit oring t he num ber of it em s in t he queue, we can know when t he syst em has
reached peak capacit y, and t hen add m ore resources wit hout t aking t he syst em down or hindering
perform ance in any way.
Summary
The m ain point t o rem em ber about SOA is t hat it is " m erely" an evolut ion of best pract ices of
dist ribut ed syst em s developm ent . The core OO principles of separat ion of concerns and independence
of int erface from im plem ent at ion cont inue t o be reflect ed in service- orient ed pract ices. Alt hough
m any t opics have been t ouched upon, each t opic has dept h t hat cannot be explored in such an
int roduct ion. Hopefully you have underst ood what SOA is not and what t ools shouldn't be used
bet ween services. How t he logic of a service is int ernally st ruct ured is a quest ion t hat I assum e will
never be decisively answered, but I 'm sure Jim m y will get you on t rack.
Thanks, Udi!
And for readers who would like t o get m ore int o dept h wit h SOA, or m ore specifically m essaging, a
good book t o st art wit h is [ Hohpe/ Woolf EI P] .
One of t he driving forces behind SOA is t o reduce coupling. Anot her t echnique for reducing coupling
is t he subj ect of t he next sect ion.
I have pret t y oft en writ t en in t his book about Dependency I nj ect ion, but I applied it only m anually.
To m any people, inj ect ing what t he inst ance will need in t he const ruct or is t he m ost nat ural t hing in
t he world. That 's easy looking at it on a sm all scale and som et hing we want t o be able t o do during
t est , but on a large scale during runt im e it becom es t ricky, cum bersom e, and som et hing t hat m akes
reuse m uch harder t han it has t o be.
I n t he next sect ion, Erik Dörnenburg will discuss inversion of cont rol as t he principle and Dependency
I nj ect ion as t he pat t ern. Erik, t he readers are yours.
Inversion of Control and Dependency Injection
By Erik Dörnenburg
Previous chapt ers discussed how dom ain obj ect s and t he corresponding infrast ruct ure can be
designed and developed. I n t his sect ion, I want t o present a part icular design t echnique, or pat t ern,
t hat can be used t o assem ble obj ect s at runt im e. The general principle is known as I nversion of
Cont r ol and t he part icular pat t ern has been nam ed Dependency I nj ect ion.
No Object Is an Island
Alm ost any obj ect in our applicat ions t hat provides business funct ionalit y depends on ot her obj ect s.
These can be obj ect s t hat provide dat a or a service of som e form . When we design and develop our
obj ect s using TDD, we usually explicit ly provide t he obj ect s required, and oft en we use st ubs or
m ocks in place of t hem t o isolat e t he obj ect under t est . At runt im e, however, our obj ect s require a
real im plem ent at ion, and in one way or anot her all obj ect s in our applicat ion m ust be inst ant iat ed
and wired up.
The m ost com m on approach t o resolving a dependency bet ween one obj ect and anot her is t o place
t he responsibilit y for creat ing or acquiring t he dependent obj ect wit h t he obj ect t hat has t he
dependency. The sim plest way t o do t his is t o have t he obj ect t hat has t he dependency inst ant iat e
t he obj ect it requires.
As an exam ple, let us assum e we are creat ing a pricer, an obj ect t hat calculat es t he price for a
financial inst rum ent such as a bond. Of course, t he pricer needs t he bond t hat should be priced, but
we decide t hat t his is not part of t he st at e of t he pricer obj ect and is t o be passed in wit h each pricing
request . Therefore, our class could look as follows:
The price of t he bond depends on ot her fact ors, t hough, and one exam ple is som et hing called a
discount curve. ( I t does not m at t er whet her you are fam iliar wit h t he dom ain or not ; for t his
exam ple, t he pricer could also depend on a wom bat and not hing would be different .) A curve can be
used t o price m any different bonds and rem ains relat ively const ant . We t herefore decide t hat t he
curve should be part of t he st at e of t he pricer and keep it in a m em ber variable which is init ialized in
t he const ruct or.
//BondPricer
private readonly DiscountCurve curve;
public BondPricer() {
curve = new DiscountCurve();
}
Not e t hat we could have creat ed t he curve on dem and, but t he discussion on when lazy inst ant iat ion
is useful is a different one. I n any case, t he pricer now has a direct dependency on t he curve. I t is
also likely t hat t he discount curve obj ect it self depends on ot her obj ect s t hat it inst ant iat es at an
appropriat e t im e. This looks like a viable approach, but upon closer inspect ion problem s becom e
visible: We have a funct ioning set of obj ect s t o price our bonds, but how flexible and m aint ainable is
our solut ion?
Let us assum e t hat t he discount curve obj ect reads t he individual point s of t he curve from a
dat abase. This is what t he users want ed. I n a lat er it erat ion, we are asked t o build a feat ure t hat
allows t he users t o analyze what - if scenarios. For t his t he users want t o specify t he point s for t he
curve in t he UI . Not hing easier t han t hat : We creat e an int erface from t he DiscountCurve class and
provide t wo separat e im plem ent at ions, DatabaseDiscountCurve and InMemoryDiscountCurve. We
change BondPricer class so t hat it only uses t he m et hods on t he int erface and is t hus no longer
coupled t o t he dat abase- based im plem ent at ion.
Unfort unat ely, even t hough t he calculat ion code in t he bond pricer only depends on t he discount
curve int erface, we m ust inst ant iat e a concret e im plem ent at ion of t he IDiscountCurve int erface at
som e point , t he const ruct or of BondPricer in t his exam ple. At t his point , we have t o decide which of
our t wo im plem ent at ions we want t o inst ant iat e, but whichever one we choose, our class is coupled
t o t he int erface as well as t o t hat im plem ent at ion. The following diagram (Figure 10- 9) shows t he
class design and clearly illust rat es t he problem : t he creat es link bet ween t he BondPricer and t he
DatabaseDiscountCurve.
Anot her issue wit h direct inst ant iat ion is t hat t here is no single place in t he applicat ion t o cont rol t he
creat ion of discount curves, which m akes it im possible t o reuse t he sam e inst ance for different
purposes. This can be quit e problem at ic, and if we consider t hat t he original version of t he curve
loads inform at ion from a dat abase, it becom es obvious t hat recreat ing new inst ances can have a
severe im pact on t he perform ance of our applicat ion.
Before we discuss I nversion of Cont rol and Dependency I nj ect ion, let us first look at anot her com m on
approach t o solving t hese issues.
public BondPricer() {
curve = DiscountCurveFactory.GetCurve();
}
}
Wit h t his fact ory, t he pricer is no longer t ight ly coupled t o a curve im plem ent at ion, which is what we
want ed t o achieve. Unfort unat ely, in it s place, t he fact ory class it self is now t ight ly coupled t o a
specific IDiscountCurve im plem ent at ion, so it rem ains difficult t o use different curve im plem ent at ions
in different applicat ions of t he pricer. To overcom e t his problem we could creat e a fact ory int erface
and pass in different fact ory im plem ent at ions, but t his m eans t hat we would have t o solve t he
problem of get t ing t he right fact ory, which is sim ilar t o get t ing t he right obj ect s. I n ot her words, we
would add a level of indirect ion t hat provides addit ional flexibilit y but would j ust m ove t he key
problem we have.
What we have not shown in t he code is t hat t he Fact ory pat t ern also addresses t he issue of inst ance
m anagem ent . Because we have a cent ral place in our code t hat is responsible for providing curve
inst ances, nam ely t he GetCurve() m et hod, we can choose t o im plem ent alt ernat ive policies t hat
apply t o t he ent ire applicat ion. For exam ple, rat her t han always creat ing a new curve, we could
m aint ain a single inst ance or, if our applicat ion is m ult i- t hreaded, we could choose t o m anage a pool
of inst ances.
I n a furt her st ep t oward com plet e decoupling, we can replace t he fact ory wit h an im plem ent at ion of
t he Regist ry pat t ern [ Fowler PoEAA] . Much like a fact ory, a regist ry provides obj ect s of a given t ype
but rat her t han hard- coding t he t ype of obj ect , it ext ernalizes t his decision and inst ant iat es t he
obj ect s using reflect ion. This approach represent s an im provem ent on t he Fact ory pat t ern for our
purposes because we have now separat ed t wo concerns: We have one class t hat is responsible for
t he provisioning of obj ect s, t he regist ry, and we can m ove t he code t hat decides which concret e class
t o use in each case t o ot her m ore suit able places in our code base.
The im plem ent at ion of such a regist ry is sim ple but effect ive and finally achieves our goal of
decoupling BondPricer from a concret e im plem ent at ion of IDiscountCurve.
The curve obj ect s we are using in t his exam ple are dat a sources, but it is easy t o see t hat we can use
t he sam e pat t erns t o locat e services providing obj ect s ( for exam ple, an audit service t hat writ es t he
calculat ed price t o a log) . Used in t his way, t he pat t ern is oft en referred t o as Service Locat or
[ Alur/ Crupi/ Malks Core J2EE Pat t erns] .
I n im plem ent at ion, m ost locat ors go one st ep furt her and do not provide individual set s of regist er
and get m et hods for each service, but inst ead provide a single set of generic m et hods and a dynam ic
nam ing schem e.
Using a Service Locat or, we regist er a concret e curve im plem ent at ion wit h t he locat or under a nam e,
m ost likely t he nam e of t he int erface. Wit h t his set up, our bond pricer can now get hold of t he
discount curve by asking t he locat or for one.
public BondPricer() {
curve = (IDiscountCurve)Locator.GetInstance("MyBank.IDiscountCurve");
}
}
We have chosen t o use st rings in our nam ing schem e, which is a com m on pract ice, but obj ect t ypes
would serve equally well. Using obj ect t ypes has t he advant age of m aint aining full support for
aut om at ic refact orings provided by our I DE and also helps wit h bet t er error checking, t hough t hese
benefit s com e at t he expense of som e flexibilit y. Whichever approach we choose, t he pat t ern rem ains
t he sam e and provides t he sam e degree of decoupling.
I n cont rast t o t hat , Dependency I nj ect ion t urns t his process around and m akes t he obj ect t hat has
t he dependencies passive. The obj ect declares it s dependencies but is ot herwise com plet ely oblivious
as t o where t he dependencies com e from . The process for resolving t he dependencies and finding t he
dependent obj ect s is left t o an ext ernal m echanism , which m ay be im plem ent ed in a variet y of ways.
Usually, applicat ions cont ain generic infrast ruct ure code t hat loads a configurat ion file or uses an
int ernal regist ry t o keep a list of all obj ect s and t heir dependencies. However, t he Dependency
I nj ect ion pat t ern is not concerned wit h t his aspect . The infrast uct ure code is st rict ly com plim ent ary,
and it is even possible t o sat isfy t he dependencies by passing in t he obj ect s from applicat ion code.
There are several flavors of dependency inj ect ion. Let us have a look at Const ruct or Dependency
I nj ect ion first . Following t his pat t ern, an obj ect declares it s dependencies in it s const ruct or, and t he
code t hat creat es t he obj ect ensures t hat valid inst ances are supplied at runt im e.
An im port ant observat ion is t hat t his code does not depend on anyt hing but concept s relat ed t o t he
problem dom ain. I t does not require a reference t o a fact ory or regist ry, and it is not concerned wit h
finding or creat ing t he inst ances. As such, dependency inj ect ion prom ot es t he design of elegant
soft ware, which usually exhibit s a good separat ion bet ween dom ain and infrast ruct ure concerns.
Figure 10- 11 shows t he design using dependency inj ect ion. We have also included an assem bler
obj ect t hat is responsible for creat ing t he pricer and t he curve on which t he pricer depends. The
diagram highlight s t he fact t hat wit h t his design t here is no dependency from any dom ain specific
obj ect t o generic infrast ruct ure code such as t he assem bler.
[Test]
public void testPriceIncludesValuesForOutstandingCoupons () {
IMock curveMock = new DynamicMock(typeof(IDiscountCurve));
IDiscountCurve curve = curveMock.MockInstance as IDiscountCurve;
BondPricer pricer = new BondPricer(curve);
/* do actual test */
}
This approach is sim pler t han any solut ion t hat can be achieved wit h t he ot her pat t erns we have
discussed before. I f we had opt ed for a design wit h a regist ry, for exam ple, it would have been
necessary for t he t est t o creat e a regist ry and regist er t he m ock wit h it . Wit h dependency inj ect ion,
we sim ply pass in t he required obj ect . The underlying reason for t his sim plicit y is t he high level of
decoupling provided by t he Dependency I nj ect ion pat t ern, which m akes it easy t o use an obj ect in
m ult iple environm ent s, at a m inim um in t he norm al runt im e environm ent and t he t est ing
envir onm ent .
We have not m anaged t o replace all t he funct ionalit y of t he Regist ry pat t ern by int roducing t he
Dependency I nj ect ion pat t ern. I n t he previous design, t he regist ry did also provide anot her im port ant
service, nam ely a m apping bet ween abst ract t ypes, t he IDiscountCurve int erface, and a concret e
im plem ent at ion t o be used in a given applicat ion or cont ext .
Surprisingly oft en, it is sufficient t o hard- code t he m apping in t he code t hat creat es t he obj ect . I n our
exam ple, we m ay have t wo different m et hods t hat are invoked from different point s in t he user
int erface, one t hat prices t he select ed bond based on inform at ion from t he dat abase and anot her one
t hat first asks t he user for a few point s, t hen const ruct s an in- m em ory curve from t he point s and
finally creat es a pricer based on t hat curve. I n bot h cases, we can sim ply configure t he pricer in t he
corresponding m et hods. As a m at t er of fact , using a regist ry in t his exam ple would feel awkward.
public class BondInfoForm : Form {
private TextBox priceTextBox;
I n m any cases, sim plicit y is a t rade off, and sim ple designs oft en fail t o address m ore com plex
requirem ent s. Fort unat ely, t he sim plicit y in creat ing com ponent s designed according t o t he
Dependency I nj ect ion pat t ern does not m ake it hard t o creat e com plex m apping and configurat ion
schem es, and t here are several light weight I oC cont ainers t hat can fulfill t he sam e role as a regist ry.
( I will discuss t wo of t hem lat er.) This m eans t hat we can choose bet ween a sim ple hard- coded
solut ion as shown previously and a m ore flexible m apping provided by som e infrast ruct ure code.
Anot her int erest ing considerat ion is an obj ect t hat has opt ional dependencies. I n t he case of t he bond
pricer, t he accuracy of cert ain calculat ions can be increased by t aking local holidays int o account ,
which m eans t hat a holiday calendar is an opt ional dependency. Wit h const ruct or dependency
inj ect ion, we express t his by providing t wo const ruct ors, one for each valid set of dependencies.
I t would also be possible t o use a const ruct or wit h all argum ent s and pass in null for t he opt ional
ones, but t his m akes t he cont ract less explicit , especially when t he num ber of dependencies
increases. I t is t herefore advisable t o always provide one const ruct or for each valid set of
dependencies and, if possible, t o chain t he const ruct ors. I f t his seem s im possible, it is probable t hat
t he class in quest ion has t oo m any dependencies and should be broken up.
public BondPricer() {
}
public IDiscountCurve DiscountCurve {
set { curve = value; }
}
}
Set t er inj ect ion provides t he sam e degree of decoupling as const ruct or inj ect ion, and it is easy t o see
t hat creat ing pricer obj ect s in unit t est s is as st raight forward as wit h const ruct or inj ect ion. An
im port ant difference is t hat t he pricer is in an invalid st at e unt il t he set t er m et hod has been called,
som et hing t hat is not possible wit h const ruct or inj ect ion. Addit ionally, we cannot declare t he curve
variable as readonly because it is not init ialized in t he const ruct or and, finally, wit h set t er inj ect ion it
is a lit t le m ore t ricky and error- prone t o im plem ent final init ializat ion funct ionalit y t hat needs t o be
run aft er all t he dependencies have been inj ect ed.
Set t er inj ect ion has it s uses despit e t hese short com ings because it scales bet t er t o com ponent s wit h
m any dependencies. I n a com ponent wit h t hree opt ional dependencies and a st rict view on
const ruct or inj ect ion, we would need eight const ruct ors. One could argue t hat t he com ponent needs
refact oring, but t his is not always pract ical, and it is good t o have a pat t ern at hand for sit uat ions like
t his. I n a sim ilar vein, m any exist ing obj ect s have a default const ruct or and propert ies, and t herefore
we can only use t hem wit h I oC cont ainers t hat support Set t er Dependency I nj ect ion.
There are furt her st yles of Set t er Dependency I nj ect ion, such as I nt erface Driven Set t er Dependency
I nj ect ion, t hat use m arker int erfaces t o dist inguish set t er m et hods t hat describe dependencies from
ot her public set t er m et hods. These st yles are eit her not widely used or do not significant ly change
t he key charact erist ics of set t er inj ect ion, so I will not discuss t hem here.
Inversion of Control
Having discussed t he Dependency I nj ect ion pat t ern and concret e im plem ent at ions of it , let us now
t urn t o I nversion of Cont rol, also known as t he Hollywood Principle ( " Don't call us, we'll call you! " ) .
St rict ly speaking, I oC is not a pat t ern but a general principle t hat sim ply st at es t hat obj ect s should
rely on t heir environm ent t o provide ot her obj ect s rat her t han act ively obt aining t hem .
Hist orically, t he t erm I oC was frequent ly used t o describe t he approach cert ain cont ainers t ook t o
creat e com ponent s at runt im e. Looking at t hese cont ainers, Mart in Fowler raised an im port ant
quest ion, nam ely " What aspect of cont rol are t hey invert ing?" He suggest ed t hat we recognize t he
set t er- and const ruct or- based approaches im plem ent ed by t hese cont ainers as a concret e pat t ern
and use t he m ore specific nam e Dependency I nj ect ion for it [ Fowler I nversion- OfCont rol] . This also
allowed people t o dist inguish bet ween t he Dependency I nj ect ion pat t ern and ot her t ypes of I oC.
A widely used pat t ern t hat adheres t o t he I oC principle but is not a Dependency I nj ect ion variant is
Cont ext ualized Dependency Lookup. For our bond pricer, using t his pat t ern would m ean t hat we
cont inue t o use a regist ry- like class, which is oft en called cont ext in t his pat t ern, but let t he cont ainer
provide t his cont ext t o our obj ect , which is t he inversion of cont rol aspect . I n code t his can look as
follows:
On closer inspect ion, t his pat t ern looks like a hybrid bet ween t he Service Locat or and t he Set t er
Dependency I nj ect ion pat t erns. This is no accident because hist orically t his pat t ern is one of t he first
I oC pat t erns and proved t o be an im port ant st epping st one t o t he m ore elegant Dependency
I nj ect ion pat t erns.
Ret urning t o t he const ruct or inj ect ion exam ple described earlier, let us exam ine how we would use
t he cont ainer provided by Spring.NET t o get a configured inst ance of a pricer.
The preferred way t o describe com ponent s and t heir dependencies wit h Spring.NET is wit h an XML
configurat ion file. We declare our obj ect s by t ype, including t he assem bly t hey are loaded from , and
t hen resolve t he dependency of t he pricer on t he discount curve by a nest ed const ruct or- arg elem ent
in t he declarat ion of t he pricer.
<objects>
<object name="DbCurve" type="MyBank.DatabaseDiscountCurve, MyBank"/>
<object name="DbPricer" type="MyBank.BondPricer, MyBank">
<constructor-arg><ref local="DbCurve"/></constructor-arg>
</object>
</objects>
To access t he obj ect s in our code, we can creat e an inst ance of IApplicationContext, t ell it t o load
t he configurat ion from t he config file, and t hen ask it for an obj ect by nam e. The cont ext ensures
t hat all dependent obj ect s are creat ed and inj ect ed where required.
I n t his case, however, t here m ust be som e ot her piece of code t hat creat es t he form , and t his code
would look up t he form from t he cont ext and would t herefore be coupled t o t he cont ext . Clearly, it
cannot be t urt les all t he way down. To solve t his issue m ost cont ainers provide int egrat ion wit h t he
applicat ion fram eworks, Spring.Web for exam ple, such t hat t he init ial applicat ion- specific
com ponent s, t he Windows form s and Web pages, can sim ply use dependency inj ect ion while t he
applicat ion fram ework is responsible for creat ing t hem using t he cont ext . I f t here is no int egrat ion for
a part icular cont ainer/ fram ework com binat ion it is best t o use dependency inj ect ion as m uch as
possible and lim it t he dependency on t he cont ext t o one class.
I f we prefer t o use set t er inj ect ion, we can use t he set t er- based pricer im plem ent at ion discussed
before and change t he Spring.NET configurat ion elem ent for t he pricer. The code t hat obt ains t he
pricer rem ains unchanged because t he cont ainer deals wit h creat ing t he obj ect s.
<objects>
<object name="DbCurve" type="MyBank.DatabaseDiscountCurve, MyBank" />
<object name="DbPricer" type="MyBank.BondPricer, MyBank" >
<property name="DiscountCurve">
<ref local="DbCurve"/>
</property>
</object>
</objects>
The aut hors of Spring.NET generally advocat e set t er inj ect ion, but t he cont ainer support s bot h st yles
equally well. As a m at t er of fact , not hing st ops us from com bining const ruct or and set t er inj ect ion. I f
we design our pricer so t hat it declares it as required, or non- opt ional, dependency on t he discount
curve in t he const ruct or and provides a set t able propert y for t he opt ional dependency on t he holiday
calendar, we can configure a pricer wit h a calendar as follows:
<objects>
<object name="DbCurve" type="MyBank.DatabaseDiscountCurve, MyBank" />
<object name="Calendar" type="MyBank.DefaultHolidayCalendar, MyBank" />
<object name="DbPricer" type="MyBank.BondPricer, MyBank" >
<constructor-arg><ref local="DbCurve"/></constructor-arg>
<property name="HolidayCalendar">
<ref local="Calendar"/>
</property>
</object>
</objects>
This only scrat ches t he surface of t he possibilit ies t hat Spring.NET offers, but even t hese sim ple
feat ures can help enorm ously wit h configuring com ponent s t hat are designed according t o t he
Dependency I nj ect ion pat t ern. One can even argue t hat placing t oo m uch and t oo com plex logic int o
t he configurat ion file provides flexibilit y t hat is rarely needed at t he expense of m aint ainabilit y.
Most I oC cont ainers support t he resolut ion of dependencies based on runt im e inform at ion. This
feat ure is known as aut o- wiring because t he set t ing of dependent com ponent s, t he wiring, occurs
aut om at ically, wit hout any addit ional configurat ion. Spring.NET support s aut o- wiring as an
alt ernat ive t o XML files, but I will use PicoCont ainer.NET [ PicoCont ainer] in t his sect ion t o add variet y
and because for t his cont ainer, aut o- wiring is t he preferred opt ion.
Using PicoCont ainer.NET, t he only st ep t hat is required t o enable t he cont ainer t o resolve
dependencies and creat e obj ect s is t o regist er t he concret e im plem ent at ion classes wit h t he
cont ainer.
By placing t he declarat ions int o code, we rem ove redundancy and we get bet t er support from t he I DE
because it is now able t o det ect m isspelled t ype nam es, and it can also safely renam e t ypes in
aut om at ed refact orings.
The obj ect s are obt ained from t he cont ainer in alm ost t he sam e way as t hey are obt ained from t he
applicat ion cont ext in Spring.NET, and for t hat reason t he sam e considerat ions regarding a
dependency on t he cont ainer apply: Alm ost all classes should m ake use of dependency inj ect ion,
leaving only one cent ral class t hat int eract s wit h t he cont ainer t o obt ain t he init ial com ponent s.
The previous exam ple also shows t hat , in addit ion t o using t he t ype syst em , PicoCont ainer.NET
support s nam ed com ponent s: t he pricer in t his exam ple. This m akes it possible t o look up obj ect s
wit hout having t o specify t heir t ype, which int roduces anot her degree of decoupling.
Opt ional dependencies are handled aut om at ically because PicoCont ainer. NET uses t he m ost com plex
const ruct or for which it can sat isfy t he dependencies. I n t he previous exam ple, PicoCont ainer.NET
uses t he one argum ent const ruct or for BondPricer, which only t akes a curve, but if we add t he
regist rat ion of t he holiday calendar, PicoCont ainer uses t he t wo argum ent const ruct or when we get
t he pricer obj ect .
As far as obj ect dependencies are concerned, we are not losing any flexibilit y by using t ype- based
aut o- wiring inst ead of a configurat ion file- based approach, and at t he sam e t im e we benefit from an
im proved developm ent experience. Aut o- wiring does not work equally well if a class expect s
param et ers, such as host nam es, port num bers and t im eout s, in t heir const ruct or because prim it ive
t ypes do not convey m uch inform at ion about t heir int ended purpose. I f we regist er t wo int egers wit h
t he cont ainer, one t hat specifies a port num ber and t he ot her one a t im eout , t he cont ainer sees bot h
of t hem as int egers and has no way of det erm ining which one t o use in a const ruct or t hat t akes one
int eger.
The underlying quest ion is whet her t he cont ainer should support t he inj ect ion of required
com ponent s in t he sam e way as it handles t he set t ing of configurat ion param et ers or whet her bot h
requirem ent s are seen as different concerns t hat should be handled wit h t he m ost suit able approach
for each concern. Using t ype- based aut o- wiring arguably provides benefit s over configurat ion files
when m anaging dependencies, so one could use aut o- wiring for t his purpose. I n t he sam e scenario,
configurat ion param et ers can be set wit h set t ers for nam ed propert ies, which is arguably m ore
int uit ive for t hat purpose.
A t hird I oC cont ainer t hat is available for t he .NET plat form is Windsor, which is part of t he Cast le
proj ect [ Cast le] . The core cont ainer im plem ent at ion of t he Cast le proj ect , which t he developers call
m icro- kernel, uses t ype- based aut o- wiring but it also allows plug- ins t o add addit ional dependency
resolut ion st rat egies. The Windsor cont ainer [ Windsor] , which is based on t he m icro- kernel, adds
support for configurat ion files, t hus allowing developers t o choose t he m ost appropriat e m echanism .
This is an approach t hat was successfully pioneered by NanoCont ainer [ NanoCont ainer] , a Java
cont ainer t hat is layered on t op of t he Java version of PicoCont ainer.
Nested Containers
The fact t hat t he cont ainer in Spring.NET is nam ed ApplicationContext hint s at t he fact t hat t he
cont ainer defines a cont ext for t he obj ect s t hat ret rieve com ponent s from t he cont ainer. These
obj ect s int eract wit h t he ret urned obj ect s, and t heir behavior depends on t he concret e
im plem ent at ions provided by t he cont ainer; hence, t he cont ainer can be seen as t he provider of a
cont ext in which obj ect s act . The nam e furt her suggest s t hat t he cont ext creat ed from t he
configurat ion file is applicat ion- wide, and all lookups in an applicat ion share t he sam e cont ext .
Web applicat ions use m ult iple cont ext s, and m ost Web fram eworks m ake t hem explicit in t he form of
applicat ion, session, and request obj ect s. Request - handling code, such as t he code behind a Web
page, usually depends on several com ponent s. Som e of t he com ponent s are part of t he applicat ion
cont ext because t hey can be shared by all request handlers while ot hers are part of t he individual
request cont ext because t hey should only be used by a single request .
Som e I oC cont ainer im plem ent at ions support t his m odel and allow cont ainers t o be nest ed, which
m eans t hat a cont ainer can have a parent cont ainer and, as a direct consequence, child cont ainers.
When a cont ainer cannot sat isfy all dependencies required t o creat e a com ponent , it t ries t o obt ain
t he m issing com ponent s from it s parent cont ainer, which in t urn can request com ponent s from it s
own parent cont ainer. This set - up broadly resem bles t he Chain of Responsibilit y design pat t ern [ GoF
Design Pat t erns] .
As an exam ple, consider t he creat ion of a request handler or page t hat has a dependency on a
dat abase connect ion and a logger. The dat abase connect ion should only be used by one request at a
t im e while t he logger can be shared by all request s. This, however, is of no concern t o t he request
handler.
public RequestHandlerFactory {
IPicoContainer sessionContainer;
Aft er t he request cont ainer is creat ed in t he CreatePage() m et hod, t he code regist ers t he page t ype
wit h t he request cont ainer so t hat t he page it self can use dependency inj ect ion. When it ret rieves t he
act ual page inst ance in t he t hird line, t he request cont ainer t ries t o creat e t he page but , assum ing a
ResultPage is required, it cannot resolve t he dependency on t he Logger class because t his has not
been regist ered wit h t he request cont ainer. I n t his sit uat ion, it will t ry t o obt ain t he m issing
com ponent from it s parent , t he session cont ainer, which also does not cont ain a logger and t hus
request s t he logger from it s parent , t he applicat ion cont ainer. Provided t hat a logger is regist ered
wit h t hat cont ainer, all dependencies for t he page can be sat isfied and it is creat ed by t he request
cont ainer.
The advant age of t his approach is t hat on t he one hand com ponent s can be regist ered and shared at
t he appropriat e level, while on t he ot her hand obj ect s t hat ret rieve com ponent s from a cont ainer only
have t o deal wit h one cont ainer and can rely on it t o find t he required com ponent s in t he chain of
cont ainer s.
I t is safe t o say t hat t he Service Locat or pat t ern is m ore com m only used t oday, but t his is not
necessarily because it is a bet t er m at ch for m ost applicat ions. I nst ead, t he m ost likely reason is t hat
t he Service Locat or pat t ern has been around for a long t im e while Dependency I nj ect ion is a
com parat ively new pat t ern t hat is not as well known yet . I n fact , developers arrived at t he
Dependency I nj ect ion pat t ern when t hey t ried t o im prove t he Service Locat or pat t ern.
The com plet e decoupling of t he com ponent s from t he dependency resolut ion m echanism t hat is
achieved by t he Dependency I nj ect ion pat t ern im proves t est abilit y because t he t est s do not have t o
set up specialized versions of a locat or t o provide st ubs or m ocked obj ect s. I t also helps wit h reuse in
large syst em s as it avoids t he problem at ic sit uat ion where different com ponent s t o be used in a
syst em are t ied t o different locat or im plem ent at ions.
Anot her advant age of t he Dependency I nj ect ion pat t ern, especially wit h Const ruct or Dependency
I nj ect ion, is t hat all dependencies of an obj ect are easily visible in code. Modern I DEs are capable of
highlight ing all usages of a service locat or in a given class ( by pressing Ct rl- Shift - F7) , but even wit h
a sophist icat ed I DE t his is not as easy as looking at a const ruct or.
I t is oft en st at ed t hat Dependency I nj ect ion couples t he life cycle of t he obj ect A t hat has t he
dependencies wit h t he life cycles of t he obj ect s B and C it depends on, because B and C m ust be
creat ed before A so t hat t hey can be inj ect ed. This is not a problem wit h t he Service Locat or pat t ern
because t he creat ion of B and C can be post poned unt il t hey are request ed from t he locat or by A.
Fort unat ely, t he sam e can be achieved, if not as nat urally, wit h t he Dependency I nj ect ion pat t ern, as
one usage of t he Com ponent Adapt ors in PicoCont ainer shows. I nst ead of inj ect ing an inst ance of t he
act ual class, t he cont ainer inj ect s a proxy t hat only creat es t he real inst ance when it is first used and
from t hen on forwards all m et hod calls t o it . This is com plet ely t ransparent t o t he obj ect t hat has t he
dependencies, but it effect ively decouples t heir lifecycles.
Summary
I n t his sect ion, we looked at t wo issues t hat arise in t he const ruct ion of any soft ware syst em : t he
coupling of obj ect s t hat depend on ot her obj ect s and t he m anaging of com ponent inst ances. We first
described how t hese issues can be addressed wit h t he com m only used Fact ory, Regist ry, and Service
Locat or pat t erns. Realizing t hat t hese pat t erns have cert ain short com ings, we discussed t he
Dependency I nj ect ion pat t ern, which addresses t hese issues in a novel way. This pat t ern, which is
based on t he I nversion of Cont rol principle, provides bet t er decoupling and scales well, from sim ple
problem s t o very com plex dependencies. I t also im proves t est abilit y, which is im port ant for TDD, and
allows dom ain m odels t o be com plet ely separat ed from infrast ruct ure code, which m akes it a useful
t ool for DDD.
As wit h alm ost any pat t ern, Dependency I nj ect ion is not a silver bullet and one cannot m ake t he
general recom m endat ion t o always replace t he use of t he Service Locat or pat t ern wit h Dependency
I nj ect ion. I t is im port ant t o underst and t he differences and benefit s of each pat t ern and use t hem
appropriat ely. We have also seen t hat t he Dependency I nj ect ion pat t ern has several flavors t hat
provide t rade- offs. Fort unat ely, choosing a cert ain flavor does not affect t est abilit y, which is
im port ant for developm ent , and t he cont ainers t hat are used at runt im e generally support all m ain
variant s. We can t herefore choose, or even m ix, different flavors as required.
The m ost im port ant considerat ion when designing syst em s is t o separat e concerns, in t his case
configurat ion and usage of com ponent s, and t hen choose t he m ost suit able design pat t ern from a
rich cat alogue.
Thanks, Erik!
I j ust want t o st ress once m ore what Erik ended wit h. You can t hink about Dependency I nj ect ion as
what Mart in Fowler t alks about in his DSL art icle [ Fowler LW] when he says t hat developm ent can be
t hought of as creat ing good abst ract ions and t hen configuring t hem . Dependency I nj ect ion is one
approach t o t aking care of part of t he configurat ion.
I had t o bit e m y t ongue not t o say " configurat ion aspect " in t he previous sent ence. You wouldn't
have forgiven m e for providing such a weak t hread t o t he next subj ect , right ? As a m at t er of fact ,
Dependency I nj ect ion and Aspect - Orient ed Program m ing ( AOP) act ually oft en live in sym biosis, as
you soon will find out .
Do you rem em ber t he discussions about Reposit ory design? We can choose am ong several principles,
such as
1 . Specific Reposit ories
2 . A base class
The problem wit h approaches 2 ( on t op of t he lack of t ype safet y, if you see t hat as a problem ) and 3
is t hat t hey kind of creat e an aut om at ic, unnat ural abst ract ion t hat all Reposit ories will have. For
exam ple, not all Reposit ories should have delet e possibilit ies.
The answer m ight be t o creat e a sm aller base class and writ e specific code for t he variat ions. I f you
go t hat rout e, you m ight find t hat your base class will only have perhaps t wo or t hree m et hods
( GetById(), MakePersistent(), and so on) and you get pret t y close t o approach 1 again.
You can t ry t o lessen t he code duplicat ion by fact oring out general code int o helper classes t hat your
specific Reposit ories delegat e t o. Then you'll have t o writ e t hat boring and t edious delegat ion code,
which won't m ake anyone happy.
I nst ead of st art ing wit h a base class t hat " never" has t he right granularit y, anot her approach is t o
build up t he right Reposit ory out of several t iny aspect s, m ixing in t he right aspect s t o t he right
Reposit ory. This is anot her way of t hinking about t he problem . I t m ay not necessarily always be t he
right way ( t here is never one right way) , but it is definit ely wort h m ore t hought . I asked m y friend
Aleksandar Seovi t o writ e a short int roduct ion t o Aspect Orient at ion ( AO) .
Aspect-Oriented Programming (AOP)
By Aleksandar Seovi
I n t he last couple of years, AOP has been generat ing a lot of buzz in t he soft ware developm ent
com m unit y. AOP was invent ed in t he lat e 1990s by Gregor Kiczales [ Gregor Kiczales] and his t eam at
Xerox PARC labs in an at t em pt t o solve a problem of code duplicat ion in obj ect - orient ed syst em s by
encapsulat ing crosscut t ing concerns of t he syst em int o reusable aspect s.
Aspect J [ Aspect J] , which could be considered a reference AOP im plem ent at ion, was released in 2001
and has spurred a lot of act ivit y in t he Java com m unit y, including a num ber of alt ernat ive AOP
im plem ent at ions.
While m ost of t he AOP- relat ed act ivit y is st ill happening in t he Java com m unit y, t here are several
.NET AOP im plem ent at ions t hat you can use t oday t o reap t he benefit s of AOP, such as Spring.NET
AOP [ Spring.NET] , Loom .NET [ Loom .NET] and Aspect Sharp [ Aspect Sharp] .
Even t hough every art icle ever writ t en on AOP t hat you run across will probably have t he sam e
boring exam ple, we will use m et hod invocat ion logging t o show you what t ypes of problem s AOP t ries
t o address.
Let 's assum e t hat we've im plem ent ed a sim ple calculat or service t hat support s four basic arit hm et ic
operat ionsaddit ion, subt ract ion, division and m ult iplicat ionas t he following code shows. Not e how
sim ple and readable t he m et hods are because t hey only cont ain t he core logic.
For t he sake of argum ent , let 's say t hat a new user request com es up t hat requires you t o log every
call t o your service m et hods. Class nam e, m et hod nam e, param et er values passed t o it , and it s
ret urn value should be logged.
Using only OOP, t his seem ingly sim ple request would force you t o m odify all four m et hods and add
logging code t o t hem . The end result would look sim ilar t o t his:
using System;
namespace LoggingAspectDemo
{
public class LoggingCalculator : ICalculator
{
public int Add(int n1, int n2)
{
Console.Out.WriteLine("-> LoggingCalculator.Add
(" + n1 + ", " + n2 + ")");
int result = n1 + n2;
Console.Out.WriteLine("<- LoggingCalculator.Add
(" + n1 + ", " + n2+ ") returned " + result);
return result;
}
return result;
}
public int Multiply(int n1, int n2)
{
Console.Out.WriteLine("-> LoggingCalculator.Multiply
(" + n1 + ", " + n2 + ")");
int result = n1 * n2;
Console.Out.WriteLine("<- LoggingCalculator.Multiply
(" + n1 + ", " + n2 + ") returned " + result);
return result;
}
As you can see, sim ilar logging code exist s in each of t he m et hods.
N ot e
As you underst and, t he previous exam ple could have been done a bit bet t er even wit hout
AOP, such as by using t he Decorat or pat t ern [ GoF Design Pat t erns] , but we are t rying t o
m ake a pedagogic point here, so please be pat ient .
I t 's also t he case t hat t he Decorat or pat t ern would affect t he consum er because it has t o
inst ant iat e t he decorat or inst ead of t he decorat ed class, and if you need t o add m ult iple
services you need t o im plem ent and chain m ult iple decorat ors.
There is a lot of code duplicat ion, which is never a good sign. I n t his case, duplicat e code could
possibly be sim plified by creat ing st at ic ut ilit y m et hods for logging t hat would t ake class and
m et hod nam e and param et er or ret urn values as argum ent s, but duplicat ion it self cannot be
rem oved using OOP.
Logging code dist ract s a reader from t he core logic of t he m et hod, t hus m aking t he m et hod less
readable and m ore difficult t o m aint ain in t he long run.
Code t hat im plem ent s core logic is longer t han necessary. Met hods t hat could've been sim ple
one- liners had t o be broken int o result assignm ent and it s ret urn, j ust so t he result could be
print ed in t he logging code.
I f you had t o rem ove logging code at som e point , you would be faced wit h a daunt ing t ask of
m anually rem oving or com m ent ing out all t he logging code from your classes.
I f you decided t hat you want t o log t he full class nam e, including nam espace, you would have t o
find all t he m et hods t hat cont ain logging code and add m issing nam espace inform at ion by hand.
The sam e applies if you decide t hat you want t o log except ions such as overflow and division by
zero when t hey occuryou'd have t o add a t ry/ cat ch block and a st at em ent t hat would log
except ions in m any, m any places t hroughout your code base.
Of course, one could argue t hat if you used a sophist icat ed logging solut ion, such as Log4Net
[ Log4Net ] or Ent erprise Library Logging Applicat ion Block [ Ent erprise Library Logging] , inst ead of
plain Console.Out.WriteLine st at em ent s, you could t urn logging off by sim ply changing t he
configurat ion set t ing, wit hout t he need t o t ouch any of your classes.
While t hat is ent irely t rue, it really m isses t he point in t his case. Your core logic would st ill be
int erm ingled wit h ancillary logging code, and you would st ill have t o edit m any m et hods by hand if
you want ed t o m ake any changes t o t he logging logic. Moreover, if we change our exam ple from
logging t o securit y policy enforcem ent or t ransact ions, you won't be able t o t urn it on or off so easily
eit her.
What AOP prom ises t o do for you is t o allow you t o separat e crosscut t ing code, such as logging or
securit y, int o aspect s and t o apply t hose aspect s easily t o all t he classes and m et hods t hat need
t hem . Of course, t here is a lot m ore t o AOP t han t his. I t also allows you t o separat e business rules
from t he core logic and t o change your exist ing obj ect s by adding bot h st at e and behavior t o t hem .
We'll see exam ples of t his in t he following sect ions.
What is im port ant t o underst and is t hat AOP is not a replacem ent for OOPit is sim ply an ext ension t o
it t hat allows you t o go t o places t hat are difficult t o reach wit h OOP alone. Good obj ect - orient ed
principles and pract ices st ill apply. Act ually, it is probably even m ore im port ant t han ever before t o
have a solid OO design in place, as it will m ake applicat ion of aspect s m uch easier.
An a dvice is a piece of code t hat you want t o encapsulat e and reuse. For exam ple, logging code
would be im plem ent ed as an advice and applied wherever you need it . There are several t ypes
of advice, such as before, aft er , and around advice.
An in t r odu ct ion is a som ewhat special t ype of advice t hat only applies t o classes. I nt roduct ions
allow you t o int roduce new m em bers int o exist ing classes, bot h st at e and behavior, and could
be used t o achieve t he benefit s of m ult iple inherit ance in languages t hat do not support it ,
wit hout it s t radeoffs. ( I nt roduct ion is called m ixin in som e languages.)
A j oin poin t is any place in t he code where an advice could be applied. I n t heory, a j oinpoint
could be alm ost anyt hinginst ance variable, for loop, if st at em ent , and so on. I n pract ice,
however, m ost com m only used j oin- point s are classes, m et hods, and propert ies.
A poin t cu t ident ifies a set of j oinpoint s where advice should be applied. For exam ple, if you
want t o apply t ransact ion advice t o all t he m et hods t hat are m arked wit h transaction at t ribut e,
you would have t o declare a point cut t hat ident ifies t hose m et hods.
An a spe ct groups advices and t he point cut s t hey apply t o, which is in a way sim ilar t o how a
class groups dat a and associat ed behavior t oget her.
AOP in .NET
Enough t heorylet 's see how AOP can help us solve real- world problem s t hat we face alm ost every day
during developm ent .
Exam ples in t his sect ion are built using t he Spring.NET AOP im plem ent at ion, so you will need t o
download and inst all t he lat est Spring.NET release in order t o t ry t hem .
N ot e
Please not e t hat , as of t his book's writ ing, t he exam ples in t his sect ion are based on t he
planned im plem ent at ion of t he AOP support in Spring. NET. Visit t his book's Web sit e
( w w w .j nsk.se/ adddp) for inform at ion about changes, or check t he official Spring.NET
docum ent at ion, which can be found at www.springfram ework.net .
So let 's see how we can leverage AOP t o solve t he problem s associat ed wit h t he previous logging
code.
The first t hing we need t o do is creat e an advice t hat will encapsulat e logging code:
using System;
using System.Text;
using AopAlliance.Intercept;
namespace LoggingAspectDemo
{
public class MethodInvocationLoggingAdvice
: IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
Console.Out.WriteLine("-> " +
GetMethodSignature(invocation));
object result = invocation.Proceed();
Console.Out.WriteLine("<- " +
GetMethodSignature(invocation)
+ " returned " + result);
return result;
}
return sb.ToString();
This advice will log t he class nam e, m et hod nam e, and param et er values and ret urn values for each
call t o t he m et hod t o which it is applied.
I t uses t he ToString() m et hod t o print param et er and ret urn values. That m ight not be sufficient in
all cases, but it should work for t he vast m aj orit y of m et hods, especially if you t ake care t o
im plem ent ToString() for your applicat ion classes. I n t he case of an except ion, t his advice will sim ply
propagat e it , so any error handling code you m ight have in place should work fine.
I t 's in t he Invoke() m et hod where m ost of t he m agic happens. What we are basically saying here is
t hat we want t o log t he st art of t he m et hod call, capt ure t he result by assigning t he value of t he
invocation.Proceed() call t o a result variable, and log t he result before ret urning it . The call t o
invocation.Proceed() is crit icalt hat is what causes our calculat or m et hod t o be execut ed.
The GetMethodSignature() helper m et hod is used t o build a m et hod signat ure in a generic fashion by
inspect ing t he invocation obj ect . You'll probably not ice t hat we called GetMethodSignature() t wice,
even t hough it seem s t hat we could've opt im ized t he advice a bit by assigning it s result t o a local
variable and using t hat variable inst ead. The reason for t hat is so t hat we can also see any changes
in t he param et ers t hat were used, in case t hey are m odified by our advised m et hod. This is especially
helpful when logging calls t o m et hods t hat have " out " param et ers.
Now t hat we have our advice defined, what happens if we find out t hat we need t o log any except ions
t hat t he advised m et hods t hrow? As you can probably guess by now, t his change is t rivialall we need
t o do is add necessary logic t o our advice's Invoke() m et hod:
Changing GetMethodSignature() t o include t he class nam espace is even sim pler, so we'll leave it as
an exercise t o t he reader.
Creat ing an advice is only half of t he st ory. Aft er all, what good is an advice if it 's never used? We
need t o apply t he logging advice t o our Calculator class from t he first code list ing, which in
Spring.NET can be accom plished in t wo ways.
The first approach is t o apply it using code. While t his is very sim ple in t his part icular case, it is not
ideal because you are m anually applying an advice t o a part icular obj ect inst ead of relying on t he
cont ainer t o apply it aut om at ically for you wherever necessary based on aspect configurat ion.
Nevert heless, let 's see how we can apply our logging advice in t he code.
using Spring.Aop.Framework;
...
That 's it wit h only t hree lines of code you have applied t he logging advice t o all t he m et hods of t he
Calculator inst ance and obt ained a reference t o it . You can now call any m et hod on it , and you will
see t hat t he calls are properly logged.
The Spring.NET declarat ive approach t o AOP is m uch m ore powerful and doesn't require you t o writ e
any code. However, it does require you t o use Spring.NET t o m anage your obj ect s, which is out of
t he scope of t his sect ion. For t he sake of com plet eness, I will show you what a declarat ive aspect
definit ion would look like in t his case, but you will have t o refer t o t he Spring.NET Reference Manual
for m ore det ails:
<aop:aspect name="MethodInvocationLoggingAspect">
<aop:advice
type="LoggingAspectDemo.MethodInvocationLoggingAdvice"
pointcut=
"class(LoggingAspectDemo.Calculator) and method(*)"/>
</aop:aspect>
This will cause t he Spring.NET cont ainer t o apply t he advice we creat ed t o all t he m et hods of all
inst ances of a Calculator class.
Just t o give you a feel for t he power of t he declarat ive approach and AOP in general, t his is all you
would have t o change in t he previous declarat ion t o apply our logging advice t o all t he m et hods of all
t he classes in t he LoggingAspect-Demo nam espace:
<aop:aspect name="MethodInvocationLoggingAspect">
<aop:advice
type="LoggingAspectDemo.MethodInvocationLoggingAdvice"
pointcut="class(LoggingAspectDemo.*) and method(*)"/>
</aop:aspect>
The second exam ple we are going t o cover uses a com binat ion of int r oduct ion and before advice t o
im plem ent and enforce obj ect locking.
Let 's say t hat you have dom ain obj ect s in your applicat ion t hat you need t o be able t o lock wit hin a
session. When t he obj ect is locked, every at t em pt by ot her sessions t o m odify it s st at e should result
in a LockViolationException being t hrown.
Using t he OOP- only approach, you would add necessary st at e and m et hods t o classes t hat need t his
behavior eit her direct ly or by m aking t hem inherit from som e base class t hat im plem ent s core locking
and unlocking funct ionalit y.
The form er solut ion is bad because it result s in a lot of duplicat e code. The second solut ion is OK as
long as t he classes t hat need locking behavior belong t o t he sam e class hierarchy and all of t hem
need t o support locking. I f t hey belong t o different hierarchies, or if you don't want t o int roduce
locking behavior int o t hem all, you are back t o square one.
A m uch bet t er approach is t o leverage AOP feat ures and declarat ively add locking support only t o t he
classes t hat need it . This can be easily accom plished using a com binat ion of int roduct ion and before
adv ice.
The first st ep in t his case is t o creat e an int roduct ion t hat will be used t o add st at e and behavior t o
advised classes. I n order t o do t hat , we need t o define an int erface t hat we want t o int roduce.
namespace LockableAspectDemo
{
public interface ILockable
{
void Lock();
void Unlock();
bool IsLocked { get; }
}
}
The next st ep is t o creat e an int roduct ion class t hat im plem ent s t his int erface. I n t his exam ple, we
will assum e t hat we are writ ing an ASP.NET Web applicat ion and will use
HttpContext.Current.Session.SessionID as a session I D for locking purposes.
using AopAlliance.Aop;
namespace LockableAspectDemo
{
public class LockableIntroduction : ILockable, IAdvice
{
private bool isLocked;
private string sessionId;
So far we've creat ed an int roduct ion t hat we want t o use. Now we need t o creat e an advice t hat will
enforce t he lock im plem ent ed by t his int roduct ion.
I n t his part icular case, we don't need a full- blown around advice, such as t he one we used in t he
logging exam ple. All t hat our advice needs t o do is t o check whet her t he t arget obj ect is locked and
t hrow an except ion if it is.
For t hat purpose, we can use a som ewhat sim pler before advice, which doesn't require us t o m ake a
call t o IMethodInvocation.Proceed():
using System;
using System.Reflection;
using Spring.Aop;
namespace LockableAspectDemo
{
public class LockEnforcerAdvice : IMethodBeforeAdvice
{
public void Before(MethodBase method, object[] args,
object target)
{
ILockable lockable = target as ILockable;
if (lockable != null && lockable.IsLocked)
{
throw new LockViolationException
("Attempted to modify locked object.", target);
}
}
}
}
The last st ep is t o apply t he int roduct ion and advice we defined earlier t o dom ain obj ect s t hat we
want t o m ake lockable. For t he purpose of t his exam ple, let 's say t hat we want t o m ake t he Account
class and all it s descendant s lockable.
namespace LockableAspectDemo.Domain
{
public class Account
{
private string name;
private double balance;
public Account() {}
[StateModifier]
public virtual void Withdraw(double amount)
{
balance -= amount;
}
[StateModifier]
public virtual void Deposit(double amount)
{
balance += amount;
}
}
}
We'll om it descendant s for brevit y, but we can assum e t hat locking also needs t o be applied t o t he
CheckingAccount, SavingsAccount, and MoneyMarketAccount classes t hat inherit from our base Account
class.
There are several t hings t hat m ake t his class suit able for proxy- based AOP. First of all, propert ies are
im plem ent ed using a com binat ion of privat e fields and propert y get t ers and set t ers. I f you used
public fields inst ead, it would be im possible for an AOP proxy t o int ercept propert y access.
Second, all propert ies and m et hods are declared as virt ual. This allows Spring. NET t o creat e a
dynam ic proxy by inherit ing t he Account class and inj ect ing int ercept ion code. I f m et hods were final,
t he Account class would have t o im plem ent an int erface in order t o be proxied using t he com posit ion
proxy. I f neit her int erface nor virt ual m et hods were present , it would've been im possible t o creat e a
proxy for t he Account class and apply AOP advices t o it .
The final t hing t o not ice is t he usage of t he StateModifier at t ribut e. We defined t his at t ribut e
prim arily t o show how advices can be applied based on at t ribut es, but t his is also a case where using
an at t ribut e m akes a lot of sense. I t provides addit ional m et adat a t hat m akes it very obvious which
m et hods m odify obj ect 's st at e.
We could've used t he StateModifier at t ribut e in front of propert y set t ers as well, but in m y opinion
t hat is som ewhat redundant . I n addit ion t o t hat , om it t ing StateModifier in t he case of propert ies
gives us an opport unit y t o show you how t o define a com posit e point cut .
While it is possible t o configure t he locking aspect using a code- only approach, it is som ewhat
cum bersom e, so we'll show you only t he declarat ive approach in t his case.
<aop:aspect name="LockEnforcementAspect">
<aop:pointcut name="StateModifiers"
expression="class(Account+)
and (setter(*) or attribute(StateModifier))"/>
<aop:advice type="LockableAspectDemo.LockableIntroduction"
pointcut="class(Account+)"/>
<aop:advice type="LockableAspectDemo.LockEnforcerAdvice"
pointcut-ref="StateModifiers"/>
</aop:aspect>
Most of t he declarat ion should be self- explanat ory. Things t hat deserve at t ent ion are
The plus sign behind t he class nam e in t he point cut definit ion specifies t hat t he point cut should
m at ch t he specified class and classes derived from it .
The expression "setter(*)" is used t o m at ch all propert y set t ers, regardless of t heir t ype and
nam e.
Finally, we need t o creat e a client t hat will leverage t he int roduced ILockable int erface t he sam e way
as if it was im plem ent ed direct ly by t he Account class.
using LockableAspectDemo.Domain;
namespace LockableAspectDemo.Services
{
public class AccountManager
{
public void TransferFunds(Account from, Account to
, double amount)
{
ILockable acctFrom = from as ILockable;
ILockable acctTo = to as ILockable;
try
{
acctFrom.Lock();
acctTo.Lock();
from.Withdraw(amount);
to.Deposit(amount);
}
finally
{
acctFrom.Unlock();
acctTo.Unlock();
}
}
}
}
As you can see, by using AOP we can t ruly m odularize t he obj ect locking feat ure and apply it
wherever appropriat e wit hout t he short com ings of t he pure OOP approaches.
N ot e
While t he previous exam ple is t echnically no different t han if we used lock st at em ent s t o
synchronize access t o acctFrom and acctTo from t he m ult iple t hreads, t here is a big
difference in t he sem ant ics bet ween t he t wo. Wit h ILockable we could keep t he lock for t he
durat ion of t he m ult iple HTTP request s, not j ust for t he single request .
The final exam ple we are going t o show in t his sect ion dem onst rat es a som ewhat advanced AOP
usage. We do not recom m end t hat you st art experim ent ing wit h AOP by m oving all your business
rules int o aspect s. I t is probably t he best idea t o int roduce AOP int o your proj ect s slowly by m aking
t hem handle obvious crosscut t ing concerns, such as logging, securit y, and t ransact ions. However, we
feel it is im port ant t hat you underst and it s full pot ent ial so you can apply it effect ively when you
becom e m ore fam iliar wit h it .
Every business applicat ion has various business rules t hat are t ypically em bedded int o t he applicat ion
logic. While t his works j ust fine for m ost rules and m ost applicat ions, it m akes t hem less flexible t han
t hey need t o be and usually requires code m odificat ion when business rules change. By m oving som e
of t he business rules int o aspect s, you can m ake t he applicat ion m uch easier t o cust om ize. Unlike in
previous exam ples, rem oving code duplicat ion is usually not t he m ain reason you would m ove
business rules int o aspect st he prim ary driver in t his case is increased applicat ion flexibilit y.
The best candidat es are rules t hat cause secondary logic t o be im plem ent ed along wit h t he core
logic. For exam ple, t he core logic of t he Account.Withdraw() m et hod from t he previous exam ple is t o
reduce t he account balance. Secondary logic would be t o enforce m inim um balance requirem ent s or
t o send an em ail alert t o t he account holder when balance falls below a cert ain am ount .
Let 's see what our Account class would look like if we added bot h m inim um balance enforcem ent and
a balance alert t o it .
using System;
namespace BusinessRulesDemo.Domain
{
public class Account
{
private AccountHolder accountHolder;
private string name;
private double balance;
private double minimumBalance;
private double alertBalance;
public Account() {}
balance -= amount;
[StateModifier]
public virtual void Deposit(double amount)
{
balance += amount;
}
}
}
While you could argue t hat t he m inim um balance check should rem ain in t he Account class, it is
obvious t hat t he not ificat ion sending code is not t he prim ary funct ionalit y of t he Withdraw() m et hod,
which m akes it a great candidat e for an aspect . Let 's refact or it .
First , we'll creat e a generic advice t hat will be used t o send not ificat ions.
using System.Reflection;
using BusinessRulesDemo.Domain;
using Spring.Aop;
namespace BusinessRulesDemo
{
I n t his exam ple we are using an aft er advice t hat checks if t he new balance is below t he alert balance
level and sends a not ificat ion if it is. We also defined several propert ies on t he advice class in order
t o show how you can configure advices using t he Spring.NET I oC cont ainer.
Tight coupling bet ween t he advice and our Account class is not a problem in t his case because we
know t hat our advice will only apply t o inst ances of t he Account class anywaywe are sim ply using t he
advice t o m ove t he not ificat ion sending rule out side t he core logic of t he Account class.
What t his really buys us is flexibilit y. I f we sell t he applicat ion t o anot her client who want s us t o
rem ove t he not ificat ion we can easily do it by rem oving t he advice applicat ion from t he configurat ion
file. Sim ilarly, if a client asked us t o im plem ent t he logic in such a way t hat aut om at ic t ransfer from a
Line of Credit account happens whenever t he balance falls below a m inim um am ount allowed, we
could easily im plem ent anot her advice and apply it t o our Account class inst ead, or even in addit ion
t o t he not ificat ion advice.
Just like in t he previous exam ple, we will only show t he declarat ive aspect configurat ion t o com plet e
t his exam ple.
<aop:aspect name="BalanceNotificationAspect">
<aop:advice
type="BusinessRulesDemo.AccountBalanceNotificationAdvice"
pointcut="class(Account+) and method(Withdraw)">
<aop:property name="Sender" ref="NotificationSender"/>
<aop:property name="Subject" value="Low Balance"/>
<aop:property name="Template"
value="~/Templates/LowBalance.vm"/>
</aop:advice>
</aop:aspect>
The only t hing wort h point ing out here is t hat you can use Spring I oC feat ures t o configure your
advices, j ust like you would use it t o configure any ot her obj ect . I n t his exam ple, we are using t hat t o
specify t he not ificat ion subj ect and t he filenam e of t he NVelocit y m essage t em plat e, as well as t he
inst ance of t he not ificat ion sender t o use.
Summary
AOP can help you solve som e of t he problem s you are facing every day. While it would be great t o
have support for AOP in .NET on t he language and CLR level, t here are t ools in t he .NET open source
com m unit y t hat can give you a decent set of AOP feat ures t oday.
Probably t he best way t o st art learning m ore about AOP is t o download som e of t hese t ools and
experim ent wit h t hem , and m aybe even st art int roducing t hem int o real- world proj ect s t o help wit h
t he basic usage scenarios, such as logging or profiling. As you becom e m ore knowledgeable about
AOP and m ore fam iliar wit h t he t ool of your choice, you will likely find m any ot her areas of your
applicat ion where aspect s can help you.
Thanks, Aleksandar!
So by applying AOP t o t he problem of Reposit ory design as I t alked about before Aleksandar's
sect ion, som e int erfaces t o int roduce for CustomerRepository could be GetByIdable, Deletable, and so
on.
Pret t y neat , don't you t hink? And of course t here are m ore obvious t hings t o use AOP for, such as t he
ordinary exam ple of logging. I t 's a bit boring, as Aleks point ed out , but aft er all a very useful
t echnique for solving a com m on problem .
Summary
I n t his chapt er we have covered t hree very different and pot ent ially very im port ant design t echniques
t hat you need t o keep an eye on or st art invest igat ing. I n t he last chapt er, we will discuss
present at ion services, which are oft en pret t y im port ant as well: im port ant in t he past , present , and
t he fut ure.
Chapter 11. Focus on the UI
Test ing t he dat abase and t he User I nt erface ( UI ) is hard. We discussed t est ing of t he dat abase in
Chapt er 6, " Preparing for I nfrast ruct ure," but I owe it t o you t o have som e m at erial about t est ing of
t he UI as well. You'll find quit e a lot of t hat in t his chapt er.
We will also discuss UI design t hat is m ore in line wit h DDD t han usual, at least when com pared t o
Rapid Applicat ion Developm ent ( RAD) in .NET. We will do t hat by invest igat ing t he Model- View-
Cont roller ( MVC) and Model- View - Present er ( MVP) pat t erns.
We will also look at ot her t ypes of m apping: not obj ect relat ional m apping t his t im e, but obj ect - t o-
obj ect m apping and UI m apping.
But first of all, t o get us int o t he right m ood, here is a " prepilogue" by m y old friend Dan Byst rö.
What 's a " prepilogue" you m ay ask? I t 's an early or " pre" epilogue. I asked Dan t o writ e a short
epilogue for m y book. What he cam e up wit h was good and fit t ing, but on reflect ion, it was m ore like
an int roduct ion t o t he last chapt er rat her t han an ending t o t he book. So here is Dan's prepilogue.
A Prepilogue
Now you're sit t ing here, adm iring your work: t he m ost perfect Dom ain Model ever t o see t he light of
day. You have m anaged t o do what at first seem ed like an im possible m ission: you have m apped a
large part of your cust om er's business t o your Dom ain Model. Not only t hat you have got t en rid of
quit e a bunch of special cases and shown your cust om er a m ore general view of t heir business t han
t hey could ever im agine.
And if t his wasn't enough, t he int erface is clean and t he code is even cleaner. Whoever it is who uses
t his Dom ain Model will gasp in am azem ent at your achievem ent and secret ly envy you. What m ore
could you ask for? Now you can surely die happy!
" Did you say w hoev er? Who is w hoev er in t his case, anyway?"
" Well," you say, " it is any program m er who uses a .NET- enabled language." ( Or you m ay say t hat it
is all Java developers, or som e ot her group, depending upon your im plem ent at ion.)
" So hundreds of t housands of program m ers m ay use your Dom ain Model? That 's quit e som et hing! "
" Yeah, isn't it j ust great ?" you answer. " I have encapsulat ed a big chunk of t he business m odel as
well as t he whole issue of dat a st orage int o t his m odel so it can easily be used wit hout having t o
m ess wit h t hese gory det ails."
" Are you sure nobody but program m ers will be int erest ed in using your Dom ain Model?"
" Well, I 'm j ust curious... don't you t hink t hat t here are a lot of users out t here who would like t o
benefit from your work? I n fact , isn't it t he users who ordered your Dom ain Model in t he first place?"
" Yes t hat 's t rue. What are you get t ing at ?"
" Don't you t hink t hat you need a user int erface in order t o let t hese users com e in cont act wit h your
brand new Dom ain Model t hen?"
" Oh..."
I current ly have t he good fort une t o be working wit h Jim m y on a proj ect where he focuses on t he
Dom ain Model and does t he O/ R Mapping, while I focus on t he UI . As a lucky t wist of fat e, it so
happens t hat we bot h feel like winners and t hink t hat t he ot her one has pulled t he short est st raw.
When I develop an applicat ion I consider t he UI t o be t he cent ral part , because wit hout t he UI t he
applicat ion won't be, well, usable. This is equally t rue for dat a represent at ion and dat a st orage part
as well, in m ost business applicat ions. What it really com es down t o is j ust a m at t er of perspect ive,
personal t ast e, and int erest .
Som e program m ers don't seem t o have a problem wit h m ixing direct DB access right int o t he UI .
One ext rem e exam ple of t his is obviously classic dat a- binding, in which you bind your user cont rols
direct ly t o dat abase fields. Every t im e I 've t ried t hat I 've prom ised m yself never t o t ry it again! ( On
t he ot her hand, I 'm really looking forward t o finding an easy way t o bind direct ly t o t he Dom ain
Model.)
As t he applicat ion grows and has t o be m aint ained, logical layers com e as a blessing.
Having t he dat a of t he UI logically bridged away in a separat e view, a Present at ion Model [ Fowler
PoEAA2] , is yet anot her great enhancem ent .
I really can't say I live up t o t his m yself when it com es t o sim ple UI s, but for t he t ricky part s I
definit ely do it t his way, even if it 's not t ot ally pure all t he t im e. I 'm sad t o say I don't work wit h
proj ect s wit h unlim it ed budget s. ( On t he ot her hand, if t he problem is sim ple, only a sim ple solut ion
should be used.)
I n fact , t he very first t im e I faced a SQL Dat abase ( before t hat I had always coded m y own st orage
m echanism s, which I st ill prefer when possible) I im m ediat ely realized t hat I needed som e kind of
layer bet ween t he dat abase and m y UI , alt hough it t ook m ore t han t en years before I encount ered
t he phrase Dom ain Model.
So a Dom ain Model is great for UI program m ers. But it is really j ust t he beginning. The fun st art s
here!
So let 's t hink som e m ore about t he present at ion services in t he cont ext of a rich Dom ain Model, first
from t he perspect ive of a rich client and wit h a focus on t est ing.
As Mart in Fowler said [ Fowler PoEAA] , t he MVC pat t ern is one of t he m ost m isunderst ood pat t erns
around. St ill, it 's very powerful and widely popular. The purpose and basic idea of t he pat t ern isn't so
hard t o grasp, but as usual, t he devil's in t he det ails. Christ offer Skj oldborg will clarify how MVC can
be applied, and he will discuss it in t he cont ext of a det ailed exam ple.
The Model-View-Controller Pattern
The int ent of t he Model- View- Cont roller pat t ern ( MVC) is t o break UI behavior up int o separat e pieces
in order t o increase reuse possibilit ies and t est abilit y. The t hree pieces are t he View, t he Model, and
t he Cont roller.
The M od e l is som e represent at ion of ent it y st at e. I t can range from sim ple dat a st ruct ures ( XML
docum ent s, Dat aSet s, and Dat a Transfer Obj ect s) t o a full- blown Dom ain Model if you have one.
The Vie w should consist only of logic direct ly relat ed t o " paint ing t he pixels on t he screen." Keeping
t he View as " dum b as possible" is oft en t he m aj or design obj ect ive when applying MVC. The rat ionale
is t hat Views/ Screens in pract ice require a hum an eye t o be t est ed. This is an error prone and cost ly
process com pared t o aut om at ed unit t est s. I f we m inim ize t he logic we put in t he Views in t he first
place, we m inim ize t he risk of int roducing bugs t hat can only be det ect ed by m anual t est ing, or, in
ot her words, we m inim ize t he m anual t est ing effort s we have t o apply.
Finally, t he Con t r olle r , which is really t he heart of t he MVC, is t he glue t hat t ies t he Model and t he
View t oget her. The Cont roller receives m essages when t he user int eract s wit h t he View, t ranslat es
t hose m essages int o act ions t hat are perform ed on t he underlying Model, and t hen updat es t he View
accordingly.
The MVC Pat t ern has it s root s in t he Sm allt alk com m unit y back in t he 70s and 80s [ MVC Hist ory] .
As m ent ioned, one of t he m ain reasons for int roducing MVC is t o increase t est abilit y. Ot her benefit s
are as follows:
The very process of explicit ly ext ract ing t he code from t he Views does t end t o force m ore
st ruct ure upon t he UI code t han would ot herwise have been t he case. Many m odern t ools m ake
it very easy t o j ust click your way around and quickly add code behind various event s wit hout
t hinking t oo hard. By deploying t he MVC pat t ern, one m ust exercise a bit m ore effort and be
very explicit about what goes on in t he UI .
I t m akes it easier t o change t he look and feel or even support ent ire new UI s or even Plat form s.
The reuse value in MVC is som et im es exaggerat ed a bit , especially when it com es t o cross
plat form ( rich client / Web/ handheld device) port abilit y. Oft en t he Cont roller will have t o be
m odified significant ly in order t o m ake full use of t he t arget plat form 's capabilit ies.
Different t eam m em bers can work sim ult aneously on t he View and t he cont roller, even if you
use a file- locking source cont rol syst em , because t hey can now easily be separat ed.
I 'm using C# and Windows Form s here, but t he code should be sim ple enough t o be underst ood even
if you are not fam iliar wit h C# and Windows Form s.
Consider a product cat alog for a shoe shop, Joe's Shoe Shop. Joe only sells t wo t ypes of shoes:
dancing shoes and safet y shoes. Dancing shoes have a hardness propert y and safet y shoes a
m axim um pressure. All shoes have an I D, nam e, and price. The screen t hat Joe uses t o m aint ain his
cat alog could look som et hing like t his:
Shoes can be viewed, added, rem oved, and updat ed. When a new shoe has been saved, t he I D
cannot change anym ore. When Joe select s a dancing shoe, he expect s t o see t he hardness of t he
shoe, and when he select s a safet y shoe, he expect s t o see t he m axim um pressure t hat t he shoe can
wit hst and. While t his View is probably not t he m ost com plex you have ever seen, it does have a few
im port ant and com m on concept s such as a grid and part s of t he screen t hat dynam ically need t o
change based upon act ions in ot her part s in t he screen.
I n order t o det ach logic from t he View, we first det erm ine roughly which event s/ user int eract ions we
t hink we need t o handle. I n t his case, it would be event s such as t he following:
LoadView t o load dat a and inst ant iat e t he ent ire View when first brought up.
ChangeType needs t o change t he descript ion of t he variant label ( Hardness or Max Pressure) as
well as clear t he value.
All t hese event s would be prim e candidat es for m et hods on t he Cont roller class. Even t hough t he
MVC pat t ern form ally st at es t hat t he Cont roller should receive t he event s and act upon t he View, it is
oft en m ore pract ical t o have t he View subscribe t o t he event s and t hen delegat e t he handling ont o
t he Cont roller. ( This slight variat ion on t he basic MVC is called Model- View- Present er by Mart in
Fowler [ Fowler PoEAA2] .)
Now we have a fairly good idea of what kind of logic we would like t o put in t he Cont roller, but we
st ill need t o enable t he Cont roller t o t alk t o t he View. Rem em ber, we st rive t o m ake t he View as
dum b as possible, so we'd prefer t o m ake t he Cont roller do all t he hard work and j ust hand t he View
som e sim ple inst ruct ions t hat do not require any furt her processing. We do t his by defining an
int er face, ICatalogView, which t he View m ust im plem ent .
At first glance, som e of t he m et hod nam es in t he ICatalogView int erface m ay look like t hey expose
som e fairly com plex funct ionalit y, but in realit y t he funct ionalit y is st rict ly relat ed t o paint ing pixels
on t he screen, int eract ing wit h various UI widget s, enabling/ disabling but t ons, and so on. A subset of
t he im plem ent at ion is shown in t he following code list ing.
N ot e
This sect ion will focus on t he scenario of loading t he View wit h t he list of shoes, and t hat
goes for all t he shown code regarding t he View, t he Cont roller, and t he t est .
I f you'd like t o see t he com plet e codebase, you can download t hat from t his book's Web
sit e at w w w .j nsk.se/ adddp.
this.grdShoes.Items.Clear();
}
parent.SubItems.Add(Enum.GetName(typeof(Shoe.ShoeType),
shoe.Type));
parent.SubItems.Add(shoe.Price.ToString());
}
The SetController ( ) enables us t o t ell t he View which Cont roller inst ance it m ust forward event s t o,
and all event handlers sim ply call t he corresponding " event " m et hod on t he Cont roller.
You m ight not ice t hat several m et hods on t he ICatalogView int erface m ake use of a Shoe obj ect . This
Shoe class is a Model class. I t is t hus perfect ly fine t o have t he View know about t he Model. I n t his
exam ple, t he Shoe is an ext rem ely sim ple dom ain class wit h no behavior, whereas in a real- world
Dom ain Model you would probably have m uch m ore funct ionalit y in t he dom ain classes.
N ot e
You m ight wonder why I use t he singular " Shoe" and not " Pair of Shoes" or som et hing
sim ilar as a class nam e. I 'm sim ply st aying wit h t he lingo used by shoe professionals here.
I 've not iced t hat t hey always say " t his shoe" and " t hat shoe" where ot hers would say " t his
pair of shoes" or " t hese shoes." This, plus t he word Shoe is m ore st raight forward as a class
nam e t han PairOfShoes.
At t his point we have t wo pieces of t he puzzle: t he View and t he Model. Bot h are m ainly concerned
wit h st at e; t he Model holds t he in- m em ory st at e in a st ruct ured form at , and t he View holds t he visual
represent at ion as well as m eans t o m odify t he st at e. Let 's hook up t he t wo t hrough t he Cont roller.
We already have a rough idea of t he t ypes of event s we need t o handle, but in order t o get t he
specifics pinned down, I 'll st art out by writ ing t est s for each of t he event s. I n t he t est s I will be using
NMock [ NMock] .
You'll find t he code in t he next list ing, but let m e first com m ent on t he pieces. The getTestData( ) is a
privat e helper m et hod t hat builds up a list of shoes in m em ory. This is used as t he Model in t he
rem ainder of t he t est suit e.
There is one t est for each ident ified m et hod on t he Cont roller, as I said, we will focus here on t he
scenario of loading t he View wit h dat a, and t herefore t he t est t hat is shown is t he LoadView_test ( ) .
First I creat e t he viewMock t hat represent s t he View in t he t est , and t hen I creat e t he shoes list ( t he
Model) , and finally t he Cont roller ( what I want t o t est ) . Not ice how t he Cont roller is fed t he m ock
im plem ent at ion of t he View in it s const ruct or. I t will operat e on t his m ock j ust as it would a real View
because all t he Cont roller knows about t he View is t he ICatalogView int erface.
Next I t ell t he viewMock which calls t o expect and wit h what param et ers. These represent t he " orders"
I expect our dum b View t o receive from t he Cont roller. I t hen call t he event handler I want t o t est in
t he Cont roller, and finally I ask t he viewMock t o verify t hat t he expect at ions were m et . Behind t he
scenes, t he viewMock will assert t hat each of t he expect ed calls were received and issued wit h t he
right param et ers. The following list ing shows t he code.
shoes.Add(new Shoe("1002",
"Heavy Duty Master",Shoe.ShoeType.Safety,299m,"500 lbs"));
shoes.Add(new Shoe("1003",
"Tango Beginner",Shoe.ShoeType.Dancing,149m,"Medium"));
return shoes;
}
[Test]
public void LoadView_test ()
{
DynamicMock viewMock=new DynamicMock(typeof(ICatalogView));
IList shoes=getTestData();
CatalogController ctrl = new CatalogController
((ICatalogView)viewMock.MockInstance, shoes);
ctrl.LoadView();
viewMock.Verify();
}
Wit h t he t est s all in place ( alt hough only one was shown in t he previous list ing) , all t hat is left is t o
show t he act ual im plem ent at ion of t he CatalogController ( see t he following code list ing) .
_view.SetSelectedShoeInGrid((Shoe)_shoes[0]);
}
}
Regardless of t he im plem ent at ion det ails, t he advant age of decoupling t he Cont roller from t he View
is t hat we can vary t he Cont roller behind t he View. This can be very useful when a View can show up
in a lot of different cont ext s, and it m ight not m ake sense t o always have t o enforce a part icular
Cont roller t o go along wit h it . An exam ple of t his could be special logic t hat has t o be applied t o t he
View for part icular cust om ers. I n t his case, we could have a fact ory m et hod t hat serves up t he
appropriat e Cont roller depending on which cust om er t he syst em is dealing wit h.
Combining Views/Controllers
More com plex Views are oft en m ade up of m ult iple sm aller Views. Exam ples are wizards where t he
user navigat es t hrough a bunch of Views t hrough next and previous but t ons or m aybe even j um p
back and fort h several st eps at a t im e. I nform at ion m ight be saved along t he way, but it does not
really get com m it t ed unt il t he user clicks Save on t he final screen.
Anot her exam ple is Mast er/ Det ails Views where changes m ade t o t he det ails View m ight cause
changes in t he Mast er View as well.
Bot h exam ples can t echnically be coded wit h one huge Cont roller, but it will m ost likely be a m essy
experience m inim izing t he reuse possibilit ies. We m ay want t o use som e of t he st eps in t he wizard
elsewhere in t he applicat ion, or we m ay want t o show t he Mast er View wit hout t he Det ail View, for
exam ple. The solut ion here is obviously t o separat e t he View and Cont rollers int o sm aller pieces. ( " I f
you want t o eat an elephant you have t o do it in sm all pieces." ) I n t he case of t he wizard, we could
have a FlowController t hat cont rols t he basic flow back and fort h t hrough t he wizard, and each st ep
could have it s own View and Cont roller.
I n t he Mast er/ Det ail, we m ight have t he Cont roller for t he Det ail View raise an event on changes. Any
ot her Cont roller could t hen subscribe t o t his event , including t he Cont roller for t he Mast er View.
Is It Worth It?
The key benefit of applying t he MVC pat t ern is t hat it m akes your UI code t est able. Secondarily, it
forces a very st ruct ured approach ont o t he coding/ design process of t he UI , which m ay in it self cause
cleaner code in t he end. You're forced t o t hink a lit t le m ore, so t o speak.
On t he flip- side it should be not ed t hat j ust because we can t est every line of code does not m ean we
should. Wit h t he MVC in place, it is possible t o writ e an ext ensive t est suit e for every View, and it
sure feels good t he first couple of t im es get t ing a bunch of green bars for t he UI logic. However, t he
value of t est s t hat t est som et hing very sim ple t hat is unlikely t o get broken wit h fut ure changes
because of low int erdependence wit h ot her part s of t he syst em m ay not be t hat huge. Especially if
t hose UI t est suit es im pose huge m aint enance overhead on your codebase. Every t im e you change
t he UI slight ly, you have t o m ake a lot of changes t o t he corresponding UI t est s.
Thanks, Chris!
Whet her we want t o t est t he UI wit h rigorous unit t est s or not , I t hink what Christ offer j ust showed
us is a very valuable t echnique for m aking t he view part of a Windows Form s applicat ion t hinner, so
it 's j ust about paint ing t he form s and for fact oring out som e of t he present at ion logic int o a layer of
it s own.
That 's pret t y m uch t he t hem e of t he next sect ion as well, but t his t im e in t he cont ext of t he Web.
I ngem ar Lundberg discusses how he applies t he MVP pat t ern [ Fowler PoEAA2] as t he t ool for t est ing
a Web applicat ion.
Test-Driving a Web Form
By I ngem ar Lundberg
How can you unit t est and t hereby also use TDD foryour GUI ?
I n t his short sect ion I 'll t ry t o give you a general idea of how you can unit t est your GUI . I n t he
process, t echniques such as self- shunt ing [ Feat hers Self- Shunt ] and m ocking will be shown.
However, t he TDD process in it self is not described. Self- shunt ing is ( very briefly) a t echnique where
you're let t ing t he t est class also act as a st ub or m ock.
Background
Typical GUI code consist s of a bunch of callback m et hods t hat are called as a result of som et hing t he
user does wit h t he GUI , such as pressing a but t on. Typically, a callback m et hod does som et hing wit h
a dom ain obj ect ( or possibly even execut es som e SQL) . The problem is t hat t he callback m et hods get
called from an environm ent , such as WinForm s or ASP.NET, t hat isn't easy t o hook up in your NUnit
t est s. You sim ply can't do it .
The goal is t o have as lit t le unt est ed code as possible. The first t hing t o do is t o m ove as m uch code
as possible out of t he callback m et hods. I f t he code isn't t angled in t he callback m et hods, you've
creat ed t he possibilit y t o unit t est it .
But t hat isn't enough. What about t he st at e of t he GUI ? You know, t hings like if t he user has select ed
t hat row, t his and t hat but t on should be disabled. This will not be covered sim ply by m oving code out
of t he callback m et hods. Don't get m e wrongit is a good first st ep.
To t ake it furt her, we need t o use t he sharpest t ool in our box: abst ract ion. We need a m odel of t he
int eract ion, and we need an abst ract ion of t he form we're program m ing. At t his point , I 'll st op t alking
about t he GUI in general t erm s and st art t alking about a form , or m ore specifically about an ASP.NET
Web Form . However, t his t echnique is also applicable t o Windows Form s, and it is even plat form
neut ral.
An Example
This is, in m y opinion, by far t he hardest part of writ ing about program m ingfinding a problem
scenario t hat could be used t o illust rat e your point wit hout sidet racking t he reader. I need an
exam ple t hat m akes m y GUI change st at e; in ot her words, som et hing needs t o be disabled when t he
user does som et hing special.
I n Sweden we have t he t radit ion of only let t ing our kids have candy on Sat urdays. Let 's say t hat I
have one box of chocolat e bars, one of lollipops, and one of port ion- sized peanut bags. The kids can
have t hree goodies of t heir choice, but no m ore t han t wo of t he sam e kind. A sim plificat ion of t he
m odel is t hat we never run out of candy.
This is wit hout doubt anot her silly exam ple, but hopefully it will do it s j ob. I n Figure 11- 2 you can see
t he end result . I could have shown you m y original pencil sket ch of t he GUI , but t his will do t oo. I n
t he left pane we have all t he t ypes of candy available. I t is from t his pane t hat t he user ( kids of all
ages) picks candy for t heir Sat urday candy st ash, shown in t he right pane. You can see how you're
prevent ed from picking anot her chocolat e bar while you m ight pick a lollipop or a bag of peanut s.
The reader is kindly asked t o disregard t he lack of st yling, which isn't covered here ( and I should not
express any opinions what soever on t hat subj ect ) .
Domain Model
To be able t o m ove on wit h t oday's lesson, I need a dom ain m odel. I t is shown in Figure 11- 3.
Figu r e 1 1 - 3 . Th e D om a in M ode l
I 've t est ed t his m odel separat ely. OkToAdd( ) checks t he business rules I st at ed previously. I t 's OK t o
add t hree it em s, but only t wo of t he sam e t ype ( CandyType) . This isn't rocket science.
TDD of GUI
Finally, we're com ing t o t he point . Before we st art , I 'd like t o rem ind everyone t hat even t hough
we're int roducing an abst ract ion of t he form , we have a pret t y concret e pict ure of how it is going t o
work, as shown in Figure 11- 4.
Figu r e 1 1 - 4 . M ode l of t h e UI
[View full size image]
When t he form is first shown, we want t o be able t o fill t he left pane wit h nam es of all t he t ypes of
candy. I t should be possible t o pick from all of t he sources. The t est looks like t his. ( I 'm going t o t ake
a fairly big st ep here based on m y previous experience of t his, dare I call it , pat t ern.)
I t doesn't even com pile. I need t o add Fill() and Render() t o PickCandyMdl. That 's easy; I j ust add
t wo em pt y public m et hods, one nam ed Fill( ) and one nam ed Render( ) . But what is t he t est
expressing? What am I assert ing? The assert ion is expressing what t he " form " should look like nowin
a very abst ract way. The st ring SrcPanel is used inst ead of t he HTML t able ( t he left one in t he form )
t hat we're aim ing for at t he end.
Where does SrcPanel com e from ? Well, SrcPanel is a st ring in t he t est fixt ure ( t he class) t hat is
m anipulat ed by m y self- shunt ed [ Feat hers Self- Shunt ] im plem ent at ion of t he PickCandyView . This is
t he recurring pat t ern when I m ock t he view.
PickCandyMdl mdl;
string SrcPanel;
[SetUp]
protected void Setup()
{
mdl = new PickCandyMdl();
SrcPanel = string.Empty;
}
...snip...
I t com piles, but it t urns red. What 's m issing? Well, t he form m odel, mdl of t ype PickCandyMdl, needs
t o know about it s view. That 's easy! I add a SetView( ) m et hod t o t he m odel. ( By t he way, t his is one
of t he few occasions where I use " int erface im plem ent at ion" t he way I did wit h
PickCandyView.SourceItem( ) , as in { int erface nam e} .{ m em ber nam e} .)
I m plem ent at ion of m et hods can only exist on classes. I f a class, Foo , im plem ent s an
int er face, Bar , t he int erface's m et hods are a part of t hat class. I would in m ost cases
im plem ent Bar 's m em bers as public on Foo . Rem em ber t hat t he int erface of t he class
it self is all it s public m em bers. Foo is a Bar , hence t he m em bers of Bar are a part of Foo .
I t j ust so happens t hat I im plem ent an int erface's m em bers as privat e in ot her sit uat ions
as a m eans t o solve nam e collisions, as in t he case of a self- shunt ing m ock. Here I don't
act ually see t he int erfaces ( PickCandyView and CandySourceRetriever) as a part of t he
t est fixt ure's int erface.
The form m odel needs t o know how t o obt ain all Candy Sources. This could be easily fixed by j ust
supplying t he m odel wit h a list of Candy Sources. But inst ead I 'm going t o show you anot her lit t le
t rick t hat im proves t est abilit y in t he general case. I 'm let t ing t he form m odel ( or rat her t hat
package/ assem bly) own an int erface represent ing t he needed ret rieve operat ion.
Let m e ask youwhat good would it do you? This convent ion cam e from an environm ent
where t he not ion of an int erface it self was a convent ion, a rule, and not a first - class
language concept ( t hat changed, m ore or less, wit h m idl) . When it com es t o t rying t o
inst ant iat e an int erface ( wit h new ) t he C# com piler ( at least m y version) t reat s abst ract
classes and int erfaces as one and t he sam e.
Why do we not have an A- nam e convent ion for abst ract classes? Because when you refer
t o a t ype t hat has m et hods and propert ies, you don't care if it is an int erface, abst ract
class, or concret e dit t o. The I - nam e convent ion seem s t o have been adopt ed by t he
Fram ework Class Library ( FCL) wit hout furt her considerat ion.
Alternative Explanation/Rambling
The I - nam e convent ion m ade sense in COM. COM wasn't really obj ect - orient ed, was it ? I t
was ( well, is) com ponent - orient ed. I s t here a reason t o t reat int erfaces of com ponent s as
som et hing inherent ly different from t he com ponent it self? Maybe, but t he quest ion t o ask
is if int erfaces in FCL are int erfaces t o com ponent s or if t hey are t he answer/ com prom ise
t o t he difficult ( com piler) problem of m ult iple inherit ance. I f so, an int erface in CLR is
very close t o an abst ract class. There's no A- nam e convent ion for abst ract classes. Drop
t he I - nam e convent ion; it serves no purpose. When you refer/ use a t ype t hat has
m et hods and propert ies, you don't care if it is an int erface, abst ract class, or concret e
dit t o.
I 'll also m ock t his int erface as a self- shunt . Of course, t he form m odel needs t o know about it s
ret riever. Wit h all t his in account , t he t est fixt ure st art s as t he following:
IList CandySourceRetriever.Retrieve()
{
return sources;
}
PickCandyMdl mdl;
ArrayList sources;
string SrcPanel;
Of course, t he t est st ill com es out red because we haven't im plem ent ed anyt hing in PickCandyMdl
yet . Let 's do it now.
As you can see, m ost of t his is t rivial. I n Fill() we pick up t he available candy sources and in
Render( ) we it erat e over t hem passing inform at ion t o t he view for it t o display. Not e t hat we've faked
t he im plem ent at ion so far; t he candy sources are not going t o be " pickable" ( t he t rue const ant ) in all
circum st ances. SetView( ) and SetRetriever( ) are t rivial. The [ NonSerialized ] at t ribut e on _ view is
needed when you use out of process handling of t he Session st at e in t he ASP.NET applicat ion.
We need t o be able t o pick candy from t he source list . Let 's express t hat as a t est .
StashPanel is of course t he t est fixt ure represent at ion of t he right - hand panel displaying what you ( I
m ean your kids) have picked so far ( a HTML t able in t he real form ) . A new m et hod is needed,
PickAt() .We also need a new m et hod on t he view.
PickAt( ) is an excellent incit em ent t o int roduce CandyStash t o t he form m odel, only hint ed at as
_stash in t he following code:
I 'm sure you can im plem ent t he StashItem( ) m et hod t he sam e way I im plem ent ed SourceItem( ) .
Running t he t est now t akes us t o green again. Before I m ove on, I com plem ent m y first t est t o assert
t hat t he StashPanel is em pt y ( string.Empty) .
When we picked t wo of t he sam e candy t ype, t hat t ype is not supposed t o be " pickable" anym ore
( have a look at t he first figure of t he applicat ion again) . Let 's express t hat as a t est .
The st ash of candy now cont ains t wo " a" s. The m issing great er t han sym bol ( > ) in SrcPanel aft er t he
" a" is t he key t hing here. This t est doesn't int roduce any new m et hods, but it com es out red due t o
t he short cut im plem ent at ion of Render( ) we m ade earlier. Rem em ber t he t rue const ant ? I sn't t he
OkToAdd( ) m et hod on CandyStash exact ly what we're looking for here?
I grab one from t he source ( s.GrabOne( ) ) and pass it t o OkToAdd( ) t o see if it is " pickable." The
CandySource is an infinit e source ( it is act ually an obj ect fact ory) . I n real life you'd probably rat her die
t han wast e chocolat e bars like t his, but t his isn't real life, t his is soft ware.
I f we picked t hree of an allowed m ix, we're not allowed t o pick anyt hing else, right ? Let 's express
t hat as a t est , t oo.
This t urns green right away. The OkToAdd() check for " pickable" was a st roke of genius, don't you
t hink? We shouldn't be surprised, because it ( OkToAdd()) capt ures t he very essence of our business
rule.
void MyInit()
{
if (!IsPostBack)
{
_mdl = new PickCandyMdl();
Session["PickCandyMdl"] = _mdl;
_mdl.SetRetriever(CreateRetriever());
_mdl.Fill();
}
else
{
_mdl = (PickCandyMdl)Session["PickCandyMdl"];
}
_mdl.SetView(this);
MdlRender();
}
PickCandyMdl _mdl;
HtmlTable _srcTbl, _stashTbl;
void MdlRender()
{
_srcTbl = new HtmlTable();
srcpnl.Controls.Add(_srcTbl);
_srcTbl.Width = "100%";
_mdl.Render();
}
The srcpnl, t he candy source panel, and stashpnl , t he candy st ash panel, are Panels ( t he cont rol in
t he WebControls nam espace) I 've added wit h t he form designer in Visual St udio.
Of course, t he form im plem ent s PickCandyView . The code is fairly sim ple. Any decisions m ade ( if
st at em ent s) concern appearance only, not t he st at e of t he int eract ion. This is crucial. The m odel
m ust be responsible for t he lat t er.
td = AddTD(tr);
if (pickable)
{
LinkButton lb = new LinkButton();
td.Controls.Add(lb);
lb.ID = "pick@" + index.ToString();
lb.Text = ">>";
lb.Click += new EventHandler(Pick_Click);
}
}
Yes, I t rust you t o read bet ween t he lines. The only possibly non- t rivial t hing I left for you t o figure
out is t he CreateRetriever( ) m et hod. You've seen som et hing sim ilar t o what 's needed in t he t est
fixt ure.
Figure 11- 5 shows t he app in sort of a com ic st rip. The kid picks t wo chocolat e bars followed by a bag
of peanut s.
Summary
Most code for handling t he GUI is in a m odel of t he int eract ion. Only a sm all port ion of t rivial code is
left unt est ed. Graphical appearance is, however, not what 's t est ed wit h t his m et hodology but rat her
t he dynam ics of t he GUI .
I n t his quit e unfinished exam ple I got away wit h very lit t le handling in t he form m odel. Wrapping t he
candy picked in, say, a CandyItem obj ect is one possible developm ent if we decided t o add feat ures
for regret t ing a choice ( ret urn t o t he source) .
Mocking with NMock
Let m e, as a sm all addendum and appet izer, show you anot her way t o m ock during t est ing using
NMock [ NMock] . I 'll be very brief, let t ing t he t est code speak for it self allowing you t o com pare it wit h
t he previous t est s. Let 's first have a look at t he set up. Let m e j ust point out t hat t he t est fixt ure class
doesn't im plem ent t he int erfaces PickCandyView and CandySourceRetriever as it did earlier in our
self- shunt ing fixt ure.
PickCandyMdl mdl;
IMock data, view;
const bool Pickable=true, NotPickable=false;
[SetUp] protected void Setup()
{
data = new DynamicMock(typeof(CandySourceRetriever));
view = new DynamicMock(typeof(PickCandyView));
data.SetupResult("Retrieve", sources);
}
The inst ant iat ion of DynamicMock( s) does t he m agic and creat es obj ect s adhering t o t he int erfaces
specified. The dynam ically " coded and com piled" obj ect of a m ock is found as IMock.MockInstance .
Wit h SetupResult( ) , we t ell t he dat a m ock t o ret urn sources when it get s called wit h Retrieve ( ) .
Now let 's have a look at t he equivalence of t he first t est from earlier.
The com m ent s in t he code are t here j ust t o show you t he general phases, besides set up, when
t est ing wit h NMock. We declare t hat we're expect ing SourceItem () of PickCandyView t o be called
t hree t im es and what values we expect . We also st at e t hat StashItem () is not t o be called.
I n t he execut ion phase we, well, do t he execut ion of t he obj ect we're t est ing by calling som e
m et hods on it . And finally, we ask t he view m ock t o verify t hat our expect at ions were m et during
execut ion.
I t hink it is best t o follow t he red- green ( - refact or) form ula of TDD. I n t he previous t est at least , if
you forget t o call Verify() you'll end up wit h a green t est regardless of whet her t he expect at ions are
m et or not . I f you first require a red run, you're sure t hat you're act ually verifying ( assert ing)
som et hing.
Thanks, I ngo!
Again, t est ing is an ext rem ely im port ant fact or and som et hing wort h preparing and adj ust ing for.
Now we have discussed t wo different variat ions regarding t he UI , but wit h sim ilarit ies on how t hat
can be done.
Last but not least , we will discuss som e aspect s regarding t he dat a for t he UI in cont rast t o t he dat a
in t he Dom ain Model.
Som e m ight feel m y approach is " I have a ham m er; let 's find nails" when t alking about m apping for
t he present at ion services j ust because m apping is a popular solut ion for t he persist ence services. But
I t hink it 's very m uch in t he spirit of DDD t o focus on t he core, t he Dom ain Model, as m uch as
possible and t hen creat e sim ple, flexible solut ions for dealing wit h t he infrast ruct ural problem s
" around" t he Dom ain Model, such as t ransform ing t he Dom ain Model int o anot her m odel for anot her
t ier. That 's why I t hink obj ect - t o- obj ect m apping and UI m apping have a lot of pot ent ial, especially
for rout ine t asks t hat are j ust a wast e of t im e t o hand code.
I n t his sect ion, Mat s Helander discusses som e aspect s of UI Mapping, focusing on aut om at ic m apping
bet ween a present at ion friendly m odel ( such as a Present at ion Model [ Fowler PoEAA2] ) and t he
Dom ain Model. Over t o Mat s.
Mapping and Wrapping
By Mat s Helander
Wit h t he aid of O/ R Mapping, we are able t o connect our Dom ain Model t o t he relat ional dat abase.
Toget her wit h t he business m et hods t hat we add t o t he Dom ain Model classes and possibly t o a
Service Layer [ Fowler PoEAA] , we have a pret t y solid archit ect ure in place for t he st ruct ural and
funct ional foundat ion of t he applicat ion.
That brings us t o t he last st ret cht he Present at ion Layer ( PL) . While you and I m ay consider t he
Dom ain Model t o be t he heart of t he applicat ion, end users are likely t o t hink of what ever t hey are
present ed wit h as t he final basis for j udgm ent .
This m eans t hat no m at t er how cool your Dom ain Model ( and support ing Service Layer) is, no one
will applaud your work ( except a fellow developer) unless you provide access t o your m odel via som e
whiz- bang UI .
The good news is t hat , if you're lucky, connect ing a PL t o your Dom ain Model can be a piece of cake.
The bad news is t hat , whenever you're not t hat lucky, it can be quit e a challenge.
I n t he sim plest case, your Dom ain Model is already " present able" and you could j ust dat a bind
direct ly t o t he Dom ain Model obj ect s. However, t he int erface of an applicat ion frequent ly dem ands
t hat inform at ion is present ed in a m ore " user friendly" form t han it was in t he Dom ain Model.
For exam ple, say t hat you have a DM class called Person, wit h FirstName and LastName propert ies.
However, in t he UI , you want t o have a single t ext box for edit ing a person's full nam e.
One way of doing t his, of course, is t o have som e code in your UI t hat sim ply reads from t he DM
Employee obj ect 's first and last nam es and writ es t o t he t ext box and t hat reads from t he t ext box and
writ es t o t he Employee obj ect propert ies when t he user hit s Save.
A lot of t he t im e, in t he so called " real world," t his is how UI requirem ent s are solvedby what is
essent ially an accum ulat ing heap of hacks.
I n t he end, t his is not t he pat h t oward a m aint ainable applicat ion, and t hat is what m ot ivat es us t o
look for a design t hat will scale wit h increasing com plexit y and size of t he applicat ion.
One recurring solut ion is t o com plem ent t he Dom ain Model obj ect s wit h a new set of obj ect s, oft en
referred t o as t he Present at ion Model ( PM) .
The Present at ion Model obj ect s are a part of t he PL and should have a st ruct ure and behavior
m at ching t he requirem ent s of t he PL ( in effect , m at ching t he needs of t he UI ) . I n our exam ple, t he
PM Person class would have a FullName propert y rat her t han FirstName and LastName propert ies found
in t he Dom ain Model Person class.
Why not j ust put t he GetFullName () m et hod in t he Dom ain Model Person class? We could, if it had a
use in som e business logic operat ion, but if t he only use of t he GetFullName () m et hod is in t he PL,
t he m et hod should go in t he PM and not in t he Dom ain Model.
Keeping your Dom ain Model free of non- business aspect s, such as present at ion and persist ence, is
every bit as im port ant as it was t o keep t he Business Logic Layer of yest eryear free of Present at ion
logic and Dat a Access logic, and for j ust t he sam e reason: Keeping t he Dom ain Model free from any
non- business aspect s is key t o keeping t he " heart " of your applicat ion underst andable and
m aint ainable.
So for t his exam ple, assum e t hat GetFullName() is only used in present at ion and is t hus a good
candidat e for a m et hod t hat should go on a PM rat her t han on t he Dom ain Model.
The quest ion becom es how we can connect t he PM classes t o t he Dom ain Model classes, and t hus we
arrive at t he choice: Mapping or Wr apping?
public int Id
{
get { return this.employee.Id; }
set { this.employee.Id == value; }
}
Using t he EmployeeWrapper class is a m at t er of bringing up an Employee obj ect from t he Dom ain
Model and t hen passing it t o t he EmployeeWrapper const ruct or ( see t he following code list ing) .
SomeControl.DataSource = employeeWrapper;
Big advant ages wit h t he wrapping approach include sim plicit y and flexibilit y. You can writ e pret t y
m uch any t ransform at ions you like in your wrapper obj ect s, t ransform at ions far m ore com plex t han
our relat ively sim ple FullName t ransform at ion, if required.
A big drawback is t hat you will find yourself writ ing a lot of repet it ive code in your wrapper classes
for delegat ing t o propert ies t hat don't need any t ransform at ionlike t he Id propert y in t he previous
exam ple.
This m ay m ake it t em pt ing t o j ust go ahead and let t he Present at ion Model obj ect s inherit from t he
Dom ain Model obj ect s inst ead, overriding what ever propert ies t hat need t ransform at ion, but leaving
all ot hers as t hey are. The problem wit h t his is t hat t hen you are st uck wit h t he public API of t he
Dom ain Model, because all public m em bers of a superclass are inherit ed by t he subclass.
I n our exam ple, we could have let t he PM Employee inherit from t he Dom ain Model Employee , and we
could have added t he FullName propert y t o t he PM Employee , but t he PM Employee would also have
exposed t he FirstName and LastName propert ies from t he Dom ain Model Employee , because t hese
public propert ies would be inherit ed.
Wrapping your Dom ain Model obj ect s rat her t han inherit ing from t hem gives a higher level of
encapsulat ion t hat is usually well wort h t he ext ra, adm it t edly t edious, work of delegat ing bet ween PM
and Dom ain Model propert ies.
Furt herm ore, t he delegat ion code for propert ies t hat don't require any advanced t ransform at ions can
be fruit fully at t acked wit h code generat ion solut ions or even j ust code snippet t em plat es. I f all else
fails, let t he int ern writ e t he boilerplat e code!
employeeView.Id = employee.Id;
employeeView.Salary = employee.Salary;
employeeView.FullName = employee.FirstName + " " +
employee.LastName;
As wit h t he wrapping exam ple, t he code for copying t he dat a could be placed in t he const ruct or of
t he PM obj ect , in which case t he const ruct or would accept t he DM obj ect in a param et er. The
previous exam ple shows only t he operat ive lines of code for clarit y.
I f you suffer from t he sam e afflict ion as I , abst ract us m anicus, you will im m ediat ely recognize t he
pot ent ial for abst ract ing t his work int o a fram ework of som e kind. I n short , we should be able t o
specify ( in, say, an XML file) what PM propert ies m ap t o what DM propert ies and t hen let t he
fram ework use reflect ion t o m ove t he dat a.
Such a fram ework would have t o m ap one set of obj ect s t o anot her set of obj ect s, and so t he logical
t erm for t his t ype of fram ework would be " Obj ect / Obj ect Mapper" or O/ O Mapper for short !
I f you decide t o writ e such a fram ework, you m ay realize t hat solving t he non- t ransform at ional
cases, such as m apping Id t o Id and Salary t o Salary in t he previous case, should be a pret t y
st raight forward t ask. Mapping FullName t o First-Name and LastName , on t he ot her hand, is t rickier.
I t is quit e solvable, but t he quest ion becom es if it is t he right approach t o t ry t o build advanced
t ransform at ion services int o t he O/ O Fram ework.
The alt ernat ive is t o avoid charging t he O/ O Mapper wit h responsibilit y for act ual st ruct ural
t ransform at ions and let it concent rat e on j ust m oving dat a back and fort h bet ween obj ect s t hat share
t he sam e or a very sim ilar st ruct ure.
I n our exam ple, t he solut ion becom es giving t he PM Employee class a FirstName and a LastName
propert y in addit ion t o it s FullName propert y, but also m aking t he FirstName and LastName propert ies
prot ect ed.
The O/ O Mapper should have no problem s accessing t he prot ect ed PM propert ies using reflect ion, so
it will be able t o m ap t o t hem from t he Dom ain Model's FirstName and LastName propert ies, but only
t he FullName propert y will be exposed t o t he client by t he PM obj ect .
I n fact , t he O/ O Mapper could even writ e direct ly t o t he privat e fields of t he PM obj ect s, so you
wouldn't have t o im plem ent t he prot ect ed propert ies at all indeed, t he m apper probably should
access t he privat e fields direct ly in order t o avoid t riggering side effect s in t he propert y get t ers and
set t ers t hat should only be invoked when client code accesses t he propert ies, not when t he
fram ework want s t o m ove dat a.
However, som e O/ O Mappers m ay offer advanced feat ures ( such as Lazy Loading) t hat depend on
propert ies being t here so t hat access t o t hem can be int ercept ed, and so you m ay want t o keep t he
propert ies around for t hat reason. The following code list ing shows a PM obj ect t hat relies on O/ O
Mapping.
public EmployeeView() {}
public int Id
{
get { return this.id; }
set { this.id = value; }
}
this.firstName = names[0];
this.lastName = names[1];
}
}
}
}
Of course, what ever you do in a fram ework, you could also do m anually. I f you were t o copy t he dat a
m anually from Dom ain Model t o PM wit hout t he aid of an O/ O Mapping fram ework, in order t o writ e
t o t he prot ect ed propert ies you could eit her use reflect ion or creat e short cut m et hods for accessing
your propert ies by nam e. Som e code using t he second approach m ight look like t he following:
employeeView.Id = employee.Id;
employeeView.Salary = employee.Salary;
Using t his approach, t he t ask of m oving t he dat a bet ween t he PM and t he Dom ain Model becom es
st raight forwardalm ost t rivial, had it not been for t he pesky reference propert ies.
Managing Relationships
When we t ake relat ionships bet ween t he obj ect s int o account , t he t ask becom es m ore difficult again.
Obj ect graphs ( a group of obj ect s t hat are all int erconnect ed via relat ionships) are pot ent ially very
large, and if asking t he O/ O Mapper t o fill a PM Employee obj ect from a DM Employee obj ect also
result s in t he filling up of a few hundred relat ed obj ect s, we m ay have effect ively killed perform ance
in our applicat ion.
Anot her issue is t hat you have t o rem em ber t o ret urn PM obj ect s from PM reference propert ies. For
exam ple, when I read t he AssignedToProject propert y of a PM Employee obj ect , I want a PM Project
obj ect back, not a DM Project obj ect . Consider a naïve im plem ent at ion of a Wrapper obj ect wit h a
reference propert y as shown in t he following:
The problem here is t hat t he Project propert y of t he PM EmployeeWrapper obj ect will ret urn a DM
Project obj ect rat her t han a PM ProjectWrapper obj ect . This is usually not at all what we want , and
so we have t o t ake care t o writ e our PM reference propert ies in t he fashion shown here:
So when we im plem ent reference propert ies, we suddenly have t o supply a m et hod for get t ing at t he
Dom ain Model obj ect referenced int ernally by a PM obj ect som et hing t hat m ight not be needed
ot herwise.
For com plet eness, and in order t o be able t o im plem ent a corresponding AssignedEmployees propert y
in t he ProjectWrapper class, we have also provided a GetdomainObject( ) m et hod on t he
EmployeeWrapper class.
But even t his isn't really enough. Looking crit ically at t he code, we can't help but not ice t hat each
t im e we read from t he AssignedToProject propert y, a new ProjectWrapper obj ect is creat ed.
Assum ing t he I dent it y Mapping in our Dom ain Model layer is working, each new ProjectWrapper
obj ect creat ed when reading t he sam e propert y over and over will wrap t he sam e DM Project obj ect ,
and so we shouldn't run t he risk of dat a inconsist ency and corrupt ion, but it is hardly ideal
nonet heless.
I n t he end, we m ight want a full- blown solut ion t hat could handle I dent it y Mapping in t he PM as well,
m aking sure t hat t here are never t wo different PM inst ances represent ing t he very sam e Dom ain
Model inst ance around in a session.
The code in t he AssignedToProject propert y would t hen have t o be rewrit t en so t hat inst ead of
creat ing a new inst ance of t he ProjectWrapper obj ect it self, it would ask a PM Reposit ory wit h an
I dent it y Map for t he ProjectWrapper obj ect .
That m eans t hat t he EmployeeWrapper obj ect will need a reference t o t he ProjectRepository obj ect .
Say goodbye t o t he com fort ing sim plicit y t hat has hit hert o graced t he Present at ion Model. The end
result is t hat t he whole slew of fascinat ing and ent ert aining horrors and hardships t hat we rem em ber
from m anaging reference propert ies in t he Dom ain Layer will rear t heir ugly heads again.
One way of " solving" t hese issues wit h reference propert ies is t o sim ply avoid reference propert ies in
your PM obj ect s, using " flat t ened" obj ect s inst ead t hat expose only prim it ive propert ies, quit e
possibly from referenced obj ect s as well. See t he following code list ing.
public int Id
{
get { return this.employee.Id; }
set { this.employee.Id == value; }
}
This approach is oft en very useful, especially because m any UI cont rols are designed for showing
t ables of rows, and flat t ened obj ect s adapt well t o t his paradigm . But whenever you are int erest ed in
represent ing navigable, deep st ruct ures rat her t han j ust grids of st uff, t he flat t ened approach falls
short . However, you m ay oft en find yourself com plem ent ing a fully part it ioned PM wit h som e flat
obj ect s specifically writ t en for som e grid in your applicat ion.
" Flat t ened" PM obj ect s provide a good exam ple of how t he PM oft en looks very different from t he
Dom ain Model and, of course, t he m ore different t hey are, t he m ore m ot ivat ed we are t o have t wo
separat e m odels inst ead of j ust adding t he feat ures needed by t he PL t o t he Dom ain Model.
Matters of State
When m aking t he choice bet ween Mapping and Wrapping, special at t ent ion should be paid t o t he
difference in how st at e is handled in t he t wo approaches.
When wrapping your Dom ain Model obj ect s, only one inst ance of t he dat a is used by t he applicat ion.
I f you have t wo views showing t he sam e em ployee at t he sam e t im e, and you updat e t he em ployee's
nam e in one view, t he single inst ance of t he dat a in t he wrapped obj ect is updat ed. I f t he second
view is t hen refreshed, it should display t he updat ed dat a, because it is also m apping direct ly t o t he
sam e wrapped, updat ed obj ect .
When m apping your PM obj ect s t o your Dom ain Model obj ect s, however, you could pot ent ially have
several different set s of PM obj ect s represent ing t he sam e Dom ain Model obj ect , but wit h different
st at e in t hem .
Even if you have an I dent it y Map for your PM, you m ay have t wo different PM Employee classes t hat
look slight ly different for different present at ion purposes, in which case t he I dent it y Map is of no help
at all.
This could lead t o conflict s. On t he ot her hand, it also opens up t he possibilit y of m ore sophist icat ed,
disconnect ed dat a m anagem ent .
For exam ple, a m apped set of PM obj ect s m ay be worked wit h for a long t im e in isolat ion in som e
wizard. At t he last st ep of t he wizard, t he user could decide t o com m it t he work t o t he Dom ain Model
( and t hen t o com m it t he updat ed Dom ain Model t o t he dat abase) or t o discard t he changes. Had t he
user been working wit h a set of PM obj ect s t hat direct ly wrapped t he Dom ain Model obj ect s, t his
opt ion of canceling t he changes would not have been available because t he Dom ain Model obj ect s
would have been cont inuously updat ed when t he user worked in t he wizard!
Cert ainly, t he opt ion of canceling so t hat t he changes aren't forwarded t o t he dat abase is t here even
wit hout t he PM, assum ing your Dom ain Model support s disconnect ed operat ions ( for exam ple, by
using a Unit of Work [ Fowler PoEAA] ) . However, if you press cancel at t he end of a wizard t hat works
direct ly wit h t he Dom ain Model, even if your dat abase is spared from t he changes, your Dom ain
Model will st ill have been changed so t hat when you present it in t he next screen of your applicat ion,
t he changes are visible.
I f you are prepared t o t hrow away your Dom ain Model if t he user cancels, t here is no problem . There
is also no problem if t he Unit of Work support s full rollback of t he st at e in t he Dom ain Model. But if
you are writ ing a rich client where you int end t o let t he Dom ain Model live for t he scope of t he
applicat ion ( for exam ple, you don't want t o t hrow t he DM away if t he user cancels) and your Unit of
Work does not support full rollbacks, you m ay well run int o t his issue.
I n som e sit uat ions, you'll find t hat wrapping best suit s your needs, while m apping works bet t er in
ot her sit uat ions. Som et im es you'll use bot h in t he sam e applicat ion, perhaps using wrapping as t he
default approach but using m apping j ust for wizards or ot her " bat ch j obs" t hat should be possible t o
discard wit hout com m it t ing.
Final Thoughts
Som et im es you're j ust plain lucky. Whenever you're able t o present your Dom ain Model t o t he user
right away ( or wit h a m inor am ount of support ive hacks) you should t hank your lucky st ars, because
t here's no get t ing around t he fact t hat connect ing a PM t o a Dom ain Model can be quit e headache-
inducing.
The headache is significant ly reduced if you decide t o go wit h " flat t ened" PM obj ect s, because m ost of
t he m ore severe issues arise direct ly as a result of t rying t o m anage reference propert ies.
The choice bet ween wrapping and m apping is influenced by a num ber of fact ors, including how st at e
is m anaged and t he opport unit ies for reducing t he am ount of boilerplat e code in your applicat ions via
code generat ion ( wrapping) or via using an O/ O Mapping fram ework ( m apping) .
By t rying t o keep st ruct ural t ransform at ions out side t he scope of any fram eworks or code generat ors
you em ploy ( inst ead placing all such advanced t ransform at ion logic in code wit hin your PM classes
and hiding non- t ransform ed m em bers in t he PM by m aking t hem prot ect ed) , you great ly reduce t he
com plexit y required by such fram eworks/ code generat ors and t hereby im prove your chances of
writ ing som et hing useful yourself or finding som et hing available online.
I f you doubt t hat all t his ext ra archit ect ural overhead in t he form of PMs, O/ O Mappers, and
t ransform at ion logic m et hods is really necessaryfine, perhaps you're lucky enough t o find yourself
wit h a present able Dom ain Model.
The bot t om line, however, is t hat you should really, really t ry t o avoid m odifying t he Dom ain Model in
order t o suit it t o t he needs of t he PLdon't t ry t o m ake your Dom ain Model work double as a PM
unless you can get away wit h t hat wit hout changing t he Dom ain Model.
As soon as you recognize t hat t here is a difference bet ween t he way you want t o represent your
Dom ain Model in t he core of t he applicat ion and t he way you want t o present it t o t he user, you
recognize t he need for a PMat least as long as you want t o follow t he advice of never burdening t he
Dom ain Model wit h PL aspect s.
I am slight ly fanat ic about keeping m y Dom ain Model obj ect s com plet ely oblivious of PL aspect s. This
m eans t hat if m y Dom ain Model could be dat a bound t o direct ly and if only som e at t ribut es were
added t o t he propert ies ( like at t ribut es for specifying cat egory and default value for binding t o t he
propert y grid) , I 'll refrain from adding t hose PL at t ribut es t o m y Dom ain Model obj ect s. I nst ead I 'll
opt for com plem ent ing m y Dom ain Model wit h a PM even if it is in every det ail exact ly t he sam e as
t he Dom ain Model, except for t he at t ribut es. I f you can't ident ify yourself wit h t he lunat ic fringe
dem ographic, t hough, perhaps you'll st op short of t hat .
But one reason I keep doing t hat is t hat as soon as t he PM is t hereas well as t he support ing
infrast ruct ure for Wrapping or Mapping t o t he Dom ain Model I usually find plent y of opport unit y for
refining t he present at ional aspect s of t he PM, and soon enough t he t wo m odels will begin t o becom e
m ore and m ore different , m aking it easier and easier t o m ot ivat e com plem ent ing t he Dom ain Model
wit h a PM.
Thanks, Mat s!
Summary
I t hink m y friends j ust described how you can benefit from t he Dom ain Model again t hrough t he
discussions of present at ion services.
Even t hough you focus on t he core wit h t he Dom ain Model, t hat 's not t he sam e as saying t hat t he
present at ion service is less im port ant . On t he cont rary! The im port ance of t he present at ion service is
one of t he reasons why you should work hard on t he Dom ain Model. By m oving out as m any t hings
as possible from t he PL t hat are j ust dist ract ions in t hat cont ext , it is easier or m ore possible t o
creat e a first - class UI .
Epilogue
So we have been t hinking about an applicat ion in som et hing of a DDD- ish way. The book was pret t y
m uch st ruct ured t he sam e way, by which I m ean t he following:
2 . Next we t hink about which approach t o use for st ruct uring t he m ain logic. According t o Fowler,
we can choose from Transact ion Script , Table Module, and Dom ain Model [ Fowler PoEAA] . I f t he
requirem ent s signal t hat t his is a com plex ( regarding behavior and/ or relat ionships) and long-
lived proj ect , we will probably choose Dom ain Model.
3 . Then we need a cert ain st yle for t he Dom ain Model, not only t o avoid com m on t raps, but also t o
creat e som et hing really powerful. That 's where DDD com es in. We t ry t o set t le t he Ubiquit ous
Language [ Evans DDD] . We work hard wit h t he Dom ain Model, t rying t o m ake it knowledge
rich.
4 . Aft er t hat it 's t im e t o t hink about t he dist ract ions: t he required infrast ruct ure. The m ost t ypical
problem t o consider is how t o deal wit h persist ence. I f possible, obj ect relat ional m apping is a
popular choice for DDD proj ect s. ( I nst ead of t he som ewhat overloaded t erm " infrast ruct ure,"
let 's describe t his as it 's all about m apping t he m odel t o ot her t iers, such as present at ion,
persist ence, and int egrat ion services.)
5 . Finally, needless t o say, t here are lot s of ot her t hings t o consider, such as how t o deal wit h
present at ion.
Not t hat I t hink it 's a wat erfall process, not at all, but a book is sequent ial by nat ure and
consequent ly m ore oft en t han not t he descript ion will be as well. I t 's im port ant t o rem em ber and
st ress t he it erat ive and increm ent al st yle of developm ent t hat is required t o m it igat e risk and lead t o
a successful proj ect .
OK, it 's over. This book, t hat is. But as Dan said, it 's j ust t he beginning.
Just one m ore t hing: I st art ed t his book t alking about how I value " lagom " ( som et hing like not t oo
m uch and not t oo lit t le, but rat her balanced) . Has t he book been " lagom " ? Well, I t hink t o som e it
has been ext rem e in som e direct ions, and perhaps " lagom " in ot hers.
1 . List cust om ers by applying a flexible and com plex filt er.
The cust om er support st aff needs t o be able t o search for cust om ers in a very flexible m anner.
They need t o use wildcards on num erous fields, such as nam e, locat ion, st reet address,
reference person, and so on. They also need t o be able t o ask for cust om ers wit h orders of a
cert ain kind, orders of a cert ain size, orders for cert ain product s, and so on. What we're t alking
about here is a full- fledged search ut ilit y. The result is a list of cust om ers, each wit h a cust om er
num ber, cust om er nam e, and locat ion.
The t ot al value for each order should be visible in t he list , as should t he st at us of t he order,
t ype of order, order dat e, and nam e of reference person.
An order can have m any order lines, where each line describes a product and t he num ber of
it em s of t hat product t hat has been ordered.
I t 's alright t o use opt im ist ic concurrency cont rol. That is, it 's accept ed t hat when a user is
not ified aft er he or she has done som e work and t ries t o save, t here will be a conflict wit h a
previous save. Only conflict s t hat will lead t o real inconsist encies should be considered as
conflict s. So t he solut ion needs t o decide on t he versioning unit for cust om ers and for orders.
( This will slight ly affect som e of t he ot her feat ures.)
The lim it is specific per cust om er. We define t he lim it when t he cust om er is added init ially, and
we can change t he am ount lat er on. I t 's considered an inconsist ency if we have unpaid orders of
a t ot al value of m ore t han t he lim it , but we allow t hat inconsist ency t o happen in one sit uat ion
and t hat is if a user decreases t he lim it . Then t he user t hat decreases t he lim it is not ified, but
t he save operat ion is allowed. However, it 's not allowed t o add an order or change an order so
t hat t he lim it is exceeded.
This lim it ( unlike t he previous one) is a syst em - wide rule. ( SEK is t he Swedish currency, but
t hat 's not im port ant .)
7 . Each order and cust om er should have a unique and user- friendly num ber.
8 . Before a new cust om er is considered OK, his or her credit will be checked wit h a credit inst it ut e.
That is, t he lim it discussed previously t hat is defined for a cust om er will be checked t o see if it 's
reasonable.
9 . An order m ust have a cust om er; an order line m ust have an order.
There m ust not be any orders wit h an undefined cust om er. The sam e goes for order lines, t hey
m ust belong t o an order.
To be honest , I 'm not act ually sure t hat t his feat ure is necessary. I t m ight be alright if t he order
is creat ed first and t he order lines are added lat er on, but I want t he rule t o be like t his so t hat
we have a feat ure request relat ed t o t ransact ional prot ect ion.
First up is Mat s Helander wit h t he variat ion he calls " Obj ect - orient ed dat a m odel, sm art service layer,
and docum ent s." Here goes.
Object-Oriented Data Model, Smart Service
Layer, and Documents
By Mat s Helander
Som et im es, during dark wint er night s, I recall faint ly what life was like in t he days before t he Dom ain
Model. I t is at t im es like t hose t hat I pour a lit t le cognac int o m y hot chocolat e and t hrow an ext ra
log on t he fire.
The evolut ion of t he archit ect ure in m y applicat ions, finally leading up t o t he use of t he Dom ain
Model, followed a pat t ern som e readers m ay feel fam iliar wit h. I 'm going t o out line t his evolut ion
quickly, as it helps put m y current approach for using t he Dom ain Model int o cont ext .
In the Beginning
I st art ed out writ ing client - server applicat ions where all t he applicat ion code was st uffed int o t he
client , which would t alk direct ly t o t he dat abase. When I st art ed writ ing Web applicat ions, t hey
consist ed of ASP pages wit h all t he applicat ion code in t hem including t he code for calling t he
dat abase.
Because t he result of t his t ype of applicat ion archit ect ure is, wit hout except ion, a horrific m ess
whenever t he applicat ion grows beyond t he com plexit y of a " Hello World" exam ple, I soon learned t o
fact or out m ost of t he code from t he present at ion layer and t o put it in a Business Logic Layer ( BLL)
inst ead.
I m m ediat ely, t he applicat ions becam e easier t o develop, m ore m aint ainable, and as a bonus t he BLL
could be m ade reusable bet ween different present at ion layers. I t should also be not ed t hat in t hose
days, it could m ake a big difference t o t he perform ance and scalabilit y of a Web applicat ion t o have
t he bulk of it s code com piled in a com ponent .
The next st ep was t o lift out all t he code responsible for com m unicat ing wit h t he dat abase from t he
BLL and put it in a layer of it s own, t he Dat a Access Layer ( DAL) . I recall t hat I was slight ly surprised
t o see t hat t he DAL was oft en subst ant ially larger t han t he BLLm eaning m ore of m y applicat ion logic
dealt wit h dat abase com m unicat ion t han wit h act ual business logic.
At t his t im e, I was alm ost at t he point where t he Dom ain Model would ent er int o t he equat ion. The PL
would t alk t o t he BLL t hat would t alk t o t he DAL t hat would t alk t o t he dat abase. However, all dat a
from t he dat abase was passed around t he applicat ion in t he form of Recordset s, t he in- m em ory
represent at ion of rows in t he dat abase ( see Figure A- 1) .
Relat ionships bet ween ent it ies are sim pler, for one t hing. I n t he case of m any- t o- m any relat ionships,
t his is especially so, because t he relat ional dat a st ruct ure requires an addit ional t able whereas no
addit ional class is required in t he obj ect - orient ed dat a st ruct ure.
Collect ion propert ies are anot her case where an addit ional t able is used in t he relat ional m odel but no
ext ra class is required in t he obj ect - orient ed dat a st ruct ure. Furt herm ore, obj ect - orient ed dat a
st ruct ures are t ype safe and support inherit ance.
What Obj ect - Relat ional Mapping does is t o let you t ake an obj ect - orient ed dat a st ruct ure and m ap it
t o t he t ables in a relat ional dat abase. The advant age is t hat you will be able t o work wit h your
obj ect - orient ed dat a st ruct ure as if working wit h an OO dat abase like Jasm ine, while in realit y you're
st ill using a relat ional dat abase t o st ore all your dat a.
Furt herm ore, you can add business logic t o t he classes of t he obj ect - orient ed dat a st ruct ure in t he
form of business m et hods. As you m ay have guessed, t he obj ect - orient ed dat a st ruct ure wit h
business m et hods t hat I 'm t alking about is t hat 's right t he Dom ain Model.
By learning about Obj ect - Relat ional Mapping I could finally t ake t he st ep t oward including t he
Dom ain Model in m y applicat ion archit ect ure. I nsert ed bet ween t he BLL and t he DAL, t he Dom ain
Model Layer now allowed m y business logic t o work wit h an obj ect - orient ed dat a st ruct ure ( see
Figure A- 2) .
Ever since, I 've been a devot ed user of t he Dom ain Model and I haven't looked backexcept during
t hose cold, dark wint er night s.
As I m ent ioned, anot her advant age wit h t he Dom ain Model is t hat it let s you dist ribut e your business
logic over t he Dom ain Model classes. I 've experim ent ed a lot wit h where t o put m y business logic.
I 've shift ed bet ween put t ing m ost of it in t he Business Logic Layer t o put t ing m ost of it in t he Dom ain
Model Layer and back again.
Service Layer
I 've also com e t o prefer t he t erm Service Layer [ Fowler PoEAA] t o Business Logic Layer, as it bet t er
covers what I 'm doing at t im es when m ost of m y business logic is in t he Dom ain Model Layer. When
m ost of m y business logic is in t he Service Layer I see no reason t o swit ch back t o t he t erm Business
Logic Layer, t hough I som et im es refer t o it as a " t hick" Service Layer t o dist inguish it from a m ore
convent ionally t hin Service Layer.
These days I alm ost always put m ost of t he business logic in a " t hick" Service Layer. While som e OO
purist s m ight argue t hat st ruct ure and behavior should be com bined, every so oft en I find it pract ical
t o keep t he business logic- relat ed behavior in t he Service Layer.
The m ain reason for t his is t hat in m y experience, business rules governing t he behavior of t he
Dom ain Model will usually change at a different pace, and at different t im es, from t he rules governing
t he st ruct ure of t he Dom ain Model. Anot her reason is t hat it easily let s you reuse t he Dom ain Model
under different set s of business rules.
Norm ally, t he only business m et hods I would put on t he Dom ain Model obj ect s t hem selves are ones
t hat I believe are fundam ent al enough t o be valid under any set of business rules and are probably
going t o change at t he sam e t im e and pace as t he st ruct ure of t he Dom ain Model.
Wit h m ost of m y business logic in t he Service Layer, t he applicat ion archit ect ure is nicely prepared
for t he st ep int o t he world of SOA. But before we go t here and t ake a look at how I would t ackle
Jim m y's exam ple applicat ion, I 'd j ust like t o st ress anot her part icular benefit of t his approach.
Combining Things
As I m ent ioned earlier, t he obj ect - orient ed dat a st ruct ure offered by t he Dom ain Model isn't t he
perfect fit for every operat ion you'll want t o perform . There are reasons why relat ional dat abases are
st ill so popular and why m any people prefer t o use Obj ect - Relat ional Mapping before going wit h an
act ual OO dat abase. For m any t asks, t he relat ional dat a st ruct ure and t he set - based operat ions
offered by SQL are t he perfect fit .
I n t hese cases, slapping m et hods ont o t he Dom ain Model obj ect s t hat will act ually be perform ing set -
based operat ions direct ly on t he relat ional dat a st ruct ures m ay not seem like a very nat ural way t o
go.
I n cont rast , let t ing Service Layer m et hods t hat access t he dat abase direct ly ( or via t he DAL) co- exist
side by side wit h m et hods t hat operat e on t he Dom ain Model is no st ret ch at all. Convert ing a Service
Layer m et hod from using one approach t o t he ot her is also easily accom plished.
I n short , I 'm free t o im plem ent each Service Layer m et hod as I see fit , bypassing t he Dom ain Model
Layer where it is not useful as well as t aking full advant age of it where it is useful ( which, in m y
experience, happens t o be quit e oft en) .
I n cases where a lot , if not all, of t he business logic has been dist ribut ed over t he Dom ain Model, a
t em pt ing approach is t o t ry t o export bot h dat a and behavior packaged t oget her in t his way t o t he
Rich Client by giving it access t o t he Dom ain Model. Wit h t he archit ect ure I 'm using, where m ost of
t he behavior is found in t he Service Layer, a m ore nat ural approach is t o expose t he behavior and
t he dat a separat ely.
Concret ely, t he Service Layer is com plem ent ed wit h a Web Service façade ( a t ype of t he Rem ot e
Façade pat t ern [ Fowler PoEAA] ) , which is j ust a t hin layer for exposing t he business logic m et hods in
t he Service Layer as Web Services. The Rich Client com m unicat es wit h t he server by calling t he Web
Services, exchanging XML docum ent s cont aining serialized Dom ain Model obj ect s.
For our exam ple applicat ion, t his m eans t hat each t im e t he Rich Client needs new inform at ion it will
call a Web Service on t he server t hat will ret urn t he inform at ion in t he form of an XML docum ent . To
begin wit h, let 's t ake t he case of list ing cust om ers m at ching a filt er.
I would begin by creat ing a GetCustomersByFilter() Service Layer m et hod im plem ent ing t he act ual
filt ering. The Service Layer m et hod would t ake t he filt er argum ent s and ret urn t he m at ching Dom ain
Model obj ect s. Then I 'd add a GetCustomersByFilter() Web Service exposing t he Service Layer
m et hod t o t he Rich Client .
The Web Service accept s t he sam e filt er argum ent s and passes t hem on in a call t o t he Service Layer
m et hod. The Dom ain Model obj ect s ret urned by t he Service Layer m et hod would t hen be serialized t o
an XML docum ent t hat would finally be ret urned by t he Web Service. The Rich Client can t hen use
t he inform at ion in t he XML docum ent t o display t he list of cust om ers t o t he user ( see Figure A- 3) .
Not e t hat t he event ual client - side Dom ain Model doesn't have t o m at ch t he Dom ain Model on t he
server. Accordingly, if t he client - side Dom ain Model is persist ed t o an offline dat abase, t he client - side
dat abase will presum ably follow t he design of t he client - side Dom ain Model and t hus doesn't have t o
look like t he server- side dat abase.
N ot e
One im port ant difference regarding t he schem a of t he server- side dat abase and t he client -
side dat abase is t hat if a server- side dat abase t able uses aut om at ically increasing ident it y
fields, t he corresponding client - side dat abase t able norm ally shouldn't .
The new row in t he client - side Employees t able should not be assigned wit h a new I Dt he I D
t hat was assigned t o t he em ployee in t he server- side dat abase should be used. This m eans
t hat t he propert ies for t he I D colum ns m ay be different on t he client and t he server.
The point here is t hat t he developers of t he Rich Client applicat ion are free t o decide whet her or not
t hey want t o use a Dom ain Model at all, and if t hey want one t hey are free t o design it as t hey see
fit . The com m unicat ion bet ween client and server is 100% docum ent - orient ed, and no assum pt ions
about t he Dom ain Models on eit her side are m ade by t he ot her.
For exam ple, m aybe t he Rich Client calls Web Services of m any different com panies, all capable of
ret urning list s of cust om ers but all wit h slight ly different fields in t heir XML docum ent s. One way t o
deal wit h t his would be t o creat e a " superset " client - side Customer Dom ain Model obj ect wit h
propert ies for all t he different fields t hat were ret urned from all t he com panies called.
Next , we want t he user of t he Rich Client applicat ion t o be able t o look at t he orders belonging t o a
part icular cust om er. The unique I D of each cust om er was of course included in t he XML docum ent
ret urned by t he first Web Service, so we know t he I D of t he cust om er in which we're int erest ed.
What I have t o do is t o im plem ent a Web Service t hat t akes t he I D of a cust om er and ret urns t he
orders for t hat cust om er. Again, I begin by creat ing a GetOrdersByCustomerID() Service Layer
m et hod t hat accept s t he I D of a cust om er and ret urns t he Dom ain Model Order obj ect s belonging t o
t he cust om er.
I 'll t hen proceed by adding a GetOrdersByCustomerID() Web Service t hat t akes a cust om er I D, passes
it along t o t he Service Layer m et hod, and finally serializes t he ret urned order obj ect s int o an XML
docum ent t hat can be ret urned by t he Web Service.
However, in t his case, som e ext ra at t ent ion has t o be paid t o t he XML serializat ion. We want t he XML
docum ent t o include t he t ot al value for each order, but t he Order Dom ain Model obj ect doesn't
cont ain any TotalValue propert y because t he t ot al value of an order is not st ored in any field in t he
dat abase.
Rat her, t he t ot al value is calculat ed whenever it is needed by adding t he values of t he order lines
t oget her. The value of each order line, in it s t urn, is calculat ed by m ult iplying t he price t hat t he
purchased product had when it was bought by t he num ber of it em s bought .
Because t he order lines aren't included in t he XML docum ent sent t o t he client , t he client applicat ion
can't calculat e t he t ot al values for t he orders, which m eans t hat t he calculat ion has t o be done on t he
server and t he result has t o be included in t he XML docum ent .
The m et hods for calculat ing t he value of an order line and t he t ot al value for an order are good
exam ples of t he t ype of m et hod t hat m any people would prefer t o put on t he OrderLine and Order
Dom ain Model obj ect s but t hat I prefer t o put in t he Service Layer.
For services t hat don't need any t ransact ion cont rol, I also usually im plem ent t he Service Layer
m et hods as st at ic m et hods so t hat t hey can be called wit hout inst ant iat ing any obj ect from t he
Service Layer classes.
myOrder.GetTotalValue();
OrderServices.GetTotalValue(myOrder);
I t is t his kind of procedural synt ax t hat has som e OO purist s j um ping in t heir seat s, hollering, and
t hrowing rot t en fruit , but I t hink t hat t he benefit s t hat follow from separat ing t he behavior from t he
st ruct ure of t he Dom ain Model are well wort h t he slight ly uglier synt ax.
Of course, t he service m et hods don't have t o be st at ic, and som et im es t hey can't befor exam ple, if
t hey should init iat e a declarat ive t ransact ions or if you want t o configure your SL classes using
Dependency I nj ect ion ( see Chapt er 10, " Design Techniques t o Em brace" ) .
But when st at ic m et hods will do, I usually m ake t hem st at ic sim ply because t hat m eans less code ( no
need t o wast e a line of code inst ant iat ing a SL obj ect every t im e I want t o call a service) . Because it
m akes for less code, I 'll cont inue using st at ic service m et hods in m y exam ples.
The point is t hat I don't really lose t he opport unit y for organizing m y m et hods pret t y m uch as nicely
as if I had put t hem on t he Dom ain Model classes. Because for every Dom ain Model class I have a
corresponding Service Layer class, I 'm able t o part it ion m y business logic in j ust t he sam e way as if I
had dist ribut ed it over t he act ual Dom ain Model.
The benefit com es when t he rules for GetTotalValue() st art changing even t hough t he underlying
dat a st ruct ure doesn't changesuch as when suddenly a syst em wide rule should be im plem ent ed
st at ing t hat an order m ay not have a t ot al value exceeding one m illion SEK. You can t hen j ust m odify
t he relevant Service Layer m et hods wit hout having t o recom pile or even t ouch your Dom ain Model
Layer t hat can rem ain t est ed and t rust ed.
Ret urning t o t he GetOrdersByCustomerID() Web Service, I j ust add a call t o t he Service Layer
OrderServices.GetTotalValue() m et hod t o which I pass each order during t he serializat ion rout ine
and add a field t o t he XML docum ent for holding t he result .
This provides us wit h a good exam ple of how t he Dom ain Model on t he client , should t he client
applicat ion developer choose t o im plem ent one, can differ from t he server- side Dom ain Model. The
client - side Dom ain Model Order obj ect m ight well include a propert y for t he t ot al value as present ed
in t he XML docum ent a propert y t hat t he server- side Dom ain Model Order obj ect doesn't have.
Following t his approach, we m ay decide t o include even m ore fields in our XML docum ent wit h values
t hat have been calculat ed by Service Layer m et hods.
For inst ance, consider a syst em - wide rule specifying t hat a cust om er m ay not owe m ore t han a
cert ain am ount of m oney. The precise am ount is individual and calculat ed by som e special Service
Layer m et hod. When designing t he XML docum ent t o ret urn from t he GetCustomersByFilter() Web
Service, you m ay want t o include a field for t he m axim um am ount each cust om er can owe, or at
least a flag st at ing if t he cust om er is over t he lim it .
This goes t o dem onst rat e t hat t he docum ent s offered by t he server don't have t o m at ch t he Dom ain
Modelcom m unicat ion bet ween client and server is ent irely docum ent - orient ed.
Looking at what we have at t he m om ent , t he user of t he Rich Client applicat ion should be able t o
view filt ered list s of cust om ers and t o view t he list of orders belonging t o each cust om er. Next , we
want t o let t hem check out t he order lines belonging t o a specific order.
There's no news in how t his is im plem ent ed: The client calls a Web Service wit h t he I D of t he order,
t he Web Service forwards t he call t o a Service Layer m et hod and serializes t he result s t o XML. By
now, we know t he drill for let t ing t he client fet ch dat a. What about let t ing t he client subm it dat a?
Submitting Data
Let 's say we want t he user t o be able t o updat e t he st at us of an order from " Not inspect ed" t o
" Approved" or " Disapproved." At first glance it m ay seem like a st raight forward request , but we're
really opening a Pandora's Box of concurrency problem s here as we m ove from read- only t o read-
writ e access.
So let 's begin by st icking wit h t he first glance and not look any closer for a lit t le while. How would we
do it t hen?
The first t hing t o do is t o creat e an UpdateOrderStatus() Service Layer m et hod and a corresponding
Web Service. The m et hods should accept t he I D of t he order and t he new order st at us as param et ers
and ret urn a bool value t elling you if t he operat ion com plet ed successfully. ( We won't go int o any
advanced cross- plat form except ion handling hereeven t hough it 's a whole bunch of fun! )
So far, so good; t he Service Layer m et hod is easy enough t o im plem ent , and t he Web Service is j ust
a wrapper, forwarding t he call t o t he Service Layer m et hod. Now let 's look at t he problem s we're
going t o run int o.
The problem s arise if t wo users t ry t o updat e t he st at us of t he sam e order at t he sam e t im e. Say t hat
user A fet ches an order, not es t hat it is " Not inspect ed" and goes on t o inspect it . Just a lit t le lat er,
user B fet ches t he sam e order, not es t he sam e t hing, and also decides t o inspect it . User A t hen
not es a sm all problem wit h t he order, causing her t o m ark t he order as " Disapproved" in her
following call t o t he UpdateOrderStatus() Web Service.
Just aft er user A has updat ed t he st at us of t he order, user B proceeds t o call t he sam e Web Service
for updat ing t he st at us of t he sam e order. However, user B hasn't not iced t he problem wit h t he order
and want s t o m ark t he order as " Approved." Should user B be able t o overwrit e t he st at us t hat A
gave t he order and t hat is now st ored in t he dat abase?
A st andard answer would be " No, because user B didn't know about t he changes user A had m ade."
I f user B had known about t he change t hat user A m ade and st ill decided t o override it , t he answer
would be " Yes" because t hen B could be t rust ed not t o overwrit e A's dat a by m ist ake. So t he
challenge becom es t his: How do we keep t rack of what B, or any ot her client , " knows" ?
One approach is t o keep t rack of t he original values from t he dat abase for updat es fields and t hen at
t he t im e when t he m odified dat a is saved t o t he dat abase, check if t he original values m at ch t hose
t hat are in t he dat abase now. I f t he values in t he dat abase have changed, t he client didn't know
about t hese changes and t he client 's dat a should be rej ect ed.
This approach is called opt im ist ic concurrency. Let 's look at a very sim ple way t hat opt im ist ic
concurrency could be im plem ent ed for t he case at hand.
To begin wit h, t he client applicat ion has t o be coded so t hat when t he user changes t he st at us of an
order, t he st at us t hat was originally ret urned from t he dat abase via t he XML docum ent is st ill kept
around.
Then t he UpdateOrderStatus() Web Service and t he Service Layer m et hod wit h t he sam e nam e have
t o be m odified t o accept an addit ional param et er for t he original order st at us value. Thus, when t he
client calls t he Web Service, t hree param et ers are passed: t he I D for t he order, t he new order st at us,
and t he original order st at us.
This version of opt im ist ic concurrency, m at ching t he original values of updat ed fields wit h t hose in
t he dat abase, will give good perform ance and scalabilit y, but it can be a bit cum bersom e t o
im plem ent , at least in a Rich Client scenario. An alt ernat ive way of using opt im ist ic concurrency is t o
add a versioning field t o t he t ables in your dat abase.
Som et im es even st rat egies like opt im ist ic concurrency won't work, so dom ain- specific solut ions have
t o be applied in t hose cases. A norm al t hem e is t o use som e sort of check- in/ out syst em , where t he
user m arks an obj ect as " checked out " or " locked" when it is fet ched for writ e access, prevent ing
ot her users from updat ing it unt il she is done. Ot her, m ore sophist icat ed schem es include m erging of
concurrent ly updat ed dat a.
The only way t o decide on what st rat egy is appropriat e in t he part icular case is t o ask t he dom ain
specialist t hat is, t he person underst anding t he business im plicat ions of t hese decisionswhat behavior
is desired. There's no general way t o select a concurrency st rat egy.
Even so, I 'm guessing t hat t he appropriat e way t o go in t his case would be t o use opt im ist ic
concurrency, wit h or wit hout a versioning field. The point is t hat it is st ill up t o som ebody who knows
what t he expect ed behavior is for t heir business t o decide.
Perhaps t he biggest problem wit h t he approach we have used here is t hat we have asked t he client
t o keep t rack of t he original values for us. This is probably asking a bit t oo m uch of t he client
applicat ion developer, so a bet t er alt ernat ive m ight be t o st ore t he original values on t he server in a
Session variable or a sim ilar const ruct .
How Fine-Grained?
Anot her t hing t o consider is whet her t he service is t oo fine- grained. Rat her t han providing a separat e
Web Service for every field of an order t hat can be updat ed, could we, perhaps, im plem ent a single
UpdateOrder() Web Service inst ead?
I n t his case, rat her t han providing a param et er for each updat eable field, t he Web Service could
accept an XML docum ent represent ing t he updat ed order. That is, inst ead of t his:
[WebMethod]
public bool UpdateOrder(string xmlOrder)
I n t his way t he client bot h receives and subm it s dat a in t he form of XML docum ent s. This st rict ly
docum ent - orient ed approach helps in keeping t he Web Services API coarse- grained and avoiding
overly " chat t y" conversat ions bet ween t he client and t he server ( see Figure A- 4) .
This im plies t hat , for exam ple, t he UpdateOrderStatus() m et hod should be t ransact ional. What t his
m eans is t hat inst ead of m aking t his m et hod st at ic I t urn it int o an inst ance- level m et hod and m ark it
wit h t he [AutoComplete] .NET at t ribut e. Because I 'm also going t o m ark t he whole class t hat t he
m et hod belongs t o wit h t he [transaction] at t ribut e and let it inherit from ServicedComponent, I
decide t o lift t his m et hod out of t he OrderServices class and int o a new class called OrderServicesTx,
where " Tx" st ands for " t ransact ional."
And t hat 's it . All m y UpdateOrderStatus() Web Service has t o do now is t o creat e an inst ance of t he
OrderServicesTx class and call t he UpdateOrderStatus() on t hat obj ect inst ead of calling t he old st at ic
m et hod on t he OrderServices class. The execut ion of t he OrderServicesTx.UpdateOrderStatus() will
use dist ribut ed t ransact ions t hat will be aut om at ically com m it t ed if t he m et hod finished wit hout
except ions and rolled back ot herwise.
The Service Layer is, in m y opinion, t he perfect place t o enforce t ransact ion cont rol in your
applicat ion. I t is also a great place for put t ing your securit y checks, logging, and ot her sim ilar
aspect s of your applicat ion.
Not e t hat all t he m et hods in t he Service Layer don't have t o be organized around t he ent it ies from
t he Dom ain Model layer. Just because I 'll have EmployeeServices, CustomerServices, and so on, t hat
doesn't m ean I won't also have LoggingServices and SecurityServices classes in m y Service Layer
as well.
Summary
My preferred st yle is t o put m ost of t he business logic in t he Service Layer and let it operat e on t he
obj ect - orient ed dat a st ruct ure represent ed by t he Dom ain Model. The com m unicat ion bet ween client
and server is com plet ely docum ent - orient ed, and no at t em pt t o export t he Dom ain Model t o t he
client or even t o let t he client access t he server- side Dom ain Model ( for exam ple, via Rem ot ing) is
m ade.
I hope I 've been able t o give som e idea about how I use t he Dom ain Layer and whyas well as how I
would go about designing Jim m y's applicat ion.
The Database Model Is the Domain Model
By Frans Boum a
To work wit h dat a on a sem ant ic basis, it 's oft en useful t o specify general definit ions of t he elem ent s
a given port ion of logic will work wit h. For exam ple, an order syst em works wit h, am ong ot her
elem ent s, Order elem ent s. To be able t o define how t his logic works, a definit ion of t he concept Order
is pract ical: We will be able t o describe t he funct ionalit y of t he syst em by specifying act ions on Order
elem ent s and supply wit h t hat a definit ion of t hat elem ent Order.
This Order elem ent cont ains ot her elem ent s ( values like t he OrderID and ShippingDate) and has a
t ight connect ion wit h anot her elem ent , OrderRow , which in t urn also cont ains ot her elem ent s. You can
even say t hat Order cont ains a set of OrderRow elem ent s like it cont ains value elem ent s. I s t here a
difference bet ween t he cont ainm ent of t he value OrderID and t he cont ainm ent of t he set of OrderRow
elem ent s? The answer t o t his quest ion is im port ant for t he way t he concept of Order is im plem ent ed
furt her when t he order syst em is realized wit h program code.
However, looking at t he Dom ain Model, pioneered by Mart in Fowler [ Fowler PoEAA] and ot hers, it
doesn't have t o be t hat way. You could see t he OrderRow elem ent s in a set as a value of Order and
work wit h Order as a unit , including t he OrderRow elem ent s.
What's an Entity?
I n 1970, Dr. Pet er Chen defined t he concept ent it y for his Ent it y Relat ionship Model [ Chen ER] , which
builds on t op of Codd's Relat ional Model. The concept of t he ent it y is very useful in defining what
Order and OrderRow look like in a relat ional m odel. Chen defined Ent it y as
" En t it y and En t it y se t . Let e denot e an ent it y which exist s in our m inds. Ent it ies are classified
int o different ent it y set s such as EMPLOYEE, PROJECT, and DEPARTMENT. There is a predicat e
associat ed wit h each ent it y set t o t est whet her an ent it y belongs t o it . For exam ple, if we know
an ent it y is in t he ent it y set EMPLOYEE, t hen we know t hat it has t he propert ies com m on t o t he
ot her ent it ies in t he ent it y set EMPLOYEE. Am ong t hese propert ies is t he afore- m ent ioned t est
pr edicat e."
By using t he Ent it y Relat ionship Model, we're able t o define ent it ies like Order and OrderRow and place
t hem int o a relat ional m odel, which defines our dat abase. Using Eric Evans' definit ion of Ent it y,
however, we are far away from t he relat ional m odel, which I t hink com es down t o t he following
definit ion: " An obj ect t hat is t racked t hrough different st at es or even across different
im plem ent at ions." The im port ant difference bet ween Evans' definit ion and Chen's definit ion of an
ent it y is t hat Chen's definit ion is t hat of an abst ract elem ent ; it exist s wit hout having st at e or even a
physical represent at ion. Wit h Evans, t he ent it y physically exist s; it 's an obj ect , wit h st at e and
behavior. Wit h t he abst ract ent it y definit ions, we're not influenced by t he cont ext in which an ent it y's
dat a is used, as t he int erpret at ion of t he dat a of an ent it y is not done by t he ent it y it self ( as t here is
no behavior in t he ent it y) but by ext ernal logic.
To avoid m isint erpret at ions, we're going t o use t he definit ion of Dr. Pet er Chen. The reason for t his
choice is because it defines t he abst ract t erm for t hings we run int o every day, bot h physical it em s
and virt ual it em s, wit hout looking at cont ext or cont ained dat a as t he definit ion is what 's im port ant .
I t is t herefore an ideal candidat e t o describe elem ent s in relat ional m odels like Customer or Order. A
physical Customer is t hen called an ent it y inst ance.
Every applicat ion has t o deal wit h a phenom enon called st at e. St at e is act ually a t erm t hat is t oo
generic. Most applicat ions have several different kinds of st at e: user st at e and applicat ion st at e are
t he m ost im port ant ones. User st at e can be seen as t he st at e of all obj ect s/ dat a st ores t hat hold dat a
on a per- user basis ( t hat is, have " user scope" ) at a given t im e T. An exam ple of user st at e is t he
cont ent s of t he Session obj ect of a given user in an ASP.NET applicat ion at a given m om ent .
Applicat ion st at e is different from user st at e; it can be seen as t he st at e of all obj ect s/ dat a st ores
t hat hold dat a on an applicat ion scope basis. An exam ple can be t he cont ent s of a dat abase shared
am ong all users of a given Web applicat ion at a given m om ent . I t is not wise t o see t he user st at e as
a subset of t he applicat ion st at e: When t he user is in t he m iddle of a 5- st ep wizard, t he user st at e
holds t he dat a of st ep one and t wo; however, not hing in t he applicat ion st at e has changed; t hat will
be t he case aft er t he wizard is com plet ed.
I t is very im port ant t o define where an ent it y inst ance lives: in t he applicat ion st at e or in t he user
st at e. I f t he ent it y inst ance lives in t he user st at e, it 's local t o t he user owning t he user st at e, and
ot her users can't see t he ent it y and t herefore can not use it . When an ent it y inst ance is creat ed, like
an order is physically creat ed in t he aforem ent ioned order syst em , it is living inside t he act ual
applicat ion; it is part of t he applicat ion st at e. However, during t he order creat ion process, when t he
user fills in t he order form , for exam ple, t he order is not act ually creat ed; a t em porary set of dat a is
living inside t he user's st at e, which will becom e t he order aft er it is finalized. We say t he ent it y
inst ance get s per sist ed when it is act ually creat ed in t he applicat ion st at e.
You can have different t ypes of applicat ion st at e: a shared, in- m em ory syst em t hat holds ent it y
inst ances, or you can have a dat abase in which ent it y inst ances are st ored. Most soft ware
applicat ions dealing wit h ent it y inst ances use som e kind of persist ent st orage t o st ore t heir ent it y
inst ance dat a t o m ake it survive power out ages and ot her t hings causing t he com put er t o go down,
losing it s m em ory cont ent s. I f t he applicat ion uses a persist ent st orage, it is likely t o call t he dat a in
t he persist ent st orage t he act ual applicat ion st at e: when t he applicat ion is shut down, for exam ple,
for m aint enance, t he applicat ion doesn't lose any st at e: no order ent it y inst ance is lost , and it is st ill
available when t he applicat ion is brought back up. An ent it y inst ance in m em ory is t herefore a m irror
of t he act ual ent it y inst ance in t he persist ent st orage, and applicat ion logic uses t hat m irror t o alt er
t he act ual ent it y inst ance t hat lives in t he persist ent st orage.
O/ R Mapping deals wit h t he t ransform at ion bet ween t he relat ional m odel and t he obj ect m odel: t hat
is, t ransform ing obj ect s int o ent it y inst ances in t he persist ent st orage and back. Globally, it can be
defined as t he following:
A field in a class in t he obj ect m odel is relat ed t o an at t ribut e of an ent it y in t he relat ional m odel
and vice versa.
A chicken- egg problem arises: what follows what ? Do you first define t he ent it y classes ( classes
r epr esent ing ent it y definit ions) , like an Order class represent ing t he Order ent it y) and creat e
relat ional m odel ent it ies wit h at t ribut es using t hese classes, or do you define a relat ional m odel first
and use t hat relat ional m odel when you define your ent it y classes?
As wit h alm ost everyt hing, t here is no clear " t his is how you do it " answer t o t hat quest ion. " I t
depends" is probably t he best answer t hat can be given. I f you're following t he Dom ain Model, it is
likely you st art wit h dom ains, which you use t o define classes, som e probably in an inherit ance
hierarchy. Using t hat class m odel, you sim ply need a relat ional m odel t o st ore t he dat a, which could
even be one t able wit h a prim ary key consist ing of t he obj ect I D, a binary blob field for t he obj ect ,
and a couple of m et adat a elem ent s describing t he obj ect . I t will t hen be nat ural t o m ap a class ont o
elem ent s in t he relat ional m odel aft er you've m ade sure t he relat ional m odel is const ruct ed in a way
t hat it serves t he obj ect m odel best .
I f you st art wit h t he relat ional m odel and you const ruct an E/ R m odel, for exam ple, it is likely you
want t o m ap an ent it y in your relat ional m odel ont o a class. This is different from t he approach of t he
Dom ain Model, for inst ance, because t he relat ional m odel doesn't support inherit ance hierarchies:
you can't m odel a hierarchy like Person < Em ployee < Manager such t hat it also represent s a
hierarchy. I t is, of course, possible t o creat e a relat ional m odel t hat can be sem ant ically int erpret ed
as an inherit ance hierarchy; however, it doesn't represent an inherit ance hierarchy by definit ion.
This is t he fundam ent al difference bet ween t he t wo approaches. St art ing wit h classes and t hen
working your way t o t he dat abase uses t he relat ional m odel and t he dat abase j ust as a place t o st ore
dat a, while st art ing wit h t he relat ional m odel and working your way t owards classes uses t he classes
as a way t o work wit h t he relat ional m odel in an OO fashion.
As we've chosen t o use Chen's way of defining ent it ies, we'll use t he approach of defining t he
relat ional m odel first and working our way up t o classes. Lat er on in t he " The I deal World" sect ion
we'll see how t o bridge t he t wo approaches.
Ent it y- represent ing classes are t he developer's way t o define ent it ies in code, j ust as a physically
im plem ent ed E/ R m odel wit h t ables defines t he ent it ies in t he persist ent st orage. Using t he O/ R
Mapping t echnique discussed in t he previous sect ion, t he developer is able t o m anipulat e ent it y
inst ances in t he persist ent st orage using in- m em ory m irrors placed in ent it y class inst ances. This is
always a bat ch- st yle process, as t he developer works disconnect ed from t he persist ent st orage. The
cont rolling environm ent is t he O/ R Mapper, which cont rols t he link bet ween ent it y inst ances in t he
persist ent st orage and t he in- m em ory m irrors inside ent it y class inst ances.
A developer m ight ask t he O/ R Mapper t o load a given set of Order inst ances int o m em ory. This
result s in, for each Order inst ance in t he persist ent st orage, a m irror inside an ent it y class inst ance.
The developer is now able t o m anipulat e each ent it y inst ance m irror t hrough t he ent it y class inst ance
or t o display t he ent it y inst ance m irrors in a form or offer it as out put of a service. Manipulat ed ent it y
inst ance m irrors have t o be persist ed t o m ake t he changes persist ent . From t he developer's point of
view, t his looks like saving t he m anipulat ed ent it y inst ance dat a inside t he obj ect s t o t he persist ent
st orage, like a user saves a piece of t ext writ t en in a word processor t o a file. The O/ R Mapper is
perform ing t his save act ion for t he developer. But because we're working wit h m irrors, t he act ual
act ion t he O/ R Mapper is perform ing is updat ing t he ent it y inst ance in t he persist ent st orage wit h t he
changes st ored in t he m irror received from t he developer's code.
The relat ionships bet ween t he ent it ies in t he relat ional m odel are represent ed in code by funct ionalit y
provided by t he O/ R Mapper. This allows t he developer t o t raverse relat ionships from one ent it y
inst ance t o anot her. For exam ple, in t he Order syst em , loading a Customer inst ance int o m em ory
allows t he developer t o t raverse t o t he Customer's Order ent it y inst ances by using funct ionalit y
provided by t he O/ R Mapper, be it a collect ion obj ect inside t he Customer obj ect or a new request t o
t he O/ R Mapper for Order inst ances relat ed t o t he given Customer inst ance.
This way of working wit h ent it ies is rat her st at ic: const ruct ing ent it ies at runt im e t hrough a
com binat ion of at t ribut es from several relat ed ent it ies does not result in ent it y- represent ing classes,
as classes have t o be present at com pile t im e. This doesn't m ean t he ent it y inst ances const ruct ed at
runt im e t hrough com binat ions of at t ribut es ( for exam ple, t hrough a select wit h an out er j oin) can't
be loaded int o m em ory; however, t hey don't represent a persist able ent it y, but rat her a virt ual
ent it y. This ext ra layer of abst ract ion is m ost ly used in a read- only scenario, such as in report ing
applicat ions and read- only list s, where a com binat ion of at t ribut es from relat ed ent it ies is oft en
required. An exam ple of a definit ion for such a list is t he com binat ion of all at t ribut es of t he Order
ent it y and t he " com pany nam e" at t ribut e from t he Customer ent it y.
To successfully work wit h dat a in an OO fashion, it is key t hat t he funct ionalit y cont rolling t he link
bet ween in- m em ory m irrors of ent it y inst ances and t he physical ent it y inst ances offers enough
flexibilit y so t hat report ing funct ionalit y and list s of com bined set of at t ribut es are definable and
loadable int o m em ory wit hout needing t o use anot her applicat ion j ust for t hat m ore dynam ic way of
using dat a in ent it y inst ances.
The advant age of m odeling t he research findings wit h t echniques like NI AM or ORM is t hat t he
abst ract m odel bot h docum ent s t he research findings during t he funct ional research phase and at t he
sam e t im e it is t he source for t he relat ional m odel t he applicat ion is going t o work wit h. Using t ools
like Microsoft Visio, a relat ional m odel can be generat ed by generat ing an E/ R m odel from an
NI AM/ ORM m odel, which can be used t o const ruct a physical relat ional m odel in a dat abase syst em .
The m et adat a form ing t he definit ion of t he relat ional m odel in t he dat abase syst em can t hen be used
t o generat e classes and const ruct m appings.
The advant age of t his is t hat t he class hierarchy t he developers work wit h has a t heoret ical basis in
t he research perform ed at t he st art of t he proj ect . This m eans t hat when som et hing in t he design of
t he applicat ion changes, such as a piece of funct ionalit y, t he sam e pat h can be followed: t he NI AM
m odel changes, t he relat ional m odel is adj ust ed wit h t he new E/ R m odel creat ed wit h t he updat ed
NI AM m odel, and t he classes are adj ust ed t o com ply t o t he new E/ R m odel. The ot her way around is
also t rue: t o find a reason for code const ruct s t he developer has t o work wit h. For exam ple, for code
const ruct s t o t raverse relat ionships bet ween ent it y inst ance obj ect s, you only have t o follow back t he
pat h from t he class t o t he funct ional research result s and t he t heoret ical basis for t he code const ruct s
is revealed. This st rong connect ion bet ween a t heoret ical basis and act ual code is key t o a successful,
m aint ainable soft ware syst em .
Functional Processes as Data Consumers and Location of Business Logic
As t he real ent it y definit ions live in t he relat ional m odel, inside t he dat abase, and in- m em ory
inst ances of ent it ies are j ust m irrors of real inst ances of ent it ies in t he dat abase, t here is no place for
behavior, or Business Logic rules, in t hese ent it ies. Of course, adding behavior t o t he ent it y classes is
easy. The quest ion is whet her t his is logical, when ent it y classes represent ent it y definit ions in t he
relat ional m odel. The answer depends on t he cat egory of t he Business Logic you want t o add t o t he
ent it y as behavior. There are roughly t hree cat egories:
At t ribut e- orient ed Business Logic is t he cat egory t hat cont ains rules like OrderId > 0. These are very
sim ple rules t hat act like const raint s placed on a single ent it y field. Rules in t his cat egory can be
enforced when an ent it y field is set t o a value.
The cat egory of single- ent it y- orient ed Business Logic cont ains rules like ShippingDate >= OrderDate,
and t hose also act like const raint s. Rules in t his cat egory can be enforced when an ent it y is loaded
int o an ent it y obj ect in m em ory, saved int o t he persist ent st orage, or t o t est if an ent it y is valid in a
given cont ext .
The m ult i- ent it y- orient ed Business Logic cat egory cont ains rules spanning m ore t han one ent it y: for
exam ple, t he rule t o check if a Customer is a Gold Cust om er. To m ake t hat rule t rue, it has t o consult
Order ent it ies relat ed t o t hat Customer and Order Detail ent it ies relat ed t o t hese Order ent it ies.
All t hree cat egories have dependencies on t he cont ext t he ent it y is used in, alt hough not all rules in a
given cat egory are cont ext - dependent rules. At t ribut e- orient ed Business Logic is t he cat egory wit h
t he m ost rules t hat are not bound t o t he cont ext t he ent it y is used in, and it is a good candidat e t o
add t o t he ent it y class as behavior. Single- ent it y- orient ed Business Logic) is oft en not a good
candidat e t o add t o t he ent it y class as behavior, because m uch of t he rules in t hat cat egory, which
are used t o m ake an ent it y valid in a given cont ext , can and will change when t he ent it y is used in
anot her cont ext . Rules in t he m ult i- ent it y- orient ed Business Logic cat egory span m ore t han one
ent it y and are t herefore not placeable in a single ent it y, besides t he fact t hey're t oo bound t o t he
cont ext in which t hey're used.
Pluggable Rules
To keep an ent it y usable as a concept t hat isn't bound t o a given cont ext , t he problem wit h cont ext -
bound Business Logic rules in t he cat egory at t ribut e- orient ed Business Logic and t he cat egory single-
ent it y- orient ed Business Logic can be solved wit h pluggable rules. Pluggable rules are obj ect s t hat
cont ain Business Logic rules and t hat are plugged int o an ent it y obj ect at runt im e. The advant age of
t his is t hat t he ent it y classes are not t ied t o a cont ext t hey are used in but can be used in any
cont ext t he syst em design asks for: j ust creat e per- cont ext a set of pluggable rules obj ect s, or even
m ore per- ent it y, and depending on t he cont ext st at e, rules can be applied t o t he ent it y by sim ply
set t ing an obj ect reference. The processes t hat decide which rules obj ect s t o plug int o ent it ies are
t he processes m aint aining t he cont ext t he ent it y is used in: t he processes represent ing act ual
business processes t hat are called funct ional processes.
Functional Processes
I n t he previous sect ion, The I m port ance of Funct ional Research Result s," t he funct ional research
phase was described, and t he point was m ade concerning how im port ant it is t o keep a st rong link
bet ween researched funct ionalit y and act ual im plem ent at ion of t hat funct ionalit y. Oft en a syst em has
t o aut om at e cert ain business processes, and t he funct ional research will describe t hese processes in
an abst ract form . To keep t he link bet ween research and im plem ent at ion as t ight as possible, it 's a
com m on st ep t o m odel t he act ual im plem ent at ion aft er t he abst ract business process, result ing in
classes t hat we'll call funct ional processes because t hey're m ore or less dat a- less classes wit h sole
funct ionalit y.
The funct ionalit y processes are t he ideal candidat es in which t o im plem ent m ult i- ent it y- orient ed
Business Logic rules. I n our exam ple of t he Gold Cust om er, a process t o upgrade a Customer t o a
Gold Cust om er can be im plem ent ed as a funct ional process t hat consum es a Customer ent it y obj ect
and it s Order ent it y obj ect s, updat es som e fields of t he Customer ent it y, and persist s t hat Customer
ent it y aft er t he upgrade process is com plet e. Furt herm ore, because funct ional processes act ually
perform t he st eps of a business process, t hey are also t he place where a cont ext is present in which
ent it ies are consum ed and t he only correct place t o decide which rules t o plug int o an ent it y obj ect at
a given t im e T for a given cont ext st at e.
For m ost people, realit y is not always in sync wit h what we expect t o be an ideal world, and everyday
soft ware developm ent is no except ion t o t hat . I n t he funct ional research paragraph, physical
relat ional m odel m et adat a were used t o produce m appings and classes t o get t o t he ent it y class
definit ions for t he developer t o work wit h. A m ore ideal approach would be if t he NI AM/ ORM m odel
could also be used t o generat e ent it y classes direct ly, avoiding a t ransform at ion from m et adat a t o
class definit ion. I t would m ake t he ult im at e goal, where t he design of t he applicat ion is as usable as
t he applicat ion it self, appear t o be one st ep closer.
When t hat ideal world will be a realit y, or even if it will be a realit y, is hard t o say as a lot of t he
fact ors t hat influence how a soft ware proj ect could be m ade a success can be found in areas out side
t he world of com put er science. Nevert heless, it 's int erest ing t o see what can be accom plished t oday,
wit h t echniques developed t oday, like m odel- driven soft ware developm ent .
Pragmatism and the Nontraditional Approach
By I ngem ar Lundberg
When Jim m y first asked m e if I was willing t o writ e t his " guest segm ent " I im m ediat ely said " Yes, of
course." I m ust adm it I was flat t ered. Not surprisingly, I becam e doubt ful j ust a short while lat er.
What do I have t o say? Can I be precise enough t o fit it in a very lim it ed space? And above all, how
can m y .NET archit ect ure fit int o t he Dom ain Model concept ?
I will at t em pt t o give you a general descript ion of t he archit ect ure I 've built for m y form er em ployer,
which, wit hout sham e, I will call m y archit ect ure from now on. I t is however not t he archit ect ure I 'm
using nowadays. I will also address som e of t he issues in Jim m y's exercise t hat I find int erest ing wit h
regards t o t he st rengt hs and weaknesses in m y archit ect ure. I can't possibly give you t he whole
pict ure in t his lim it ed space, but because t he int ent ion of t his sect ion is t o show you t hat t here is
m ore t han one way t o skin a cat , I hope t his brief descript ion is sufficient enough t o fulfill it s
purpose. When I t alk about how t hings are done, please rem em ber t hat t he cont ext is t his part icular
archit ect ure and not a general dogm a.
The basis in t he archit ect ure is a fram ework of collaborat ing classes. I t is usable by it self, but t o be
really effect ive it has a com panion t ool, BODef ( for a snapshot of a part of it , look ahead t o Figure A-
11 ) , where you define your business obj ect s and generat e boilerplat e code. The code generat or is
m ore t han a wizard because it let s you generat e t im e aft er t im e wit hout losing m anual code
addit ions. I t uses t he Generat ion Gap pat t ern [ Vlissides Pat t ern Hat ching] t o accom plish t his. I n
Figure A- 5, you can see one ( part ial) definit ion of t he BOs of t he problem at hand.
The " st andard" way of dividing applicat ion classes is shown in Figure A- 6. All packages/ assem blies,
except t hose m arked wit h < < fram ework> > , are applicat ion specific. The BoSupport assem bly is
supposed t o be available not only in t he m iddle t ier but also in Rem ot ing client s. The rich client
required in Jim m y's problem challenge is going t o com m unicat e wit h t he m iddle t ier via Rem ot ing. [ 3]
[3]
Jimmy's note: As I mentioned in the introduction to this appendix, an application server was in the requirement from the
beginning but was removed later on.
Figu r e A- 6 . Ove r a ll a r ch it e ct u r e
The Service assem bly should cont ain at least one façade obj ect t hat im plem ent s som e basic
int erfaces t o support basic CRUD, IBvDBOReq being t he m ost im port ant ; see Figure A- 7.
Figu r e A- 7 . Ar ch it e ct u r e for t h e fa ca de
This façade isn't generat ed; inst ead, you inherit all base funct ionalit y ( from FacadeBase) , including
t he im plem ent at ion of t he m ent ioned int erfaces.
When it com es t o persist ent st orage, t he presence of a relat ional dat abase syst em ( RDBMS) is as
sure as t he presence of t he file syst em it self at t he sit e. I n fact , t he RDBMS was an unspoken
requirem ent , and if I want ed proper backup handling of m y applicat ions dat a, I 'd bet t er use one. This
is an im port ant st at em ent . This is why I don't bot her t o pret end t hat we didn't use an RDBMS.
Retrieval of Data
I t is possible t o ret urn dat a from t he m iddle t ier t o t he client in any form at : DataTable, DataSet,
st rongly t yped DataSet, XML or serialized obj ect graphs, t o m ent ion a few ( or m aybe m ost ) . The
sim plest and m ost com m on ret urn form at ( in m y case) is t he DataTable. To ret urn a bunch of
" business obj ect dat a," you sim ply ret urn each as a row.
A row in t he DataTable can easily be convert ed t o a business obj ect placeholder, BoPlaceholder . The
BoPlaceholder class, locat ed in t he BoSupport assem bly, is usable in it s own right , but it 's also t he
base class of specific business obj ect placeholders.
The specific placeholders, one of t hem being POrderPh ( purchase order) in Figure A- 8, are generat ed
by BODef. The Impl class is generat ed each t im e you choose generat e. The leaf class is only
generat ed once, which is pret t y m uch t he essence of t he Generat ion Gap pat t ern.
Figu r e A- 8 . Usa ge of BoPla ce h olde r
You m ight t hink of t hese placeholder obj ect s as inform at ion carriers or dat a t ransfer obj ect s, but t hey
m ight be used in m ore com plex behavior scenarios. And, yes, t he BoPlaceholder derivat es are in t he
BoSupport assem bly, which is supposed t o be present at bot h t he m iddle t ier and in t he client t ier
( t he rich/ fat client ) .
You can ret urn a DataTable from t he m iddle t ier t o t he client , leaving it t o t ransform from DataRow
inst ances t o BoPlaceholder inst ances. You can also ret urn a set ( ArrayList, for inst ance) of
BoPlaceholders t o be used direct ly in t he client . BoPlaceholder is serializable. However, rem em ber
t hat you can find loads of sam ples out t here of how t o dat abind a DataTable, but sam ples of dat a
bound BoPlaceholders, alt hough possible, are rare.
Process Objects
The final execut ion and enforcem ent of t he business rules is a j ob for t he core business obj ect s, also
known as t he process obj ect s. These obj ect s are st at eless and very short - lived. You can see t he
POrder process obj ect in Figure A- 9 and see t hat t hey follow t he generat ion gap pat t ern. These
obj ect s are im plem ent ed in t he Core assem bly. Because I consider aut horizat ion t o be a core part of
business rules, it 's no surprise t hat roles are specified on ( public) m et hods of t hese obj ect s.
The process obj ect s are oft en handed BoPlaceholders and are " hidden" behind a façade obj ect . The
process obj ect and t he placeholder, such as POrder and POrderPh , are concept ually part s of t he sam e
( logical) business obj ect .
Metadata
As you m ight have not iced in som e of t he previous figures, t here's plent y of m et a- dat a available in
t he fram ework classes. A m ore com plet e pict ure of t he m et a- dat a, alt hough not explained in dept h,
is found in Figure A- 10 . The m et adat a can give you som e dynam ics, bot h on dat a st orage handling
and UI handling.
I 've cut out m ost real- world at t ribut es t o keep it com pact . Most of t hat st uff, such as t he cust om er's
invoice address and order delivery address, isn't part icularly difficult t o handle. I n t he early phases of
real applicat ion developm ent , I oft en concent rat e on t he relat ionship bet ween obj ect s ( and on t heir
behavior and collaborat ion, of course) rat her t han on specific at t ribut es anyway.
This problem dem ands t he handling of cust om er dat a. This is what I would call a bread and but t er
regist ry handling funct ionalit y. I j ust have t o show you m y solut ion t o t his because it reveals som e of
m y ideas and t he pot ent ial for including m et adat a for t he business obj ect s.
Figure A- 11 is a snapshot from m y business obj ect definit ion t ool, BODef, showing you t he Customer
obj ect . You can see t hat besides t he field nam e and it s t ype, t here's m ore inform at ion at t ached t o a
field.
I n Figure A- 12 , which shows a form in t he order applicat ion, t he labels are t aken from t he m et adat a.
Wit h t his grid you can add, edit and delet e cust om ers. The code t o achieve t his is rat her com pact
( see t he following code list ing) . The m agic is all in t he generic TableHandler, a class t hat t akes
advant age of t he m et a- dat a of t he Customer BO as well as of t he generic façade int erface, IBvDBOReq,
and t he BoPlaceholder and DataRow relat ionship of t he archit ect ure.
public CustomerFormList()
{
InitializeComponent();
There's no point in describing each lit t le det ail. You m ight want t o t ake away ideas of what you can
do wit h m et adat a. And not shown here, it 's possible t o have m et adat a describing t he relat ionships
bet ween business obj ect s, t oo. ( Associat ion obj ect s are first - class cit izens in m y archit ect ure.)
You can sort of read bet ween t he lines in Jim m y's problem descript ion and see t hat t his is where he
want s us guest writ ers t o dig in. Sure, I 'm gam e.
Let m e first t ell you what I choose not t o com m ent on in t he problem descript ion, which isn't t he
sam e as not having it im plem ent ed. The search problem is ignored. I n m y priorit y list , it was
disqualified due t o lack of space. The sam e goes for t he per cust om er order list ing. The credit abilit y
of a new cust om er went t he sam e way. I have classified t he unique num ber of t he order as a m inor
challenge in m y fake scenario. I sim ply assign it at t he t im e when an order is subm it t edt he order
t aker get s it ret urned at t hat point and doesn't need it before t hen.
Good support for t he order t aking/ fill- in process is a given. I pict ured a " builder" [ 4] t hat 's used t o
m anipulat e t he order form ( t hink piece of paper) , t he order form being t he m et aphor I 'll reason
around. I also im agined t his builder as a serializable obj ect t hat is, upon com plet ion, subm it t ed from
t he client t o t he m iddle t ier.
[4] You can, for instance, think of the StringBuilder class that is used to build a string.
The m ult i- user aspect adds a few t ough issues t o solve. For inst ance, when t he order t aker t alks t o
t he presum pt ive cust om er and t he price of an it em is changed, should he get t o know t hat
im m ediat ely? I t doesn't help t hat t he price is checked wit h t he it em reposit ory because if you ret rieve
t he price at 10: 55 a.m . and list it on t he screen, it m ight very well be changed at 10: 56 a.m . The
sam e problem exist s for your st ock; is t he it em available or do you need t o order it from your
supplier?
One way t o solve t his problem is t o have t he m iddle t ier not ify all client s ( order t akers) as soon as
t here is a price or st ock change so t hat t he client can t ake m easures for t his. However, t his would
com plicat e t hings considerably. The client is no longer only t alking t o t he m iddle t ier, t he m iddle t ier
is also, on it s own init iat ive so t o speak, t alking t o all t he ( act ive) client s. And besides t hat , t he
t im ing problem isn't elim inat ed, only m inim ized.
I want t o keep it sim ple but st ill support t he needs. I need t o look at t he business process. The order
t aker t alks wit h a cust om er on t he phone. They discuss what t he cust om er needs, and price and
availabilit y is com m unicat ed. Event ually t he cust om er decides t o buy, and t he order t aker subm it s
t he order t o t he m iddle t ier. I n response, t he m iddle t ier ret urns a report . The report st at es t he final
prices and availabilit y. The lat t er will have an im pact on delivery dat e. All discrepancies wit h t he
previously ( orally) given fact s are m arked in t he report ( if any) . The order t aker discusses t hem wit h
t he cust om er and if he is unhappy wit h t hat , t he order can be cancelled. Cancelling t he order is a
t ransact ion of it s own, an undo/ delet e t ransact ion.
I underst and t hat if you give a price t o a cust om er you m ay have t o st ick t o it t o som e ext ent at
least . [ 5] This can be correct ed quit e easily. One cheap way is t o leave t he price set t ing t o a few
people who only change prices aft er business hours. Anot her way is t o have t he syst em it self
post pone effect uat ion of price changes t o t he next non- dealing m om ent . I f t he client caches price
inform at ion, she m ust som ehow have t he knowledge t o refresh ( or drop) t he cache on suit -
able/ st rat egic occasions.
[5] If you, an order taker, misread two zeros in the price, are you then liable?
The problem wit h availabilit y ( st ock) is, however, in cont rast t o prices, a dynam ic one. Therefore, t he
need t o have a report given as a response t o an order subm it t ed st ands. I t m ight as well report any
price discrepancies found even if a policy t o avoid t hat is im plem ent ed, j ust t o be sure. The report
will also have t he final say on whet her t he order is wit hin t he global m axim um lim it or not and if t he
cust om er's credit is exceeded or not .
When an order is persist ed, we st ick t o t he price given. We don't want t o t ick our cust om er off wit h
an invoice wit h higher prices t han prom ised. This forces us t o st ore t he prom ised prices ( OrderPrice
in Figure A- 5) wit h t he order inst ead of j ust referring t o t he it em ( t hat has a price) . An alt ernat ive is
t o have price hist ory on t he it em s, which is t oo m uch of a hassle. And, yes, we do not " reopen"
subm it t ed orders for com plem ent ing it em s in case of, say, t he cust om er realizing he want s t hree
inst ead of t wo of som et hing short ly aft er t alking t o us. We m ight place an order wit h no cost for
delivery and/ or invoicing t o t ake care of t his sit uat ion. [ 6] Changing an order line t o fewer it em s is
anot her st ory t hat we can handle easily ( it m ight affect high- volum e discount s in t he real world) .
[6] This is one of the many problems in a toy sample like this that are not stated well.
POrderBuilder
The support for t aking and handling purchase orders is wit hin t he class POrderBuilder . I t 's a class
m eant t o be used bot h in client and m iddle t ier, and it 's t ransport ed via serializat ion over t he wire.
POrderBuilder int eract s wit h t he warehouse on several occasions, such as when an order line is
creat ed when AddItemToOrder() is called. This int eract ion is capt ured in an abst ract ion called
ItemStore consist ing of one single m et hod, GetItem().
[Test]
public void Stock()
{
itmStore.Items[0].Stock = 1;
POrderDiscrepancyReport r = bldr.CheckDiscrepancies();
Assert.AreEqual(0, r.PriceCount);
Assert.AreEqual(1, r.StockCount);
Assert.AreEqual(1, r.GetStockAt(0).NumberOfMissingItems);
}
Please pict ure how t he discrepancy report is creat ed early in t he order subm it handling before t he
order is com m it t ed. However, t here is a problem concerning t ransact ion handling here, a problem
t hat is oft en overlooked or oversim plified. I f you're not careful, t he check can com e out alright , in
ot her words wit hout any discrepancies, but when you com m it t he order, for inst ance t he last it em in
st ock has been " assigned" t o anot her order and cust om er. I 'm saying t hat t he discrepancy check
should happen in t he sam e t ransact ion as t he order com m it and wit h locks t hat prevent ot hers from
" st ealing" it em s from t he warehouse t hat you're about t o sell.
I t m ight be int erest ing t o t ake a closer look at ItemStore. I t alked about a local client version as well
as a m iddle t ier, t ransact ional, version in t he t ext earlier. What 's t hat all about ? Well, let m e show
you.
I n Figure A- 13 you can see how POrderBuilder holds a reference t o an ItemStore. The reference is
im plem ent ed as a public propert y t hat is assigned by t he applicat ion code. I n t he client I use an
im plem ent at ion of ItemStore t hat is, and I 'm sorry if I overst at e t his, very different from t he
t ransact ional im plem ent at ion t hat I use in t he m iddle t ier during order subm it . ItemStore isn't m uch
of an int erface t o im plem ent when it com es t o t he num ber of m et hods; however, it is very cent ral t o
t he POrderBuilder . The ItemStore is, for inst ance, used by all m et hods showed in Figure A- 13 .
I 've im plem ent ed t he client version of ItemStore as a sim ple " read all it em s from st ore and cache."
This st rat egy is fine as long as t he num ber of it em s isn't t oo great . I f it com es t o t hat , it 's no big deal
t o im plem ent a version t hat queries t he m iddle t ier " sm art er." I n t he client , when t he order t aker has
t he privilege t o " work wit h an order," a POrderBuilder is inst ant iat ed and assigned an inst ance of t he
client side ItemStore im plem ent at ion. At any t im e, a CheckDiscrepancies() against t he client
ItemStore is possible.
While we're at it , let 's t ake a look at t he process obj ect 's TakeOrder() m et hod in t he following list ing:
POrderPh ordr =
((POrderBuilder.IOrderInternal)order.POrder).POrder;
new POrder().InsertNoRBS(cn, ordr);
return res;
}
You can see how ItemStore is act ually an inst ance of TxItemStore t hat is passed t he param et er cn
cont aining/ wrapping a dat abase connect ion and an ongoing t ransact ion. This im plem ent at ion of
ItemStore reads t he st ore wit h an UPDLOCK hint ( or what ever m et hod you prefer) , causing t he st ore
t o be locked for updat e by ot hers at t his point . Grant ed, t his is som et hing of a bot t leneck but
correct ness is high.
CheckDiscrepancies() will t hrow an except ion in case t here are severe business rule violat ions, such
as if t he global m axim um lim it is exceeded. I f t he only discrepancies are price differences or st ock
short age, t hese will be not ed in t he report , but t he order will be fully placed.
Do you rem em ber what I said about double- checking business rules t hat " run" on bot h t he client and
t he server? The essence is never t o t rust t he client . Well, t he checking is done in
CheckDiscrepancies(). For inst ance, any t am pering wit h t he prices on t he client side would com e out
as a discrepancy. I n t his part icular sit uat ion, t he client is running in your cont rolled environm ent , but
you should nevert heless be caut ious. Code execut ing on t he server is m uch safer t han code on t he
client . Rem em ber t hat t he server can't know ( not generally) if t he caller is your program sending
inform at ion on t he wire or if it 's anot her program .
What I want t o say is don't get hung up on what 's right and what 's wrong. Generally, t here is no such
t hing ( I 'm sure Jim m y agrees) . Get t he j ob done. Supply your business wit h t he soft ware it needs.
Know what your design goals are ( for inst ance, having t he business rules in one place) , and realize
t hem .
Summary
Now I 'm back again; Jim m y, t hat is. I t 's t im e t o sum m arize t he st yle variat ions j ust described by
Mat s, Frans, and I ngo. Which one is best ? I t depends! Life is full of t radeoffs! Would you like t o hear
som e m ore very good and useful nugget s? What is good and what is bad about t he different st yles?
Here's anot her good nugget : Make your own decisions, for your own specific sit uat ions.
I 'm sure you got m y point here. As you underst and, I didn't ask m y friends t o writ e som e about t heir
ideas on t he subj ect t o see which approach is best . I asked t hem writ e about t his problem t o get you
som e exposure t o ot her point s of view and som e inspirat ion from ot her st yles.
I f I were t o writ e m icro- sum m aries of t heir st yles, I would express it like t his. I n Mat s' case, I believe
t he t it le is a great sum m ary, nam ely " Obj ect - Orient ed Dat a Model, Sm art Service Layer, and
Docum ent s." Mat s is fond of locat ing t he behavior in t he Service Layer and seeing t he Dom ain Model
as an obj ect - orient ed represent at ion of t he dat a. " Docum ent s" is about t he exchange form at bet ween
different t iers.
Frans st resses t he im port ance of using t he power of t he dat abase and t hat t he represent at ion in t he
dat abase is t he t rue one.
I ngo t alks about t he im port ance of finding t he right abst ract ions and t hat you shouldn't expect t o be
able t o use a single st andard st yle for all sit uat ions. Add t o t hat a big chunk of pragm at ism .
Appendix B. Catalog of Discussed Patterns
This appendix is a cat alog of t he pat t erns t hat are discussed in t he book. No new inform at ion is t o be
found here; inst ead, t his is int ended t o be a service t o t he reader. You'll find here t he source of t he
pat t ern where you can read m ore, a very condensed descript ion, and m ost oft en a URL where you
can inst ant ly get m ore inform at ion.
N ot e
You find t his appendix online as well if you would like it t o be clickable:
www.j nsk.se/ adddp/ pat t erns
When t he descript ion is writ t en bet ween quot at ion m arks, t hat m eans t hat t he descript ion is t aken
direct ly from t he provided URL ( or from t he m ent ioned book's inner cover in t he case of som e of t he
[ GoF Design Pat t erns] ) .
Abstract Factory [GoF Design Patterns]
" Provides an int erface for creat ing fam ilies of dependent obj ect s wit hout specifying t heir concret e
classes."
" St ruct ures applicat ions t hat can be decom posed int o groups of subt asks in which each group of
subt asks is at a part icular level of abst ract ion."
An obj ect for locat ing a cert ain Ent it y ( or a set of Ent it ies) t hat is in t he m iddle of t he life cycle.
Capt ures and exposes predicat es wit h concept describing nam es.
State [GoF Design Patterns]
" Allow an obj ect t o alt er it s behavior when it s int ernal st at e changes. The obj ect will appear t o
change it s class."
Table Module [Fowler PoEAA]
" A single inst ance t hat handles t he business logic for all rows in a dat abase t able or view."
" Many obj ect s have no concept ual ident it y. These obj ect s describe som e charact erist ic of a t hing."
[ Alur/ Crupi/ Malks Core J2EE Pat t erns] Alur, Deepak, John Crupi, and Dan Malks. Core J2EE Pat t erns,
Second Edit ion: Best Pract ices and Design St rat egies. New Jersey: Prent ice Hall, 2003.
[ Arlow/ Neust adt Archet ype Pat t erns] Arlow, Jim , and I la Neust adt . Ent erprise Pat t erns and MDA:
Building Bet t er Soft ware wit h Archet ype Pat t erns and UML. Bost on, MA: Addison- Wesley, 2004.
[ Ast els TDD] Ast els, David. Test Driven Developm ent . A Pract ical Guide. New Jersey: Prent ice Hall,
2004.
[ Bauer/ King HiA] Bauer, Christ ian, and Gavin King. Hibernat e in Act ion. Greenwich, CT: Manning,
2005.
[ Beck SBPP] Beck, Kent . Sm allt alk Best Pract ice Pat t erns. New Jersey: Prent ice Hall, 1997.
[ Beck TDD] Beck, Kent . Test - Driven Developm ent : By Exam ple. Bost on, MA: Addison- Wesley, 2003.
[ Beck XP] Beck, Kent . Ext rem e Program m ing Explained: Em brace Change. Bost on, MA: Addison-
Wesley, 2000.
[ Bloch Effect ive Java] Bloch, Joshua. Effect ive Java Program m ing Language Guide. Bost on, MA:
Addison- Wesley, 2001.
[ Booch OOAD] Booch, Grady. Obj ect - Orient ed Analysis and Design wit h Applicat ions, Second Edit ion.
Reading, MA: Addison- Wesley, 1994.
[ Bosch Product Line] Bosch, Jan. Design and Use of Soft ware Archit ect ures: Adopt ing and Evolving a
Product - Line Approach. Bost on, MA: Addison- Wesley, 2000.
[ POSA] Buschm ann, Frank, Regine Meunier, Hans Rohnert , and Pet er Som m erlad, and Michael St al.
Pat t ern- Orient ed Soft ware Archit ect ure. A Syst em of Pat t erns. New York: Wiley, 1996.
[ Cast le] ht t p: / / www.cast leproj ect .org/
[ Cat t ell ODM] Cat t ell, R.G.G. Obj ect Dat a Managem ent : Obj ect - Orient ed and Ext ended Relat ional
Dat abase Syst em s. Reading, MA: Addison- Wesley, 1994.
[ Chen ER] Chen, P. " The ent it y- relat ionship m odelt oward a unified view of dat a." ACM Transact ions
on dat abase syst em s, vol.1 no.1, 1976.
[ Cockburn Agile] Cockburn, Alist air. Agile Soft ware Developm ent . Bost on, MA: Addison- Wesley,
2002.
[ Codd Relat ional Model] Codd, E. F. " A Relat ional Model of Dat a for Large Shared Dat a Banks."
Com m unicat ions of t he ACM, vol. 13 # 6, 1970.
[ Connolly/ Begg DB Syst em s] Connolly, Thom as M. and Carolyn E. Begg. Dat abase Syst em s, Fourt h
Edit ion: A Pract ical Approach t o Design, I m plem ent at ion, and Managem ent. Bost on, MA: Addison-
Wesley, 2004.
[ Dem eyer/ Ducasse/ Nierst rasz OORP] Dem eyer, Serge, St éphane Ducasse, and Oscar Nierst rasz.
Obj ect - Orient ed Reengineering Pat t erns. San Francisco: Morgan Kaufm ann, 2002.
[ Ent erprise Library Logging] ht t p: / / m sdn.m icrosoft .com / library/ default .asp?url= / library/ en-
us/ dnpag2/ ht m l/ ent lib.asp
[ Evans DDD] Evans, Eric. Dom ain- Driven Design: Tackling Com plexit y in t he Heart of Soft ware.
Bost on, MA: Addison- Wesley, 2004.
[ Ewald TxCOM+ ] Ewald, Tim . Transact ional COM+ : Building Scalable Applicat ions. Bost on, MA:
Addison- Wesley, 2001.
[ Feat hers Hum ble Dialog Box] Feat hers, Michael. " The Hum ble Dialog Box."
ht t p: / / www.obj ect m ent or.com / resources/ art icles/ TheHum bleDialogBox.pdf
[ Feat hers Self- Shunt ] Feat hers, Michael. " The 'Self'- Shunt Unit Test ing Pat t ern."
ht t p: / / www.obj ect m ent or.com / resources/ art icles/ SelfShunPt rn.pdf
[ Fowler Analysis Pat t erns] Fowler, Mart in. Analysis Pat t erns: Reusable Obj ect Models. Reading, MA:
Addison- Wesley, 1997.
[ Fowler FixedLengt hSt ring] Fowler, Mart in. ht t p: / / m art infowler.com / bliki/ FixedLengt hSt ring.ht m l
[ Fowler LW] Fowler, Mart in. " Language Workbenches: The Killer- App for Dom ain Specific Languages?
" ht t p: / / www.m art infowler.com / art icles/ languageWorkbench.ht m l
[ Fowler Mocks Aren't St ubs] Fowler, Mart in. " Mocks Aren't St ubs."
ht t p: / / m art infowler.com / art icles/ m ocksArent St ubs.ht m l
[ Fowler PoEAA] Fowler, Mart in. Pat t erns of Ent erprise Applicat ion Archit ect ure. Bost on, MA: Addison-
Wesley, 2003.
[ Fowler R] Fowler, Mart in. Refact oring: I m proving t he Design of Exist ing Code. Reading, MA:
Addison- Wesley, 1999.
[ Fowler UML Dist illed] Fowler, Mart in. UML Dist illed, Third Edit ion: A Brief Guide t o t he St andard
Obj ect Modeling Language. Bost on, MA: Addison- Wesley, 2004.
[ GoF Design Pat t erns] Gam m a, Erich, Richard Helm , Ralph Johnson, and John M. Vlissides. Design
Pat t erns: Elem ent s of Reusable Obj ect - Orient ed Soft ware. Reading, MA: Addison- Wesley, 1995.
[ Greenfield/ Short SF] Greenfield, Jack, and Keit h Short . Soft ware Fact ories: Assem bling Applicat ions
wit h Pat t erns, Models, Fram eworks, and Tools. I ndianapolis, I N: Wiley, 2004.
[ Halpin I MRD] Halpin, Terry. I nform at ion Modeling and Relat ional Dat abases: From Concept ual
Analysis t o Logical Design. San Francisco: Morgan Kaufm ann, 2001.
[ Halpin/ Nij ssen Concept ual Schem a] Halpin, T.A. G.M. Nij ssen. Concept ual Schem a and Relat ional
Dat abase Design: A Fact Orient ed Approach. New Jersey: Prent ice Hall, 1989.
[ Hay Dat a Model Pat t erns] Hay, David. Dat a Model Pat t erns: Convent ions of t hought . NewYork:
Dorset House, 1996.
[ Hibernat e] ht t p: / / hibernat e.org
[ Hohpe/ Woolf EI P] Hohpe, Gregor and Bobby Woolf. Ent erprise I nt egrat ion Pat t erns. Designing,
Building, and Deploying Messaging Solut ions. Bost on, MA: Addison- Wesley, 2004.
[ Jacobson OOSE] Jacobson, I var, Magnus Christ erson, Pat rik Jonsson, and Gunnar Overgaard.
Obj ect - Orient ed Soft ware Engineering: A Use Case Driven Approach. Reading, MA: Addison- Wesley,
1992.
[ Johnson J2EE Developm ent wit hout EJB] Johnson, Rod wit h Juergen Hoeller. Expert one- on- one
J2EE Developm ent wit hout EJB. I ndianapolis, I N: Wiley, 2004.
[ Jordan/ Russell JDO] Jordan, David, and Craig Russel. Java Dat a Obj ect s. Sebast opol, CA: O'Reilly,
2003.
[ Kerievsky R2P] Kerievsky, Joshua. Refact oring t o Pat t erns. Bost on, MA: Addison- Wesley, 2005.
[ Lhot ka BO] Lhot ka, Rocky. Expert C# Business Obj ect s. Berkeley, CA: APress, 2004.
[ Löwy Program m ing .NET Com ponent s] Löwy, Juval. Program m ing .NET Com ponent s. Second
Edit ion . Cam bridge, MA: O'Reilly, 2005.
[ Mart in PPP] Mart in, Robert C. Agile Soft ware Developm ent : Principles, Pat t erns, and Pract ices. New
Jersey: Prent ice Hall, 2002.
[ Meszaros XUnit ] Meszaros, Gerard. ht t p: / / t ap.t est aut om at ionpat t erns.com : 8080/ index.ht m l
[ Meyer OOSC] Meyer, Bert rand. Obj ect - Orient ed Soft ware Const ruct ion, Second Edit ion . New Jersey:
Prent ice Hall, 2000.
[ Nicola et al. SOM] Nicola, Jill, Mark Mayfield, and Mike Abney. St ream lined Obj ect Modeling:
Pat t erns, Rules, and I m plem ent at ion. New Jersey: Prent ice Hall, 2002.
[ Nilsson COMB] Nilsson, Jim m y. The Cost of GUI Ds as Prim ary Keys.
ht t p: / / www.inform it .com / art icles/ art icle.asp?p= 25862
[ Nilsson NED] Nilsson, Jim m y. .NET Ent erprise Design wit h Visual Basic .NET and SQL Server 2000.
I ndianapolis, I N: Sam s Publishing, 2001.
[ Pawson/ Mat t hews Naked Obj ect s] Pawson, Richard, and Robert Mat t hews. Naked Obj ect s. New
York: Wiley, 2003.
[ Pfist er Wolfpack] Gregory F. Pfist er. I n Search of Clust ers. Upper Saddle River, NJ: Prent ice Hall,
1998.
[ Richt er .NET Fram ework] Richt er, Jeffrey. Applied Microsoft .NET Fram ework Program m ing.
Redm ond, Wash: Microsoft Press, 2002.
[ Ross BRB] Ross, Ronald. The Business Rules Book: Classifying, Defining and Modeling Rules. Second
edit ion. Houst on, TX: Business Rule Solut ions, 1997.
[ Rum baugh OMT] Rum baugh, Jam es R., Michael R. Blaha, William Lorensen, Frederick Eddy, and
William Prem erlani. Obj ect - Orient ed Modeling and Design. New Jersey: Prent ice Hall, 1990.
[ SnapDAL] ht t p: / / sourceforge.net / proj ect s/ snapdal
[ Spolsky Leaky Abst ract ions] Spolsky, Joel. The Law of Leaky Abst ract ions.
ht t p: / / www.j oelonsoft ware.com / art icles/ LeakyAbst ract ions.ht m l
[ Szyperski Com ponent Soft ware] Szyperski, Clem ens. Com ponent Soft ware, Second Edit ion. Bost on,
MA: Addison- Wesley, 2003.
[ Vlissides Pat t ern Hat ching] Vlissides, John M. Pat t ern Hat ching: Design Pat t erns Applied. Reading,
MA: Addison- Wesley, 1998.
[ von Halle BRA] von Halle, Barbara. Business Rules Applied: Building Bet t er Syst em s Using t he
Business Rules Approach. New York: Wiley, 2001.
[ Woolf Null Obj ect ] Woolf, Bobby. " The Null Obj ect Pat t ern," in Pat t ern Languages of Program Design
I I I . By Robert C. Mart in, Dirk Riehle, and Frank Buschm ann ( Eds.) . Reading, MA: Addison- Wesley,
1998.
Bar
BDUF (Big Design Up Front)
BeginReadTransaction()
behavior, adding to existing classes
Big Design Up Front (BDUF)
BLL (Business Logic Layer)
BO (Business Object)
placeholders
Booch, Grady
BoSupport
Bouma, Frans; The Database Model Is the Domain Model
Bounded Context 2nd
bridging gaps
BrokenRulesRegardingPersistence
Burhhop, Mark
Business Logic Layer (BLL)
Business Logic, Functional Research
functional processes
pluggable rules
Business Object (BO)
business processes
Bystrom, Dan
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
C++
caches, querying and
callback methods
CanAddOrder()
CanFindOrdersViaCustomer()
CantExceedStringLengthWhenPersisting()
CatalogController
categorizing rules
CC.NET (CruiseControl.NET)
Chain of Responsibility
CheckDiscrepancies()
CheckOKToAccept()
Chen, Peter
chunky interfaces
classes
adding state and behavior to
entity-representing classes
mapping classes onto tables versus mapping tables onto classes
classification
NHibernate
advanced database support
API
Domain Model
functionality
Mapper Style
query languages
starting points
O/R Mapper
advanced database support
API
Domain Model
functionality of
metadata-based mappings
query languages
starting points
Class Table Inheritance
client-side databases versus server-side databases
client control, TDD
client server, SOA and
client-side Domain Model
Coarse-Grained Lock 2nd
Codd, E.F.
code generation of custom code
Data Mapper pattern
code smells 2nd
refactoring
cleaning tools
preventing growing problems
preventing growing problems: Form Template Method
preventing growing problems: Inline Singleton
routine cleanings
routine cleanings: Encapsulate Collection
routine cleanings: Encapsulate Field
routine cleanings: Extract Method
CollectBrokenRules()
_CollectBrokenRulesRegardingAccepted()
Collecting Parameter pattern 2nd
combining Views/Controllers (MVC pattern)
COMBs, NHibernate
compile time versus runtime, PI
complete Domain Model instantiation
complex rules
compliers, TDD
Component Adapters
components, TDD
Concrete Table Inheritance
concurrency
controlling
NHibernate
Domain Model 2nd
optimistic concurrency
config
configuring advices
consequences, mock objects and stubs
consistency, up-front architecture design
constraints, database constraints (creating APIs)
Constructor Dependency Injection
constructors
PI
reconstituting entities from persistence
constructs, PI
consumers, providing with metadata
consumers of Repositories, locations of queries
containers, Inversion of Control
nested containers
context
Bounded Context
creating APIs
layers
partitions 2nd
reasons for using
scaling up DDD projects
Contextualized Dependency Lookup
continuous integration
Controllers, MVC pattern
controlling concurrency
NHibernate
cooperation, domain-related rules
cost
for PI
speed
for single-set of Query Objects
for single-set Repositories, PI
coupling TDD
Create, Read, Update, and Delete (CRUD) 2nd 3rd
CreatePage()
credit institutes, checking with
CreditService
CRUD (Create, Read, Update, and Delete) 2nd 3rd
CruiseControl.NET (CC.NET)
customers
discussing models
historic customer information
CustomerSnapshot
customization
custom manual code, Data Mapper pattern
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
Dahan, Udi
DAL (Data Access Layer)
data
retrieving, example of
storing (persistence infrastruc-ture) 2nd
choosing how to store data
file system
object database
RAM
relational database
resource managers
submitting, example
working with data in an OO fashion
data access code
Data Access Layer (DAL)
data access, testing
database constraints, creating APIs
databases
advanced database support: NHibernate
filtering in databases with huge parameter lists
legacy databases:mapping
maintainability
performance
relational databases 2nd
impedance mismatch with Domain model
NHibernate
storing data (persistence infrastructure)
database schemas
database support, O/R Mapper
database testing
evolving schemas
maintaining the state of the database during the run
resetting data used by a test before the test
resetting database before each test
separating the testing of the unit from the testing of the call to the
databinding
Data Mapper 2nd 3rd
choosing approach
code generation of custom code
custom manual code
Metadata mapping
Data Transfer Objects (DTO) 2nd
datatypes, special datatypes (PI)
DbUnit
DDD (Domain-Driven Design) 2nd
layering
model focus
NHibernate and
assemblies
ISession
repositories
transactions
refactoring
Decorator pattern 2nd 3rd
decoupling Controllers from the View (MVC pattern)
dependency, TDD
Dependency Injection 2nd 3rd 4th 5th
Constructor Dependency Injection
registries
Setter Dependency Injection
Spring.NET
versus Service Locator
Design Patterns 2nd
Query Objects (example) 2nd
problem
solution proposal one: filter within Domain
solution proposal three: query objects
solution proposal two: filtering in database
state pattern (example) 2nd
problem
solution proposal four
solution proposal one
solution proposal three
solution proposal two
Strategy
Design Patterns (ital)
developers
Diagnostics
directionality
discount curves
display dynamics, unit testing example
displaying object types, unit testing example
distribution
fault tolerance
scalability
security
documentation, TDD
Domain-Driven Design (DDD) 2nd
layering
model focus
NHibernate and
assemblies
ISession
repositories
transactions
refactoring
domain-related rules
Aggregates
avoiding problems
cooperation
IDs
locating set-based processing methods
service validation
transitions
Domain Mode, starting point for approaching feature list
Domain Model 2nd 3rd
client-side Domain Model
complete or subset instantiation
concurrency 2nd
DDD
layering
model focus
NHibernate and
refactoring
executing
impedance mismatch with relational database
instances, life cycle of
isolating instances
location of
queries
mapping Presentation Model
model focus
NHibernate:classification
O/R Mapper
Object-Relational Mapping and
orders
partitions
PL and
problems/features
checking with credit institutes
concurrency conflict detection
customers may not owe more than a certain amount of
list customers by applying flexible and complex filters
list orders when looking at specific customers
order may not have a total of more than one million
orders and customers should have unique numbers
orders have acceptance status
orders must have customers, orderlines must have
orders with many different lines
saving orders
Query Objects (example), filtering within Domain Model
refining
historic customer information
Order
OrderDate
OrderFactory
OrderRepository
OrderType
ReferencePerson
through TDD experimentation
total amount of each order
semantics for the life cycle of the Domain Model instances
shifting from database focus
stateful or stateless Domain Model instantiation
TDD
UI
adding orders
list orders for customers
Separated Presentation pattern
unit testing GUI
wrapping with Presentation Model
Domain Model instantiation
domain objects, applying locking aspects to
Domain Patterns
Factory (example) 2nd
problem
solution proposal one
solution proposal three
solution proposal two
Domain Specific Languages (DSL)
Dornenburg, Erik
DoSomething() method
DSL (Domain Specific Languages)
DTO (Data Transfer Objects)
DynamicMock
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
Eager Load
NHibernate
Effective Java
efficiency
Embedded Value 2nd
NHibernate
Encapsulate Collection, routine cleaning (code smells)
Encapsulate Field, routine cleaning (code smells)
Entity 2nd 3rd
location of
PI
entity-representing classes
Entity Relationship Model
Equals()
Evans, Eric 2nd 3rd
Execute () method
executing Domain Model
Extract Method, routine cleaning (code smells)
Extreme Programming (XP) 2nd
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
factories
instantiating via a provided factory, PI
TDD
Factory
Factory Method 2nd
Factory pattern 2nd
Inversion of Control
list customers by applying flexible and complex filters
problem
solution proposal one
solution proposal three
solution proposal two
Fake
Aggregate
building
GetById()
implementing
logging
PersistAll()
PI for Repositories
unit tests
structure of Repository-related tests
fake objects
_FakeACustomer()
_FakeAnOrder()
fakes
faking OrderRepository
fault tolerance, distribution
features of Domain Model 2nd
problems/features
checking with credit institutes
concurrency conflict detection
customers may not owe more than a certain amount of
list customers by applying flexible and complex filters
list orders when looking at specific customers
order may not have a total of more than one million
orders and customers should have unique numbers
orders must have customers, orderlines must have
orders orders have acceptance status
orders with many different lines
saving orders
fetching lists of orders
fields
PI
public fields
file system, storing data (persistence infrastructure)
Fill()
filtering
in databases with huge parameter lists
within Domain Model
Filters 2nd
applying by list customers (Domain Model)
finding problems in APIs
First Law of Distributed Object Design
Flashback
flattened PM objects
flexibility, mechanisms
flow, TDD 2nd
FlowController
fluent interfaces
Foo
Foreign Key Mapping 2nd
NHibernate
Form Template Method
Fowler, Martin
First Law of Distributed Object Design
MVC pattern
functional processes, Business Logic
Functional Research
Business Logic
functional processes
pluggable rules
results
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
Halpin, T.A.
Helander, Mats 2nd
Object-oriented Data Model, Smart Service Layer, and Documents
Hibernate
Hollywood Principle
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
I-name convention
ICatalogView
IDENTITY
Identity Field 2nd
NHibernate
orders and customers should have unique numbers
Identity Fields, NHibernate
Identity Map 2nd
NHibernate
querying
save scenarios
Identity Map pattern 2nd
IDs, domain-related rules
IList
ILockable
IMethodInvocation.Proceed()
impedance mismatch between domain model and relational database
implementing
APIs, improvements
creating rule classes
Fake
interface methods
list of rules
setting up
lock enforcement advice
locking introduction
naïve implementation
setting up a list of rules
sublists
web forms
Implicit Lock
independence, TDD
infrastructure
persistence
requirements for
storing data
infrastructure patterns
controlling concurrency
Eager Load
Embedded Value
Foreign Key Mapping
Identity Field
Identity Map
Inheritance hierarchies
Lazy Load
Metadata Mapping
NHibernate
controlling concurrency
Embedded Value
Foreign Key Mapping
Identity Field
Identity Map
inheritance
Lazy Load
Metadata Mapping
Unit of Work
validation hooks
Unit of Work
inheritance
from a certain base class, PI
Class Table Inheritance
NHibernate
Single Table Inheritance
inheritance hierarchies
Inheritance, Domain Model
injecting rules
Inline singleton
Insert()
instances
isolating or sharing
life cycle of
instantiating via a provided factory, PI
integration, continuous integration
interface implementation, Domain Model
interface methods, implementation
interfaces
chunky interface
fluent interfaces
I-name convention
PI
reconstituting entities from persistence
TDD
validation interfaces, making pluggable
introduction, AOP
invariants
Inversion of Control (IoC) 2nd 3rd
containers
containers:nested containers
Service Locator
invocation.Proceed()
IOrderRepository
IQuery
IRepository
Irwin, Gregg, pattern adoption
ISession 2nd
NHibernate
IsOKAccordingToSize()
IsOKToAccept
isolating instances
IsOrderOK
IsValid
IsValidRegardingPersistence 2nd
ItemStore
IUserInfo
IUserType
IValidateableRegardingPersistence 2nd
IValidator
IWorkspace
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
Jacobson, Ivar
Joe's Shoe Shop, MVC pattern
joinpoints, AOP
JUnit
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
Kerievsky, Joshua
Kiczales, Gregor
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
lagom
language, ubiquitous language
layering DDD
layers 2nd
BLL (Business Logic Layer)
DAL (Data Access Layer)
Layer Supertype
Service Layer 2nd
example
Layer Supertype
Lazy Load 2nd 3rd
list orders when looking at specific customers
NHibernate
legacy databases, mapping
life cycle
of persisitent entities (NHiber-nate)
Liskoy Substitution Principle (LSP)
list orders for customers 2nd
lists of orders, fetching
LoadView_test
locating set-based processing methods, domain-related rules
location
of Domain Model
of Entity
of queries
in consumers of Repositories
in Domain Model
in Repositories
location transparency
lock enforcement advice, implementing
locking aspects, applying to domain objects
locking introduction, implementing
locks
Coarse-Grained Lock
Implicit Lock
Optimistic Offline Lock 2nd
Pessimistic Offline Lock 2nd
LockViolationException
logging
Fake
logging advice
applying
creating
logging code
modularizing with aspects
LSP (Liskoy Substitution Principle)
Lundberg, Ingemar 2nd
Pragmatism and the Nontraditional Approach
background and history
overview of the
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
maintainability, databases
maintenance
Domain Model
TDD
MakePersistent()
managing relationships
mappers
O/O Mapper
O/R Mapper
classification
Data Mapper pattern
Eager Load
Identity Field
Lazy Load
relationships between entities in relational model
working with data in an OO fashion
mapping
classes onto tables versus mapping tables onto classes
considerations for using
legacy databases
metadata
NHibernate
reusing
Metadata Mapping
Presentation Model, Domain Model
Marshal By Value
Martin, Robert C.
Martinís principles
maturity, storing data (persistence infrastructuure)
MDA (Model-Driven Architecture)
mechanisms
auditing
config
flexibility
logging
no tracing
performance monitoring
security
tracing
messages, SOA (complex messaging processes)
messaging
one-way asynchronous messaging
metadata
mapping
in NHibernate 2nd
O/R Mapper
providing consumers with
Metadata Mapping 2nd
Data Mapper pattern
NHibernate
methods, reconstituting entities from persistence
Microsoft Transaction Server (MTS)
mocking with NMock
mock objects 2nd
consequences
mocks 2nd
mock statement
model focus 2nd
DDD
Domain Model
use cases
Model-Driven Architecture (MDA)
Model-View-Controller (MVC pattern) 2nd 3rd
benefit of
combining Views/Controllers
decoupling the Controller from the View
Joe's Shoe Shop example
simplifying view interfaces through adapters
Model-View-Presenter (MVP pattern) 2nd
models
defined
discussing with customers
modularizing logging code with aspects
MTS (Microsoft Transaction Server)
multi-entity-oriented Business Logic
MVC (Model-View-Controller) 2nd 3rd
benefit of
combining Views/Controllers
decoupling the Controller from the View
Joe's Shoe Shop example
simplifying view interfaces through adapters
MVP (Model-View-Presenter) pattern
MyInit()
MyTrace.Assert()
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
naked objects
naming tests
navigation, relational model
Nelson, Philip
nested containers, Inversion of Control
.NET
AOP
adding state and behavior to existing classes
modularizing logging code using aspects
moving business rules into aspects
object-orientation
.NET Mock Objects
NHibernate
API example
create (CRUD)
delete (CRUD)
read many (CRUD)
read one (CRUD)
transactions
update (CRUD)
classification
advanced database support
API
Domain Model
functionality
Mapper style
query languages
starting points
COMBs
controlling concurrency
DDD and
assemblies
ISession
repositories
transactions
Embedded Value
Foreign Key Mapping
Identity Field 2nd
Identity Map
inheritance
Lazy Load
life cycle of Domain Model instances
life cycle of persistent entities
mapping metadata
Metadata Mapping
open source
PI (Persistent Ignorant)
preparations
reasons for using
relational databases
Unit of Work
validation hooks
versions
NIAM
NIAM/ORM model
NMock 2nd 3rd
Notification
notification advice, creating
Notification pattern
null object
Null Object pattern
NUnit
NWorkspace
queries
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
O/O Mapper
O/O Mapping, PM objects
O/R Mapper
classification
advanced database support
API
Domain Model
functionality of
metadata-based mappings
query languages
starting points
Data Mapper pattern
Eager Load
Identity Field
Lazy Load
relationships between entities in relational model
working with data in an OO fashion
object-oriented data structures
Object-Relational Mapping, Domain Model and
object database, storing data (persistence infrastructure)
object graphs
Object Modeling Technique (OMT)
Object Relational Mapping
classification
advanced database support
API
Domain Model
functionality of
metadata-based mappings
query languages
starting points
Data Mapper pattern
Eager Load
Identity Field
Lazy Load
relationships between entities in relational model
working with data in an OO fashion
Object Role Modeling (ORM)
objects
fake objects
flattened PM objects
mock objects 2nd
naked objects
picking, unit testing example
process objects
Query Objects 2nd
Design Patterns
list customers by applying flexible and complex filters
single-set of Query Objects
OCP (Open-Closed Principle)
OkToAdd()
OMT (Object Modeling Technique)
one-way asynchronous messaging, SOA
OnInit()
OO
SOA
working with data in an OO fashion 2nd
OOP
open source, NHIbernate
Open-Closed Principle (OCP)
optimistic concurrency
Optimistic Offline Lock 2nd
Order 2nd
O/R (Object Relational) Mapping
classification
advanced database support
API
Domain Model
functionality of
metadata-based mappings
query languages
starting points
Data Mapper pattern
Eager Load
Identity Field
Lazy Load
relationships between entities in relational model
working with data in an OO fashion
OrderDate
OrderFactory
ordering advanced database support
OrderLine 2nd 3rd 4th
Orderline
OrderNumber
OrderNumberCantBeZeroAfterReconstitution() 2nd 3rd
order numbers
order placement business rules
OrderRepository 2nd 3rd 4th
faking
GetOrders()
OrderRow
orders
acceptance status
adding
Domain Model
fetching a list of oroders
saving
total amount of each order
OrderSnapshot
OrderType 2nd
OrderWithLinesHasTotalAmount()
ORM (Object Role Modeling)
O/R Mappers
O/R Mapping
Osherove, Roy
overview of TDD problems
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
ParticipatingLogicalFields
partitions
Domain Model
reasons for using
Party Archetype
pattern adoption
patterns
Aggregates 2nd
advanced database support
concurrency
domain-related rules
Fake
queries
save scenarios
versioning
Architectural Patterns
Domain Model pattern
layers (example)
Chain of Responsibility
Collecting Parameter 2nd
Concrete Table Inheritance
Data Mapper 2nd 3rd
choosing approach
code generation of custom code
custom manual code
Metadata mapping
Decorator 2nd 3rd
Design Patterns
Query Objects (example)
state pattern (example)
Strategy
Domain Model Pattern
Domain Patterns
Factory (example)
Factory Method
Factory pattern 2nd 3rd 4th
Inversion of Control
list customers by applying flexible and complex filters
problem
solution proposal one
solution proposal three
solution proposal two
Generation Gap 2nd
GoF
Identity Map
infrastructure patterns
controlling concurrency
Eager Load
Embedded Value
Foreign Key Mapping
Identity Field
Identity Map
Inheritance hierarchies
Lazy Load
Metadata Mapping
NHibernate
Unit of Work
Lazy Load pattern
list orders when looking at specific customers
MVC pattern 2nd
benefit of
combining Views/Controllers
decoupling the Controller from the View
Joe's Shoe Shop example
simplifying view interfaces through adapters
Notification, rules
over-designing
Query Object
reasons for learning about patterns
Registry, Inversion of Control
Remote Facade
reusability
Separation Presentation
Service Locator 2nd 3rd 4th
Inversion of Control
versus Dependency Injection
Specification pattern 2nd
complex rules
generics
queries
State
Template Method
Unit of Work
Patterns of Enterprise Application Architecture 2nd
performance monitoring
performance, databases
Perrone, Claudio
continuous integration
unit tests
PersistAll() 2nd
Fake
persistence
APIs
finding problems
forgetting to check transitions
incorrect transitions
reconstituting entities from
reflection against private fields
specific constructors
specific methods
persistence abstraction
making validation interfaces pluggable
reactive validation on save
reusing mapping metadata
Persistence Ignorance (PI) 2nd
avoiding certain constructs
constructors
cost for
speed
Domain Model
implementing specific interfaces
inheritance from a certain base class
instantiating via a provided factory
NHibernate
providing mandatory specific fields
Repositories
cost for single-set Repositories
Fake
problems testing
problems with small scale integration testing
runtime versus compile time
special datatypes
persistence infrastructure
requirements for
storing data 2nd
choosing
file system
object database
RAM
relational database
resource managers
persistent data, TDD problems
PersistentObjectBase
Pessimistic Offline Lock 2nd
PI (Persistence Ignorance) 2nd
avoiding certain construccts
constructors
cost for
speed
Domain Model
implementing specific interfaces
inheritance from a certain base class
instantiating via a provided factory
NHibernate
providing mandatory specific fields
Repositories
cost for single-set Repositories
Fake
problems testing
problems with small scale integration testing
runtime versus compile time
special datatypes
PickAt()
picking objects, unit testing example
PicoContainer.NET, auto-wiring
Pipes 2nd
PL (Presentation Layer)
Domain Model and
placeholders, BO placeholders
Plain Old CLR Object (POCO)
Plain Old Java Object (POJO)
Platform Specific Model (PSM)
pluggable rules, Business Logic
PM (Presentation Model) 2nd
managing relationships
mapping to Domain Model
wrapping the Domain Model
PM objects
flattened PM objects
O/O Mapping
POCMock
POCO (Plain Old CLR Object)
PoEAA (Patterns of Enterprise Application Architecture) 2nd
pointcut, AOP
POJO (Plain Old Java Object)
policy, services (SOA)
POrderBuilder 2nd
Presentation Layer (PL)
Domain Model and
Presentation Model (PM) 2nd
managing relationships
mapping to Domain Model
wrapping the Domain Model
presentation service
Prevayler
preventing growing problems
Form Template Method
Inline Singleton
pricers
principles for rules
configurability
location within state
prevent you from getting into bad states
productivity
states
testability
two-way rules checking
private fields, reflection
problems
avoiding with domain-related rules
testing Repositories, PI
with Domain Model, problems/features
checking with credit institutes
concurrency conflict detection
customers may not owe more than a certain amount of
list customers by applying flexible and complex filters
list orders when looking at specific customers
order may not have a total of more than one million
orders and customers should have unique numbers
orders must have customers, orderlines must have
orders orders have acceptance status
orders with many different lines
saving orders
processes
waterfall process
XP 2nd
process objects
productivity, principles for rules
ProjectWrapper
properties, public properties
providing consumers with metadata
Proxy
PSM (Platform Specific Model)
public fields
public properties
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
queries
Aggregates
locations of
in consumers of Repositories
in Domain Model
in Repositories
NWorkspace
Specification pattern
Query Constructor
querying
caches and
Identity Map
single-set of Query Objects
cost for
query languages
NHibernate
O/R Mapper
Query Object pattern
Query Objects
Design Patterns
list customers by applying flexible and complex filters
single-set of Query Objects
cost of
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
ubiquitous language
UI (user interface)
Domain Model
adding orders
list orders for customers
Separated Presentation pattern
reusing rules
TDD problems
testing
UML (Unified Modeling Language) 2nd
Unit of Work pattern 2nd 3rd
NHibernate
save scenarios
saving orders
unit testing
domain model
example
displaying candy types
handling display dynamics
picking objects
GUI
mocking:with NMock
TDD of GUI
display dynamics
displaying object types
picking objects
unit tests
Fake
structure of Repositoryrelated tests
TDD
up-front architecture design
consistency
MDA
reusing ideas
Software Factories
UpdateOrderStatus()
use cases, model focus
UserBC
UserDao
UserDaoStub
UserInfo 2nd
user interface (UI)
Domain Model
adding orders
list orders for customers
Separated Presentation pattern
reusing rules
TDD problems
testing
user numbers
user state
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
waterfall process
web forms
domain model
example
GUI
implementing
mocking with NMock
TDD of GUI
unit testing
Web Service
how fine-grained?
SOA
Web services
Windsor
WinForms
Application Server and
without an Application Server
wrapping
considerations for using
Domain Model with Presentation Model
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y]
YAML
Young, Gregory 2nd
code smells
snapshots