SlideShare a Scribd company logo
1 of 63
OLD CODE DOESN'T STINK
Refactor or Rewrite
Martin Gutenbrunner
FORD FIELD, DETROIT – OCT 16, 2018
DEVELOPER AND OPS CONFERENCE
ABOUT ME
Interested in Software and Hardware.
Started coding at 14
Programmer, team lead, software architect, operator,
administrator
In pursuit of the right way to build software
Passionate about technology, and much more about the
people he's working with
Find me on Twitter: @MartinGoodwell
Considers himself a lucky guy
THIS WILL BE LIKE
• James Camerson's Avatar
• at least 50% of it is "heavily inspired by others"
• A river runs through it, feat Brad Pitt and Tom Skerrit
• the other 50% is real-life experience
• The Walking Dead
• we'll have a Walker
• Real-life Example: Classic ASP, 15 years later
• The basics – aka "Mastering the craft"
• The Magic Sauce. The Kool Aid. Mr Miyagi's ultimate wisdom.
Yes or no?
Refactor or Rewrite?
WHAT A REAL REWRITE REALLY MEANS
• Netscape Navigator 6 goes public beta in Nov 2000
• last major release (4.0) released almost 3 years ago (there was no v5)
• " During this time, Netscape sat by, helplessly, as their market share
plummeted. "
SAME MISTAKES
• Borland  Arago  dBase for Windows
• Microsoft Access ate their lunch
• then they made the same mistake again in rewriting Quattro Pro from scratch
and astonishing people with how few features it had.
• Microsoft  Pyramid  Word for Windows from scratch
• Lucky for Microsoft, they had never stopped working on the old code base, so
they had something to ship, making it merely a financial disaster, not a
strategic one.
WHY?
It’s harder to read code than to write it.
- Joel Spolsky
https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/
What is usually wrong?
• Architectural problems
• Even fairly major architectural changes can be done without throwing away
the code. By just moving things around, cleaning them up, creating base
classes that made sense, and creating sharp interfaces between the modules.
• Because it's inefficient
• When optimizing for speed, 1% of the work gets you 99% of the bang
• The code is doggone ugly
• One project I worked on actually had a data type called a FuckedString
• So half the functions started with “_” and half with “m_”, which looked ugly.
• This is the kind of thing you solve in five minutes with a macro in Emacs, not
by starting from scratch.
When to Rewrite?
• Is your code closely tied to a certain lifecycle / framework?
• eg Reactive, Mobile Apps, ...
• No one can maintain the existing code
• obsolete technology
• everyone's scared by just thinking about touching the code
• Always ask yourself: does this need to be a full rewrite?
MAKE or BUY?
• Make the parts that make your solution unique
• "Buy" the parts that are common
Online Shop, written in ASP, rendering XHTML
Back then, in development for 15 years
EXAMPLE: classic ASP
PROJECT SETUP
• Use-case: eCommerce
• close connection to a business backend system
• Native Windows desktop application, connected to database
• Core: classic ASP
• Database: Pervasive SQL
• the actual database from the business backend
• Interfaces to
• MSMQ for sending orders to the business backend
• COM+ for querying prices from the business backend
OLD ARCHITECTURE
ASP UI
XHTML
Business
Backend
System
SQL-DB
MSMQ
(Orders)
COM+
(Prices)
Browser
(XHTML)
~ 1999
WE WANTED TO REWRITE. WHY?
• 15 year old VB-Script codebase
• lack of structure
• hard to find VB-Script talent
• not up to today's standards (eg Unit Testing)
• Too closely bound to the business backend system
• Major updates of the system locked the database and stalled the online shop
CUSTOM BRANCHING
<%
if nCategoryId = 0 and (hostInfo.Path = "clayshop" or hostInfo.Path="bikershop" or hostInfo.Path="steelshop") then
out GetPageHTML(1,"de")
end if
%>
• Individual code branches for most tenants (~30 of them)
• If a tenant canceled his contract, the codebase usually was not
cleaned
RENDERING WHILE ITERATING RECORDSET
<%
set rsProd= oProduct.GetProduct(CLng(nProductId), CLng(nTenantId))
if not rsProd.eof then %>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr><td><img height="20" width="3" src="../../layout/pic/pix_tr.gif" border="0"></td></tr>
<tr><td class="productheadcolor">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="productheadiconcolor"><img height="20" width="20" src="../../layout/pic/icons/icon_kl_produkttip.gif" border="0"></td>
<td><div class="productheadcolor">&nbsp;<%= getText("product") %>:</div></td>
</tr>
</table>
<% if (sTenantPath <> "that_special_shop") then DrawProducts rsProd, "productreplacement" end if %>
<% end if
rsProd.close
set rsProd= nothing
%>
• No separation between data-access, business logic, and UI
• Made it hard to see what really needs refactoring
OUR PLAN WAS
• 100% re-write in Java
• Create a separate database for the eCommerce part
• Move all tenants to the new codebase within six months
PLANNED ARCHITECTURE
Business
Backend
SystemSQL
DB
MSMQ
(Orders)
COM+
(Prices)
Importer
Java
Spring MVC
MongoD
B
Browser
(HTML5)
~ 2012
LEARNINGS
• 100% re-write in Java not possible
• no stable Java libraries for MSMQ and COM+ at the time
• Planned timeframe (of course) didn't work
• first tenant went online after 9 months
• but it was using the new UI
• (so, the old solution was still running in production in parallel)
• Re-doing the UI turned out to be the hard part
• we still didn't have all tenants converted after 2,5 years
DONE ARCHITECTURE
ASP
Bridge
Business
Backend
SystemSQL
DB
MSMQ
(Orders)
COM+
(Prices)
Importer
Java
MongoD
B
Browser
(HTML5)
ASP
Backend
Browser
(XHTML)
~ 2014
WHAT WENT WELL?
• Introduction of dedicated DB
• Having a separate Importer component
• We built deployment automation with Jenkins
• The ASP-bridge turned out to work really well
WHAT WE SHOULD HAVE DONE
• Identify the UI-part as the real problem
• impossible to see due to non-layered codebase
• Embrace the fact that we have a huge number of customers on the
"old" codebase and design the new system for multiple UI
technologies
• EOL the old codebase
• If customers want new features, migrate them over
• Not a full rewrite
INTRODUCING BFF
• BFF
• Backend-for-Frontend
• aka Edge-Service
• source: Sam Newman's Microservice book
• can be used for
• routing
• authentication
• filtering
BETTER ARCHITECTURE
Java
Backend
API-only
Browser
(HTML5)
Browser
(XHTML)
BFF
ASP
BFF
Spring MVC
Android
(JSON)
BFF
Node.js
iOS
(JSON)
MongoDB
ASP-bridge
BENEFITS OF DOING IT RIGHT
• Save months of efforts, porting the messy UI code
• Have ASP UI benefit from separate database
• Only have a single touchpoint with the business backend system
• for any client
• XHTML rendered by ASP
• HTML5 rendered by Spring MVC
• potential mobile apps
IT MIGHT SMELL, THOUGH.
MASTERING THE CRAFT
OLD CODE DOESN'T STINK
HOW CAN THAT EVEN HAPPEN?
• Bounded contexts
• Things built in-house that would have been readily available
• a lot of the mess happens in boilerplate
• Code that's not testable
• Code that's not clearly/properly structured
• Harder to read than to write, remember?
• Bugs due to premature optimization
• YAGNI – You aren't gonna need it
• I think we tought that we'll need this for that feature that's coming up.
BOUNDED CONTEXTS
Don't mix things that don't belong together
• Do you see what's wrong with the "UserAccount" table?
BOUNDED CONTEXTS
Wrong: sharing DTOs between different domains
Some services use same attributes, some use specific ones
CatalogService
ShoppingCart
Service
OrderService
ProductDto
* id
* name
* description
* userRatings
* imageUrls
* price
* vat
* quantity
BOUNDED CONTEXTS
Right: dedicated DTOs for each domain
but smells like duplication a lot, because of the names
better: each DTO only contains the attributes it needs
CatalogService
ShoppingCart
Service
OrderService
CatalogProductDto
* id
* name
* description
* userRatings
* imageUrls
* price
CartProductDto
* id
* name
* price
* quantity
OrderProductDto
* id
* name
* price
* vat
* quantity
BOUNDED CONTEXTS
Same DTOs, but different names. Much better fit to the domain.
CatalogService
ShoppingCart
Service
OrderService
ProductDto
* id
* name
* description
* userRatings
* imageUrls
* price
CartEntryDto
* id
* name
* price
* quantity
LineItemDto
* id
* name
* price
* vat
* quantity
NOT INVENTED HERE
• Focus on business logic
• and separate it from boilerplate
• Don't build what you don't need to
• Queues
• Connection Pools
• Anything you build needs to be maintained.
• The only thing you'd want to maintain is business logic.
CODE DUPLICATION
CODE DUPLICATION
Wrong: use inheritance for saving number of attributes in classes
abstract class MasterPojo {
protected int id;
}
public class AnyPojo extends MasterPojo {
...
}
public class AnyOtherPojo extends MasterPojo {
...
}
CODE DUPLICATION
Right: don't mix unrelated objects
public class AnyPojo {
private int id;
}
public class AnyOtherPojo {
private int id;
}
CODE DUPLICATION
Code duplication really means that any code that makes decisions (eg
IF, loops, ...) should not be copy/pasted.
Example:
• We have integrated with MailChimp for sending Emails
• We also want to integrate with other messaging services
• So, we copy the code from our MailChimp integration, paste it into a
new package and just rename the classes and make changes
according to the new 3rd party there.
• Right way: identify common behavior. Have that in base-classes or a
library that can be used by both implementations.
WHY UNIT TESTS?
DESIGN FOR TESTABILITY
• Try to be as atomic as possible (complex objects vs atomic)
• In Java: use package private instead of private
• Have methods do as little as possible
• Methods that do more should just call other methods
TESTABLE CODE
for
if
break condition
boolean condition
public int categorize(Client client, int metric) {
return result;
}
TESTABLE CODE
for
break condition
public int categorize(Client client, int metric) {
return result;
}
boolean cascadedMethod() {
if
}
cascadedMethod()
THINGS TO CONSIDER
• Integers: negative, ranges
• Strings: length, special characters, null, empty, case-sensitive
• Objects:
• all of the above, depending on member variables datatypes
TESTING CODE
A code tester walks into a bar.
Orders a beer.
Orders 2.15 billion beers.
Orders -1 beers.
Orders äüöß beers.
Orders a nothing.
Orders a cat.
Tries to leave without paying.
TESTABLE CODE
• every IF in a method requires a test for every branch
• that's why code inside blocks should go into a separate method
• allows to test that method independently
• any possible input parameters require a test
• any possible return values require a test
• the smaller your classes, the smaller your methods, the easier it is to
maintain test code
• the amount of test code can easily be equal to your "real" code
• any method should be testable independently
TESTABLE CODE
• Some relationships are hard to test.
public int calcIt(int a, int b) {
int one = CalcUtil.calcIt(a,b);
int result = doSomethingElse(one);
return result;
}
TESTABLE CODE
• Some relationships are hard to test.
public int calcIt(int a, int b) {
int one = CalcUtil.getInstance().calcIt(a,b);
int result = doSomethingElse(one);
return result;
}
TESTABLE CODE
• Any dependencies to other classes should be easy to change.
private CalcUtil calcUtil = CalcUtil.getInstance();
public int calcIt(int a, int b) {
int one = calcUtil.calcIt(a,b);
int result = doSomethingElse(one);
return result;
}
void setCalcUtil(CalcUtil calcUtil) {
this.calcUtil = calcUtil;
}
READABLE CODE
• Be as descriptive in your code as possible
public class Walker {
public int moveAround(int position, int angle) {
if (angle > 0 && angle < 180) { //go left
...
}
...
}
}
READABLE CODE
• Be as descriptive in your code as possible
public class Walker {
public int moveAround(int position, int angle) {
boolean goLeft = angle > 0 && angle < 180;
if (goLeft) {
...
}
...
}
}
READABLE AND TESTABLE CODE
• Be as descriptive in your code as possible
public class Walker {
public int moveAround(int a, int b) {
boolean goLeft = shouldGoLeft(a,b);
if (goLeft) {
...
}
}
boolean shouldGoLeft(int a, int b) {
return angle > 0 && angle < 180;
}
}
MEANINGFUL DOCUMENTATION
• Class-level comments to give context.
/**
* This is the entry class. You'll find most
* interesting entrypoints here.
* @see: ThatOther.class
*/
public class Lala {
}
MISSING INTEGRATION TESTS
AGAIN, NO INTEGRATION TEST DONE
PREMATURE OPTIMIZATION
• "Because we need the performance"
• We need to implement it in "D"
• Do everything in Stored Procedures (even simple CRUDs)
• You need to declare that variable outside of the loop to reduce the load on
the GC
• Specialize first, generalize later
• "I think we thought that we will need that for one of the screens."
• Release often
• finish one feature  release it  get feedback  improve it
• The IT-world has changed. It's not about CPU-cycles anymore
• It's about codebases that can scale to a large number of programmers.
READ
• Find all this and lots more here:
• Clean Code, by
• Robert C. Martin
READ
• Find all this and lots more here:
• Growing Object-Oriented Software,
guided by Tests, by
• Steve Freeman, Nat Pryce
CAN WE USE SOME OF THAT FOR MOBILE OR DESKTOP?
THE PROPER MONOLITH
LAYERS
• One artifact per business domain
• 3-tiered architecture inside of each artifact
• Sharing of interfaces by means of –api artifacts
• No shared database schemas between domains
PROPER MONOLITH
.war file
catalog.jar cart.jar billing.jar order.jar
Controllers
Physical Database
Catalog
DB
Cart
DB
Billing
DB
Order
DB
catalog-api.jar cart-api.jar billing-api.jar order-api.jar
TOOLS THAT HELP
• Black Duck
• Sonar
HOW TO DO IT RIGHT FROM NOW ON?
THE ULTIMATE TRUTH
• Master the craft of programming
• Avoid the mess
• Bounded Contexts
• domain-driven thinking and architecture
FORD FIELD, DETROIT – OCT 16, 2018
DEVELOPER AND OPS CONFERENCE

