SlideShare a Scribd company logo
1 of 33
Download to read offline
Restructuring Rails
Eric Marthinsen
CTO and Founder, Agile Commerce
A Refactoring Story
Overview
•CTO and Founder of Agile
Commerce.
•Part of team that bought Sortfolio
from 37signals in 2012.
•Have been enhancing it for about a
year.
How was
their code?
Rule
Stable code running a
profitable company is
always successful code.
However
•Sortfolio was a successful MVP.
•37signals’ testing philosophy differs
from my own.
•Rails 2.3.8
•Needed some work to prepare for
new features.
Refactoring Result
•Improved from a CodeClimate
score of 2.78 to 3.51.
•Drastically improved test coverage,
while decreasing test run time.
•Doubled, roughly, our development
velocity.
Today’s Objective
Share the principles I used to
improve the Sortfolio codebase in a
way that you can apply these
principles to your own projects.
Reduce callbacks
Embrace CSS3
Inline concerns
Add decorators
STI
Create services
Create gateways
Custom presenters
DRY
Config to ENV
ElasticSearch
Method extraction
Fewer static methods
Extract class
Extract Class
Benefits
•Better domain model
•Easier comprehension
•More granular tests
•Faster tests
•More hooks for mocking
•Overall, better software
My Thesis
I believe that having classes with too
many responsibilities is the primary
cause of poor object-oriented code.
This is true of any object-oriented
platform, but doubly true of Rails.
Why Doubly True?
•ActiveRecord combines data and
business layers.
•View code often leaks into models
and controllers.
•Helpers are dumping grounds for
procedural code.
•Rails conventions support
overburdened objects.
“Fat model,
skinny controller”
Wrong - everything
should be skinny.
Example: Search
Step 0: Start
class Listing < ActiveRecord::Base
# associations
# validations
def self.get_pro_listings(location_id, budget_id, start, offset)
# lots of code
end
def self.get_free_listings(location_id, budget_id, start, offset)
# lots of similar code
end
end
Object-Orientation
•An object is data and the methods
that operate on that data.
•An object should represent a single
thing.
•A class defines the type of the
object.
Problems
•Why does a listing know how to
find its peers?
•We’re attaching collection methods
to a type declaration.
•A domain concept is being hidden.
Step 1
class Listing < ActiveRecord::Base
# associations
# validations
end
class ListingIndex
def self.get_pro_listings(location_id, budget_id, start, offset)
# lots of code
end
def self.get_free_listings(location_id, budget_id, start, offset)
# lots of similar code
end
end
Progress
•Now expressing the collection of
Listings in the domain model.
•Creating a “preferred” interface.
•But, not DRY, and two domain
concepts remain unexpressed.
Step 2
class Listing < ActiveRecord::Base
# associations
# validations
end
class ListingIndex
def self.get_listings(is_pro, location_id, budget_id, start, offset)
# lots of code
end
end
Progress
•ListingIndex is now DRY
•Still a couple domain concepts
hidden in there.
•Adding arguments is not scalable.
Step 3
class Listing < ActiveRecord::Base
# associations
# validations
end
class ListingIndex
def self.search(query)
# less code
end
end
class ListingQuery
def initialize(options)
# set properties
end
end
Progress
•We’ve teased out another domain
concept.
•Queries are now scalable and easy
to augment.
•ListingIndex has an intuitive
#search method.
•Still one domain concept hiding in
there.
Step 4
class ListingIndex
def self.search(query)
# less code
end
end
class ListingQuery
def initialize(options)
# set properties
end
end
class ListingResults
# mostly attrs
end
Progress
•Results are now expressed in the
domain model.
•Big improvements to other areas of
the code.
•Set up for success and making big
changes behind a stable interface.
Step 5: Final
class ListingIndex
def self.search(query)
# less code
end
def self.add_listing(listing)
# trivial
end
def self.remove_listing(listing)
# trivial
end
end
class ListingQuery
# no change
end
class ListingResults
# mostly attrs
end
Results
•Listing was split into Listing,
ListingIndex, ListingQuery, and
ListingResults.
•Better design allowed for trivial
introduction of ElasticSearch.
•Much easier and faster to test.
Takeaways
Your app probably
has fewer classes
than it should.
It’s easier to
combine classes
than to separate
them.
Models don’t need
to inherit from
ActiveRecord::Base
Conventions don’t
always apply.
More Info
Eric Marthinsen
emarthinsen@agilecommerce.com
www.agilecommerce.com/blog
@agilecommerce
@ericmarthinsen
THANKS!

More Related Content

Similar to Restructuring Rails Code for Scalability and Maintainability

Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing SoftwareSteven Smith
 
Art of refactoring - Code Smells and Microservices Antipatterns
Art of refactoring - Code Smells and Microservices AntipatternsArt of refactoring - Code Smells and Microservices Antipatterns
Art of refactoring - Code Smells and Microservices AntipatternsEl Mahdi Benzekri
 
Improving the Quality of Existing Software - DevIntersection April 2016
Improving the Quality of Existing Software - DevIntersection April 2016Improving the Quality of Existing Software - DevIntersection April 2016
Improving the Quality of Existing Software - DevIntersection April 2016Steven Smith
 
Refactoring to SOLID Code
Refactoring to SOLID CodeRefactoring to SOLID Code
Refactoring to SOLID CodeAdil Mughal
 
