SlideShare a Scribd company logo
REFACTORING WORKSHOP 
Bruce Li @ Rails Pacific 2014 
Please clone this repo 
https://github.com/ascendbruce/refactoring-workshop 
run bundle install 
and Check your ruby version
ABOUT ME 
• Li, Po-Chun a.k.a. Bruce Li 
• Work at Techbang 
• http://ascendbruce.logdown.com/ 
• @BruceToyRoom, @techbangtech
REFACTORING 
is important 
• Reduce maintenance cost 
• Technical debt is not about technology. It’s about 
people 
• programmer happiness is very important
TEST COVERAGE 
is important 
• Confident in changes 
• Code School, TeaLeaf are good start 
• SimpleCov and CodeClimate can make you 
happier while repairing test cases
PRY 
is useful 
• gem "pry-rails" 
gem "pry-byebug" # or pry-debugger for ruby 1.9 
• binding.pry # to entering debug mode 
• Commands: next, step, break, continue, exit 
• It’s all you need at first
COMMENTS IN CODE 
is bad (in some cases) 
• Ideally, code should describe itself. 
• Out-dated comments are worser than none. It’s 
actively misleading. 
• Comments is helpful for providing additional 
information or link to issue tracking history.
1. INTENTION REVEALING 
METHOD 
• Add comments if code need it. 
• Transform comments into methods. 
• Comments are now code. Code describes itself.
Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)
Refactoring Workshop (Rails Pacific 2014)
user_is_admitted?
user_is_admitted?
user_is_admitted? 
set_marketing_flash
user_is_admitted? 
set_marketing_flash
2. MOVE MODEL LOGIC INTO 
THE MODEL 
• Move the logic, which belongs to model, into the 
model 
• instance variable should change to self in model
class ProjectsController 
def new 
# @#$^$%&#%&*#$%& 
@project = Project.new 
! 
! 
@project.do_ooxx 
@project.xxoo = "xxoo" 
# &*%^&@#$! 
end 
end 
class Project 
! 
! 
! 
! 
end 
def do_something 
! 
! 
end
class ProjectsController 
def new 
# @#$^$%&#%&*#$%& 
@project = Project.new 
@project.do_something 
! 
! 
# &*%^&@#$! 
end 
end 
class Project 
! 
! 
! 
! 
end 
def do_something 
! 
! 
end 
@project.do_ooxx 
@project.xxoo = "xxoo"
class ProjectsController 
def new 
# @#$^$%&#%&*#$%& 
@project = Project.new 
@project.do_something 
! 
! 
# &*%^&@#$! 
end 
end 
class Project 
! 
! 
! 
! 
end 
def do_something 
! 
! 
end 
@project.do_ooxx 
@project.xxoo = "xxoo"
class ProjectsController 
def new 
# @#$^$%&#%&*#$%& 
@project = Project.new 
@project.do_something 
do_ooxx 
self.xxoo = "xxoo" 
! 
! 
# &*%^&@#$! 
end 
end 
class Project 
! 
! 
! 
! 
end 
def do_something 
! 
! 
end
3. REPLACE METHOD WITH 
METHOD OBJECT 
• Create a class with same initialization arguments as 
BIG method 
• Copy & Paste the method's body in the new class, 
with no arguments 
• Replace original method with a call to the new class 
• Apply "Intention Revealing Method" to the class
class OriginMethods 
def a_fat_method 
! 
! 
! 
! 
end 
end 
# $%@ + ($@# / ^%) 
# && ^ %& * #%%^ 
# wtf 
# and 100 lines...
class NewMethods 
def perform 
end 
end 
class OriginMethods 
def a_fat_method 
! 
! 
! 
! 
end 
end 
# $%@ + ($@# / ^%) 
# && ^ %& * #%%^ 
# wtf 
# and 100 lines...
class NewMethods 
def perform 
! 
! 
! 
! 
end 
end 
# $%@ + ($@# / ^%) 
# && ^ %& * #%%^ 
# wtf 
# and 100 lines... 
class OriginMethods 
def a_fat_method 
! 
! 
! 
! 
end 
end
class NewMethods 
def perform 
! 
! 
! 
! 
end 
end 
# $%@ + ($@# / ^%) 
# && ^ %& * #%%^ 
# wtf 
# and 100 lines... 
class OriginMethods 
def a_fat_method 
! 
! 
! 
! 
end 
end 
NewMethods.new.perform
class NewMethods 
! 
! 
! 
! 
def perform 
File.open(??????????) 
# ... 
end 
end 
! 
class OriginMethods 
def a_fat_method(file_name) 
NewMethods.new.perform 
end 
end 
?
class NewMethods 
! 
! 
! 
! 
def perform 
File.open( ) 
# ... 
end 
end 
! 
class OriginMethods 
def a_fat_method(file_name) 
NewMethods.new 
end 
end
class NewMethods 
! 
! 
! 
! 
def perform 
File.open( ) 
# ... 
end 
end 
! 
class OriginMethods 
def a_fat_method(file_name) 
NewMethods.new 
end 
end 
(file_name).perform
class NewMethods 
! 
! 
! 
! 
def perform 
def initialize(file_name) 
@file_name = file_name 
end 
File.open( ) 
# ... 
end 
end 
! 
class OriginMethods 
def a_fat_method(file_name) 
NewMethods.new 
end 
end 
(file_name).perform
class NewMethods 
! 
! 
! 
! 
def perform 
def initialize(file_name) 
@file_name = file_name 
end 
@file_name 
File.open( ) 
# ... 
end 
end 
! 
class OriginMethods 
def a_fat_method(file_name) 
NewMethods.new 
end 
end 
(file_name).perform
4. SERVICE OBJECT 
• If we add new functionality to an object and: 
• It couples to a new dependency 
• It loses cohesion 
• Testing gets harder and slower
4. SERVICE OBJECT 
• If it's a domain concept, it's an Object. If it's only 
an algorithm (no state) we call it a Service. 
• Delegate to the Service Object
5. FORM OBJECT 
• accepts_nested_attributes_for is hard to track 
• Making very different forms for the same object is 
a pain. The model is messed up
5. FORM OBJECT 
• include ActiveModel::Model 
• Set attr_reader for related models 
• Set attr_accessor for accepted fields 
• Add validators (ActiveModel::Model will take care of validation and 
errors) 
• Define persisted? method (false for create, true for update form) 
• Add initialize, save, update etc… if needed
REFERENCE 
• Crisp's Blog - Good and Bad Technical Debt 
• RailsCasts - Form Objects 
• 7 Patterns to Refactor Fat ActiveRecord Models