More Related Content

What's hot

Usability in the GeoWeb
Usability in the GeoWebUsability in the GeoWeb
Usability in the GeoWeb
Dave Bouwman
 
Web Standards And Protocols
Web Standards And ProtocolsWeb Standards And Protocols
Web Standards And Protocols
Steven Cahill
 
High Performance JavaScript (CapitolJS 2011)
High Performance JavaScript (CapitolJS 2011)High Performance JavaScript (CapitolJS 2011)
High Performance JavaScript (CapitolJS 2011)
Nicholas Zakas
 

What's hot (18)

Don't make me wait! or Building High-Performance Web Applications
Don't make me wait! or Building High-Performance Web ApplicationsDon't make me wait! or Building High-Performance Web Applications
Don't make me wait! or Building High-Performance Web Applications
 
Edge of the Web
Edge of the WebEdge of the Web
Edge of the Web
 
Web Standards
Web StandardsWeb Standards
Web Standards
 
plumbing for the next web
plumbing for the next webplumbing for the next web
plumbing for the next web
 
Seven Reasons for Code Bloat
Seven Reasons for Code BloatSeven Reasons for Code Bloat
Seven Reasons for Code Bloat
 
Usability in the GeoWeb
Usability in the GeoWebUsability in the GeoWeb
Usability in the GeoWeb
 
