SlideShare une entreprise Scribd logo
1  sur  46
Télécharger pour lire hors ligne
1. Embrace complexity
2. Know where you’re going
3. Be more than just a
“Rails Developer”
app
├── assets
├── controllers
├── helpers
├── mailers
├── models
└── views
V
CM
V
CM
def pricing_range_fold_and_save(new_range)
pos = 0
pricings = self.product_pricings
other_range = ProductPricing.new
if pricings.length == 0
pricings.push(new_range)
else
pricings.each_with_index do |e, i|
if i == 0 && new_range.start_date < e.start_date
pricings.unshift(new_range)
if new_range.end_date <= e.end_date
e.start_date = new_range.end_date + 1.day
break
else
while pricings[1].present? && new_range.end_date >= pricings[1].end_date
pricings[1].destroy
pricings.delete pricings[1]
end
if pricings[1].present?
pricings[1].start_date = new_range.end_date + 1.day
end
break
end
elsif new_range.start_date <= e.end_date && new_range.start_date >= e.start_date
!
if new_range.end_date < e.end_date
other_range = e.dup
other_range.start_date = new_range.end_date + 1.day
if new_range.start_date == e.start_date
e.destroy
pricings.delete e
i -= 1
else
e.end_date = new_range.start_date - 1.day
end
pricings.insert(i+1, new_range)
pos = i+1
pricings.insert(i+2, other_range)
break
else
if new_range.start_date == e.start_date
e.destroy
pricings.delete e
i -= 1
else
e.end_date = new_range.start_date - 1.day
end
pricings.insert(i+1, new_range)
pos = i+1
while pricings[i+2].present? && new_range.end_date >= pricings[i+2].end_date
pricings[i+2].destroy
pricings.delete pricings[i+2]
end
if pricings[i+2].present?
pricings[i+2].start_date = new_range.end_date + 1.day
end
break
end
!
elsif i == pricings.size-1
pricings[i].end_date = new_range.start_date-1.day
pricings.push(new_range)
break
end
end
end
!
pricings.each_with_index do |pricing, i|
if i != pricings.size-1 && pricing.price ==pricings[i+1].price
pricing.end_date = pricings[i+1].end_date
end
if i != 0 && pricing.end_date == pricings[i-1].end_date
pricing.destroy
pricings.delete pricing
end
if pricing.end_date < pricing.start_date
pricing.destroy
pricings.delete pricing
end
end
!
pricings.each do |pricing|
if pricing != pricings[pos]
pricing.currency = pricings[pos].currency
pricing.save
end
end
pricings[pos].save
return pricings
!
end
Pencil Sharpener
!
C V
M
E
E
S
S
C
V
M
R
Application
Domain
S
Complexity
The critical complexity of
most software projects is in
understanding the domain
itself.
!
Eric Evans
Ubiquitous Language
Domain Driven Design
Hexagonal Architecture
http://blog.mattwynne.net/2012/05/31/hexagonal-rails-objects-values-and-hexagons/
Matt Wynne
Form Object
FOworld C
Form Object
FOworld C
class TicketForm!
include ActiveModel::Model!
!
validates :trip, :price, :passengers, presence: true!
!
def passengers!
@passengers ||= [Passenger.new]!
end!
!
def tickets!
@tickets ||= self.passengers.map do |passenger|!
Ticket.new(...)!
end!
end!
end!
class TicketsController < ApplicationController!
!
def create!
@ticket_form = TicketForm.new(params)!
tickets = @ticket_form.tickets!
!
if @ticket_form.valid? && TicketCharger.new(tickets).charge!!
redirect_to success_url!
else!
render 'new'!
end!
end!
!
end
Request Object
ROCworld
Request Object
RO Cworld
class CreateOrderRequest
!
include Virtus.value_object
include ActiveModel::Validations
!
attribute :customer, Customer
validates :customer, nested: true, presence: true
!
attribute :billing, Billing
validates :billing, nested: true, presence: true
!
attribute :shipping, Shipping
validates :shipping, nested: true, presence: true
!
end
class ApplicationController < ActionController::Base
before_filter :validate_request
!
def validate_request
handle_error(request_object) unless request_object.valid?
end
!
def request_object
@request_object ||= request_class.new(request_parameters)
end
!
def request_class
"#{action_name}#{resource_name}Request".constantize
end
!
def handle_error(request_object)
[...]
end
end
Service Object
SOworld C
Service Object
SOworld C
class OrderService
!
def create(order)
authorize!(order)
!
repository.save!(order)
!
purchase(order) do |transaction|
repository.save!(order)
end
end
!
def purchase(order, &block)
PaymentService.new.purchase(order, &block)
end
!
end
class OrdersController < ApiController
!
def create
order = request_object.to_order
transaction = OrderService.new.create(order)
!
if transaction.success?
order_created(order)
else
payment_failed(transaction)
end
end
!
end
OK, so now what?
“I’m right there in the room, and no
one even acknowledges me.”
E
E
S
S
C
V
M
R
Application
Domain
S
Repository
MS R
E
class Repository!
!
class << self!
!
attr_accessor :mapper!
!
def save!(domain)!
record = mapper.export(domain, record)!
response = record.save!!
domain.id = record.id!
response!
end!
!
end!
!
def self.method_missing(method_name, *args, &block)!
Scope.new(mapper).send(method_name, *args, &block)!
end!
!
end
class Scope!
!
attr_accessor :mapper, :scope!
!
def initialize(mapper)!
@mapper = mapper!
@scope = mapper.export_class!
end!
!
def method_missing(method_name, *args, &block)!
@scope = scope.send(method_name, *args, &_map_block(block))!
!
scope.is_a?(ActiveRecord::Relation) ? self : _map(scope)!
end!
!
def _map_block(block)!
Proc.new { |*args| block.call(_map(*args)) } if block!
end!
!
def _map(object)!
if object.is_a?(mapper.export_class)!
mapper.map(object)!
elsif object.is_a?(Enumerable)!
object.map { |e| e.is_a?(mapper.export_class) ? mapper.map(e) : e }!
else!
object!
end!
end!
!
def respond_to?(method_name, include_private = false)!
scope.respond_to?(method_name, include_private) || super!
end!
end
class Mapper!
class << self!
!
attr_reader :base_class, :export_class!
!
def maps(mapping)!
@base_class, @export_class = mapping.first!
end!
!
def map(object)!
if object.is_a? base_class!
export(object)!
else!
import(object)!
end!
end!
!
def export(base, record=nil)!
return unless base!
!
if record!
record.assign_attributes(base.attributes)!
else!
record = export_class.new(base.attributes)!
end!
!
record!
end!
!
def import(record)!
base_class.new(record.attributes) if record!
end!
end!
end!
class Repository!
!
class << self!
!
attr_accessor :mapper!
!
def save!(domain)!
record = IdentityMap.get(mapper.export_class, domain.id)!
record = mapper.export(domain, record)!
response = record.save!!
IdentityMap.add(record)!
domain.id = record.id!
response!
end!
!
end!
!
def self.method_missing(method_name, *args, &block)!
Scope.new(mapper).send(method_name, *args, &block)!
end!
!
end
class IdentityMap!
!
class << self!
def add(record)!
raise ArgumentError.new('Record cannot be added with a nil id') unless record.id!
repository[key(record.class)][record.id] = record!
end!
!
def remove(record)!
repository[key(record.class)].delete(record.id)!
end!
!
def get(klass, id)!
repository[key(klass)][id]!
end!
!
def clear!
repository.clear!
end!
!
def repository!
Thread.current[:identity_map] ||= Hash.new { |h,k| h[k] = {} }!
end!
!
def key(klass)!
klass!
end!
!
end!
end!
So, what’s the point again?
1. Embrace complexity
!
2. Know where you’re going
!
3. Be more than just a “Rails Developer”
https://github.com/dwhelan/hex-ddd
Continue the discussion
Reading
Patterns of Enterprise Application Architecture

