• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Restructuring rails
 

Restructuring rails

on

  • 516 views

 

Statistics

Views

Total Views
516
Views on SlideShare
506
Embed Views
10

Actions

Likes
0
Downloads
1
Comments
0

1 Embed 10

https://twitter.com 10

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Restructuring rails Restructuring rails Presentation Transcript

    • 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!