SlideShare ist ein Scribd-Unternehmen logo
1 von 45
Downloaden Sie, um offline zu lesen
Domain Driven 
Design 
in Ruby on Rails 
Created by Angelo Maron
Wer bin ich? 
Angelo Maron 
Sofware-Entwickler seit ca. 7 Jahren (Ruby on Rails) 
bei AKRA seit 2,5 Jahren 
Xing: https://www.xing.com/profile/Angelo_Maron 
Twitter: @MrRaffnix
Agenda 
1. MVC & Rails 
2. Domain Driven Design 
3. Domain Driven Design in Rails 
4. Zusammenfassung
MVC 
(Model View Controller) 
Wikipedia: 
Der englischsprachige Begriff "model view 
controller" (MVC) ist ein Muster zur 
Strukturierung von Software-Entwicklung in die 
drei Einheiten Datenmodell (engl. model), 
Präsentation (engl. view) und 
Programmsteuerung (engl. controller).
Ruby on Rails 
Ruby on Rails ist ein in der Programmiersprache Ruby 
geschriebenes und quelloffenes Web Application Framework. 
wird dieses Jahr 10 Jahre alt. 
basiert auf dem MVC-Pattern 
Prinzipien: 
Don't repeat yourself (DRY) 
Convention over Configuration
!Convention!
MVC in Ruby on Rails 
M odel: ActiveRecord 
V iew: ActionView 
C ontroller: ActionController
Fat Model, Skinny Con-troller 
(1) 
"Im Zusammenspiel von Controller und Model, 
versuche im Controller nur das Objekt zu 
instanzieren und einen Methodenaufruf 
durchzuführen. Der Rest wird im Model 
definiert."
Fat Model, Skinny Con-troller 
(2) 
def index 
@published_posts = Post.all.where('published_at <= ?', Time.now) 
@unpublished_posts = Post.all.where('published_at IS NULL or published_at > ?', Time.now) 
end 
def index 
@published_posts = Post.all_published 
@unpublished_posts = Post.all_unpublished 
end
Problematik 
Mit zunehmenden Anforderungen werden können die folgenden 
Problematiken auftreten: 
Die Model-Dateien werden immer größer (500+ Zeilen) 
Die Actions der Controller werden immer größer (30+ Zeilen) 
Dies führt zur Verschlechterung der Testbarkeit, Wartbarkeit und 
Verständnis des Codes. 
Daher habe ich versucht nach den folgenden Regeln zu arbeiten. 
(nach Sandy Matz) 
Eine Klasse hat maximal 100 Zeilen. 
Eine Methode hat maximal 5 Zeilen. 
--> Domain Driven Design
Domain Driven Design 
Domain-Driven Design (DDD) ist eine 
Herangehensweise an die Modellierung 
komplexer objektorientierter Software. Die 
Modellierung der Software wird dabei 
maßgeblich von den umzusetzenden 
Fachlichkeiten der Anwendungsdomäne 
beeinflusst.
Warum DDD? 
1. Fachliche Begrifflichkeiten und Codestruktur angleichen. 
2. kleinere Dateien (bessere Wartbarkeit) 
3. höhere Codeunabhängigkeit (bessere Wartbarkeit) 
4. Bessere Testbarkeit (durch kleinere Klassen)
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Rails Helpers 
Interne Struktur von Rails um Funktionen für views zur Verfügung 
zu stellen. 
Funktionen um komplexen Code aus der View zu halten. 
Sich wiederholende Funktionen wieder zu verwenden. 
Persönlich: (erinnert mich an funktionale Programmierung)
Beispiel Rails Helper (1) 
<div> 
<%- if @user.image.present? %> 
<%= image_tag(@user.image.path) %> 
<%- else %> 
<%= image_tag(asset_path('default_profile.png')) %> 
<%- end %> 
</div>
Beispiel Rails Helper (2) 
module UserHelper 
def user_picture_path(user) 
if user.image.present? 
user.image.path 
else 
asset_path('default_profile.png') 
end 
end 
end 
<div> 
<%= image_tag(user_picture_path(@user)) %> 
</div>
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Rails Concerns 
Rails Concerns ist eine Möglichkeit Code in Module auszulagern, 
die man über ein include in ein beliebiges Model inkludieren kann. 
Dieses hat folgende Anwendungsmöglichkeiten: 
1. Aufteilen des Codes eines Models in mehrere Dateien 
2. Auslagerung von Mechanismen/Pattern zur Wiederverwendung 
Rails bietet hier ein hauseigenes Konzept: 
ActiveSupport::Concern
Beispiel Rails Concerns (1) 
class Article < ActiveRecord::Base 
belongs_to :create_user, class_name: 'User' 
belongs_to :update_user, class_name: 'User' 
end 
class Job < ActiveRecord::Base 
belongs_to :create_user, class_name: 'User' 
belongs_to :update_user, class_name: 'User' 
end
Beispiel Rails Concerns (2) 
module Trackable 
extend ActiveSupport::Concern 
included do 
belongs_to :create_user, class_name: 'User' 
belongs_to :update_user, class_name: 'User' 
end 
end 
class Article < ActiveRecord::Base 
include Trackable 
end 
class Job < ActiveRecord::Base 
include Trackable 
end
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Service Objects 
Verlagerung bestimmter Funktionen eines Anwendungsfall in ein 
eigenes Objekt, dass genau diese Funktionen zur Verfügung stellt. 
zum Beispiel: 
SearchService (Suchkomponente) 
InvoiceService (Rechnungserstellung) 
RegistrationService (RegistrierungsValidierung)
Beispiel Service Object (1) 
class Article < ActiveRecord::Base 
def search(term, options = {}) 
# execute search 
end 
def admin_search(term, options = {}) 
# execute search from admin perspective 
end 
end 
def Job < ActiveRecord::Base 
def search(term, options = {}) 
# execute search 
end 
def admin_search(term, options = {}) 
# execute search from admin perspective 
end 
end
Beispiel Service Object (2) 
class SearchService 
def self.article_search(term, options = {}) 
# execute search here 
end 
def self.job_search(term, options = {}) 
# execute search here 
end 
end 
class AdminSearchService 
def self.article_search(term, options = {}) 
# execute search here 
end 
def self.job_search(term, options = {}) 
# execute search here 
end 
end
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Presenter Objects 
Oft haben Get-Operationen komplexe Analyse von Parametern, 
um die genau angeforderten Objekte anzuzeigen. Hier gibt es eine 
gute Möglichkeit, diese in eigene Objekte auszulagern.
Beispiel Presenter Object 
(1) 
class JobController < ApplicationController::Base 
def index 
@jobs = Job.active.preload(:items) 
if params[:state] 
@jobs = @jobs.by_state(params[:state]) 
end 
if params[:order] 
order_string = "#{params[:order]} #{params[:dir].presence || 'asc'}" 
@jobs = @jobs.order(order_string) 
end 
@jobs = @jobs.page(params[:page].presence || 1).per(params[:per].presence || 10) 
end 
end
Beispiel Presenter Object 
(2) 
class JobController < ApplicationController::Base 
def index 
@jobs = JobPresenter.get_all(params) 
end 
end 
class JobPresenter 
def self.get_all(params) 
self.new(params).get_all 
end 
def new(params) 
@params = params 
end 
def get_all 
jobs = Job.active.preload(:items) 
if @params[:state] 
jobs = jobs.by_state(@params[:state]) 
e n d
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Strukturierte Namen-srääume 
Strukturierung aller Objekte (Models, Services, Presenters, 
Decorators, Controllers usw.) in Domain-basierte Namespaces. 
Dies hat folgende Vorteile: 
Code-Unabhängigkeit 
kleinere Dateien 
bessere Abbildung der Businessdomäne im Code.
Beispiel Namensrääume (1) 
class Job < ActiveRecord::Base 
def self.all_for_admins 
#execute query here 
end 
def self.all_for_moderators 
# execute query here 
end 
def self.all_for_visitors 
#execute query here 
end 
end
Beispiel Namensrääume (2) 
module Admins 
class Job 
def self.all 
#execute query here 
end 
end 
end 
module Moderators 
class Job 
def self.all 
#execute query here 
end 
end 
end 
module Visitors 
class Job 
def self.all 
#execute query here 
end 
end 
end
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
Decorator Pattern
Decorators in Rails (1)
Decorators in Rails (2)
Beispiel Decorator (1) 
class UserController < ApplicationController::Base 
def show 
@user = User.find(params[:id]) 
end 
end 
<div> 
<p>Erstellt am: <%= @user.registered_at.strftime('%Y%m%d')</p> 
<p>Name: <%= @user.first_name + @user.last_name %></p> 
<%- if @user.image.present? %> 
<%= image_tag(@user.image.path) %> 
<%- else %> 
<%= image_tag(asset_path('default_profile.png')) %> 
<%- end %> 
</div>
Beispiel Decorator (2) 
class UserDecorator < SimpleDelegator 
def registered_at 
@object.registered_at.strftime('%Y%m%d') 
end 
def name 
"#{@object.first_name} #{@object.last_name}" 
end 
def image_path 
# return image.path or default 
end 
end 
class UserController < ApplicationController::Base 
def show 
@user_decorator = UserDecorator.new(User.find(params[:id])) 
end 
end 
<div> 
<p>Erstellt am: <%= @user_decorator.registered_at</p>
Und was nun?
Die alles entscheidene 
Frage 
Welches Pattern benutzt man wann? 
Ab wann benutzen wir überhaupt diese Pattern?
Neuprogrammierung 
Abwägung der Komplexität gegen den entstehenden Aufwand. 
Wichtig: Komplexe Business-Logik lässt sich nur durch komplexen 
Code abbilden.
Refactoring 
Oft ist schon ein gewisser Fortschritt da, bevor man merkt, dass die 
Komplexität der Domaine sich direkt im Code wiederspiegelt. 
Nicht gleich alles komplett refactorn, sondern Step by Step.
Beispiel:
Domain Driven Design in Rails
Domain Driven Design in Rails
Domain Driven Design in Rails

