SlideShare a Scribd company logo
1 of 25
Refactoring Legacy
Code
Learnings from RedBubble
Paul Coia
What is Legacy Code?
Untested code
Dead code
Large classes/methods
Spaghetti architecture
Models too rigid to meet new
requirements
Product model
Available Option
Value
Product Type
Enumeration table
Product
Artwork
OptionOption Value
Print Size,
Frame Colour,
Matte Colour,
Frame Style
Small,
Medium,
Large,
Red,
etc.
FramedPrint
Enumeration table
Easy to add new products or options
 No new columns, just insert rows
No code changes
Can query against it
 “Find all artworks available on red t-shirts”
Populate web form elements easily
Domain model is in the DB
Product class is a generic type
What about domain logic?
„Instances‟ need a separate set of
tables
Buying a product
OptionOption Value
Available Option
Value
Product
Artwork
Product Type
Selected
Product
Selected
Option Value
Preparing the product form
framed_print = ProductType.find_by_name(“FramedPrint”)
# Get the Framed Print product
fp_product = artwork.products.detect do |p|
p.product_type == framed_print
end
aovs = fp_product.available_option_values
# Group these into the options
options_hash = {}
aovs.each do |aov|
options_hash[aov.option_value.option] << aov.option_value
end
# Order the option values, so we have S, M, L, etc.
# Populate form elements
SQL view
1. Load products by artwork_id
2. Load available_product_options by
product_id
3. Load option_values by option_value_id
4. Load options by option_id
Troublesome requirements
Some products have default
options
T-Shirt default colour and style
Options that are not constrained
Calendar start month
Inter-option constraints
Longsleeve Tee colours
Default options
Flag on available_product_option
Need to enforce one default per
option type
Render artwork with default
options
Rendering default options
Rendering the defaults
# Get the default product
tee_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_value
end
# Need to validate that we have all required defaults
# and only one per option, etc.
SQL view
1. Load products by product_id
2. Load available_product_options by
product_id
3. Load option_values by option_value_id
4. Load options by option_id
 Same joins as the first example
Rendering lots of products!
Data volumes
0
50
100
150
200
250
300
350
Works Products Available Option Values
Millions
Inter option constraints
Roundneck 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?
Original driver
Want to add new products weekly
Really?
Real-world constraints
Product preparation takes months
Cannot cover all eventualities
New products always required new
code anyway
Alternative approach
Model product types as classes
Define options and constraints (DSL)
Available products is a list of keys
on Artwork
Available product options is a hash
on the Artwork
So is the default options
Product class
class 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
Database model
Artwork
What have we gained?
An expressive, flexible product
model
Simpler code, overall
Actually easier to add products now
And easier to modify existing ones
Nearly 25% average speed increase
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!
Refactoring product model

More Related Content

Viewers also liked (6)

Session hijacking
Session hijackingSession hijacking
Session hijacking
 
Donors profiling softlab
Donors profiling softlabDonors profiling softlab
Donors profiling softlab
 
Binary tree
Binary treeBinary tree
Binary tree
 
วิชาคอมพรีเซ็นเรื่อง วิวัฒนาการอินเตอร์เน็ตของโลก
วิชาคอมพรีเซ็นเรื่อง วิวัฒนาการอินเตอร์เน็ตของโลกวิชาคอมพรีเซ็นเรื่อง วิวัฒนาการอินเตอร์เน็ตของโลก
วิชาคอมพรีเซ็นเรื่อง วิวัฒนาการอินเตอร์เน็ตของโลก
 
Competencia liderazgo
Competencia liderazgoCompetencia liderazgo
Competencia liderazgo
 
Cloud computing and business impact
Cloud computing and business impactCloud computing and business impact
Cloud computing and business impact
 

Similar to Refactoring product model

