Top Banner
@skwp @reverbdotcom #wcr14 Yan Pritzker CTO, Reverb.com @skwp @reverbdotcom Domain Driven Rails https://speakerdeck.com/skwp
105

Domain Driven Rails

Jul 21, 2015

Download

Technology

Yan Pritzker
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Yan PritzkerCTO, Reverb.com

@skwp @reverbdotcom

Domain Driven Rails

https://speakerdeck.com/skwp

Page 2: Domain Driven Rails
Page 3: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Are you happy with the SIZE and COMPLEXITY

of your models?

Page 4: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Are you happy with the SCALABILITY of your team?

Page 5: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Are you happy with the ADAPTABILITY

of your business?

Page 6: Domain Driven Rails

@skwp @reverbdotcom #wcr14

What are you building?

Page 7: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Rails is a detail!"

Decouple all things"

Is the code better?"

Keep it Railsy"

Page 8: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Somewhere in between

Simple CRUD"Apps"

Complex Enterprise

Logic"

Page 9: Domain Driven Rails

@skwp @reverbdotcom #wcr14

I want to discover relevant compromises

rather than defend ideals

Page 10: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 11: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Over 115

Model Classes

Page 12: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Over 1000 Total

Classes

Page 13: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 14: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Not great, but we have only three chubby models

Page 15: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Are monoliths bad for business?

Page 16: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Quick IterationsLow Operational

ComplexityRefactoring

Page 17: Domain Driven Rails

Monolith

ServiceService

Service Service

Service

Early 2013 - Startup / Proof of Concept

Page 18: Domain Driven Rails

Monolith

ServiceService

Service Service

Service

2014 - Growth Phase

Page 19: Domain Driven Rails

@skwp @reverbdotcom #wcr14

http://martinfowler.com/articles/distributed-objects-microservices.html

“I'm wary of distribution and my default inclination is to prefer

a monolithic design”

“While small microservices are certainly simpler to reason about, I worry that this pushes complexity into the

interconnections between services”

“Refactoring becomes much harder when you have to do it across remote boundaries.”

Page 20: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Quick IterationsLow Operational

ComplexityMay lead to a BBOM

Page 21: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Maintainable Monoliths

Can Be Achieved

Page 22: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 23: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 24: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Product 400 LOC

~150 LOC non-ActiveRecord Churn: 49 changes this year"

Order 333 LOC

~200 LOC non-ActiveRecord Churn: 36 changes this year

User 338 LOC

~200 LOC non-ActiveRecord Churn: 29 changes this year

Page 25: Domain Driven Rails

CHURN

Product

OrderUser

Page 26: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Commonly used classes are hard

to refactor

Page 27: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Stop modifying

code!(Open/Closed Principle)

Page 28: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Don’t put different rates

of change together"

Kent Beck - Smalltalk Best Practice Patterns(see also: Single Responsibility Principle)

Page 29: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Don’t put different rates

of change together"

Kent Beck - Smalltalk Best Practice Patterns

Data Model

Business Logic

Page 30: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Separate what the system is "

from what the system does"

James Copelien & Trygve Reenskaug(Data, Context, Interaction)

Page 31: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Where does business logic go?

Page 32: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Controller

2005

ActiveRecord

Mailers

Services

User

Page 33: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Console?"Rake task?"

Background jobs?"API layer?"Testing?

What about…

Page 34: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

Fat models?

Page 35: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderRefund

Page 36: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderRefund

Ship

Page 37: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderRefund

ShipCheck Fraud Risk

Page 38: Domain Driven Rails

@skwp @reverbdotcom #wcr14

“Active Record is a good choice for domain logic that isn't too

complex, such as creates, reads, updates, and deletes”

Martin Fowler

Page 39: Domain Driven Rails

@skwp @reverbdotcom #wcr14

If Controller and Model are all you have then

one has to be skinny and one has to be fat

Page 40: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Domain Layerskinny framework,

healthy business logic,"no fat anywhere

http://joncairns.com/2013/04/fat-model-skinny-controller-is-a-load-of-rubbish/

Page 41: Domain Driven Rails

Model

Controller

View

The Rails WayThe

WayActiveRecord

Use Cases

Grape API

ControllersCron

Redis

Rake

HTTP Services

Workers

REntities

Roles

DB

ListenersEvents

Page 42: Domain Driven Rails

@skwp @reverbdotcom #wcr14

app/reverbfor app specific

Page 43: Domain Driven Rails

@skwp @reverbdotcom #wcr14

lib/reverbfor Open Source / Generic

Page 44: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Reverb::Namespace to avoid collisions with gems

Page 45: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 46: Domain Driven Rails

@skwp @reverbdotcom #wcr14

This is amarketplace!

http://blog.8thlight.com/uncle-

bob/2011/09/30/Screaming-

Architecture.html

Page 47: Domain Driven Rails

@skwp @reverbdotcom #wcr14

http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

