Top Banner
Luca Guidi March 22nd, 2013 A Rails Criticism how i learned to stop worrying about the Golden Path
66

Una Critica a Rails by Luca Guidi

Sep 12, 2014

Download

Technology

Un profondo punto di vista sul perché Ruby on Rails ha rivoluzionato lo sviluppo web.

Questo talk focalizzerà la sua attenzione sul “Golden Path” di Rails, sui motivi del suo successo, sui problemi più comuni, e su come le sue API possano essere migliorate.

Impareremo a trarre beneficio da uno strumento tanto potente quanto pericoloso, di come mitigare le implicazioni architetturali, di design e testabilità delle vostre applicazioni, migliorando la qualità del codice..
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Una Critica a Rails by Luca Guidi

Luca Guidi

March 22nd, 2013

A Rails Criticismhow i learned to stop worrying about the Golden Path

Page 2: Una Critica a Rails by Luca Guidi

AGENDA

intro

Page 3: Una Critica a Rails by Luca Guidi

Luca GuidiSenior Developer at Litmus

@jodosha - http//lucaguidi.com

Page 4: Una Critica a Rails by Luca Guidi

litmusBeautiful Email previews

Campaign analytics

Spam filter tests

HTML code analysis

And many other..

Page 5: Una Critica a Rails by Luca Guidi

Why Railshas revolutionized web

development?(IMHO)

Page 6: Una Critica a Rails by Luca Guidi

Why Railshas revolutionized web

development?

(IMHO)

Convention Over Configuration

:)

Page 7: Una Critica a Rails by Luca Guidi

Why Railshas revolutionized web

development?

(IMHO)

Convention Over Configuration

Dynamic and innovativeecosystem

:)

Page 8: Una Critica a Rails by Luca Guidi

Why Railshas revolutionized web

development?

(IMHO)

Convention Over Configuration

Dynamic and innovativeecosystem

Productivity andDeveloper Happiness

:)

Page 9: Una Critica a Rails by Luca Guidi

..but

The Framework is almost ten years old

Page 10: Una Critica a Rails by Luca Guidi

..but

The Framework is almost ten years old

A Lot of Legacy Codeis around

Page 11: Una Critica a Rails by Luca Guidi

..but

The Framework is almost ten years old

A Lot of Legacy Codeis around

Upgrades to a major release are *painful*

Page 12: Una Critica a Rails by Luca Guidi

AGENDA

intro problems

Page 13: Una Critica a Rails by Luca Guidi

ActiveRecord

Active

Record

Page 14: Una Critica a Rails by Luca Guidi

Models != Records

Active

Record

Page 15: Una Critica a Rails by Luca Guidi

Encapsulation violations

Active

Record

1 if article.state != 'published'2 article.update_attribute(state: 'published')3 end

1 unless article.published?2 article.publish!3 end4 # not completely right...

Page 16: Una Critica a Rails by Luca Guidi

Encapsulation violations

Active

Record

1 if article.state != 'published'2 article.update_attribute(state: 'published')3 end

1 unless article.published?2 article.publish!3 end4 # not completely right...

Page 17: Una Critica a Rails by Luca Guidi

Encapsulation violations

Active

Record

1 if article.state != 'published'2 article.update_attribute(state: 'published')3 end

1 unless article.published?2 article.publish!3 end4 # not completely right...

Page 18: Una Critica a Rails by Luca Guidi

Tell, Don’t Askviolations

Active

Record

1 unless article.published?2 article.publish!3 end4 # not completely right...

1 article.publish!2 # push the implementation3 # into the model

Page 19: Una Critica a Rails by Luca Guidi

Tell, Don’t Askviolations

Active

Record

1 unless article.published?2 article.publish!3 end4 # not completely right...

1 article.publish!2 # push the implementation3 # into the model

Page 20: Una Critica a Rails by Luca Guidi

Tell, Don’t Askviolations

Active

Record

1 unless article.published?2 article.publish!3 end4 # not completely right...

1 article.publish!2 # push the implementation3 # into the model

Page 21: Una Critica a Rails by Luca Guidi

Implicit vs Explicit API

Active

Record

1 Post.where(state:'published').2 order('created_at DESC').3 limit(5)

