An Introduction to Domain Driven Design in PHP
Post on 16-Apr-2017
417 Views
Preview:
Transcript
An Introduction to Domain Driven Design
in PHPChris Renner
Nashville PHP MeetupAugust 9, 2016
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
About Me - Personal
• Married 17 years with two little ones (10 and 3)
• In Nashville 18 years, originally from Kentucky
• Interests: Too many!
The Renners
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
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
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”
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
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.
DDD is…• a process
• modeling business logic in code
• a common language among devs and stakeholders
• agile*
When to use?• Complicated business logic
• Large code base
• Multiple devs
• Long dev cycle, app lifecycle
• moving paper/human processes into an electronic system
When NOT to use?
• Short development cycle
• Microservices
• Simple business models
• Minimal business logic
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
The Big Picture
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
Model
• A software abstraction representing a specific concept in the domain.
• Data & Biz Logic
• Will be continually refined as understanding of domain grows.
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
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.
“Tactical” DDD
Entities
• e.g. Car, Patient, Invoice, Contract
• Typically 1-class per entity
• Mimic real objects
• Data + Business Logic = Domain Models
class Widget {
public $id;
public $price;
public function __construct(){}
public function isDiscountable(){// logic here
}}
Factories
• Objects that create instances of other objects
• TIP: Pass in an ID to get back hydrated instance
class Widget{
public static function factory($id = null){// create instance$obj = new Widget();
// hydrate with data from persistenceif ($id) {WidgetMapper::hydrate($obj, $id);
}
return $obj;}
}
$foo = Widget::factory(1234);
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
Domain Services• Use sparingly!
• Capture business logic that operates on more than one entity/model
• When a class isn’t a “thing”
• != application services
Domain Events
• Real actions, events or activities in the business
• Becomes your domain logic
• Place in model/entity or service layer
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
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
Patterns and Best Practices
Domain Models
• Implementation of Entity
• Use Inheritance and/or Traits & Interfaces to abstract and re-use
• Domain Model + Mapper + Table Data Gateway patterns
Domain
ModelMapper 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
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 persistenceif ($id) {
WidgetMapper::hydrate($obj, $id);}
return $obj;}
}
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();}
}
class WidgetMapper extends MapperAbstract {
public static $columns =[‘id’ => ‘ID’,‘name’ => ‘NAME,‘price’ => ‘PRICE’
]
}
Interacting with a Domain Model Instance
$myWidget = Widget::factory();$myWidget->setName(‘Acme Super Thingy’);$myWidget->price = 99.95;$id = $myWidget->save();
echo $id; // 1234
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
Getters and Setters
• Don’t Overuse!
• Opportunity to Add Logic
public function setName($string){$this->name = substr($string, 5, 100);
}
public function setStatus($status){if($status != $this->status) {$this->addtoStatusLog($status);}
$this->status = $status;}
Strategy Pattern
• aka “Policy Pattern”
• encapsulate business rules/logic
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
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
Specification Pattern Exampleclass 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
Lessons Learned
Intention-Revealing Interface
• Contextually Relevant Variable, Function and Class Names
• public function sendFullyExecutedEmail()
Comment Your Code
• comment and docblock everything
IDs for Everything!
• usernames and emails are NOT unique IDs!
• give everything an internal numeric ID, even if its never seen by user
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”
Avoid Framework Lock-In
• Preference for components
• Composer
• Consider extending a Micro-Framework v. an all-in-one package
Good OOP required
• Abstraction
• Encapsulation
• Separation of Concerns
Avoid Unnecessary Complexity
• Ask “is this necessary?”
• Don’t let DDD rules become a prison
• Simplicity = Maintainability
Become the Expert
• You will uncover flaws and inefficiencies in the business logic
• You may end up understanding the business process better than stakeholders
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
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
Find Me
• Twitter: @rennerchris
• Web: www.chrisrenner.com
• Email: rennercr@gmail.com
I’m Troy McClure, and you might remember me from such tech talks as “Creating Legacy Code”
and “Maximizing Technical Debt”
Questions?
top related