SlideShare ist ein Scribd-Unternehmen logo
1 von 66
Downloaden Sie, um offline zu lesen
March 22nd, 2013

A Rails Criticism
how i learned to stop worrying about the Golden Path
                                       Luca Guidi
AGENDA




intro
Luca Guidi
 Senior Developer at Litmus
  @jodosha - http//lucag uidi.com
litmus
Beautiful Email previews
  Campaig n analytics
   Spam filter tests
 HTML code analysis
   And many other..
Why Rails
has revolutionized web
     development?
         (IMHO)
Why Rails
  has revolutionized web
       development?


Convention Over
 Config uration
          (IMHO)

           :)
Why Rails
     has revolutionized web
          development?


Dynamic and innovative
   Convention Over
    Config uration
     ecosystem
             (IMHO)

              :)
Why Rails
     has revolutionized web
          development?


Dynamic and innovative
   Convention Over
   Productivity and
 Developer uration
    Config Happiness
      ecosystem
             (IMHO)
             :)
..but




The Framework is almost
      ten years old
..but




TheLot of Legacy Code
 A Framework is almost
     ten years old
       is around
..but




TheLot of Legacymajor
 A Frameworkais Code
  Upgrades to     almost
 release years old
     ten are *painful*
       is around
AGENDA




intro   problems
Active
 Record



Active
Record
Active
       Record




Models != Records
Active
                     Record




 Encapsulation violations
1 if article.statearticle.published?
        1 unless != 'published'
2   article.update_attribute(state: 'published')
        2   article.publish!
3 end   3 end
       4 # not completely right...
Active
                     Record

 Encapsulation violations
1 if article.statearticle.published?
        1 unless != 'published'
2   article.update_attribute(state: 'published')
        2   article.publish!
3 end   3 end
       4 # not completely right...
Active
                     Record

 Encapsulation violations
1 if article.statearticle.published?
        1 unless != 'published'
2   article.update_attribute(state: 'published')
        2   article.publish!
3 end   3 end
       4 # not completely right...
Active
            Record



  Tell, Don’t Ask
1
2     violations
 article.publish!
 unless article.published?
 # article.publish!
   push the implementation
3 end
  # into the model
4 # not completely right...
Active
              Record
    Tell, Don’t Ask
      violations
1   article.publish!
    unless article.published?
2   # article.publish!
      push the implementation
3   end
    # into the model
4   # not completely right...
Active
              Record
    Tell, Don’t Ask
      violations
1   article.publish!
    unless article.published?
2   # article.publish!
      push the implementation
3   end
    # into the model
4   # not completely right...
Active
                          Record




2
   Implicit vs Explicit API
1 class Post < ActiveRecord::Base
     1 Post.where(state:'published').
          1 Post.most_recent_published
    def self.most_recent_published(limit = 5)
3    2published.recent(limit).order('created_at DESC')
               order('created_at DESC').
4   end
5    3         limit(5)
6   private
7   scope :published, ->() { where(state: 'published') }
8   scope :recent,    ->(n) { limit(n) }
9 end
Active
                          Record


   Implicit vs Explicit API
1 class Post < ActiveRecord::Base
2    1 Post.where(state:'published').
          1 Post.most_recent_published
    def self.most_recent_published(limit = 5)
3    2published.recent(limit).order('created_at DESC')
               order('created_at DESC').
4   end
5    3         limit(5)
6   private
7   scope :published, ->() { where(state: 'published') }
8   scope :recent,    ->(n) { limit(n) }
9 end
Active
                          Record


   Implicit vs Explicit API
1 class Post < ActiveRecord::Base
2    1 Post.where(state:'published').
          1 Post.most_recent_published
    def self.most_recent_published(limit = 5)
3    2published.recent(limit).order('created_at DESC')
               order('created_at DESC').
4   end
5    3         limit(5)
6   private
7   scope :published, ->() { where(state: 'published') }
8   scope :recent,    ->(n) { limit(n) }
9 end
Active
                          Record


   Implicit vs Explicit API