Martin Fowler
Domain Driven Design

Tackling Complexity in the Heart of Software

Eric Evans
Practical Object Oriented Design in Ruby

An Agile Primer

Sandi Metz
Reading
Clean Code

A Handbook of Agile Software Craftsmanship

Robert C. Martin
Implementing Domain Driven Design

Vaughn Vern
Photo/Video Credits
https://www.youtube.com/watch?v=-JLbAePwoHQ
http://www.docstoc.com/docs/47342986/Rube-Goldberg-Project-Rube
https://sitespecific2013awe.blogs.lincoln.ac.uk/tag/tower-of-babel/
http://collabcubed.com/2012/01/17/roskilde-festival-plywood-dome/
http://mitchjackson.com/white-elephants/

Contenu connexe

Tendances

Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersRichard Baker
 
Hexagonal architecture - message-oriented software design
Hexagonal architecture  - message-oriented software designHexagonal architecture  - message-oriented software design
Hexagonal architecture - message-oriented software designMatthias Noback
 
Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8AppDynamics
 
Kafka Retry and DLQ
Kafka Retry and DLQKafka Retry and DLQ
Kafka Retry and DLQGeorge Teo
 
DDD Tactical Design with Clean Architecture - Ivan Paulovich
DDD Tactical Design with Clean Architecture - Ivan PaulovichDDD Tactical Design with Clean Architecture - Ivan Paulovich
DDD Tactical Design with Clean Architecture - Ivan PaulovichIvan Paulovich
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?VMware Tanzu Korea
 
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps Eason Kuo
 
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...Alex Cachia
 