BUSI 301 Book Review RubricScoreCommentsResearch 25.docx
BUSI 301 Book Review RubricScoreCommentsResearch 25.docxBUSI 301 Book Review RubricScoreCommentsResearch 25.docx
BUSI 301 Book Review RubricScoreCommentsResearch 25.docx
humphrieskalyn
 

Similar to Refactoring product model (20)

Le Wagon Tokyo | Build your Landing Page in 2 hours
Le Wagon Tokyo | Build your Landing Page in 2 hoursLe Wagon Tokyo | Build your Landing Page in 2 hours
Le Wagon Tokyo | Build your Landing Page in 2 hours
 
Le Wagon - 2h Landing
Le Wagon - 2h LandingLe Wagon - 2h Landing
Le Wagon - 2h Landing
 
Physical Design and Development
Physical Design and DevelopmentPhysical Design and Development
Physical Design and Development
 
Retail referencearchitecture productcatalog
Retail referencearchitecture productcatalogRetail referencearchitecture productcatalog
Retail referencearchitecture productcatalog
 
Sww 2008 Automating Your Designs Excel, Vba And Beyond
Sww 2008   Automating Your Designs   Excel, Vba And BeyondSww 2008   Automating Your Designs   Excel, Vba And Beyond
Sww 2008 Automating Your Designs Excel, Vba And Beyond
 
2018 03 27_biological_databases_part4_v_upload
2018 03 27_biological_databases_part4_v_upload2018 03 27_biological_databases_part4_v_upload
2018 03 27_biological_databases_part4_v_upload
 
Html css
Html cssHtml css
Html css
 
Introduction to Advanced Product Options
 Introduction to Advanced Product Options  Introduction to Advanced Product Options
Introduction to Advanced Product Options
 
BUSI 301 Book Review RubricScoreCommentsResearch 25.docx
BUSI 301 Book Review RubricScoreCommentsResearch 25.docxBUSI 301 Book Review RubricScoreCommentsResearch 25.docx
BUSI 301 Book Review RubricScoreCommentsResearch 25.docx
 
Le Wagon - Build your Landing Page in 2 hours
Le Wagon - Build your Landing Page in 2 hoursLe Wagon - Build your Landing Page in 2 hours
Le Wagon - Build your Landing Page in 2 hours
 
Customized Retail audit
Customized Retail auditCustomized Retail audit
Customized Retail audit
 
Le Wagon - Landing page
Le Wagon - Landing pageLe Wagon - Landing page
Le Wagon - Landing page
 
Building Sustainable Design Systems
Building Sustainable Design SystemsBuilding Sustainable Design Systems
Building Sustainable Design Systems
 
Handout7 html forms
Handout7 html formsHandout7 html forms
Handout7 html forms
 
AI Builder Deep Dive Power BI User Group Washington DC
AI Builder Deep Dive Power BI User Group Washington DCAI Builder Deep Dive Power BI User Group Washington DC
AI Builder Deep Dive Power BI User Group Washington DC
 
AI Builder Deep Dive
AI Builder Deep DiveAI Builder Deep Dive
AI Builder Deep Dive
 
Boosting Product Categorization with Machine Learning
Boosting Product Categorization with Machine LearningBoosting Product Categorization with Machine Learning
Boosting Product Categorization with Machine Learning
 
Le Wagon Tokyo - 2 hours landing page
Le Wagon Tokyo - 2 hours  landing pageLe Wagon Tokyo - 2 hours  landing page
Le Wagon Tokyo - 2 hours landing page
 
AI Builder Deep dive Super Power Saturday London 2020
AI Builder Deep dive Super Power Saturday London 2020AI Builder Deep dive Super Power Saturday London 2020
AI Builder Deep dive Super Power Saturday London 2020
 
Html 5
Html 5Html 5
Html 5
 

Recently uploaded

Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
UXDXConf
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
FIDO Alliance
 

Recently uploaded (20)

Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
 
ADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptx
 
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
AI mind or machine power point presentation
AI mind or machine power point presentationAI mind or machine power point presentation
AI mind or machine power point presentation
 
ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage Intacct
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!State of the Smart Building Startup Landscape 2024!
State of the Smart Building Startup Landscape 2024!
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Overview of Hyperledger Foundation
Overview of Hyperledger FoundationOverview of Hyperledger Foundation
Overview of Hyperledger Foundation
 
Using IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandUsing IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & Ireland
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptx
 
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfIntroduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
 
Long journey of Ruby Standard library at RubyKaigi 2024
Long journey of Ruby Standard library at RubyKaigi 2024Long journey of Ruby Standard library at RubyKaigi 2024
Long journey of Ruby Standard library at RubyKaigi 2024
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 

Refactoring product model

  • 2.
  • 3. What is Legacy Code? Untested code Dead code Large classes/methods Spaghetti architecture Models too rigid to meet new requirements
  • 5. Available Option Value Product Type Enumeration table Product Artwork OptionOption Value Print Size, Frame Colour, Matte Colour, Frame Style Small, Medium, Large, Red, etc. FramedPrint
  • 6. Enumeration table Easy to add new products or options  No new columns, just insert rows No code changes Can query against it  “Find all artworks available on red t-shirts” Populate web form elements easily
  • 7. Domain model is in the DB Product class is a generic type What about domain logic? „Instances‟ need a separate set of tables
  • 8. Buying a product OptionOption Value Available Option Value Product Artwork Product Type Selected Product Selected Option Value
  • 9. Preparing the product form framed_print = ProductType.find_by_name(“FramedPrint”) # Get the Framed Print product fp_product = artwork.products.detect do |p| p.product_type == framed_print end aovs = fp_product.available_option_values # Group these into the options options_hash = {} aovs.each do |aov| options_hash[aov.option_value.option] << aov.option_value end # Order the option values, so we have S, M, L, etc. # Populate form elements
  • 10. SQL view 1. Load products by artwork_id 2. Load available_product_options by product_id 3. Load option_values by option_value_id 4. Load options by option_id
  • 11. Troublesome requirements Some products have default options T-Shirt default colour and style Options that are not constrained Calendar start month Inter-option constraints Longsleeve Tee colours
  • 12. Default options Flag on available_product_option Need to enforce one default per option type Render artwork with default options
  • 14. Rendering the defaults # Get the default product tee_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_value end # Need to validate that we have all required defaults # and only one per option, etc.
  • 15. SQL view 1. Load products by product_id 2. Load available_product_options by product_id 3. Load option_values by option_value_id 4. Load options by option_id  Same joins as the first example
  • 16. Rendering lots of products!
  • 18. Inter option constraints Roundneck 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?
  • 19. Original driver Want to add new products weekly Really? Real-world constraints Product preparation takes months Cannot cover all eventualities New products always required new code anyway
  • 20. Alternative approach Model product types as classes Define options and constraints (DSL) Available products is a list of keys on Artwork Available product options is a hash on the Artwork So is the default options
  • 21. Product class class 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
  • 23. What have we gained? An expressive, flexible product model Simpler code, overall Actually easier to add products now And easier to modify existing ones Nearly 25% average speed increase
  • 24. 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!

Editor's Notes

  1. Legacy code slows down feature developmentWe all write itSo there’s a lot around
  2. Need to determine what the product represents before we can do anything with it.For example, we need to render it differently
  3. Joining 4 tables together
  4. Each thumbnail requires the same 4 tables joined
  5. Each work has multiple products, and each has multiple available options
  6. In 4 years, RedBubble has 11 product types.Sourcing suppliers, defining the specifications and getting samples all was time consuming.The application needed to know how to provision, configure and render the product.Genericity ended up getting in the way.
  7. Selected options and defaults are on the artworkOptions are modelled in a code (DSL)Rendering a default view requires only the loading of one record
  8. Every line of code had a reason for existenceChallenge existing models for every new requirement