1 class Post < ActiveRecord::Base
2    1 Post.where(state:'published').
          1 Post.most_recent_published
    def self.most_recent_published(limit = 5)
3    2published.recent(limit).order('created_at DESC')
               order('created_at DESC').
4   end
5    3         limit(5)
6   private
7   scope :published, ->() { where(state: 'published') }
8   scope :recent,    ->(n) { limit(n) }
9 end
Active
      Record




Callbacks abuse
               Non-persistence logic is
               tight to the persistence
               life cycle.

               Eg. Sending emails
Active
       Record




Testability issues
                Micheal Feathers
Active
                Record



A test is not a unit test if it talks
      Testability issues
          to a database.
                          Micheal Feathers
Action
  Controller



 Action
Controller
        It doesn’t affect too much your
        architecture, but it has strange
        OOP design.
Action
                                  Controller


1 class PostsController < ApplicationController
2    before_filter :authenticate


 Frankenstein Controllers
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                  Controller

 Frankenstein Controllers
1 class PostsController < ApplicationController
2    before_filter :authenticate
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                  Controller

 Frankenstein Controllers
1 class PostsController < ApplicationController
2    before_filter :authenticate
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                  Controller

 Frankenstein Controllers
1 class PostsController < ApplicationController
2    before_filter :authenticate
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                  Controller

 Frankenstein Controllers
1 class PostsController < ApplicationController
2    before_filter :authenticate
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                  Controller

 Frankenstein Controllers
1 class PostsController < ApplicationController
2    before_filter :authenticate
3
4    def new
5    end
6
7    def create
8      @post = Post.new(params[:post])
9
10     if @post.save
11       redirect_to post_url(@post), notice: 'Yay!'
12     else
13       render :new
14     end
15   end
16 end
Action
                                 Controller


1 class PostsController < ApplicationController
2    # ...


                    Odd classes
3
4    def create
5      @post = Post.new(params[:post])
6
7      if @post.save
8        # ...
9      else
10       # ...
11     end
12   end
13 end
Action
                                 Controller

                    Odd classes
1 class PostsController < ApplicationController
2    # ...
3
4    def create
5      @post = Post.new(params[:post])
6
7      if @post.save
8        # ...
9      else
10       # ...
11     end
12   end
13 end
Action
                                 Controller

                    Odd classes
1 class PostsController < ApplicationController
2    # ...
3
4    def create
5      @post = Post.new(params[:post])
6
7      if @post.save
8        # ...
9      else
10       # ...
11     end
12   end
13 end
Action
                                 Controller

                    Odd classes
1 class PostsController < ApplicationController
2    # ...
3
4    def create
5      @post = Post.new(params[:post])
6
7      if @post.save
8        # ...
9      else
10       # ...
11     end
12   end
13 end
Action
                                  Controller




3
4
 Encapsulation violations
1 class PostsController < ApplicationController
2   # ...

    def create
5     @post = Post.new(params[:post])
6     # ...
7   end
8 end
Action
                                  Controller

 Encapsulation violations
1 class PostsController < ApplicationController
2   # ...
3
4   def create
5     @post = Post.new(params[:post])
6     # ...
7   end
8 end
Action
                        Controller


1 describe PostsController do


         Testability issues
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
                        Controller

         Testability issues
1 describe PostsController do
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
                        Controller

         Testability issues
1 describe PostsController do
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
                        Controller

         Testability issues
1 describe PostsController do
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
                        Controller

         Testability issues
1 describe PostsController do
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
                        Controller

         Testability issues
1 describe PostsController do
2   it 'assigns @posts' do
3     Post.should_receive(:most_recent_published).
4       and_return(posts = [mock])
5     get :index
6
7     expect(assigns(:posts)).to eq(posts)
8   end
9 end
Action
 View



Action
View
Action
                                View




       Views aren’t views
                     (but templates with logic)

Without “real” views (or                     In an ideal world we
presenters), we’re tempted to                shouldn’t test our
push presentational methods                  templates.
into the models.
Action
                             View



          Helpers are
    functional programming
