refactoring product model
DESCRIPTION
A presentation given in early 2011 at Ruby on Rails Oceania about a conceptual refactoring of legacy code written to handle a reality that didn't eventuate.TRANSCRIPT
![Page 1: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/1.jpg)
Refactoring Legacy CodeLearnings from RedBubblePaul Coia
![Page 2: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/2.jpg)
![Page 3: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/3.jpg)
What is Legacy Code?Untested code
Dead code
Large classes/methods
Spaghetti architecture
Models too rigid to meet new requirements
![Page 4: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/4.jpg)
Product model
![Page 5: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/5.jpg)
Enumeration table
Print Size,Frame Colour,Matte Colour,Frame Style
Small, Medium,Large,Red,etc.
FramedPrint
![Page 6: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/6.jpg)
Enumeration tableEasy to add new products or options
No new columns, just insert rowsNo code changes
Can query against it“Find all artworks available on red t-shirts”
Populate web form elements easily
![Page 7: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/7.jpg)
Domain model is in the DBProduct class is a generic type
What about domain logic?
‘Instances’ need a separate set of tables
![Page 8: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/8.jpg)
Buying a product
![Page 9: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/9.jpg)
Preparing the product formframed_print = ProductType.find_by_name(“FramedPrint”)
# Get the Framed Print productfp_product = artwork.products.detect do |p| p.product_type == framed_printendaovs = fp_product.available_option_values
# Group these into the optionsoptions_hash = {}aovs.each do |aov| options_hash[aov.option_value.option] << aov.option_valueend
# Order the option values, so we have S, M, L, etc.# Populate form elements
![Page 10: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/10.jpg)
SQL view1. Load products by artwork_id2. Load available_product_options by
product_id3. Load option_values by option_value_id4. Load options by option_id
![Page 11: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/11.jpg)
Troublesome requirementsSome products have default
optionsT-Shirt default colour and style
Options that are not constrainedCalendar start month
Inter-option constraintsLongsleeve Tee colours
![Page 12: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/12.jpg)
Default optionsFlag on available_product_optionNeed to enforce one default per
option type
Render artwork with default options
![Page 13: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/13.jpg)
Rendering default options
![Page 14: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/14.jpg)
Rendering the defaults# Get the default producttee_product = artwork.get_default_product
aovs = tee_product.available_option_values
defaults = aovs.select {|aov| aov.default? }
# Group these into the options (assuming one per option)options_hash = {}defaults.each do |aov| options_hash[aov.option_value.option] << aov.option_valueend
# Need to validate that we have all required defaults# and only one per option, etc.
![Page 15: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/15.jpg)
SQL view1. Load products by product_id2. Load available_product_options by
product_id3. Load option_values by option_value_id4. Load options by option_id
Same joins as the first example
![Page 16: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/16.jpg)
Rendering lots of products!
![Page 17: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/17.jpg)
Data volumes
Works Products Available Option Values0
50000000
100000000
150000000
200000000
250000000
300000000
350000000
![Page 18: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/18.jpg)
Inter option constraintsRoundneck T-shirts can have all
colours
V-Neck can only have a few
How do you model that in the DB?Do you want to?
![Page 19: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/19.jpg)
Original driverWant to add new products weeklyReally?
Real-world constraintsProduct preparation takes monthsCannot cover all eventualitiesNew products always required new
code anyway
![Page 20: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/20.jpg)
Alternative approachModel product types as classesDefine options and constraints
(DSL)
Available products is a list of keys on Artwork
Available product options is a hash on the ArtworkSo is the default options
![Page 21: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/21.jpg)
Product classclass TShirtProduct option Style, "mens", "T-Shirt" option Style, "vneck", "V-Neck T-Shirt" option Style, "longsleeve", "Long Sleeve T-Shirt" option Style, "womens", "Girly Fitted T-Shirt" option Style, "mhoodie", "Hoodie"
option Size, "xs", "XS" option Size, "small", "Small" option Size, "medium", "Medium” ...
AVAILABLE_COLORS = { "mens" => all_colors, "vneck" => [”black”, ”grey”, "navy", "white”] }
end
![Page 22: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/22.jpg)
Database model
![Page 23: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/23.jpg)
What have we gained?An expressive, flexible product
modelSimpler code, overallActually easier to add products nowAnd easier to modify existing ones
Nearly 25% average speed increase
![Page 24: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/24.jpg)
What have we lost?“Find all red t-shirts”Utilise a search engine
“How many large framed prints have we sold?”Reporting via Data Warehouse
Online product addition
100s of millions of rows from the DB!
![Page 25: Refactoring product model](https://reader033.vdocuments.us/reader033/viewer/2022061301/548eaa45b4795939218b48f3/html5/thumbnails/25.jpg)