Weitere ähnliche Inhalte

Andere mochten auch

Die Rolle von Apps in der Second- & Multi-Screen-Nutzung
Die Rolle von Apps in der Second- & Multi-Screen-NutzungDie Rolle von Apps in der Second- & Multi-Screen-Nutzung
Die Rolle von Apps in der Second- & Multi-Screen-NutzungFLYACTS GmbH
 
Introduccionagoogleplus
IntroduccionagoogleplusIntroduccionagoogleplus
IntroduccionagoogleplusJose Poveda
 
La imprenta
La imprentaLa imprenta
La imprentajitsyj
 
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02Edison Villegas
 
Cisnes elegantes
Cisnes elegantesCisnes elegantes
Cisnes elegantesSel Selmha
 
Enciclopedia etnografica
Enciclopedia etnograficaEnciclopedia etnografica
Enciclopedia etnograficajmarquezgau
 
Unser Expertenvortrag: Gründen mit einer App
Unser Expertenvortrag: Gründen mit einer AppUnser Expertenvortrag: Gründen mit einer App
Unser Expertenvortrag: Gründen mit einer AppFLYACTS GmbH
 
Puertos esata y serial
Puertos esata y serialPuertos esata y serial
Puertos esata y serialJULI9670
 
Tencerová slowakische nationalgerichte
Tencerová  slowakische nationalgerichteTencerová  slowakische nationalgerichte
Tencerová slowakische nationalgerichtevierah
 