1   def user_full_name(user)
2     [ user.first_name, user.last_name ].join(' ')
3   end
4
5   url_for
6   # vs                                 Half-assed way to solve
7   Url.for                              presentational problems in
8                                        ActionView.
9   posts_url
Action
                             View
          Helpers are
    functional programming
1   def user_full_name(user)
2     [ user.first_name, user.last_name ].join(' ')
3   end
4
5   url_for
6   # vs                                 Half-assed way to solve
7   Url.for                              presentational problems in
8                                        ActionView.
9   posts_url
Ruby on
  Rails



Ruby on
 Rails
Ruby on
           Rails


Rails isn’t a framework,
  but an application
        template
Ruby on
           Rails



Rails is multi-paradig m
       as Ruby is.
AGENDA




intro   problems   solutions
Solutions



Decouple your logic from
ActiveRecord as much as
        possible.
                      AR is focused on data, but
                      OOP is about behavior.
Solutions




   Don’t think in
ActiveRecord terms.
                   Database is a detail,
                   forget about associations,
                   scopes, validations..
Solutions




Let your public API
 to declare intents.
                   Let your design to emerge
                   via TDD.
Solutions



 Keep methods and
accessors private as
 much as possible.
                    Public APIs are hard to
                    maintain as the codebase
                    and the team grows.
Solutions



Skinny controllers
       and
 skinny models.
             Use ser vice objects or DCI, they
             are easier and faster to test.
Solutions



Don’t be afraid to extract
  ad-hoc classes for
specific responsibilities.
                 Inner classes are your friends,
                 they help you with details, and
                 aren’t part of your public API.
Solutions




Use DIY presenters
            They will help you to keep your
            models clean from presentational
            logic.
Solutions




Refactor, refactor,
    refactor.
AGENDA




intro   problems   solutions   conclusion
Q&A
me@lucag uidi.com
         @jodosha
https://speakerdeck.com/jodosha/a-rails-criticism

               Except where otherwise noted, this work is licensed under:
                   http://creativecommons.org/licenses/by-nc-sa/3.0/
Una Critica a Rails by Luca Guidi

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Java8 tgtbatu javaone
Java8 tgtbatu javaoneJava8 tgtbatu javaone
Java8 tgtbatu javaone
 
The Ring programming language version 1.5.3 book - Part 13 of 184
The Ring programming language version 1.5.3 book - Part 13 of 184The Ring programming language version 1.5.3 book - Part 13 of 184
The Ring programming language version 1.5.3 book - Part 13 of 184
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit Testing
 
Intro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJSIntro to Unit Testing in AngularJS
Intro to Unit Testing in AngularJS
 
PgTAP Best Practices
PgTAP Best PracticesPgTAP Best Practices
PgTAP Best Practices
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS ApplicationsTest-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
 
Software engineering ⊇ Software testing
Software engineering ⊇ Software testingSoftware engineering ⊇ Software testing
Software engineering ⊇ Software testing
 
Java(8) The Good, The Bad and the Ugly
Java(8) The Good, The Bad and the UglyJava(8) The Good, The Bad and the Ugly
Java(8) The Good, The Bad and the Ugly
 
RSpec 3.0: Under the Covers
RSpec 3.0: Under the CoversRSpec 3.0: Under the Covers
RSpec 3.0: Under the Covers
 
Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101
 
Legacy Code Kata v3.0
Legacy Code Kata v3.0Legacy Code Kata v3.0
Legacy Code Kata v3.0
 
Legacy Dependency Kata v2.0
Legacy Dependency Kata v2.0Legacy Dependency Kata v2.0
Legacy Dependency Kata v2.0
 
Qunit Java script Un
Qunit Java script UnQunit Java script Un
Qunit Java script Un
 
The Ring programming language version 1.8 book - Part 89 of 202
The Ring programming language version 1.8 book - Part 89 of 202The Ring programming language version 1.8 book - Part 89 of 202
The Ring programming language version 1.8 book - Part 89 of 202
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 
Full Stack Unit Testing
Full Stack Unit TestingFull Stack Unit Testing
Full Stack Unit Testing
 
