SlideShare ist ein Scribd-Unternehmen logo
1 von 46
Downloaden Sie, um offline zu lesen
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/

Weitere ähnliche Inhalte

Was ist angesagt?

Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven DesignRyan Riley
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive ProgrammingAndres Almiray
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in phpLeonardo Proietti
 
Event Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQEvent Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQAraf Karsh Hamid
 
Domain driven design and model driven development
Domain driven design and model driven developmentDomain driven design and model driven development
Domain driven design and model driven developmentDmitry Geyzersky
 
Domain-Driven Design
Domain-Driven DesignDomain-Driven Design
Domain-Driven DesignAndriy Buday
 
CQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDDCQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDDDennis Doomen
 
Domain Driven Design (Ultra) Distilled
Domain Driven Design (Ultra) DistilledDomain Driven Design (Ultra) Distilled
Domain Driven Design (Ultra) DistilledNicola Costantino
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applicationsFabricio Epaminondas
 
CQRS and Event Sourcing
CQRS and Event Sourcing CQRS and Event Sourcing
CQRS and Event Sourcing Inho Kang
 
Domain Driven Design: Zero to Hero
Domain Driven Design: Zero to HeroDomain Driven Design: Zero to Hero
Domain Driven Design: Zero to HeroFabrício Rissetto
 
Design patterns for microservice architecture
Design patterns for microservice architectureDesign patterns for microservice architecture
Design patterns for microservice architectureThe Software House
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitecturePaul Mooney
 
Microservice Architecture
Microservice ArchitectureMicroservice Architecture
Microservice Architecturetyrantbrian
 
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
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQLI Goo Lee
 
Domain Driven Design(DDD) Presentation
Domain Driven Design(DDD) PresentationDomain Driven Design(DDD) Presentation
Domain Driven Design(DDD) PresentationOğuzhan Soykan
 
쿠버네티스 ( Kubernetes ) 소개 자료
쿠버네티스 ( Kubernetes ) 소개 자료쿠버네티스 ( Kubernetes ) 소개 자료
쿠버네티스 ( Kubernetes ) 소개 자료Opennaru, inc.
 

Was ist angesagt? (20)

Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive Programming
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
 
Event Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQEvent Sourcing & CQRS, Kafka, Rabbit MQ
Event Sourcing & CQRS, Kafka, Rabbit MQ
 
Domain driven design and model driven development
Domain driven design and model driven developmentDomain driven design and model driven development
Domain driven design and model driven development
 
Domain-Driven Design
Domain-Driven DesignDomain-Driven Design
Domain-Driven Design
 
CQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDDCQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDD
 
Domain Driven Design (Ultra) Distilled
Domain Driven Design (Ultra) DistilledDomain Driven Design (Ultra) Distilled
Domain Driven Design (Ultra) Distilled
 
Hexagonal architecture for java applications
Hexagonal architecture for java applicationsHexagonal architecture for java applications
Hexagonal architecture for java applications
 
CQRS and Event Sourcing
CQRS and Event Sourcing CQRS and Event Sourcing
CQRS and Event Sourcing
 
Domain Driven Design: Zero to Hero
Domain Driven Design: Zero to HeroDomain Driven Design: Zero to Hero
Domain Driven Design: Zero to Hero
 
Design patterns for microservice architecture
Design patterns for microservice architectureDesign patterns for microservice architecture
Design patterns for microservice architecture
 
Introduction to microservices
Introduction to microservicesIntroduction to microservices
Introduction to microservices
 
Microservice vs. Monolithic Architecture
Microservice vs. Monolithic ArchitectureMicroservice vs. Monolithic Architecture
Microservice vs. Monolithic Architecture
 
Microservice Architecture
Microservice ArchitectureMicroservice Architecture
Microservice Architecture
 
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
 
Fluentd with MySQL
Fluentd with MySQLFluentd with MySQL
Fluentd with MySQL
 
Domain Driven Design(DDD) Presentation
Domain Driven Design(DDD) PresentationDomain Driven Design(DDD) Presentation
Domain Driven Design(DDD) Presentation
 
쿠버네티스 ( Kubernetes ) 소개 자료
쿠버네티스 ( Kubernetes ) 소개 자료쿠버네티스 ( Kubernetes ) 소개 자료
쿠버네티스 ( Kubernetes ) 소개 자료
 

Andere mochten auch

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
 
От 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
 

Andere mochten auch (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#
 
От 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"
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 

Kürzlich hochgeladen (20)

HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 

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