Presentation1
Presentation1Presentation1
Presentation1eguie77
 
Exercise03
Exercise03Exercise03
Exercise03dennoli
 
Historia de la Medicina
Historia de la MedicinaHistoria de la Medicina
Historia de la MedicinaSelena Zamora
 
Virginia Galvis Capacitación actuali 3
Virginia Galvis Capacitación actuali 3Virginia Galvis Capacitación actuali 3
Virginia Galvis Capacitación actuali 3Virginia Galvis
 

Andere mochten auch (20)

Die Rolle von Apps in der Second- & Multi-Screen-Nutzung
Die Rolle von Apps in der Second- & Multi-Screen-NutzungDie Rolle von Apps in der Second- & Multi-Screen-Nutzung
Die Rolle von Apps in der Second- & Multi-Screen-Nutzung
 
Introduccionagoogleplus
IntroduccionagoogleplusIntroduccionagoogleplus
Introduccionagoogleplus
 
La imprenta
La imprentaLa imprenta
La imprenta
 
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02
Formayfunciondelaspalabrasenlaoracion 110919213931 Phpapp02
 
Rss
RssRss
Rss
 
Nebulosas de nuestra galaxia
Nebulosas de nuestra galaxiaNebulosas de nuestra galaxia
Nebulosas de nuestra galaxia
 