Stop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScriptStop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScript
 
Martin Anderson - threads v actors
Martin Anderson - threads v actorsMartin Anderson - threads v actors
Martin Anderson - threads v actors
 
Angularjs - Unit testing introduction
Angularjs - Unit testing introductionAngularjs - Unit testing introduction
Angularjs - Unit testing introduction
 
FullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + AngularFullStack Reativo com Spring WebFlux + Angular
FullStack Reativo com Spring WebFlux + Angular
 

Ähnlich wie Una Critica a Rails by Luca Guidi

Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code styleRuby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Anton Shemerey
 

Ähnlich wie Una Critica a Rails by Luca Guidi (20)

Aprendendo solid com exemplos
Aprendendo solid com exemplosAprendendo solid com exemplos
Aprendendo solid com exemplos
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
RSpec
RSpecRSpec
RSpec
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
 
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code styleRuby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
Ruby: OOP, metaprogramming, blocks, iterators, mix-ins, duck typing. Code style
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-Studio
 
Java7
Java7Java7
Java7
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
 
Writing Macros
Writing MacrosWriting Macros
Writing Macros
 
Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful Code
 
Why ruby
Why rubyWhy ruby
Why ruby
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassleGeeCON 2017 - TestContainers. Integration testing without the hassle
GeeCON 2017 - TestContainers. Integration testing without the hassle
 
JavaScript Cheatsheets with easy way .pdf
JavaScript Cheatsheets with easy way .pdfJavaScript Cheatsheets with easy way .pdf
JavaScript Cheatsheets with easy way .pdf
 
Workshop React.js
Workshop React.jsWorkshop React.js
Workshop React.js
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web Standards
 
TDD & BDD
TDD & BDDTDD & BDD
TDD & BDD
 
Troubleshooting tips from docker support engineers
Troubleshooting tips from docker support engineersTroubleshooting tips from docker support engineers
Troubleshooting tips from docker support engineers
 
Fundamental Concepts of React JS for Beginners.pdf
Fundamental Concepts of React JS for Beginners.pdfFundamental Concepts of React JS for Beginners.pdf
Fundamental Concepts of React JS for Beginners.pdf
 

Mehr von Codemotion

Mehr von Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Kürzlich hochgeladen

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Kürzlich hochgeladen (20)

ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
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
 
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
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
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
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