Using Compass to Diagnose Performance Problems
Using Compass to Diagnose Performance Problems Using Compass to Diagnose Performance Problems
Using Compass to Diagnose Performance Problems MongoDB
 
Using Compass to Diagnose Performance Problems in Your Cluster
Using Compass to Diagnose Performance Problems in Your ClusterUsing Compass to Diagnose Performance Problems in Your Cluster
Using Compass to Diagnose Performance Problems in Your ClusterMongoDB
 
Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing SoftwareSteven Smith
 
Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)Shirish Bari
 
Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing SoftwareSteven Smith
 
Improving The Quality of Existing Software
Improving The Quality of Existing SoftwareImproving The Quality of Existing Software
Improving The Quality of Existing SoftwareSteven Smith
 
Application Architecture April 2014
Application Architecture April 2014Application Architecture April 2014
Application Architecture April 2014Lars-Erik Kindblad
 
Building rich domain models with ddd and tdd ivan paulovich - betsson
Building rich domain models with ddd and tdd   ivan paulovich - betssonBuilding rich domain models with ddd and tdd   ivan paulovich - betsson
Building rich domain models with ddd and tdd ivan paulovich - betssonIvan Paulovich
 
Episode 3 – Classes, Inheritance, Abstract Class, and Interfaces
Episode 3 – Classes, Inheritance, Abstract Class, and InterfacesEpisode 3 – Classes, Inheritance, Abstract Class, and Interfaces
Episode 3 – Classes, Inheritance, Abstract Class, and InterfacesJitendra Zaa
 
Prashant technical practices-tdd for xebia event
Prashant   technical practices-tdd for xebia eventPrashant   technical practices-tdd for xebia event
Prashant technical practices-tdd for xebia eventXebia India
 
Migration strategies 4
Migration strategies 4Migration strategies 4
Migration strategies 4Wenhua Wang
 
Boosting the Performance of your Rails Apps
Boosting the Performance of your Rails AppsBoosting the Performance of your Rails Apps
Boosting the Performance of your Rails AppsMatt Kuklinski
 

Similar to Restructuring Rails Code for Scalability and Maintainability (20)

Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing Software
 
Art of refactoring - Code Smells and Microservices Antipatterns
Art of refactoring - Code Smells and Microservices AntipatternsArt of refactoring - Code Smells and Microservices Antipatterns
Art of refactoring - Code Smells and Microservices Antipatterns
 
Improving the Quality of Existing Software - DevIntersection April 2016
Improving the Quality of Existing Software - DevIntersection April 2016Improving the Quality of Existing Software - DevIntersection April 2016
Improving the Quality of Existing Software - DevIntersection April 2016
 
Refactoring to SOLID Code
Refactoring to SOLID CodeRefactoring to SOLID Code
Refactoring to SOLID Code
 
Using Compass to Diagnose Performance Problems
Using Compass to Diagnose Performance Problems Using Compass to Diagnose Performance Problems
Using Compass to Diagnose Performance Problems
 
Using Compass to Diagnose Performance Problems in Your Cluster
Using Compass to Diagnose Performance Problems in Your ClusterUsing Compass to Diagnose Performance Problems in Your Cluster
Using Compass to Diagnose Performance Problems in Your Cluster
 
Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing Software
 
Application Architecture
Application ArchitectureApplication Architecture
Application Architecture
 
Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)
 
Improving the Quality of Existing Software
Improving the Quality of Existing SoftwareImproving the Quality of Existing Software
Improving the Quality of Existing Software
 
Improving The Quality of Existing Software
Improving The Quality of Existing SoftwareImproving The Quality of Existing Software
Improving The Quality of Existing Software
 
Application Architecture April 2014
Application Architecture April 2014Application Architecture April 2014
Application Architecture April 2014
 
Building rich domain models with ddd and tdd ivan paulovich - betsson
Building rich domain models with ddd and tdd   ivan paulovich - betssonBuilding rich domain models with ddd and tdd   ivan paulovich - betsson
Building rich domain models with ddd and tdd ivan paulovich - betsson
 
Design p atterns
Design p atternsDesign p atterns
Design p atterns
 
Bdd with m spec
Bdd with m specBdd with m spec
Bdd with m spec
 
Episode 3 – Classes, Inheritance, Abstract Class, and Interfaces
Episode 3 – Classes, Inheritance, Abstract Class, and InterfacesEpisode 3 – Classes, Inheritance, Abstract Class, and Interfaces
Episode 3 – Classes, Inheritance, Abstract Class, and Interfaces
 
SDWest2005Goetsch
SDWest2005GoetschSDWest2005Goetsch
SDWest2005Goetsch
 
Prashant technical practices-tdd for xebia event
Prashant   technical practices-tdd for xebia eventPrashant   technical practices-tdd for xebia event
Prashant technical practices-tdd for xebia event
 
Migration strategies 4
Migration strategies 4Migration strategies 4
Migration strategies 4
 
Boosting the Performance of your Rails Apps
Boosting the Performance of your Rails AppsBoosting the Performance of your Rails Apps
Boosting the Performance of your Rails Apps
 

Recently uploaded

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 

Recently uploaded (20)

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 

Restructuring Rails Code for Scalability and Maintainability