Actualizacion12 (1)
Actualizacion12 (1)Actualizacion12 (1)
Actualizacion12 (1)
 
Cisnes elegantes
Cisnes elegantesCisnes elegantes
Cisnes elegantes
 
Universidad técnica particular de loja
Universidad técnica particular de lojaUniversidad técnica particular de loja
Universidad técnica particular de loja
 
Enciclopedia etnografica
Enciclopedia etnograficaEnciclopedia etnografica
Enciclopedia etnografica
 
Unser Expertenvortrag: Gründen mit einer App
Unser Expertenvortrag: Gründen mit einer AppUnser Expertenvortrag: Gründen mit einer App
Unser Expertenvortrag: Gründen mit einer App
 
Puertos esata y serial
Puertos esata y serialPuertos esata y serial
Puertos esata y serial
 
Tencerová slowakische nationalgerichte
Tencerová  slowakische nationalgerichteTencerová  slowakische nationalgerichte
Tencerová slowakische nationalgerichte
 
Tecnicadepcr
TecnicadepcrTecnicadepcr
Tecnicadepcr
 
Fiesta del cusco
Fiesta del cuscoFiesta del cusco
Fiesta del cusco
 
Presentation1
Presentation1Presentation1
Presentation1
 
Exercise03
Exercise03Exercise03
Exercise03
 
Historia de la Medicina
Historia de la MedicinaHistoria de la Medicina
Historia de la Medicina
 
Virginia Galvis Capacitación actuali 3
Virginia Galvis Capacitación actuali 3Virginia Galvis Capacitación actuali 3
Virginia Galvis Capacitación actuali 3
 
Actualizacion 4
Actualizacion 4Actualizacion 4
Actualizacion 4
 

Ähnlich wie Domain Driven Design in Rails

Django - The Web framework for perfectionists with deadlines
Django - The Web framework for perfectionists with deadlinesDjango - The Web framework for perfectionists with deadlines
Django - The Web framework for perfectionists with deadlinesMarkus Zapke-Gründemann
 
Große Applikationen mit AngularJS
Große Applikationen mit AngularJSGroße Applikationen mit AngularJS
Große Applikationen mit AngularJSSebastian Springer
 
An Introduction to Ruby On Rails
An Introduction to Ruby On RailsAn Introduction to Ruby On Rails
An Introduction to Ruby On RailsJonathan Weiss
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und ReflectionStefan Marr
 
Drupal 8: TWIG Template Engine
Drupal 8:  TWIG Template EngineDrupal 8:  TWIG Template Engine
Drupal 8: TWIG Template Enginedrubb
 
Refactoring Rails Applications
Refactoring Rails ApplicationsRefactoring Rails Applications
Refactoring Rails ApplicationsJonathan Weiss
 
Samuel Zürcher new power of search
Samuel Zürcher new power of searchSamuel Zürcher new power of search
Samuel Zürcher new power of searchDigicomp Academy AG
 
Themes – Wieso, Weshalb, Warum!?
Themes – Wieso, Weshalb, Warum!?Themes – Wieso, Weshalb, Warum!?
Themes – Wieso, Weshalb, Warum!?frankstaude
 
.NET Summit 2016 München: Angular 2 mit TypeScript
.NET Summit 2016 München: Angular 2 mit TypeScript.NET Summit 2016 München: Angular 2 mit TypeScript
.NET Summit 2016 München: Angular 2 mit TypeScriptManfred Steyer
 
Grails im Überblick und in der Praxis
Grails im Überblick und in der PraxisGrails im Überblick und in der Praxis
Grails im Überblick und in der PraxisTobias Kraft
 
2007 - Basta!: Nach soa kommt soc
2007 - Basta!: Nach soa kommt soc2007 - Basta!: Nach soa kommt soc
2007 - Basta!: Nach soa kommt socDaniel Fisher
 
Forms and Reports 12c - Processes and Automation in Development and Operations
Forms and Reports 12c - Processes and Automation in Development and OperationsForms and Reports 12c - Processes and Automation in Development and Operations
Forms and Reports 12c - Processes and Automation in Development and OperationsTorsten Kleiber
 
