We use PHP to solve problems. But as software projects grow and the business needs increase, how do we manage the complexity and still produce readable and maintainable code? Domain Driven Design is a set of concepts and practices that, when applied appropriately, help us manage complexity in large scale projects. In this talk, we will explore the broad points of DDD. I’ll also share tips, patterns and lessons-learned gained from my experiences building PHP software for complicated business processes.
1. An Introduction to Domain
Driven Design
in PHP
Chris Renner
Nashville PHP Meetup
August 9, 2016
2. Agenda
• A bit about me & what I do
• Describe our principle application and its purpose
• High-level DDD concepts
• Implementation strategies and patterns
• Lessons learned
• Conclusion
3. About Me - Personal
• Married 17 years with two little ones (10 and 3)
• In Nashville 18 years, originally from Kentucky
• Interests: Too many!
5. About Me - Professional
• Sr. Application Developer at VUMC, 12 years at
Vanderbilt,~10 years as PHP dev
• Self-taught developer*
• internal-facing enterprise scale apps
• Prior: proposal writer, contract negotiator
6. What I do
• Application Development
• User interaction & support
• Business Analysis
• Reporting and analytics
• Support one enterprise app, a few small apps and a
couple of websites
7. Our Main App
• PEER
• Went online July 2007
• Primary business application of a department of 30
users, with hundreds of other “customers”.
• Domain is “Contract Management”
8. What is DDD?
• A set of solutions to documenting, solving and
managing the complexity of business problems in
your code.
• A methodology for thinking and talking about
solving business problems with code
9. DDD is not…
• a TV show on Food Network
• anything to do with domain names or DNS
• code, but rather principles and practices.
• MVC or an MVC replacement.
• a design pattern.
• an all-or-nothing proposition.
10. DDD is…
• a process
• modeling business logic in code
• a common language among devs and stakeholders
• agile*
11. When to use?
• Complicated business logic
• Large code base
• Multiple devs
• Long dev cycle, app lifecycle
• moving paper/human processes into an electronic
system
12. When NOT to use?
• Short development cycle
• Microservices
• Simple business models
• Minimal business logic
13. Requirements
• General intelligence - must understand client’s
business process
• Communication skills - must be able to translate biz
speak to tech speak and vice versa
• Humility
15. Domain
• A sphere of knowledge, influence or activity. The
subject area to which the user applies a program is
the domain of the software
• e.g. Used Car Sales, Patient Medical Records,
Contract Management*
• not Automotive, Health Care
16. Model
• A software abstraction representing a specific
concept in the domain.
• Data & Biz Logic
• Will be continually refined as understanding of
domain grows.
17. Ubiquitous Language
• Ubiquitous: omnipresent, everywhere
• Set of terms structured around the domain model
and used by both tech and biz team members when
discussing the project.
• Use in the code
18. Bounded Context
• Limits drawn around the scope of the business
problem create a context area.
• Statements about a model can only be understood
within this context.
20. Entities
• e.g. Car, Patient, Invoice, Contract
• Typically 1-class per entity
• Mimic real objects
• Data + Business Logic = Domain Models
21. class Widget {
public $id;
public $price;
public function __construct()
{
}
public function isDiscountable()
{
// logic here
}
}
22. Factories
• Objects that create instances of other objects
• TIP: Pass in an ID to get back hydrated instance
23. class Widget
{
public static function factory($id = null)
{
// create instance
$obj = new Widget();
// hydrate with data from persistence
if ($id) {
WidgetMapper::hydrate($obj, $id);
}
return $obj;
}
}
$foo = Widget::factory(1234);
24. Aggregates
• One-to-Many
• E.g. Entity “Invoice” may have multiple line items,
each probably a LineItem Entity
• Roll up many like things into a parent
25. Domain Services
• Use sparingly!
• Capture business logic that operates on more than
one entity/model
• When a class isn’t a “thing”
• != application services
26. Domain Events
• Real actions, events or activities in the business
• Becomes your domain logic
• Place in model/entity or service layer
27. Modules
• Separate code into meaningful subject areas based
on business logic
• One module for system/application
support/architectural stuff, then modules for each
business sub-area or bundle of related code
• Personal preference
28. Layers
(Hexagonal Architecture)
• Separation of concerns
• Outer later is interface, either UI or service
connections
• middle layer that translates requests into business
actions
• inner layer is business logic
30. Domain Models
• Implementation of Entity
• Use Inheritance and/or Traits & Interfaces to
abstract and re-use
• Domain Model + Mapper + Table Data Gateway
patterns
31. Domain
Model
Mapper Table
• All SQL in Table class
• Mapper translates between Model properties and
table column
• Model has NO awareness of the Table class
• Application code (controllers, services) interact
with the Model only
32. class Widget extends DomainModelAbstract
{
public $id;
public $name;
public $price;
protected $department;
public static function factory($id = null)
{
// create instance
$obj = new Widget();
// hydrate with data from persistence
if ($id) {
WidgetMapper::hydrate($obj, $id);
}
return $obj;
}
}
33. class WidgetTable extends TableAbstract
{
public $name = ‘WIDGET_TABLE’;
public $primary = ‘ID’;
public function fetchById($id)
{
$sql = “SELECT * FROM $this->name WHERE
$this->primary = :id”;
$result = $db->query($sql, [‘:id’ = > $id]);
return $result->fetch();
}
}
35. Interacting with a Domain
Model Instance
$myWidget = Widget::factory();
$myWidget->setName(‘Acme Super Thingy’);
$myWidget->price = 99.95;
$id = $myWidget->save();
echo $id; // 1234
36. Lazy Loading
class Widget
{
public $deptId;
private $department;
public function getDept()
{
if (!$this->department) {
$this->department = Department::factory($this->deptId);
}
return $this->department;
}
}
echo $widget->getDept()->name; // Human Resources
40. Strategy Pattern Example
class Contract
{
public function isExpired()
{
if(strtotime($this->endDate) < time()) {
return true;
}
return false;
}
}
$contract->setEndDate(‘2016-08-01’);
echo $contract->isExpired(); // true
41. Specification Pattern
• like Strategy, but a separate class instead of a
function
• single public function isSatisfiedBy() determines if
an object meets specified criteria
• can be chained
42. Specification Pattern Example
class BillingAgreementSpecification
{
public function isSatisfiedBy(Contract $contract)
{
if(!$contract->requirementA) {
return false;
}
if(!$contract->requirementB) {
return false;
}
return true;
}
}
$spec = new BillingAgreementSpecification();
echo $spec->isSatisfiedBy($contract); // true
46. IDs for Everything!
• usernames and emails are NOT unique IDs!
• give everything an internal numeric ID, even if its
never seen by user
47. Minimize Shortcuts
• Code it to work first, then go back and make it right
• hack-y code will bite you later
• iterate + feedback, don’t assume you fully
understand the problem - the Model will never be
“done”
48. Avoid Framework Lock-In
• Preference for components
• Composer
• Consider extending a Micro-Framework v. an all-in-
one package
51. Become the Expert
• You will uncover flaws and inefficiencies in the
business logic
• You may end up understanding the business
process better than stakeholders
52. Summary
• DDD a way of communicating and thinking about a
complex business problem
• Implementing DDD involves the best of enterprise
design patterns, OOP and clean code principles.
• Use what works, every project is different
53. References
• Domain Driven Design: Tackling Complexity in the Heart of
Software - Eric Evans, 2003
• DDD Reference - Eric Evans,
https://www.domainlanguage.com/ddd/reference/
• Clean Code: A Handbook of Agile Software Craftsmanship -
Robert Martin, 2008
• Patterns of Enterprise Application Architecture - Martin Fowler,
2002
• phproundtable: Domain Driven Design in PHP -
https://www.phproundtable.com/episode/domain-driven-design-
in-php