quick left: confidently build complex domains in rails

40
CONFIDENTLY BUILD COMPLEX DOMAINS IN RAILS Mike AbiEzzi

Upload: quick-left-inc

Post on 26-Dec-2014

1.211 views

Category:

Technology


0 download

DESCRIPTION

Modeling large, complex domains "the Rails way” can cause some serious pain. Ruby and Rails are supposed to make developers happy. Let's not allow “the Rails way” and complex domains to take the “happy" out of ruby development. The goal is to allow your Rails application to express the domain so that the domain's business logic is clear-cut, easy to grok, and designed in a way that reduces unnecessary complexities and coupling.

TRANSCRIPT

Page 1: Quick Left: Confidently Build Complex Domains in Rails

CONFIDENTLY BUILD COMPLEX DOMAINS!

IN RAILS

Mike AbiEzzi

Page 2: Quick Left: Confidently Build Complex Domains in Rails
Page 3: Quick Left: Confidently Build Complex Domains in Rails

WHAT’S A DOMAIN?

Page 4: Quick Left: Confidently Build Complex Domains in Rails

WHY?software gets complex fast

… and nobody wants a train wreck of models

Page 5: Quick Left: Confidently Build Complex Domains in Rails

▾ app/! ▸ assets/! ▸ controllers/! ▸ helpers/! ▸ mailers/! ▸ models/! ▸ views/

Page 6: Quick Left: Confidently Build Complex Domains in Rails

Developer 1 n

App Store

Customer

App

Installnn

n

n

Purchase

Comment

1

nn

1Version

1

n

1..6

Screenshot

1

Page 7: Quick Left: Confidently Build Complex Domains in Rails

1. Process of defining the domain!2. Communicating the domain!3. Relationships between models!4. Aggregates!5. Value Objects!6. Domain Services!7. Data access

Page 8: Quick Left: Confidently Build Complex Domains in Rails

1n

App Store

Developer 1 n

Customer

App

Installnn

n

n

Purchase

Comment

1

nn

1

Review!comment!

rating

Version

1

n

1..6

Screenshot

1 Release!version_number

Developer/ CompanySeller

Page 9: Quick Left: Confidently Build Complex Domains in Rails

COMMUNICATION

Domain!Expert

Software!Expert

brainstorm → draw diagrams → !speak out assumptions → let them correct you → refine

Page 10: Quick Left: Confidently Build Complex Domains in Rails

COMMUNICATION

“Domain experts should object to terms or structures that are

awkward or inadequate to convey domain understanding”

“Developers should watch for ambiguity or inconsistency that will

trip up design.”

-- Eric Evans

Page 11: Quick Left: Confidently Build Complex Domains in Rails

UBIQUITOUS LANGUAGE“a common, rigorous language between

developers and users […]

Domain!Expert DeveloperProduct!

Owner

UserDesigner Code

the need for it to be rigorous, since software doesn't cope well with ambiguity”

— Martin Fowler

Ensure one consistent language

Page 12: Quick Left: Confidently Build Complex Domains in Rails

app.submit_release(“1.1.0”, ... , screenshots: ["shot1.png", "shot2.png"])

release = Release.new( major: 1, minor: 1, build: 0, ...) release.screenshots << [ Screenshot.new(file: "shot1.png"), Screenshot.new(file: "shot2.png")] release.status = :submitted ! app.releases << release

A BETTER WAY?Describe a domain behavior with a methodEasy to understandSimplifies InteractionManages complexities

Submit a new release of your app

Page 13: Quick Left: Confidently Build Complex Domains in Rails

App1

Comment

1n

Review!comment!

rating

n

1..6

Screenshot

1

AGGREGATE

Release!version_number

Page 14: Quick Left: Confidently Build Complex Domains in Rails

class App < ActiveRecord::Base ... ! def create_release ... def submit_release ... def approve_release ... def flag_for_abuse ... ! def mark_as_staff_favorite ... ! end

Tells a story of how the domain works

Page 15: Quick Left: Confidently Build Complex Domains in Rails

ENTITY VALUEa thing describes a thing

can change state doesn’t reference anything

unique independent!of attributes

avoids design complexities

immutablehas a lifecycle

class Customer class Name

Page 16: Quick Left: Confidently Build Complex Domains in Rails

App1

Comment

1n

Review!comment!

rating

n

1..6

Screenshot

1

Value

Value

Entity

Release!version_number

Entity

Page 17: Quick Left: Confidently Build Complex Domains in Rails

class Screenshot attr_reader :file, :position def initialize(file, position) @file, @position = file, position end def ==(other) file == other.file && position == other.position end end

VALUE OBJECT immutable / equality

Page 18: Quick Left: Confidently Build Complex Domains in Rails

class Screenshot include Comparable attr_reader :file, :position ... ! def <=>(other) position <=> other.position end end