Domain Driven Design (DDD)
Domain Driven Design (DDD)Domain Driven Design (DDD)
Domain Driven Design (DDD)Tom Kocjan
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean ArchitectureBadoo
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitecturePaul Mooney
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingEmanuele DelBono
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing ArchitecturesVictor Rentea
 
Microservices Architecture Part 2 Event Sourcing and Saga
Microservices Architecture Part 2 Event Sourcing and SagaMicroservices Architecture Part 2 Event Sourcing and Saga
Microservices Architecture Part 2 Event Sourcing and SagaAraf Karsh Hamid
 
Enterprise Software Architecture styles
Enterprise Software Architecture stylesEnterprise Software Architecture styles
Enterprise Software Architecture stylesAraf Karsh Hamid
 
Python: Common Design Patterns
Python: Common Design PatternsPython: Common Design Patterns
Python: Common Design PatternsDamian T. Gordon
 

Tendances (20)

Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and Workers
 
Hexagonal architecture - message-oriented software design
Hexagonal architecture  - message-oriented software designHexagonal architecture  - message-oriented software design
Hexagonal architecture - message-oriented software design
 
Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8Memory Management: What You Need to Know When Moving to Java 8
Memory Management: What You Need to Know When Moving to Java 8
 
Kafka Retry and DLQ
Kafka Retry and DLQKafka Retry and DLQ
Kafka Retry and DLQ
 
DDD Tactical Design with Clean Architecture - Ivan Paulovich
DDD Tactical Design with Clean Architecture - Ivan PaulovichDDD Tactical Design with Clean Architecture - Ivan Paulovich
DDD Tactical Design with Clean Architecture - Ivan Paulovich
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps
Implementing Domain-Driven Design (Study Group) Chapter 3 - Context Maps
 
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
 
DevOps 101
DevOps 101DevOps 101
DevOps 101
 
Domain Driven Design (DDD)
Domain Driven Design (DDD)Domain Driven Design (DDD)
Domain Driven Design (DDD)
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic Architecture
 
DevOps: Infrastructure as Code
DevOps: Infrastructure as CodeDevOps: Infrastructure as Code
DevOps: Infrastructure as Code
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcing
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
 
