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://...
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 ...
Ruby on Rails 
Ruby on Rails ist ein in der Programmiersprache Ruby 
geschriebenes und quelloffenes Web Application Framew...
!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 ...
Fat Model, Skinny Con-troller 
(2) 
def index 
@published_posts = Post.all.where('published_at <= ?', Time.now) 
@unpublis...
Problematik 
Mit zunehmenden Anforderungen werden können die folgenden 
Problematiken auftreten: 
Die Model-Dateien werden...
Domain Driven Design 
Domain-Driven Design (DDD) ist eine 
Herangehensweise an die Modellierung 
komplexer objektorientier...
Warum DDD? 
1. Fachliche Begrifflichkeiten und Codestruktur angleichen. 
2. kleinere Dateien (bessere Wartbarkeit) 
3. höh...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Rails Helpers 
Interne Struktur von Rails um Funktionen für views zur Verfügung 
zu stellen. 
Funktionen um komplexen Code...
Beispiel Rails Helper (1) 
<div> 
<%- if @user.image.present? %> 
<%= image_tag(@user.image.path) %> 
<%- else %> 
<%= ima...
Beispiel Rails Helper (2) 
module UserHelper 
def user_picture_path(user) 
if user.image.present? 
user.image.path 
else 
...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Rails Concerns 
Rails Concerns ist eine Möglichkeit Code in Module auszulagern, 
die man über ein include in ein beliebige...
Beispiel Rails Concerns (1) 
class Article < ActiveRecord::Base 
belongs_to :create_user, class_name: 'User' 
belongs_to :...
Beispiel Rails Concerns (2) 
module Trackable 
extend ActiveSupport::Concern 
included do 
belongs_to :create_user, class_...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Service Objects 
Verlagerung bestimmter Funktionen eines Anwendungsfall in ein 
eigenes Objekt, dass genau diese Funktione...
Beispiel Service Object (1) 
class Article < ActiveRecord::Base 
def search(term, options = {}) 
# execute search 
end 
de...
Beispiel Service Object (2) 
class SearchService 
def self.article_search(term, options = {}) 
# execute search here 
end ...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Presenter Objects 
Oft haben Get-Operationen komplexe Analyse von Parametern, 
um die genau angeforderten Objekte anzuzeig...
Beispiel Presenter Object 
(1) 
class JobController < ApplicationController::Base 
def index 
@jobs = Job.active.preload(:...
Beispiel Presenter Object 
(2) 
class JobController < ApplicationController::Base 
def index 
@jobs = JobPresenter.get_all...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Strukturierte Namen-srääume 
Strukturierung aller Objekte (Models, Services, Presenters, 
Decorators, Controllers usw.) in...
Beispiel Namensrääume (1) 
class Job < ActiveRecord::Base 
def self.all_for_admins 
#execute query here 
end 
def self.all...
Beispiel Namensrääume (2) 
module Admins 
class Job 
def self.all 
#execute query here 
end 
end 
end 
module Moderators 
...
Domain-Driven Design in 
Rails 
Rails Helpers 
Concerns 
Service Objects 
Presenter Objects 
Strukturierte Namensräume 
De...
Decorators in Rails (1)
Decorators in Rails (2)
Beispiel Decorator (1) 
class UserController < ApplicationController::Base 
def show 
@user = User.find(params[:id]) 
end ...
Beispiel Decorator (2) 
class UserDecorator < SimpleDelegator 
def registered_at 
@object.registered_at.strftime('%Y%m%d')...
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 n...
Refactoring 
Oft ist schon ein gewisser Fortschritt da, bevor man merkt, dass die 
Komplexität der Domaine sich direkt im ...
Beispiel:
Domain Driven Design in Rails
Domain Driven Design in Rails
Domain Driven Design in Rails
Nächste SlideShare
Wird geladen in …5
×

Domain Driven Design in Rails

483 Aufrufe

Veröffentlicht am

Presentation on SolutionCamp 2014 in Hamburg.

Domain Driven Design with Ruby on Rails. What can we do with the stuff Rails/Ruby gives us.

Veröffentlicht in: Software
0 Kommentare
0 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

Keine Downloads
Aufrufe
Aufrufe insgesamt
483
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
3
Aktionen
Geteilt
0
Downloads
2
Kommentare
0
Gefällt mir
0
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Domain Driven Design in Rails

  1. 1. Domain Driven Design in Ruby on Rails Created by Angelo Maron
  2. 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. 3. Agenda 1. MVC & Rails 2. Domain Driven Design 3. Domain Driven Design in Rails 4. Zusammenfassung
  4. 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. 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
  6. 6. !Convention!
  7. 7. MVC in Ruby on Rails M odel: ActiveRecord V iew: ActionView C ontroller: ActionController
  8. 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. 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. 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. 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. 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. 13. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  14. 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. 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. 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. 17. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  18. 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. 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. 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. 21. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  22. 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. 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. 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. 25. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  26. 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. 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. 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. 29. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  30. 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. 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. 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. 33. Domain-Driven Design in Rails Rails Helpers Concerns Service Objects Presenter Objects Strukturierte Namensräume Decorator Pattern
  34. 34. Decorators in Rails (1)
  35. 35. Decorators in Rails (2)
  36. 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. 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>
  38. 38. Und was nun?
  39. 39. Die alles entscheidene Frage Welches Pattern benutzt man wann? Ab wann benutzen wir überhaupt diese Pattern?
  40. 40. Neuprogrammierung Abwägung der Komplexität gegen den entstehenden Aufwand. Wichtig: Komplexe Business-Logik lässt sich nur durch komplexen Code abbilden.
  41. 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.
  42. 42. Beispiel:

×