Mobile applications for SharePoint using HTML5
Mobile applications for SharePoint using HTML5Mobile applications for SharePoint using HTML5
Mobile applications for SharePoint using HTML5
 
HTML5 and the dawn of rich mobile web applications
HTML5 and the dawn of rich mobile web applicationsHTML5 and the dawn of rich mobile web applications
HTML5 and the dawn of rich mobile web applications
 
Dreamweaver CS6, jQuery, PhoneGap, mobile design
Dreamweaver CS6, jQuery, PhoneGap, mobile designDreamweaver CS6, jQuery, PhoneGap, mobile design
Dreamweaver CS6, jQuery, PhoneGap, mobile design
 
20120802 timisoara
20120802 timisoara20120802 timisoara
20120802 timisoara
 
Making HTML5 Work Everywhere
Making HTML5 Work EverywhereMaking HTML5 Work Everywhere
Making HTML5 Work Everywhere
 
Web Standards And Protocols
Web Standards And ProtocolsWeb Standards And Protocols
Web Standards And Protocols
 
API Technical Writing
API Technical WritingAPI Technical Writing
API Technical Writing
 
Aki Salmi - Refactoring legacy code: a true story @ I T.A.K.E. Unconference 2...
Aki Salmi - Refactoring legacy code: a true story @ I T.A.K.E. Unconference 2...Aki Salmi - Refactoring legacy code: a true story @ I T.A.K.E. Unconference 2...
Aki Salmi - Refactoring legacy code: a true story @ I T.A.K.E. Unconference 2...
 