Microservices Architecture Part 2 Event Sourcing and Saga
Microservices Architecture Part 2 Event Sourcing and SagaMicroservices Architecture Part 2 Event Sourcing and Saga
Microservices Architecture Part 2 Event Sourcing and Saga
 
Enterprise Software Architecture styles
Enterprise Software Architecture stylesEnterprise Software Architecture styles
Enterprise Software Architecture styles
 
Why Microservices
Why MicroservicesWhy Microservices
Why Microservices
 
Python: Common Design Patterns
Python: Common Design PatternsPython: Common Design Patterns
Python: Common Design Patterns
 

En vedette

Refactoring for Domain Driven Design
Refactoring for Domain Driven DesignRefactoring for Domain Driven Design
Refactoring for Domain Driven DesignDavid Berliner
 
Why Domain-Driven Design Matters
Why Domain-Driven Design MattersWhy Domain-Driven Design Matters
Why Domain-Driven Design MattersMathias Verraes
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slidesthinkddd
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in RailsHans Yu
 
ZendCon 2011 UnCon Domain-Driven Design
ZendCon 2011 UnCon Domain-Driven DesignZendCon 2011 UnCon Domain-Driven Design
ZendCon 2011 UnCon Domain-Driven DesignBradley Holt
 
Introduction to Domain Driven Design
Introduction to Domain Driven DesignIntroduction to Domain Driven Design
Introduction to Domain Driven DesignChristos Tsakostas
 
Code & Cannoli - Domain Driven Design
Code & Cannoli - Domain Driven DesignCode & Cannoli - Domain Driven Design
Code & Cannoli - Domain Driven DesignFrank Levering
 
Domain-driven design
Domain-driven designDomain-driven design
Domain-driven designKnoldus Inc.
 
Domain Driven Design Introduction
Domain Driven Design IntroductionDomain Driven Design Introduction
Domain Driven Design IntroductionTung Nguyen Thanh
 
Domain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVCDomain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVCSteven Smith
 
Implementing DDD with C#
Implementing DDD with C#Implementing DDD with C#
Implementing DDD with C#Pascal Laurin
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven DesignYoung-Ho Cho
 
От Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреОт Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреIvan Nemytchenko
 
Refactoring Rails applications with RubyMine
Refactoring Rails applications with RubyMineRefactoring Rails applications with RubyMine
Refactoring Rails applications with RubyMineAndrzej Krzywda
 
Hexagonal architecture for the web
Hexagonal architecture for the webHexagonal architecture for the web
Hexagonal architecture for the webJesús Espejo
 
Hexagonal Architecture
Hexagonal ArchitectureHexagonal Architecture
Hexagonal ArchitectureMarcelo Cure
 
Domain-Driven Design at ZendCon 2012
Domain-Driven Design at ZendCon 2012Domain-Driven Design at ZendCon 2012
Domain-Driven Design at ZendCon 2012Bradley Holt
 

En vedette (20)

Ruby loves DDD
Ruby loves DDDRuby loves DDD
Ruby loves DDD
 
Refactoring for Domain Driven Design
Refactoring for Domain Driven DesignRefactoring for Domain Driven Design
Refactoring for Domain Driven Design
 
Why Domain-Driven Design Matters
Why Domain-Driven Design MattersWhy Domain-Driven Design Matters
Why Domain-Driven Design Matters
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slides
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in Rails
 
ZendCon 2011 UnCon Domain-Driven Design
ZendCon 2011 UnCon Domain-Driven DesignZendCon 2011 UnCon Domain-Driven Design
ZendCon 2011 UnCon Domain-Driven Design
 
Introduction to Domain Driven Design
Introduction to Domain Driven DesignIntroduction to Domain Driven Design
Introduction to Domain Driven Design
 
Code & Cannoli - Domain Driven Design
Code & Cannoli - Domain Driven DesignCode & Cannoli - Domain Driven Design
Code & Cannoli - Domain Driven Design
 
