SlideShare a Scribd company logo
1 of 46
Download to read offline
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/

More Related Content

What's hot

Rest api standards and best practices
Rest api standards and best practicesRest api standards and best practices
Rest api standards and best practicesAnkita Mahajan
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정Arawn Park
 
Domain Driven Design com Python
Domain Driven Design com PythonDomain Driven Design com Python
Domain Driven Design com PythonFrederico Cabral
 
Creating AWS infrastructure using Terraform
Creating AWS infrastructure using TerraformCreating AWS infrastructure using Terraform
Creating AWS infrastructure using TerraformKnoldus Inc.
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayDebasish Ghosh
 
Java 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeJava 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeSimone Bordet
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with SpringJoshua Long
 
Hexagonal Architecture.pdf
Hexagonal Architecture.pdfHexagonal Architecture.pdf
Hexagonal Architecture.pdfVladimirRadzivil
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Mark Proctor
 
Tiki.vn - How we scale as a tech startup
Tiki.vn - How we scale as a tech startupTiki.vn - How we scale as a tech startup
Tiki.vn - How we scale as a tech startupTung Ns
 
From framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvFrom framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvCodelyTV
 
Clean architecture
Clean architectureClean architecture
Clean architectureLieven Doclo
 
Redis cluster
Redis clusterRedis cluster
Redis clusteriammutex
 
Control Kubernetes Ingress and Egress Together with NGINX
Control Kubernetes Ingress and Egress Together with NGINXControl Kubernetes Ingress and Egress Together with NGINX
Control Kubernetes Ingress and Egress Together with NGINXNGINX, Inc.
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code SmellsMario Sangiorgio
 
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 GamingAmazon Web Services Korea
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingEmanuele DelBono
 

What's hot (20)

Rest api standards and best practices
Rest api standards and best practicesRest api standards and best practices
Rest api standards and best practices
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
Domain Driven Design com Python
Domain Driven Design com PythonDomain Driven Design com Python
Domain Driven Design com Python
 
Creating AWS infrastructure using Terraform
Creating AWS infrastructure using TerraformCreating AWS infrastructure using Terraform
Creating AWS infrastructure using Terraform
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 Way
 
Java 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgradeJava 9/10/11 - What's new and why you should upgrade
Java 9/10/11 - What's new and why you should upgrade
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Hexagonal Architecture.pdf
Hexagonal Architecture.pdfHexagonal Architecture.pdf
Hexagonal Architecture.pdf
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)
 
Tiki.vn - How we scale as a tech startup
Tiki.vn - How we scale as a tech startupTiki.vn - How we scale as a tech startup
Tiki.vn - How we scale as a tech startup
 
From framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytvFrom framework coupled code to #microservices through #DDD /by @codelytv
From framework coupled code to #microservices through #DDD /by @codelytv
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 
Redis cluster
Redis clusterRedis cluster
Redis cluster
 
Control Kubernetes Ingress and Egress Together with NGINX
Control Kubernetes Ingress and Egress Together with NGINXControl Kubernetes Ingress and Egress Together with NGINX
Control Kubernetes Ingress and Egress Together with NGINX
 
.Net Core
.Net Core.Net Core
.Net Core
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code Smells
 
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
게임을 위한 DynamoDB 사례 및 팁 - 김일호 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcing
 

Viewers also liked

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
Domain Driven DesignDomain Driven Design
Domain Driven DesignRyan Riley
 
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
 
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
 
Domain-Driven Design: The "What" and the "Why"
Domain-Driven Design: The "What" and the "Why"Domain-Driven Design: The "What" and the "Why"
Domain-Driven Design: The "What" and the "Why"bincangteknologi
 

Viewers also liked (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 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
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
 
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
 
Domain-Driven Design: The "What" and the "Why"
Domain-Driven Design: The "What" and the "Why"Domain-Driven Design: The "What" and the "Why"
Domain-Driven Design: The "What" and the "Why"
 

Similar to 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
 

Similar to 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
 

More from 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
 

More from 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
 

Recently uploaded

Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
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
 
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
 
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
 

Recently uploaded (20)

Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
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
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
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
 
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
 
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...
 

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