More Related Content

PDF
Make your Rails console AWESOME (Ruby SG meetup 2016-03-29)
KEY
Namespace less engine
ZIP
URUG Ruby on Rails Workshop - Sesssion 5
PDF
Gemboys
PPSX
C# Powershell and an Azure Function Walk Into a Bar...
PDF
Front-end Automated Testing
PDF
Outside-in Development with Cucumber and Rspec
PDF
Cucumber Ru09 Web
Make your Rails console AWESOME (Ruby SG meetup 2016-03-29)
Namespace less engine
URUG Ruby on Rails Workshop - Sesssion 5
Gemboys
C# Powershell and an Azure Function Walk Into a Bar...
Front-end Automated Testing
Outside-in Development with Cucumber and Rspec
Cucumber Ru09 Web

What's hot (20)

PDF
Introduction To Web Application Testing
PDF
Writing Software not Code with Cucumber
PDF
I Promise You
KEY
Sizzle jQCon San Francisco 2012
PDF
Drupal8 Front-end Automated Testing
PDF
Webcomponents are your frameworks best friend
PDF
Frameworks and webcomponents
PPTX
Automating Your Daily Tasks with Scripting - RubyConf 2015 Taiwan
KEY
PPTX
Style Is Cool
PPTX
Thing to love in Clojure
PDF
Reacting to the Isomorphic Buzz
PDF
How I ignored, discovered then loved design patterns - Abdelkader Bouadjadja
PDF
Never fear, the customizer is here!
PPT
Selenium and Cucumber Selenium Conf 2011
PDF
Angular.JS: Do it right
PDF
API Prefetching - HTML5DevConf - Oct. 21, 2014
PDF
Building testable chrome extensions
PDF
Marrying angular rails
PDF
Cucumber.js: Cuke up your JavaScript!
Introduction To Web Application Testing
Writing Software not Code with Cucumber
I Promise You
Sizzle jQCon San Francisco 2012
Drupal8 Front-end Automated Testing
Webcomponents are your frameworks best friend
Frameworks and webcomponents
Automating Your Daily Tasks with Scripting - RubyConf 2015 Taiwan
Style Is Cool
Thing to love in Clojure
Reacting to the Isomorphic Buzz
How I ignored, discovered then loved design patterns - Abdelkader Bouadjadja
Never fear, the customizer is here!
Selenium and Cucumber Selenium Conf 2011
Angular.JS: Do it right
API Prefetching - HTML5DevConf - Oct. 21, 2014
Building testable chrome extensions
Marrying angular rails
Cucumber.js: Cuke up your JavaScript!
Ad

Similar to Refactoring Workshop (Rails Pacific 2014) (20)