High Performance JavaScript (CapitolJS 2011)
High Performance JavaScript (CapitolJS 2011)High Performance JavaScript (CapitolJS 2011)
High Performance JavaScript (CapitolJS 2011)
 
Everyones invited! Meet accesibility requirements with ColdFusion
Everyones invited! Meet accesibility requirements with ColdFusionEveryones invited! Meet accesibility requirements with ColdFusion
Everyones invited! Meet accesibility requirements with ColdFusion
 
Mobile Web High Performance
Mobile Web High PerformanceMobile Web High Performance
Mobile Web High Performance
 
Web II - 01 - Introduction to server-side development
Web II - 01 - Introduction to server-side developmentWeb II - 01 - Introduction to server-side development
Web II - 01 - Introduction to server-side development
 

Similar to Old code doesn't stink - Detroit

NetWork - 15.10.2011 - Applied code generation in .NET
NetWork - 15.10.2011 - Applied code generation in .NET NetWork - 15.10.2011 - Applied code generation in .NET
NetWork - 15.10.2011 - Applied code generation in .NET
Dmytro Mindra
 
Clean Code Part III - Craftsmanship at SoCal Code Camp
Clean Code Part III - Craftsmanship at SoCal Code CampClean Code Part III - Craftsmanship at SoCal Code Camp
Clean Code Part III - Craftsmanship at SoCal Code Camp
Theo Jungeblut
 

Similar to Old code doesn't stink - Detroit (20)

Old code doesn't stink
Old code doesn't stinkOld code doesn't stink
Old code doesn't stink
 
Building a µservice with Kotlin, Micronaut & GCP
Building a µservice with Kotlin, Micronaut & GCPBuilding a µservice with Kotlin, Micronaut & GCP
Building a µservice with Kotlin, Micronaut & GCP
 