Domain-driven design
Domain-driven designDomain-driven design
Domain-driven design
 
Domain Driven Design Introduction
Domain Driven Design IntroductionDomain Driven Design Introduction
Domain Driven Design Introduction
 
Domain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVCDomain-Driven Design with ASP.NET MVC
Domain-Driven Design with ASP.NET MVC
 
Implementing DDD with C#
Implementing DDD with C#Implementing DDD with C#
Implementing DDD with C#
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
От Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреОт Rails-way к модульной архитектуре
От Rails-way к модульной архитектуре
 
DDD e Rails
DDD e RailsDDD e Rails
DDD e Rails
 
Refactoring Rails applications with RubyMine
Refactoring Rails applications with RubyMineRefactoring Rails applications with RubyMine
Refactoring Rails applications with RubyMine
 
Hexagonal architecture for the web
Hexagonal architecture for the webHexagonal architecture for the web
Hexagonal architecture for the web
 
Hexagonal Architecture
Hexagonal ArchitectureHexagonal Architecture
Hexagonal Architecture
 
Domain-Driven Design at ZendCon 2012
Domain-Driven Design at ZendCon 2012Domain-Driven Design at ZendCon 2012
Domain-Driven Design at ZendCon 2012
 

Similaire à Domain Driven Design and Hexagonal Architecture with Rails

Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Coupa Software
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Railsrstankov
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRaimonds Simanovskis
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 
Random Ruby Tips - Ruby Meetup 27 Jun 2018
Random Ruby Tips - Ruby Meetup 27 Jun 2018Random Ruby Tips - Ruby Meetup 27 Jun 2018
Random Ruby Tips - Ruby Meetup 27 Jun 2018Kenneth Teh
 
A Small Talk on Getting Big
A Small Talk on Getting BigA Small Talk on Getting Big
A Small Talk on Getting Bigbritt
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkDaniel Spector
 
Micropatterns
MicropatternsMicropatterns
Micropatternscameronp
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Toolschrismdp
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable CodeBaidu, Inc.
 
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...tdc-globalcode
 
Frozen rails 2012 - Fighting Code Smells
Frozen rails 2012 - Fighting Code SmellsFrozen rails 2012 - Fighting Code Smells
Frozen rails 2012 - Fighting Code SmellsDennis Ushakov
 
Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Brian Hogan
 
Say Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererSay Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererRuby Meditation
 

Similaire à Domain Driven Design and Hexagonal Architecture with Rails (20)

Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
Random Ruby Tips - Ruby Meetup 27 Jun 2018
Random Ruby Tips - Ruby Meetup 27 Jun 2018Random Ruby Tips - Ruby Meetup 27 Jun 2018
Random Ruby Tips - Ruby Meetup 27 Jun 2018
 
A Small Talk on Getting Big
A Small Talk on Getting BigA Small Talk on Getting Big
A Small Talk on Getting Big
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
Beware sharp tools
Beware sharp toolsBeware sharp tools
Beware sharp tools
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
 
Micropatterns
MicropatternsMicropatterns
Micropatterns
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
 
The Art Of Readable Code
The Art Of Readable CodeThe Art Of Readable Code
The Art Of Readable Code
 
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...
TDC2018SP | Trilha Ruby - Maior performance no seu sistema com o uso adequado...
 
Frozen rails 2012 - Fighting Code Smells
Frozen rails 2012 - Fighting Code SmellsFrozen rails 2012 - Fighting Code Smells
Frozen rails 2012 - Fighting Code Smells
 
The Joy Of Ruby
The Joy Of RubyThe Joy Of Ruby
The Joy Of Ruby
 
Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Say Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererSay Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick Sutterer
 
Refactoring
RefactoringRefactoring
Refactoring
 

Plus de Declan Whelan

Technical debt is a systemic problem - not a personal failing
Technical debt is a systemic problem - not a personal failingTechnical debt is a systemic problem - not a personal failing
Technical debt is a systemic problem - not a personal failingDeclan Whelan
 