iDocIt - Ein Assistent zur API-Dokumentation
iDocIt - Ein Assistent zur API-DokumentationiDocIt - Ein Assistent zur API-Dokumentation
iDocIt - Ein Assistent zur API-DokumentationJan Christian Krause
 
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDI
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDISchlanke Webarchitekturen nicht nur mit JSF 2 und CDI
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDIadesso AG
 
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...Cristina Vidu
 
APEX 5.1 Ui design crashkurs
APEX 5.1 Ui design crashkursAPEX 5.1 Ui design crashkurs
APEX 5.1 Ui design crashkursSteven Grzbielok
 

Ähnlich wie Domain Driven Design in Rails (20)

Django - The Web framework for perfectionists with deadlines
Django - The Web framework for perfectionists with deadlinesDjango - The Web framework for perfectionists with deadlines
Django - The Web framework for perfectionists with deadlines
 
react-de.pdf
react-de.pdfreact-de.pdf
react-de.pdf
 
Große Applikationen mit AngularJS
Große Applikationen mit AngularJSGroße Applikationen mit AngularJS
Große Applikationen mit AngularJS
 
An Introduction to Ruby On Rails
An Introduction to Ruby On RailsAn Introduction to Ruby On Rails
An Introduction to Ruby On Rails
 
Ruby on Rails SS09 11
Ruby on Rails SS09 11Ruby on Rails SS09 11
Ruby on Rails SS09 11
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
Drupal 8: TWIG Template Engine
Drupal 8:  TWIG Template EngineDrupal 8:  TWIG Template Engine
Drupal 8: TWIG Template Engine
 
Ruby on Rails SS09 06
Ruby on Rails SS09 06Ruby on Rails SS09 06
Ruby on Rails SS09 06
 
Refactoring Rails Applications
Refactoring Rails ApplicationsRefactoring Rails Applications
Refactoring Rails Applications
 
Samuel Zürcher new power of search
Samuel Zürcher new power of searchSamuel Zürcher new power of search
Samuel Zürcher new power of search
 
The new power of search
The new power of searchThe new power of search
The new power of search
 
Themes – Wieso, Weshalb, Warum!?
Themes – Wieso, Weshalb, Warum!?Themes – Wieso, Weshalb, Warum!?
Themes – Wieso, Weshalb, Warum!?
 
.NET Summit 2016 München: Angular 2 mit TypeScript
.NET Summit 2016 München: Angular 2 mit TypeScript.NET Summit 2016 München: Angular 2 mit TypeScript
.NET Summit 2016 München: Angular 2 mit TypeScript
 
Grails im Überblick und in der Praxis
Grails im Überblick und in der PraxisGrails im Überblick und in der Praxis
Grails im Überblick und in der Praxis
 
2007 - Basta!: Nach soa kommt soc
2007 - Basta!: Nach soa kommt soc2007 - Basta!: Nach soa kommt soc
2007 - Basta!: Nach soa kommt soc
 
Forms and Reports 12c - Processes and Automation in Development and Operations
Forms and Reports 12c - Processes and Automation in Development and OperationsForms and Reports 12c - Processes and Automation in Development and Operations
Forms and Reports 12c - Processes and Automation in Development and Operations
 
iDocIt - Ein Assistent zur API-Dokumentation
iDocIt - Ein Assistent zur API-DokumentationiDocIt - Ein Assistent zur API-Dokumentation
iDocIt - Ein Assistent zur API-Dokumentation
 
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDI
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDISchlanke Webarchitekturen nicht nur mit JSF 2 und CDI
Schlanke Webarchitekturen nicht nur mit JSF 2 und CDI
 
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...
Developer Best Practices (Robotic Enterprise Framework REF) – Anwendung und d...
 
APEX 5.1 Ui design crashkurs
APEX 5.1 Ui design crashkursAPEX 5.1 Ui design crashkurs
APEX 5.1 Ui design crashkurs
 