Page 48: Domain Driven Rails

@skwp @reverbdotcom #wcr14

see also Hexagonal, Ports & Adapters, DCI

Page 49: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Clean Enough

Architecture"

Page 50: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Choosing the right fight

Page 51: Domain Driven Rails

@skwp @reverbdotcom #wcr14

http://blog.8thlight.com/mike-ebert/2013/03/23/the-repository-pattern.html

Page 52: Domain Driven Rails

@skwp @reverbdotcom #wcr14

http://blog.8thlight.com/mike-ebert/2013/03/23/the-repository-pattern.html

(but you should still read this)

Page 53: Domain Driven Rails

@skwp @reverbdotcom #wcr14

User.where(…)User.activeUser.find(1)

This is easy to replace with something other than AR. Repository not required.

Don’t leak SQL outside of AR

Page 54: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Domain Logic in ActiveRecord and

Controllers leads to Churn

Page 55: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Use CasesReify complex business logic

into classes

Page 56: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 57: Domain Driven Rails

@skwp @reverbdotcom #wcr14

This is not"Rails

Page 58: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 59: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Explicitly Require Dependency

http://myronmars.to/n/dev-blog/2012/12/5-reasons-to-avoid-bundler-require

Invoke It

Page 60: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Code Reuse!

Thin Shell

Page 61: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Stubby

Happy Path

Page 62: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Testing conditionals and side effects has nothing to do with Rails

Page 63: Domain Driven Rails

@skwp @reverbdotcom #wcr14

NamingThe hardest problem in computer science

Page 64: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderService

Page 65: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderService

Page 66: Domain Driven Rails

@skwp @reverbdotcom #wcr14

OrderService

NounService Grows Unbounded

Page 67: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Use verbs to narrow your scope

Page 68: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

Page 69: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ShipOrder

Page 70: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ShipOrder Cancel Order

Page 71: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ShipOrder Cancel Order

RefundOrder

Page 72: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ShipOrder Cancel Order

RefundOrder

Does notgrow over time

Page 73: Domain Driven Rails

@skwp @reverbdotcom #wcr14

ShipOrder Cancel Order

RefundOrder

Don’t change"once you write them

Page 74: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Ubiquitous Language

Page 75: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 76: Domain Driven Rails

@skwp @reverbdotcom #wcr14

What is this?

Page 77: Domain Driven Rails

@skwp @reverbdotcom #wcr14

RolesAdd methods to objects on demand

in the context of a Use Case

Page 78: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Decorator

Page 79: Domain Driven Rails

@skwp @reverbdotcom #wcr14

We added these methods

Page 80: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 81: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Methods related to each"other but loosely related"

to the parent concept"and used only in a few"

Use Cases

Page 82: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 83: Domain Driven Rails

@skwp @reverbdotcom #wcr14

EventsAdd behavior with listeners

without modifying code

Page 84: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ActiveRecord Callbacks

Send Email

Page 85: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ActiveRecord Callbacks

Send Email

Call External Service

Page 86: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Order

ActiveRecord Callbacks

Send Email

Call External Service

ConditionalCallbacks

Page 87: Domain Driven Rails

@skwp @reverbdotcom #wcr14

AR callbacks become more complex as the

system supports more use cases

Page 88: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Different use cases may trigger different events

even when working with the same model

Instead

Page 89: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 90: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Page 91: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Add another listener to add behavior The core class doesn’t change

Page 92: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Global listeners for cross-cutting concerns without littering code

Wisper::GlobalListeners.add(Reverb::Listeners::AnalyticsListener.new)"

Page 93: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Controller is a listener too

Page 94: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Policy ObjectsReify complex business rules

into objects

Page 95: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Likely to change

Unlikely to change

Page 96: Domain Driven Rails

@skwp @reverbdotcom #wcr14

refactored for readability

Page 97: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Injectable, but has a default

Simple code, only need to test one pathfor the imperative side effect"

(sending an email)

Page 98: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Distillation Time

Page 99: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Language of codebase reflects language of business

Page 100: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Separate behaviors (what the system does) from models (what the system is)

Page 101: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Rates of Change

Page 102: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Is this all Unicorns and Rainbows?

Page 103: Domain Driven Rails

@skwp @reverbdotcom #wcr14

Sprawl?"Onboarding?"

Naming?"Documentation?"

Page 104: Domain Driven Rails

@skwp @reverbdotcom #wcr14

http://blog.mattwynne.net/category/hexagonal-rails/

http://clean-ruby.com/

Resourceshttp://confreaks.com/videos/759-rubymidwest2011-keynote-

architecture-the-lost-years

http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html

http://www.artima.com/articles/dci_vision.html

http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

https://speakerdeck.com/skwp

Page 105: Domain Driven Rails

@skwp @reverbdotcom #wcr14

We Are Hiring Always"

jobs.reverb.com

Ruby, ElasticSearch, DevOps, Designers, Android, and more!

[email protected]