An Introduction to Domain Driven Design in PHP

Post on 16-Apr-2017

417 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

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