Domain Driven Design in Rails

  • 1. Domain Driven Design in Ruby on Rails Created by Angelo Maron
  • 2. Wer bin ich? Angelo Maron Sofware-Entwickler seit ca. 7 Jahren (Ruby on Rails) bei AKRA seit 2,5 Jahren Xing: https://www.xing.com/profile/Angelo_Maron Twitter: @MrRaffnix
  • 3. Agenda 1. MVC & Rails 2. Domain Driven Design 3. Domain Driven Design in Rails 4. Zusammenfassung
  • 4. MVC (Model View Controller) Wikipedia: Der englischsprachige Begriff "model view controller" (MVC) ist ein Muster zur Strukturierung von Software-Entwicklung in die drei Einheiten Datenmodell (engl. model), Präsentation (engl. view) und Programmsteuerung (engl. controller).
  • 5. Ruby on Rails Ruby on Rails ist ein in der Programmiersprache Ruby geschriebenes und quelloffenes Web Application Framework. wird dieses Jahr 10 Jahre alt. basiert auf dem MVC-Pattern Prinzipien: Don't repeat yourself (DRY) Convention over Configuration
  • 7. MVC in Ruby on Rails M odel: ActiveRecord V iew: ActionView C ontroller: ActionController
  • 8. Fat Model, Skinny Con-troller (1) "Im Zusammenspiel von Controller und Model, versuche im Controller nur das Objekt zu instanzieren und einen Methodenaufruf durchzuführen. Der Rest wird im Model definiert."
  • 9. Fat Model, Skinny Con-troller (2) def index @published_posts = Post.all.where('published_at <= ?', Time.now) @unpublished_posts = Post.all.where('published_at IS NULL or published_at > ?', Time.now) end def index @published_posts = Post.all_published @unpublished_posts = Post.all_unpublished end
  • 10. Problematik Mit zunehmenden Anforderungen werden können die folgenden Problematiken auftreten: Die Model-Dateien werden immer größer (500+ Zeilen) Die Actions der Controller werden immer größer (30+ Zeilen) Dies führt zur Verschlechterung der Testbarkeit, Wartbarkeit und Verständnis des Codes. Daher habe ich versucht nach den folgenden Regeln zu arbeiten. (nach Sandy Matz) Eine Klasse hat maximal 100 Zeilen. Eine Methode hat maximal 5 Zeilen. --> Domain Driven Design
  • 11. Domain Driven Design Domain-Driven Design (DDD) ist eine Herangehensweise an die Modellierung komplexer objektorientierter Software. Die Modellierung der Software wird dabei maßgeblich von den umzusetzenden Fachlichkeiten der Anwendungsdomäne beeinflusst.
  • 12. Warum DDD? 1. Fachliche Begrifflichkeiten und Codestruktur angleichen. 2. kleinere Dateien (bessere Wartbarkeit) 3. höhere Codeunabhängigkeit (bessere Wartbarkeit) 4. Bessere Testbarkeit (durch kleinere Klassen)
  • 13. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 14. Rails Helpers Interne Struktur von Rails um Funktionen für views zur Verfügung zu stellen. Funktionen um komplexen Code aus der View zu halten. Sich wiederholende Funktionen wieder zu verwenden. Persönlich: (erinnert mich an funktionale Programmierung)
  • 15. Beispiel Rails Helper (1) <div> <%- if @user.image.present? %> <%= image_tag(@user.image.path) %> <%- else %> <%= image_tag(asset_path('default_profile.png')) %> <%- end %> </div>
  • 16. Beispiel Rails Helper (2) module UserHelper def user_picture_path(user) if user.image.present? user.image.path else asset_path('default_profile.png') end end end <div> <%= image_tag(user_picture_path(@user)) %> </div>
  • 17. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 18. Rails Concerns Rails Concerns ist eine Möglichkeit Code in Module auszulagern, die man über ein include in ein beliebiges Model inkludieren kann. Dieses hat folgende Anwendungsmöglichkeiten: 1. Aufteilen des Codes eines Models in mehrere Dateien 2. Auslagerung von Mechanismen/Pattern zur Wiederverwendung Rails bietet hier ein hauseigenes Konzept: ActiveSupport::Concern
  • 19. Beispiel Rails Concerns (1) class Article < ActiveRecord::Base belongs_to :create_user, class_name: 'User' belongs_to :update_user, class_name: 'User' end class Job < ActiveRecord::Base belongs_to :create_user, class_name: 'User' belongs_to :update_user, class_name: 'User' end
  • 20. Beispiel Rails Concerns (2) module Trackable extend ActiveSupport::Concern included do belongs_to :create_user, class_name: 'User' belongs_to :update_user, class_name: 'User' end end class Article < ActiveRecord::Base include Trackable end class Job < ActiveRecord::Base include Trackable end
  • 21. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 22. Service Objects Verlagerung bestimmter Funktionen eines Anwendungsfall in ein eigenes Objekt, dass genau diese Funktionen zur Verfügung stellt. zum Beispiel: SearchService (Suchkomponente) InvoiceService (Rechnungserstellung) RegistrationService (RegistrierungsValidierung)
  • 23. Beispiel Service Object (1) class Article < ActiveRecord::Base def search(term, options = {}) # execute search end def admin_search(term, options = {}) # execute search from admin perspective end end def Job < ActiveRecord::Base def search(term, options = {}) # execute search end def admin_search(term, options = {}) # execute search from admin perspective end end
  • 24. Beispiel Service Object (2) class SearchService def self.article_search(term, options = {}) # execute search here end def self.job_search(term, options = {}) # execute search here end end class AdminSearchService def self.article_search(term, options = {}) # execute search here end def self.job_search(term, options = {}) # execute search here end end
  • 25. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 26. Presenter Objects Oft haben Get-Operationen komplexe Analyse von Parametern, um die genau angeforderten Objekte anzuzeigen. Hier gibt es eine gute Möglichkeit, diese in eigene Objekte auszulagern.
  • 27. Beispiel Presenter Object (1) class JobController < ApplicationController::Base def index @jobs = Job.active.preload(:items) if params[:state] @jobs = @jobs.by_state(params[:state]) end if params[:order] order_string = "#{params[:order]} #{params[:dir].presence || 'asc'}" @jobs = @jobs.order(order_string) end @jobs = @jobs.page(params[:page].presence || 1).per(params[:per].presence || 10) end end
  • 28. Beispiel Presenter Object (2) class JobController < ApplicationController::Base def index @jobs = JobPresenter.get_all(params) end end class JobPresenter def self.get_all(params) self.new(params).get_all end def new(params) @params = params end def get_all jobs = Job.active.preload(:items) if @params[:state] jobs = jobs.by_state(@params[:state]) e n d
  • 29. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 30. Strukturierte Namen-srääume Strukturierung aller Objekte (Models, Services, Presenters, Decorators, Controllers usw.) in Domain-basierte Namespaces. Dies hat folgende Vorteile: Code-Unabhängigkeit kleinere Dateien bessere Abbildung der Businessdomäne im Code.
  • 31. Beispiel Namensrääume (1) class Job < ActiveRecord::Base def self.all_for_admins #execute query here end def self.all_for_moderators # execute query here end def self.all_for_visitors #execute query here end end
  • 32. Beispiel Namensrääume (2) module Admins class Job def self.all #execute query here end end end module Moderators class Job def self.all #execute query here end end end module Visitors class Job def self.all #execute query here end end end
  • 33. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  • 36. Beispiel Decorator (1) class UserController < ApplicationController::Base def show @user = User.find(params[:id]) end end <div> <p>Erstellt am: <%= @user.registered_at.strftime('%Y%m%d')</p> <p>Name: <%= @user.first_name + @user.last_name %></p> <%- if @user.image.present? %> <%= image_tag(@user.image.path) %> <%- else %> <%= image_tag(asset_path('default_profile.png')) %> <%- end %> </div>
  • 37. Beispiel Decorator (2) class UserDecorator < SimpleDelegator def registered_at @object.registered_at.strftime('%Y%m%d') end def name "#{@object.first_name} #{@object.last_name}" end def image_path # return image.path or default end end class UserController < ApplicationController::Base def show @user_decorator = UserDecorator.new(User.find(params[:id])) end end <div> <p>Erstellt am: <%= @user_decorator.registered_at</p>
  • 39. Die alles entscheidene Frage Welches Pattern benutzt man wann? Ab wann benutzen wir überhaupt diese Pattern?
  • 40. Neuprogrammierung Abwägung der Komplexität gegen den entstehenden Aufwand. Wichtig: Komplexe Business-Logik lässt sich nur durch komplexen Code abbilden.
  • 41. Refactoring Oft ist schon ein gewisser Fortschritt da, bevor man merkt, dass die Komplexität der Domaine sich direkt im Code wiederspiegelt. Nicht gleich alles komplett refactorn, sondern Step by Step.