From Technical Debt to Technical Health
From Technical Debt to Technical HealthFrom Technical Debt to Technical Health
From Technical Debt to Technical HealthDeclan Whelan
 
effective agile adoption
effective agile adoptioneffective agile adoption
effective agile adoptionDeclan Whelan
 
Navigating Organizational Change
Navigating Organizational ChangeNavigating Organizational Change
Navigating Organizational ChangeDeclan Whelan
 
Win Win Conversations
Win Win ConversationsWin Win Conversations
Win Win ConversationsDeclan Whelan
 
Agile 2012 Simple Design Applied
Agile 2012 Simple Design AppliedAgile 2012 Simple Design Applied
Agile 2012 Simple Design AppliedDeclan Whelan
 
Releasing your teams energy through 'pull' conversations
Releasing your teams energy through 'pull' conversationsReleasing your teams energy through 'pull' conversations
Releasing your teams energy through 'pull' conversationsDeclan Whelan
 
Specification by Example
Specification by ExampleSpecification by Example
Specification by ExampleDeclan Whelan
 
Learning is Key to Agile Success: Agile Vancouver 2010
Learning is Key to Agile Success: Agile Vancouver 2010Learning is Key to Agile Success: Agile Vancouver 2010
Learning is Key to Agile Success: Agile Vancouver 2010Declan Whelan
 
Agile learning agile 2010
Agile learning agile 2010Agile learning agile 2010
Agile learning agile 2010Declan Whelan
 
Agile Learning (60 minute version)
Agile Learning (60 minute version)Agile Learning (60 minute version)
Agile Learning (60 minute version)Declan Whelan
 
Agile Learning from Agile 2009
Agile Learning from Agile 2009Agile Learning from Agile 2009
Agile Learning from Agile 2009Declan Whelan
 
Agile Testing: The Role Of The Agile Tester
Agile Testing: The Role Of The Agile TesterAgile Testing: The Role Of The Agile Tester
Agile Testing: The Role Of The Agile TesterDeclan Whelan
 

Plus de Declan Whelan (18)

Technical debt is a systemic problem - not a personal failing
Technical debt is a systemic problem - not a personal failingTechnical debt is a systemic problem - not a personal failing
Technical debt is a systemic problem - not a personal failing
 
From Technical Debt to Technical Health
From Technical Debt to Technical HealthFrom Technical Debt to Technical Health
From Technical Debt to Technical Health
 
effective agile adoption
effective agile adoptioneffective agile adoption
effective agile adoption
 
Big Balls of Mud
Big Balls of MudBig Balls of Mud
Big Balls of Mud
 
Navigating Organizational Change
Navigating Organizational ChangeNavigating Organizational Change
Navigating Organizational Change
 
Simple Design
Simple DesignSimple Design
Simple Design
 
Win Win Conversations
Win Win ConversationsWin Win Conversations
Win Win Conversations
 
Agile 2012 Simple Design Applied
Agile 2012 Simple Design AppliedAgile 2012 Simple Design Applied
Agile 2012 Simple Design Applied
 
Releasing your teams energy through 'pull' conversations
Releasing your teams energy through 'pull' conversationsReleasing your teams energy through 'pull' conversations
Releasing your teams energy through 'pull' conversations
 
Specification by Example
Specification by ExampleSpecification by Example
Specification by Example
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Learning is Key to Agile Success: Agile Vancouver 2010
Learning is Key to Agile Success: Agile Vancouver 2010Learning is Key to Agile Success: Agile Vancouver 2010
Learning is Key to Agile Success: Agile Vancouver 2010
 
Agile learning agile 2010
Agile learning agile 2010Agile learning agile 2010
Agile learning agile 2010
 
Agile Learning (60 minute version)
Agile Learning (60 minute version)Agile Learning (60 minute version)
Agile Learning (60 minute version)
 
Cuke2Beer
Cuke2BeerCuke2Beer
Cuke2Beer
 