1 Post.most_recent_published1 class Post < ActiveRecord::Base2 def self.most_recent_published(limit = 5)3 published.recent(limit).order('created_at DESC')4 end5 6 private7 scope :published, ->() { where(state: 'published') }8 scope :recent, ->(n) { limit(n) }9 end

Page 22: Una Critica a Rails by Luca Guidi

Implicit vs Explicit API

Active

Record

1 Post.where(state:'published').2 order('created_at DESC').3 limit(5)

1 Post.most_recent_published1 class Post < ActiveRecord::Base2 def self.most_recent_published(limit = 5)3 published.recent(limit).order('created_at DESC')4 end5 6 private7 scope :published, ->() { where(state: 'published') }8 scope :recent, ->(n) { limit(n) }9 end

Page 23: Una Critica a Rails by Luca Guidi

Implicit vs Explicit API

Active

Record

1 Post.where(state:'published').2 order('created_at DESC').3 limit(5)

1 Post.most_recent_published1 class Post < ActiveRecord::Base2 def self.most_recent_published(limit = 5)3 published.recent(limit).order('created_at DESC')4 end5 6 private7 scope :published, ->() { where(state: 'published') }8 scope :recent, ->(n) { limit(n) }9 end

Page 24: Una Critica a Rails by Luca Guidi

Implicit vs Explicit API

Active

Record

1 Post.where(state:'published').2 order('created_at DESC').3 limit(5)

1 Post.most_recent_published1 class Post < ActiveRecord::Base2 def self.most_recent_published(limit = 5)3 published.recent(limit).order('created_at DESC')4 end5 6 private7 scope :published, ->() { where(state: 'published') }8 scope :recent, ->(n) { limit(n) }9 end

Page 25: Una Critica a Rails by Luca Guidi

Callbacks abuse

Active

Record

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

Eg. Sending emails

Page 26: Una Critica a Rails by Luca Guidi

Testability issues

Active

Record

Micheal Feathers

Page 27: Una Critica a Rails by Luca Guidi

Testability issues

Active

Record

A test is not a unit test if it talks to a database.

Micheal Feathers

Page 28: Una Critica a Rails by Luca Guidi

ActionController

Action

Controller

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

Page 29: Una Critica a Rails by Luca Guidi

Frankenstein Controllers

Action

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 30: Una Critica a Rails by Luca Guidi

Frankenstein ControllersAction

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 31: Una Critica a Rails by Luca Guidi

Frankenstein ControllersAction

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 32: Una Critica a Rails by Luca Guidi

Frankenstein ControllersAction

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 33: Una Critica a Rails by Luca Guidi

Frankenstein ControllersAction

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 34: Una Critica a Rails by Luca Guidi

Frankenstein ControllersAction

Controller

1 class PostsController < ApplicationController2 before_filter :authenticate3 4 def new5 end6 7 def create8 @post = Post.new(params[:post])9 10 if @post.save11 redirect_to post_url(@post), notice: 'Yay!'12 else13 render :new14 end15 end16 end

�!& ��������� !��!��

�!& �����"!��

�!& �����������

����!%���������!�������#����!� ���������"������ �

�%�����"�!�

Page 35: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 7 if @post.save8 # ...9 else10 # ...11 end12 end13 end

Odd classes

Action

Controller

��$�!����������!�� ������!������

��"����&!�����" ��%�"����&!������!�%��� !��!��!�������!���������$�!�������!�!�� ����������%�

Page 36: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 7 if @post.save8 # ...9 else10 # ...11 end12 end13 end

Odd classesAction

Controller

��$�!����������!�� ������!������

��"����&!�����" ��%�"����&!������!�%��� !��!��!�������!���������$�!�������!�!�� ����������%�

Page 37: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 7 if @post.save8 # ...9 else10 # ...11 end12 end13 end

Odd classesAction

Controller

��$�!����������!�� ������!������

��"����&!�����" ��%�"����&!������!�%��� !��!��!�������!���������$�!�������!�!�� ����������%�

Page 38: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 7 if @post.save8 # ...9 else10 # ...11 end12 end13 end

Odd classesAction

Controller

��$�!����������!�� ������!������

��"����&!�����" ��%�"����&!������!�%��� !��!��!�������!���������$�!�������!�!�� ����������%�

Page 39: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 # ...7 end8 end

Encapsulation violations

Action

Controller

��$�!����������!�� ������!��������� ��#���$��������������!��!� ! �����#��$ ��

Page 40: Una Critica a Rails by Luca Guidi

1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 # ...7 end8 end

Encapsulation violationsAction

Controller

��$�!����������!�� ������!��������� ��#���$��������������!��!� ! �����#��$ ��

Page 41: Una Critica a Rails by Luca Guidi

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

Testability issues

Action

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 42: Una Critica a Rails by Luca Guidi

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

Testability issuesAction

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 43: Una Critica a Rails by Luca Guidi

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

Testability issuesAction

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 44: Una Critica a Rails by Luca Guidi

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

Testability issuesAction

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 45: Una Critica a Rails by Luca Guidi

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

Testability issuesAction

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 46: Una Critica a Rails by Luca Guidi

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

Testability issuesAction

Controller

��� �� ������!����!����!� ! �����&!������!�!�� ����������%� ��$������������� !"�����!����!��

��!������������!�!���

��� �� �����������!��!�' !��� (!��� !�!�������!������!�������

Page 47: Una Critica a Rails by Luca Guidi

ActionView

Action

View

Page 48: Una Critica a Rails by Luca Guidi

Views aren’t views

Action

View

(but templates with logic)

Without “real” views (or presenters), we’re tempted to push presentational methods into the models.

In an ideal world we shouldn’t test our templates.

Page 49: Una Critica a Rails by Luca Guidi

Helpers arefunctional programming

Action

View

1 def user_full_name(user)2 [ user.first_name, user.last_name ].join(' ')3 end4 5 url_for6 # vs7 Url.for8 9 posts_url

Half-assed way to solvepresentational problems in ActionView.

Page 50: Una Critica a Rails by Luca Guidi

Helpers arefunctional programming

Action

View

1 def user_full_name(user)2 [ user.first_name, user.last_name ].join(' ')3 end4 5 url_for6 # vs7 Url.for8 9 posts_url

Half-assed way to solvepresentational problems in ActionView.

Page 51: Una Critica a Rails by Luca Guidi

Ruby onRails

Ruby on

Rails

Page 52: Una Critica a Rails by Luca Guidi

Rails isn’t a framework,but an application

template

Ruby on

Rails

Page 53: Una Critica a Rails by Luca Guidi

Rails is multi-paradigmas Ruby is.

Ruby on

Rails

Page 54: Una Critica a Rails by Luca Guidi

AGENDA

intro problems solutions

Page 55: Una Critica a Rails by Luca Guidi

Decouple your logic fromActiveRecord as much as

possible.

Solutions

AR is focused on data, but OOP is about behavior.

Page 56: Una Critica a Rails by Luca Guidi

Don’t think in ActiveRecord terms.

Solutions

Database is a detail, forget about associations,scopes, validations..

Page 57: Una Critica a Rails by Luca Guidi

Let your public APIto declare intents.

Solutions

Let your design to emerge via TDD.

Page 58: Una Critica a Rails by Luca Guidi

Keep methods and accessors private as

much as possible.

Solutions

Public APIs are hard to maintain as the codebase and the team grows.

Page 59: Una Critica a Rails by Luca Guidi

Skinny controllersand

skinny models.

Solutions

Use service objects or DCI, they are easier and faster to test.

Page 60: Una Critica a Rails by Luca Guidi

Don’t be afraid to extract ad-hoc classes for

specific responsibilities.

Solutions

Inner classes are your friends, they help you with details, and aren’t part of your public API.

Page 61: Una Critica a Rails by Luca Guidi

Use DIY presenters

Solutions

They will help you to keep your models clean from presentational logic.

Page 62: Una Critica a Rails by Luca Guidi

Refactor, refactor, refactor.

Solutions

Page 63: Una Critica a Rails by Luca Guidi

AGENDA

intro problems solutions conclusion

Page 64: Una Critica a Rails by Luca Guidi

Q&A

Page 65: Una Critica a Rails by Luca Guidi

[email protected]@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/

Page 66: Una Critica a Rails by Luca Guidi

��������