comparableVALUE OBJECT

Page 19: Quick Left: Confidently Build Complex Domains in Rails

class VersionNumber attr_reader :major, :minor, :build ... def next_major_version new VersionNumber(major + 1, minor, build) end ! def next_minor_version ... def next_build_version ... end

VALUE OBJECT factories

Page 20: Quick Left: Confidently Build Complex Domains in Rails

one-to-many or one-to-one (1-n or 1-1)

C. In its own tableB. Serialized on the Entity’s table

3 ways to persist value objects

A. Inline on the Entity’s tableone-to-one (1-1)

Page 21: Quick Left: Confidently Build Complex Domains in Rails

class Release < ActiveRecord::Base def version_number= vn version_number_major = vn.major version_number_minor = vn.minor version_number_build = vn.build end ! def version_number new VersionNumber( version_number_major, version_number_minor, version_number_build) end end

(1-1)A. Inline on the Entity’s table

Page 22: Quick Left: Confidently Build Complex Domains in Rails

class Release < ActiveRecord::Base composed_of :version_number, mapping [ %w(version_number_major major), %w(version_number_minor minor), %w(version_number_build build) ] ... end

Release attributes

VersionNumber attributes

Inline on the Entity’s table (1-1)

Page 23: Quick Left: Confidently Build Complex Domains in Rails

Gift an App SERVICE

1. Charge the gifter that’s purchasing the app.!

2. Assign access rights to the giftee receiving the app.

Facilitates a transaction between two aggregates

Page 24: Quick Left: Confidently Build Complex Domains in Rails

class GiftApp def self.execute(app, gifter, giftee) Purchase.create( app: app, customer: gifter, ...) AccessRight.create( app: app, customer: giftee, purchase: purchase, ...) end end

AccessRight

1n

Purchase

1n

Customer

Page 25: Quick Left: Confidently Build Complex Domains in Rails

▾ app/! ▸ models/! ▾ services/! create_app.rb! gift_app.rb! refund_purchase.rb! ...

Page 26: Quick Left: Confidently Build Complex Domains in Rails

Data Access App.where( "create_at > ? and purchase_count > ?", 1.week.ago, 10000).all

class App < ActiveRecord::Base scope :new_and_noteworthy, -> { where("create_at > ? and purchases > ?", 1.week.ago, 10000) } end

Use scopes

Page 27: Quick Left: Confidently Build Complex Domains in Rails

class App < ActiveRecord::Base scope :new_and_noteworthy, ... scope :staff_picks, ... scope :most_popular, ... ... def create_release(…) def submit_release(…) ... end

One expressive point of entry

* you only need to retrieve aggregate roots *

Page 28: Quick Left: Confidently Build Complex Domains in Rails

▾ app/! ▾ models/! ▾ apps/! app.rb! release.rb! review.rb! screenshot.rb! version_number.rb! ▸ customers/! ▸ sellers/! ▸ services/

Page 29: Quick Left: Confidently Build Complex Domains in Rails

IN SUMMARY

Page 30: Quick Left: Confidently Build Complex Domains in Rails

Continuously refine the domain with a

domain expert

1

Page 31: Quick Left: Confidently Build Complex Domains in Rails

Insist on having a ubiquitous language for

seamless communication

2

Page 32: Quick Left: Confidently Build Complex Domains in Rails

Constrain relationships to only what the domain needs

3

Page 33: Quick Left: Confidently Build Complex Domains in Rails

Create aggregates that express domain concepts and manage complexity

4

Page 34: Quick Left: Confidently Build Complex Domains in Rails

Create value objects to eliminate unnecessary

complexity

5

Page 35: Quick Left: Confidently Build Complex Domains in Rails

Create domain services to express transactions !between aggregates

6

Page 36: Quick Left: Confidently Build Complex Domains in Rails

Express the domain’s intent through!

well defined data access

7

Page 37: Quick Left: Confidently Build Complex Domains in Rails

▾ app/! ▸ assets/! ▸ controllers/! ▸ helpers/! ▸ mailers/! ▸ models/! ▸ views/

Page 38: Quick Left: Confidently Build Complex Domains in Rails

▾ app/! ▾ models/! ▸ apps/! ▸ customers/! ▸ sellers/! ▸ ...! ▸ services/! create_app.rb! gift_app.rb! refund_purchase.rb! ...

Page 39: Quick Left: Confidently Build Complex Domains in Rails

Some Pro Tips1. Don’t let your database diverge to far from

your domain model!

2. Don’t try to build and maintain a huge diagram of your domain!

3. Separate you domain logic from view logic!

4. You can use the gem fig_leaf to privatize ActiveRecord methods (e.g. create, where)

Page 40: Quick Left: Confidently Build Complex Domains in Rails

Thanks for Listening!

@mjezzi

www.virtual-genius.com/

www.mikeabiezzi.com