Una Critica a Rails by Luca Guidi

  • 1. March 22nd, 2013 A Rails Criticism how i learned to stop worrying about the Golden Path Luca Guidi
  • 3. Luca Guidi Senior Developer at Litmus @jodosha - http//lucag uidi.com
  • 4. litmus Beautiful Email previews Campaig n analytics Spam filter tests HTML code analysis And many other..
  • 5. Why Rails has revolutionized web development? (IMHO)
  • 6. Why Rails has revolutionized web development? Convention Over Config uration (IMHO) :)
  • 7. Why Rails has revolutionized web development? Dynamic and innovative Convention Over Config uration ecosystem (IMHO) :)
  • 8. Why Rails has revolutionized web development? Dynamic and innovative Convention Over Productivity and Developer uration Config Happiness ecosystem (IMHO) :)
  • 9. ..but The Framework is almost ten years old
  • 10. ..but TheLot of Legacy Code A Framework is almost ten years old is around
  • 11. ..but TheLot of Legacymajor A Frameworkais Code Upgrades to almost release years old ten are *painful* is around
  • 12. AGENDA intro problems
  • 14. Active Record Models != Records
  • 15. Active Record Encapsulation violations 1 if article.statearticle.published? 1 unless != 'published' 2 article.update_attribute(state: 'published') 2 article.publish! 3 end 3 end 4 # not completely right...
  • 16. Active Record Encapsulation violations 1 if article.statearticle.published? 1 unless != 'published' 2 article.update_attribute(state: 'published') 2 article.publish! 3 end 3 end 4 # not completely right...
  • 17. Active Record Encapsulation violations 1 if article.statearticle.published? 1 unless != 'published' 2 article.update_attribute(state: 'published') 2 article.publish! 3 end 3 end 4 # not completely right...
  • 18. Active Record Tell, Don’t Ask 1 2 violations article.publish! unless article.published? # article.publish! push the implementation 3 end # into the model 4 # not completely right...
  • 19. Active Record Tell, Don’t Ask violations 1 article.publish! unless article.published? 2 # article.publish! push the implementation 3 end # into the model 4 # not completely right...
  • 20. Active Record Tell, Don’t Ask violations 1 article.publish! unless article.published? 2 # article.publish! push the implementation 3 end # into the model 4 # not completely right...
  • 21. Active Record 2 Implicit vs Explicit API 1 class Post < ActiveRecord::Base 1 Post.where(state:'published'). 1 Post.most_recent_published def self.most_recent_published(limit = 5) 3 2published.recent(limit).order('created_at DESC') order('created_at DESC'). 4 end 5 3 limit(5) 6 private 7 scope :published, ->() { where(state: 'published') } 8 scope :recent, ->(n) { limit(n) } 9 end
  • 22. Active Record Implicit vs Explicit API 1 class Post < ActiveRecord::Base 2 1 Post.where(state:'published'). 1 Post.most_recent_published def self.most_recent_published(limit = 5) 3 2published.recent(limit).order('created_at DESC') order('created_at DESC'). 4 end 5 3 limit(5) 6 private 7 scope :published, ->() { where(state: 'published') } 8 scope :recent, ->(n) { limit(n) } 9 end
  • 23. Active Record Implicit vs Explicit API 1 class Post < ActiveRecord::Base 2 1 Post.where(state:'published'). 1 Post.most_recent_published def self.most_recent_published(limit = 5) 3 2published.recent(limit).order('created_at DESC') order('created_at DESC'). 4 end 5 3 limit(5) 6 private 7 scope :published, ->() { where(state: 'published') } 8 scope :recent, ->(n) { limit(n) } 9 end
  • 24. Active Record Implicit vs Explicit API 1 class Post < ActiveRecord::Base 2 1 Post.where(state:'published'). 1 Post.most_recent_published def self.most_recent_published(limit = 5) 3 2published.recent(limit).order('created_at DESC') order('created_at DESC'). 4 end 5 3 limit(5) 6 private 7 scope :published, ->() { where(state: 'published') } 8 scope :recent, ->(n) { limit(n) } 9 end
  • 25. Active Record Callbacks abuse Non-persistence logic is tight to the persistence life cycle. Eg. Sending emails
  • 26. Active Record Testability issues Micheal Feathers
  • 27. Active Record A test is not a unit test if it talks Testability issues to a database. Micheal Feathers
  • 28. Action Controller Action Controller It doesn’t affect too much your architecture, but it has strange OOP design.
  • 29. Action Controller 1 class PostsController < ApplicationController 2 before_filter :authenticate Frankenstein Controllers 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 30. Action Controller Frankenstein Controllers 1 class PostsController < ApplicationController 2 before_filter :authenticate 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 31. Action Controller Frankenstein Controllers 1 class PostsController < ApplicationController 2 before_filter :authenticate 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 32. Action Controller Frankenstein Controllers 1 class PostsController < ApplicationController 2 before_filter :authenticate 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 33. Action Controller Frankenstein Controllers 1 class PostsController < ApplicationController 2 before_filter :authenticate 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 34. Action Controller Frankenstein Controllers 1 class PostsController < ApplicationController 2 before_filter :authenticate 3 4 def new 5 end 6 7 def create 8 @post = Post.new(params[:post]) 9 10 if @post.save 11 redirect_to post_url(@post), notice: 'Yay!' 12 else 13 render :new 14 end 15 end 16 end
  • 35. Action Controller 1 class PostsController < ApplicationController 2 # ... Odd classes 3 4 def create 5 @post = Post.new(params[:post]) 6 7 if @post.save 8 # ... 9 else 10 # ... 11 end 12 end 13 end
  • 36. Action Controller Odd classes 1 class PostsController < ApplicationController 2 # ... 3 4 def create 5 @post = Post.new(params[:post]) 6 7 if @post.save 8 # ... 9 else 10 # ... 11 end 12 end 13 end
  • 37. Action Controller Odd classes 1 class PostsController < ApplicationController 2 # ... 3 4 def create 5 @post = Post.new(params[:post]) 6 7 if @post.save 8 # ... 9 else 10 # ... 11 end 12 end 13 end
  • 38. Action Controller Odd classes 1 class PostsController < ApplicationController 2 # ... 3 4 def create 5 @post = Post.new(params[:post]) 6 7 if @post.save 8 # ... 9 else 10 # ... 11 end 12 end 13 end
  • 39. Action Controller 3 4 Encapsulation violations 1 class PostsController < ApplicationController 2 # ... def create 5 @post = Post.new(params[:post]) 6 # ... 7 end 8 end
  • 40. Action Controller Encapsulation violations 1 class PostsController < ApplicationController 2 # ... 3 4 def create 5 @post = Post.new(params[:post]) 6 # ... 7 end 8 end
  • 41. Action Controller 1 describe PostsController do Testability issues 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 42. Action Controller Testability issues 1 describe PostsController do 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 43. Action Controller Testability issues 1 describe PostsController do 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 44. Action Controller Testability issues 1 describe PostsController do 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 45. Action Controller Testability issues 1 describe PostsController do 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 46. Action Controller Testability issues 1 describe PostsController do 2 it 'assigns @posts' do 3 Post.should_receive(:most_recent_published). 4 and_return(posts = [mock]) 5 get :index 6 7 expect(assigns(:posts)).to eq(posts) 8 end 9 end
  • 48. Action View Views aren’t views (but templates with logic) Without “real” views (or In an ideal world we presenters), we’re tempted to shouldn’t test our push presentational methods templates. into the models.
  • 49. Action View Helpers are functional programming 1 def user_full_name(user) 2 [ user.first_name, user.last_name ].join(' ') 3 end 4 5 url_for 6 # vs Half-assed way to solve 7 Url.for presentational problems in 8 ActionView. 9 posts_url
  • 50. Action View Helpers are functional programming 1 def user_full_name(user) 2 [ user.first_name, user.last_name ].join(' ') 3 end 4 5 url_for 6 # vs Half-assed way to solve 7 Url.for presentational problems in 8 ActionView. 9 posts_url
  • 51. Ruby on Rails Ruby on Rails
  • 52. Ruby on Rails Rails isn’t a framework, but an application template
  • 53. Ruby on Rails Rails is multi-paradig m as Ruby is.
  • 54. AGENDA intro problems solutions
  • 55. Solutions Decouple your logic from ActiveRecord as much as possible. AR is focused on data, but OOP is about behavior.
  • 56. Solutions Don’t think in ActiveRecord terms. Database is a detail, forget about associations, scopes, validations..
  • 57. Solutions Let your public API to declare intents. Let your design to emerge via TDD.
  • 58. Solutions Keep methods and accessors private as much as possible. Public APIs are hard to maintain as the codebase and the team grows.
  • 59. Solutions Skinny controllers and skinny models. Use ser vice objects or DCI, they are easier and faster to test.
  • 60. Solutions Don’t be afraid to extract ad-hoc classes for specific responsibilities. Inner classes are your friends, they help you with details, and aren’t part of your public API.
  • 61. Solutions Use DIY presenters They will help you to keep your models clean from presentational logic.
  • 63. AGENDA intro problems solutions conclusion
  • 64. Q&A
  • 65. me@lucag uidi.com @jodosha https://speakerdeck.com/jodosha/a-rails-criticism Except where otherwise noted, this work is licensed under: http://creativecommons.org/licenses/by-nc-sa/3.0/