Agile Learning from Agile 2009
Agile Learning from Agile 2009Agile Learning from Agile 2009
Agile Learning from Agile 2009
 
Agile, Tdd And .Net
Agile, Tdd And .NetAgile, Tdd And .Net
Agile, Tdd And .Net
 
Agile Testing: The Role Of The Agile Tester
Agile Testing: The Role Of The Agile TesterAgile Testing: The Role Of The Agile Tester
Agile Testing: The Role Of The Agile Tester
 

Dernier

Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 

Dernier (20)

Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 

Domain Driven Design and Hexagonal Architecture with Rails

  • 1.
  • 3. 2. Know where you’re going
  • 4. 3. Be more than just a “Rails Developer”
  • 5. app ├── assets ├── controllers ├── helpers ├── mailers ├── models └── views
  • 8. def pricing_range_fold_and_save(new_range) pos = 0 pricings = self.product_pricings other_range = ProductPricing.new if pricings.length == 0 pricings.push(new_range) else pricings.each_with_index do |e, i| if i == 0 && new_range.start_date < e.start_date pricings.unshift(new_range) if new_range.end_date <= e.end_date e.start_date = new_range.end_date + 1.day break else while pricings[1].present? && new_range.end_date >= pricings[1].end_date pricings[1].destroy pricings.delete pricings[1] end if pricings[1].present? pricings[1].start_date = new_range.end_date + 1.day end break end elsif new_range.start_date <= e.end_date && new_range.start_date >= e.start_date ! if new_range.end_date < e.end_date other_range = e.dup other_range.start_date = new_range.end_date + 1.day if new_range.start_date == e.start_date e.destroy pricings.delete e i -= 1 else e.end_date = new_range.start_date - 1.day end pricings.insert(i+1, new_range) pos = i+1 pricings.insert(i+2, other_range) break else if new_range.start_date == e.start_date e.destroy pricings.delete e i -= 1 else e.end_date = new_range.start_date - 1.day end pricings.insert(i+1, new_range) pos = i+1 while pricings[i+2].present? && new_range.end_date >= pricings[i+2].end_date pricings[i+2].destroy pricings.delete pricings[i+2] end if pricings[i+2].present? pricings[i+2].start_date = new_range.end_date + 1.day end break end ! elsif i == pricings.size-1 pricings[i].end_date = new_range.start_date-1.day pricings.push(new_range) break end end end ! pricings.each_with_index do |pricing, i| if i != pricings.size-1 && pricing.price ==pricings[i+1].price pricing.end_date = pricings[i+1].end_date end if i != 0 && pricing.end_date == pricings[i-1].end_date pricing.destroy pricings.delete pricing end if pricing.end_date < pricing.start_date pricing.destroy pricings.delete pricing end end ! pricings.each do |pricing| if pricing != pricings[pos] pricing.currency = pricings[pos].currency pricing.save end end pricings[pos].save return pricings ! end
  • 10.
  • 13.
  • 14. Complexity The critical complexity of most software projects is in understanding the domain itself. ! Eric Evans
  • 21.
  • 22. class TicketForm! include ActiveModel::Model! ! validates :trip, :price, :passengers, presence: true! ! def passengers! @passengers ||= [Passenger.new]! end! ! def tickets! @tickets ||= self.passengers.map do |passenger|! Ticket.new(...)! end! end! end!
  • 23. class TicketsController < ApplicationController! ! def create! @ticket_form = TicketForm.new(params)! tickets = @ticket_form.tickets! ! if @ticket_form.valid? && TicketCharger.new(tickets).charge!! redirect_to success_url! else! render 'new'! end! end! ! end
  • 26. class CreateOrderRequest ! include Virtus.value_object include ActiveModel::Validations ! attribute :customer, Customer validates :customer, nested: true, presence: true ! attribute :billing, Billing validates :billing, nested: true, presence: true ! attribute :shipping, Shipping validates :shipping, nested: true, presence: true ! end
  • 27. class ApplicationController < ActionController::Base before_filter :validate_request ! def validate_request handle_error(request_object) unless request_object.valid? end ! def request_object @request_object ||= request_class.new(request_parameters) end ! def request_class "#{action_name}#{resource_name}Request".constantize end ! def handle_error(request_object) [...] end end
  • 30. class OrderService ! def create(order) authorize!(order) ! repository.save!(order) ! purchase(order) do |transaction| repository.save!(order) end end ! def purchase(order, &block) PaymentService.new.purchase(order, &block) end ! end
  • 31. class OrdersController < ApiController ! def create order = request_object.to_order transaction = OrderService.new.create(order) ! if transaction.success? order_created(order) else payment_failed(transaction) end end ! end
  • 32. OK, so now what?
  • 33. “I’m right there in the room, and no one even acknowledges me.”
  • 36. class Repository! ! class << self! ! attr_accessor :mapper! ! def save!(domain)! record = mapper.export(domain, record)! response = record.save!! domain.id = record.id! response! end! ! end! ! def self.method_missing(method_name, *args, &block)! Scope.new(mapper).send(method_name, *args, &block)! end! ! end
  • 37. class Scope! ! attr_accessor :mapper, :scope! ! def initialize(mapper)! @mapper = mapper! @scope = mapper.export_class! end! ! def method_missing(method_name, *args, &block)! @scope = scope.send(method_name, *args, &_map_block(block))! ! scope.is_a?(ActiveRecord::Relation) ? self : _map(scope)! end! ! def _map_block(block)! Proc.new { |*args| block.call(_map(*args)) } if block! end! ! def _map(object)! if object.is_a?(mapper.export_class)! mapper.map(object)! elsif object.is_a?(Enumerable)! object.map { |e| e.is_a?(mapper.export_class) ? mapper.map(e) : e }! else! object! end! end! ! def respond_to?(method_name, include_private = false)! scope.respond_to?(method_name, include_private) || super! end! end
  • 38. class Mapper! class << self! ! attr_reader :base_class, :export_class! ! def maps(mapping)! @base_class, @export_class = mapping.first! end! ! def map(object)! if object.is_a? base_class! export(object)! else! import(object)! end! end! ! def export(base, record=nil)! return unless base! ! if record! record.assign_attributes(base.attributes)! else! record = export_class.new(base.attributes)! end! ! record! end! ! def import(record)! base_class.new(record.attributes) if record! end! end! end!
  • 39. class Repository! ! class << self! ! attr_accessor :mapper! ! def save!(domain)! record = IdentityMap.get(mapper.export_class, domain.id)! record = mapper.export(domain, record)! response = record.save!! IdentityMap.add(record)! domain.id = record.id! response! end! ! end! ! def self.method_missing(method_name, *args, &block)! Scope.new(mapper).send(method_name, *args, &block)! end! ! end
  • 40. class IdentityMap! ! class << self! def add(record)! raise ArgumentError.new('Record cannot be added with a nil id') unless record.id! repository[key(record.class)][record.id] = record! end! ! def remove(record)! repository[key(record.class)].delete(record.id)! end! ! def get(klass, id)! repository[key(klass)][id]! end! ! def clear! repository.clear! end! ! def repository! Thread.current[:identity_map] ||= Hash.new { |h,k| h[k] = {} }! end! ! def key(klass)! klass! end! ! end! end!
  • 41. So, what’s the point again?
  • 42. 1. Embrace complexity ! 2. Know where you’re going ! 3. Be more than just a “Rails Developer”
  • 44. Reading Patterns of Enterprise Application Architecture
 Martin Fowler Domain Driven Design
 Tackling Complexity in the Heart of Software
 Eric Evans Practical Object Oriented Design in Ruby
 An Agile Primer
 Sandi Metz
  • 45. Reading Clean Code
 A Handbook of Agile Software Craftsmanship
 Robert C. Martin Implementing Domain Driven Design
 Vaughn Vern