Basic Application Performance Optimization Techniques (Backend)
Basic Application Performance Optimization Techniques (Backend)Basic Application Performance Optimization Techniques (Backend)
Basic Application Performance Optimization Techniques (Backend)
 
Titanium #MDS13
Titanium #MDS13Titanium #MDS13
Titanium #MDS13
 
Why real integration developers ride Camels
Why real integration developers ride CamelsWhy real integration developers ride Camels
Why real integration developers ride Camels
 
Mobile Development Options
Mobile Development OptionsMobile Development Options
Mobile Development Options
 
Single Source of Truth for Network Automation
Single Source of Truth for Network AutomationSingle Source of Truth for Network Automation
Single Source of Truth for Network Automation
 
Writing clean code in C# and .NET
Writing clean code in C# and .NETWriting clean code in C# and .NET
Writing clean code in C# and .NET
 
MongoDB.local Seattle 2019: MongoDB Stitch Tutorial
MongoDB.local Seattle 2019: MongoDB Stitch TutorialMongoDB.local Seattle 2019: MongoDB Stitch Tutorial
MongoDB.local Seattle 2019: MongoDB Stitch Tutorial
 
NoSQL into E-Commerce: lessons learned
NoSQL into E-Commerce: lessons learnedNoSQL into E-Commerce: lessons learned
NoSQL into E-Commerce: lessons learned
 
MongoDB.local Atlanta: MongoDB Stitch Tutorial
MongoDB.local Atlanta: MongoDB Stitch TutorialMongoDB.local Atlanta: MongoDB Stitch Tutorial
MongoDB.local Atlanta: MongoDB Stitch Tutorial
 
NetWork - 15.10.2011 - Applied code generation in .NET
NetWork - 15.10.2011 - Applied code generation in .NET NetWork - 15.10.2011 - Applied code generation in .NET
NetWork - 15.10.2011 - Applied code generation in .NET
 
Coder sans peur du changement avec la meme pas mal hexagonal architecture
Coder sans peur du changement avec la meme pas mal hexagonal architectureCoder sans peur du changement avec la meme pas mal hexagonal architecture
Coder sans peur du changement avec la meme pas mal hexagonal architecture
 
Stapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San FranciscoStapling and patching the web of now - ForwardJS3, San Francisco
Stapling and patching the web of now - ForwardJS3, San Francisco
 
Clean Code Part III - Craftsmanship at SoCal Code Camp
Clean Code Part III - Craftsmanship at SoCal Code CampClean Code Part III - Craftsmanship at SoCal Code Camp
Clean Code Part III - Craftsmanship at SoCal Code Camp
 
Serverless Single Page Apps with React and Redux at ItCamp 2017
Serverless Single Page Apps with React and Redux at ItCamp 2017Serverless Single Page Apps with React and Redux at ItCamp 2017
Serverless Single Page Apps with React and Redux at ItCamp 2017
 
From dev to ops and beyond - getting it done
From dev to ops and beyond - getting it doneFrom dev to ops and beyond - getting it done
From dev to ops and beyond - getting it done
 
Perchè potresti aver bisogno di un database NoSQL anche se non sei Google o F...
Perchè potresti aver bisogno di un database NoSQL anche se non sei Google o F...Perchè potresti aver bisogno di un database NoSQL anche se non sei Google o F...
Perchè potresti aver bisogno di un database NoSQL anche se non sei Google o F...
 
resume
resumeresume
resume
 
MongoDB.local Dallas 2019: MongoDB Stitch Tutorial
MongoDB.local Dallas 2019: MongoDB Stitch TutorialMongoDB.local Dallas 2019: MongoDB Stitch Tutorial
MongoDB.local Dallas 2019: MongoDB Stitch Tutorial
 

More from Martin Gutenbrunner

More from Martin Gutenbrunner (6)

Smart Home - 10 Jahre danach
Smart Home - 10 Jahre danachSmart Home - 10 Jahre danach
Smart Home - 10 Jahre danach
 
DevOne - How to not fail with Azure
DevOne - How to not fail with AzureDevOne - How to not fail with Azure
DevOne - How to not fail with Azure
 
APIs in production - we built it, can we fix it?
APIs in production - we built it, can we fix it?APIs in production - we built it, can we fix it?
APIs in production - we built it, can we fix it?
 
Pushing the hassle from production to developers. Easily
Pushing the hassle from production to developers. EasilyPushing the hassle from production to developers. Easily
Pushing the hassle from production to developers. Easily
 
Monitoring 101 - Leveraging on the power of JMX
Monitoring 101 - Leveraging on the power of JMXMonitoring 101 - Leveraging on the power of JMX
Monitoring 101 - Leveraging on the power of JMX
 