PDF
Modernizing Legacy Applications in PHP, por Paul Jones
PDF
Write your Ruby in Style
PDF
The Dark Art of Rails Plugins (2008)
PDF
Metaprogramming + Ds Ls
PPT
Ruby for C# Developers
PDF
Refactoring
PDF
Ruby on Rails at PROMPT ISEL '11
ZIP
Continuous Integration For Rails Project
PPTX
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
KEY
Ruby/Rails
PDF
Rails OO views
KEY
Test First Teaching
KEY
Intro to Ruby - Twin Cities Code Camp 7
PDF
Techtalk design patterns
KEY
Dsl
PDF
Refactoring @ Mindvalley: Smells, Techniques and Patterns
PPT
Synapseindia reviews sharing intro cakephp
PPTX
Ruby basics
KEY
A tour on ruby and friends
Modernizing Legacy Applications in PHP, por Paul Jones
Write your Ruby in Style
The Dark Art of Rails Plugins (2008)
Metaprogramming + Ds Ls
Ruby for C# Developers
Refactoring
Ruby on Rails at PROMPT ISEL '11
Continuous Integration For Rails Project
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
Ruby/Rails
Rails OO views
Test First Teaching
Intro to Ruby - Twin Cities Code Camp 7
Techtalk design patterns
Dsl
Refactoring @ Mindvalley: Smells, Techniques and Patterns
Synapseindia reviews sharing intro cakephp
Ruby basics
A tour on ruby and friends
Ad

More from Bruce Li (14)

PDF
RSpec best practice - avoid using before and let
PDF
Unlock dependency between client teams and API team with API mock and proxy
PDF
011 優化時間分配的 app 跟心得
PDF
Rails Code Club 3 @ Taipei
PDF
Rails Code Club 2 @ Taipei
PDF
010 Better and Better 工程師就業兩年多的心得雜談
PDF
009 增進效率的雜七雜八mac快速鍵與設定 part 2
PDF
008 vim超基礎入門
PDF
007 Facebook Open Graph 相關開發簡單介紹 公開版
PDF
006 實作小玩具功能:chrome desktop notification
PDF
004 動機 單純的力量 讀書心得
PDF
003 Ruby小觀念與小技巧Part2
PDF
002 增進效率的有的沒的快速鍵與設定
PDF
001 Ruby小觀念與小技巧
RSpec best practice - avoid using before and let
Unlock dependency between client teams and API team with API mock and proxy
011 優化時間分配的 app 跟心得
Rails Code Club 3 @ Taipei
Rails Code Club 2 @ Taipei
010 Better and Better 工程師就業兩年多的心得雜談
009 增進效率的雜七雜八mac快速鍵與設定 part 2
008 vim超基礎入門
007 Facebook Open Graph 相關開發簡單介紹 公開版
006 實作小玩具功能:chrome desktop notification
004 動機 單純的力量 讀書心得
003 Ruby小觀念與小技巧Part2
002 增進效率的有的沒的快速鍵與設定
001 Ruby小觀念與小技巧

Recently uploaded (20)

PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Essential Infomation Tech presentation.pptx
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPTX
Introduction to Artificial Intelligence
PDF
System and Network Administraation Chapter 3
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
Transform Your Business with a Software ERP System
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
System and Network Administration Chapter 2
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Odoo Companies in India – Driving Business Transformation.pdf
How Creative Agencies Leverage Project Management Software.pdf
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
Essential Infomation Tech presentation.pptx
Odoo POS Development Services by CandidRoot Solutions
Design an Analysis of Algorithms II-SECS-1021-03
Introduction to Artificial Intelligence
System and Network Administraation Chapter 3
VVF-Customer-Presentation2025-Ver1.9.pptx
How to Migrate SBCGlobal Email to Yahoo Easily
wealthsignaloriginal-com-DS-text-... (1).pdf
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Transform Your Business with a Software ERP System
Adobe Illustrator 28.6 Crack My Vision of Vector Design
System and Network Administration Chapter 2
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Design an Analysis of Algorithms I-SECS-1021-03
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...

Refactoring Workshop (Rails Pacific 2014)

  • 1. REFACTORING WORKSHOP Bruce Li @ Rails Pacific 2014 Please clone this repo https://github.com/ascendbruce/refactoring-workshop run bundle install and Check your ruby version
  • 2. ABOUT ME • Li, Po-Chun a.k.a. Bruce Li • Work at Techbang • http://ascendbruce.logdown.com/ • @BruceToyRoom, @techbangtech
  • 3. REFACTORING is important • Reduce maintenance cost • Technical debt is not about technology. It’s about people • programmer happiness is very important
  • 4. TEST COVERAGE is important • Confident in changes • Code School, TeaLeaf are good start • SimpleCov and CodeClimate can make you happier while repairing test cases
  • 5. PRY is useful • gem "pry-rails" gem "pry-byebug" # or pry-debugger for ruby 1.9 • binding.pry # to entering debug mode • Commands: next, step, break, continue, exit • It’s all you need at first
  • 6. COMMENTS IN CODE is bad (in some cases) • Ideally, code should describe itself. • Out-dated comments are worser than none. It’s actively misleading. • Comments is helpful for providing additional information or link to issue tracking history.
  • 7. 1. INTENTION REVEALING METHOD • Add comments if code need it. • Transform comments into methods. • Comments are now code. Code describes itself.
  • 15. 2. MOVE MODEL LOGIC INTO THE MODEL • Move the logic, which belongs to model, into the model • instance variable should change to self in model
  • 16. class ProjectsController def new # @#$^$%&#%&*#$%& @project = Project.new ! ! @project.do_ooxx @project.xxoo = "xxoo" # &*%^&@#$! end end class Project ! ! ! ! end def do_something ! ! end
  • 17. class ProjectsController def new # @#$^$%&#%&*#$%& @project = Project.new @project.do_something ! ! # &*%^&@#$! end end class Project ! ! ! ! end def do_something ! ! end @project.do_ooxx @project.xxoo = "xxoo"
  • 18. class ProjectsController def new # @#$^$%&#%&*#$%& @project = Project.new @project.do_something ! ! # &*%^&@#$! end end class Project ! ! ! ! end def do_something ! ! end @project.do_ooxx @project.xxoo = "xxoo"
  • 19. class ProjectsController def new # @#$^$%&#%&*#$%& @project = Project.new @project.do_something do_ooxx self.xxoo = "xxoo" ! ! # &*%^&@#$! end end class Project ! ! ! ! end def do_something ! ! end
  • 20. 3. REPLACE METHOD WITH METHOD OBJECT • Create a class with same initialization arguments as BIG method • Copy & Paste the method's body in the new class, with no arguments • Replace original method with a call to the new class • Apply "Intention Revealing Method" to the class
  • 21. class OriginMethods def a_fat_method ! ! ! ! end end # $%@ + ($@# / ^%) # && ^ %& * #%%^ # wtf # and 100 lines...
  • 22. class NewMethods def perform end end class OriginMethods def a_fat_method ! ! ! ! end end # $%@ + ($@# / ^%) # && ^ %& * #%%^ # wtf # and 100 lines...
  • 23. class NewMethods def perform ! ! ! ! end end # $%@ + ($@# / ^%) # && ^ %& * #%%^ # wtf # and 100 lines... class OriginMethods def a_fat_method ! ! ! ! end end
  • 24. class NewMethods def perform ! ! ! ! end end # $%@ + ($@# / ^%) # && ^ %& * #%%^ # wtf # and 100 lines... class OriginMethods def a_fat_method ! ! ! ! end end NewMethods.new.perform
  • 25. class NewMethods ! ! ! ! def perform File.open(??????????) # ... end end ! class OriginMethods def a_fat_method(file_name) NewMethods.new.perform end end ?
  • 26. class NewMethods ! ! ! ! def perform File.open( ) # ... end end ! class OriginMethods def a_fat_method(file_name) NewMethods.new end end
  • 27. class NewMethods ! ! ! ! def perform File.open( ) # ... end end ! class OriginMethods def a_fat_method(file_name) NewMethods.new end end (file_name).perform
  • 28. class NewMethods ! ! ! ! def perform def initialize(file_name) @file_name = file_name end File.open( ) # ... end end ! class OriginMethods def a_fat_method(file_name) NewMethods.new end end (file_name).perform
  • 29. class NewMethods ! ! ! ! def perform def initialize(file_name) @file_name = file_name end @file_name File.open( ) # ... end end ! class OriginMethods def a_fat_method(file_name) NewMethods.new end end (file_name).perform
  • 30. 4. SERVICE OBJECT • If we add new functionality to an object and: • It couples to a new dependency • It loses cohesion • Testing gets harder and slower
  • 31. 4. SERVICE OBJECT • If it's a domain concept, it's an Object. If it's only an algorithm (no state) we call it a Service. • Delegate to the Service Object
  • 32. 5. FORM OBJECT • accepts_nested_attributes_for is hard to track • Making very different forms for the same object is a pain. The model is messed up
  • 33. 5. FORM OBJECT • include ActiveModel::Model • Set attr_reader for related models • Set attr_accessor for accepted fields • Add validators (ActiveModel::Model will take care of validation and errors) • Define persisted? method (false for create, true for update form) • Add initialize, save, update etc… if needed
  • 34. REFERENCE • Crisp's Blog - Good and Bad Technical Debt • RailsCasts - Form Objects • 7 Patterns to Refactor Fat ActiveRecord Models