Performance monitoring and call tracing in microservice environments
Performance monitoring and call tracing in microservice environmentsPerformance monitoring and call tracing in microservice environments
Performance monitoring and call tracing in microservice environments
 

Recently uploaded

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Recently uploaded (20)

WSO2Con2024 - Simplified Integration: Unveiling the Latest Features in WSO2 L...
WSO2Con2024 - Simplified Integration: Unveiling the Latest Features in WSO2 L...WSO2Con2024 - Simplified Integration: Unveiling the Latest Features in WSO2 L...
WSO2Con2024 - Simplified Integration: Unveiling the Latest Features in WSO2 L...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid EnvironmentsWSO2Con2024 - Software Delivery in Hybrid Environments
WSO2Con2024 - Software Delivery in Hybrid Environments
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
WSO2CON 2024 - Unlocking the Identity: Embracing CIAM 2.0 for a Competitive A...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public AdministrationWSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
WSO2CON 2024 - How CSI Piemonte Is Apifying the Public Administration
 
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and ApplicationsWSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
 
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of TransformationWSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
WSO2CON 2024 - Designing Event-Driven Enterprises: Stories of Transformation
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next IntegrationWSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
 

Old code doesn't stink - Detroit

  • 1. OLD CODE DOESN'T STINK Refactor or Rewrite Martin Gutenbrunner FORD FIELD, DETROIT – OCT 16, 2018 DEVELOPER AND OPS CONFERENCE
  • 2. ABOUT ME Interested in Software and Hardware. Started coding at 14 Programmer, team lead, software architect, operator, administrator In pursuit of the right way to build software Passionate about technology, and much more about the people he's working with Find me on Twitter: @MartinGoodwell Considers himself a lucky guy
  • 3. THIS WILL BE LIKE • James Camerson's Avatar • at least 50% of it is "heavily inspired by others" • A river runs through it, feat Brad Pitt and Tom Skerrit • the other 50% is real-life experience • The Walking Dead • we'll have a Walker • Real-life Example: Classic ASP, 15 years later • The basics – aka "Mastering the craft" • The Magic Sauce. The Kool Aid. Mr Miyagi's ultimate wisdom.
  • 4. Yes or no? Refactor or Rewrite?
  • 5. WHAT A REAL REWRITE REALLY MEANS • Netscape Navigator 6 goes public beta in Nov 2000 • last major release (4.0) released almost 3 years ago (there was no v5) • " During this time, Netscape sat by, helplessly, as their market share plummeted. "
  • 6. SAME MISTAKES • Borland  Arago  dBase for Windows • Microsoft Access ate their lunch • then they made the same mistake again in rewriting Quattro Pro from scratch and astonishing people with how few features it had. • Microsoft  Pyramid  Word for Windows from scratch • Lucky for Microsoft, they had never stopped working on the old code base, so they had something to ship, making it merely a financial disaster, not a strategic one.
  • 7. WHY? It’s harder to read code than to write it. - Joel Spolsky https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/
  • 8. What is usually wrong? • Architectural problems • Even fairly major architectural changes can be done without throwing away the code. By just moving things around, cleaning them up, creating base classes that made sense, and creating sharp interfaces between the modules. • Because it's inefficient • When optimizing for speed, 1% of the work gets you 99% of the bang • The code is doggone ugly • One project I worked on actually had a data type called a FuckedString • So half the functions started with “_” and half with “m_”, which looked ugly. • This is the kind of thing you solve in five minutes with a macro in Emacs, not by starting from scratch.
  • 9. When to Rewrite? • Is your code closely tied to a certain lifecycle / framework? • eg Reactive, Mobile Apps, ... • No one can maintain the existing code • obsolete technology • everyone's scared by just thinking about touching the code • Always ask yourself: does this need to be a full rewrite?
  • 10.
  • 11. MAKE or BUY? • Make the parts that make your solution unique • "Buy" the parts that are common
  • 12. Online Shop, written in ASP, rendering XHTML Back then, in development for 15 years EXAMPLE: classic ASP
  • 13. PROJECT SETUP • Use-case: eCommerce • close connection to a business backend system • Native Windows desktop application, connected to database • Core: classic ASP • Database: Pervasive SQL • the actual database from the business backend • Interfaces to • MSMQ for sending orders to the business backend • COM+ for querying prices from the business backend
  • 15. WE WANTED TO REWRITE. WHY? • 15 year old VB-Script codebase • lack of structure • hard to find VB-Script talent • not up to today's standards (eg Unit Testing) • Too closely bound to the business backend system • Major updates of the system locked the database and stalled the online shop
  • 16. CUSTOM BRANCHING <% if nCategoryId = 0 and (hostInfo.Path = "clayshop" or hostInfo.Path="bikershop" or hostInfo.Path="steelshop") then out GetPageHTML(1,"de") end if %> • Individual code branches for most tenants (~30 of them) • If a tenant canceled his contract, the codebase usually was not cleaned
  • 17. RENDERING WHILE ITERATING RECORDSET <% set rsProd= oProduct.GetProduct(CLng(nProductId), CLng(nTenantId)) if not rsProd.eof then %> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr><td><img height="20" width="3" src="../../layout/pic/pix_tr.gif" border="0"></td></tr> <tr><td class="productheadcolor"> <table border="0" cellpadding="0" cellspacing="0"> <tr> <td class="productheadiconcolor"><img height="20" width="20" src="../../layout/pic/icons/icon_kl_produkttip.gif" border="0"></td> <td><div class="productheadcolor">&nbsp;<%= getText("product") %>:</div></td> </tr> </table> <% if (sTenantPath <> "that_special_shop") then DrawProducts rsProd, "productreplacement" end if %> <% end if rsProd.close set rsProd= nothing %> • No separation between data-access, business logic, and UI • Made it hard to see what really needs refactoring
  • 18. OUR PLAN WAS • 100% re-write in Java • Create a separate database for the eCommerce part • Move all tenants to the new codebase within six months
  • 20. LEARNINGS • 100% re-write in Java not possible • no stable Java libraries for MSMQ and COM+ at the time • Planned timeframe (of course) didn't work • first tenant went online after 9 months • but it was using the new UI • (so, the old solution was still running in production in parallel) • Re-doing the UI turned out to be the hard part • we still didn't have all tenants converted after 2,5 years
  • 22. WHAT WENT WELL? • Introduction of dedicated DB • Having a separate Importer component • We built deployment automation with Jenkins • The ASP-bridge turned out to work really well
  • 23. WHAT WE SHOULD HAVE DONE • Identify the UI-part as the real problem • impossible to see due to non-layered codebase • Embrace the fact that we have a huge number of customers on the "old" codebase and design the new system for multiple UI technologies • EOL the old codebase • If customers want new features, migrate them over • Not a full rewrite
  • 24. INTRODUCING BFF • BFF • Backend-for-Frontend • aka Edge-Service • source: Sam Newman's Microservice book • can be used for • routing • authentication • filtering
  • 26. BENEFITS OF DOING IT RIGHT • Save months of efforts, porting the messy UI code • Have ASP UI benefit from separate database • Only have a single touchpoint with the business backend system • for any client • XHTML rendered by ASP • HTML5 rendered by Spring MVC • potential mobile apps
  • 27. IT MIGHT SMELL, THOUGH. MASTERING THE CRAFT OLD CODE DOESN'T STINK
  • 28. HOW CAN THAT EVEN HAPPEN? • Bounded contexts • Things built in-house that would have been readily available • a lot of the mess happens in boilerplate • Code that's not testable • Code that's not clearly/properly structured • Harder to read than to write, remember? • Bugs due to premature optimization • YAGNI – You aren't gonna need it • I think we tought that we'll need this for that feature that's coming up.
  • 29. BOUNDED CONTEXTS Don't mix things that don't belong together • Do you see what's wrong with the "UserAccount" table?
  • 30. BOUNDED CONTEXTS Wrong: sharing DTOs between different domains Some services use same attributes, some use specific ones CatalogService ShoppingCart Service OrderService ProductDto * id * name * description * userRatings * imageUrls * price * vat * quantity
  • 31. BOUNDED CONTEXTS Right: dedicated DTOs for each domain but smells like duplication a lot, because of the names better: each DTO only contains the attributes it needs CatalogService ShoppingCart Service OrderService CatalogProductDto * id * name * description * userRatings * imageUrls * price CartProductDto * id * name * price * quantity OrderProductDto * id * name * price * vat * quantity
  • 32. BOUNDED CONTEXTS Same DTOs, but different names. Much better fit to the domain. CatalogService ShoppingCart Service OrderService ProductDto * id * name * description * userRatings * imageUrls * price CartEntryDto * id * name * price * quantity LineItemDto * id * name * price * vat * quantity
  • 33. NOT INVENTED HERE • Focus on business logic • and separate it from boilerplate • Don't build what you don't need to • Queues • Connection Pools • Anything you build needs to be maintained. • The only thing you'd want to maintain is business logic.
  • 35. CODE DUPLICATION Wrong: use inheritance for saving number of attributes in classes abstract class MasterPojo { protected int id; } public class AnyPojo extends MasterPojo { ... } public class AnyOtherPojo extends MasterPojo { ... }
  • 36. CODE DUPLICATION Right: don't mix unrelated objects public class AnyPojo { private int id; } public class AnyOtherPojo { private int id; }
  • 37. CODE DUPLICATION Code duplication really means that any code that makes decisions (eg IF, loops, ...) should not be copy/pasted. Example: • We have integrated with MailChimp for sending Emails • We also want to integrate with other messaging services • So, we copy the code from our MailChimp integration, paste it into a new package and just rename the classes and make changes according to the new 3rd party there. • Right way: identify common behavior. Have that in base-classes or a library that can be used by both implementations.
  • 39. DESIGN FOR TESTABILITY • Try to be as atomic as possible (complex objects vs atomic) • In Java: use package private instead of private • Have methods do as little as possible • Methods that do more should just call other methods
  • 40. TESTABLE CODE for if break condition boolean condition public int categorize(Client client, int metric) { return result; }
  • 41. TESTABLE CODE for break condition public int categorize(Client client, int metric) { return result; } boolean cascadedMethod() { if } cascadedMethod()
  • 42. THINGS TO CONSIDER • Integers: negative, ranges • Strings: length, special characters, null, empty, case-sensitive • Objects: • all of the above, depending on member variables datatypes
  • 43. TESTING CODE A code tester walks into a bar. Orders a beer. Orders 2.15 billion beers. Orders -1 beers. Orders äüöß beers. Orders a nothing. Orders a cat. Tries to leave without paying.
  • 44. TESTABLE CODE • every IF in a method requires a test for every branch • that's why code inside blocks should go into a separate method • allows to test that method independently • any possible input parameters require a test • any possible return values require a test • the smaller your classes, the smaller your methods, the easier it is to maintain test code • the amount of test code can easily be equal to your "real" code • any method should be testable independently
  • 45. TESTABLE CODE • Some relationships are hard to test. public int calcIt(int a, int b) { int one = CalcUtil.calcIt(a,b); int result = doSomethingElse(one); return result; }
  • 46. TESTABLE CODE • Some relationships are hard to test. public int calcIt(int a, int b) { int one = CalcUtil.getInstance().calcIt(a,b); int result = doSomethingElse(one); return result; }
  • 47. TESTABLE CODE • Any dependencies to other classes should be easy to change. private CalcUtil calcUtil = CalcUtil.getInstance(); public int calcIt(int a, int b) { int one = calcUtil.calcIt(a,b); int result = doSomethingElse(one); return result; } void setCalcUtil(CalcUtil calcUtil) { this.calcUtil = calcUtil; }
  • 48. READABLE CODE • Be as descriptive in your code as possible public class Walker { public int moveAround(int position, int angle) { if (angle > 0 && angle < 180) { //go left ... } ... } }
  • 49. READABLE CODE • Be as descriptive in your code as possible public class Walker { public int moveAround(int position, int angle) { boolean goLeft = angle > 0 && angle < 180; if (goLeft) { ... } ... } }
  • 50. READABLE AND TESTABLE CODE • Be as descriptive in your code as possible public class Walker { public int moveAround(int a, int b) { boolean goLeft = shouldGoLeft(a,b); if (goLeft) { ... } } boolean shouldGoLeft(int a, int b) { return angle > 0 && angle < 180; } }
  • 51. MEANINGFUL DOCUMENTATION • Class-level comments to give context. /** * This is the entry class. You'll find most * interesting entrypoints here. * @see: ThatOther.class */ public class Lala { }
  • 54. PREMATURE OPTIMIZATION • "Because we need the performance" • We need to implement it in "D" • Do everything in Stored Procedures (even simple CRUDs) • You need to declare that variable outside of the loop to reduce the load on the GC • Specialize first, generalize later • "I think we thought that we will need that for one of the screens." • Release often • finish one feature  release it  get feedback  improve it • The IT-world has changed. It's not about CPU-cycles anymore • It's about codebases that can scale to a large number of programmers.
  • 55. READ • Find all this and lots more here: • Clean Code, by • Robert C. Martin
  • 56. READ • Find all this and lots more here: • Growing Object-Oriented Software, guided by Tests, by • Steve Freeman, Nat Pryce
  • 57. CAN WE USE SOME OF THAT FOR MOBILE OR DESKTOP? THE PROPER MONOLITH
  • 58. LAYERS • One artifact per business domain • 3-tiered architecture inside of each artifact • Sharing of interfaces by means of –api artifacts • No shared database schemas between domains
  • 59. PROPER MONOLITH .war file catalog.jar cart.jar billing.jar order.jar Controllers Physical Database Catalog DB Cart DB Billing DB Order DB catalog-api.jar cart-api.jar billing-api.jar order-api.jar
  • 60. TOOLS THAT HELP • Black Duck • Sonar
  • 61. HOW TO DO IT RIGHT FROM NOW ON?
  • 62. THE ULTIMATE TRUTH • Master the craft of programming • Avoid the mess • Bounded Contexts • domain-driven thinking and architecture
  • 63. FORD FIELD, DETROIT – OCT 16, 2018 DEVELOPER AND OPS CONFERENCE