The Technical Debt Trap - AgileIndy 2013
-
date post
17-Oct-2014 -
Category
Documents
-
view
1.737 -
download
0
description
Transcript of The Technical Debt Trap - AgileIndy 2013
The Technical Debt TrapMichael “Doc” Norton@DocOnDev
Michael “Doc” NortonGrouponDirector of [email protected]@DocOnDev
Husband Father
GrandFatherHe’s SOOO Cute!!
What is Technical Debt?
Ward CunninghamShipping first time code is like going into debt.
OOPSLA ’92
Ward CunninghamShipping first time code is like going into debt.
OOPSLA ’92
A little debt speeds development so long as it is paid back promptly with a rewrite.
Ward CunninghamThe danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt.
OOPSLA ’92
Ward CunninghamThe danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt.
OOPSLA ’92
Technical Debt is a Good Idea
Technical Debt is a Good Idea
WTF?
Technical Debt is a Good Idea
Allow for Rapid DeliveryTo Elicit Quick FeedbackAnd Correct Design
Strategic Design Decision
Technical Debt is a Metaphor
Here Be Danger
Metaphors Rock We Reason By Analogy
BUILDING ON A WEAK FOUNDATI
ON Puts pressure on
our design
Can’t keep running at this
paceIT’S RAINING
MEN(HALLELUJAH)
MetaphorphosisWhen Metaphors Go WrongSHORT-TERM
Long-Term
Inadvertent Reckless Debt in the
Third QuadrantPrudent
Intentional
Credit CardFraudulentAUTO LOAN
Student Loan
HOME LOANLoan Shark
Return on Investment
PYRAMID SCHEME
VOLUNTARY
Pragmatic Leverage
HIGH INTEREST
OPERATIONAL
MetaphorphosisWhen Metaphors Go Wrong
“QUICK AND DIRTY”MARTIN FOWLER
HTTP://WWW.MARTINFOWLER.COM/BLIKI/TECHNICALDEBT.HTML“SLOPPY”DAVID LARIBEE
HTTP://MSDN.MICROSOFT.COM/EN-US/MAGAZINE/EE819135.ASPX
“JUST HACK IT IN”
STEVE MCCONNELLHTTP://BLOGS.CONSTRUX.COM/BLOGS/STEVEMCC/ARCHIVE/2007/11/01/TECHNICAL-DEBT-2.ASPX
“CUT A LOT OF CORNERS”JAMES SHORE
HTTP://JAMESSHORE.COM/BLOG/CARDMEETING/VOLUNTARY-TECHNICAL-DEBT.HTML
The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
Ummm... no.[Many] have explained the debt metaphor and confused it with the idea that you could write code poorly with the intention of doing a good job later.
YouTube.com ’09http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
Ummm... no.[Many] have explained the debt metaphor and confused it with the idea that you could write code poorly with the intention of doing a good job later.
YouTube.com ’09http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
[Many] have explained the debt metaphor and confused it with the idea that you could write code poorly with the intention of doing a good job later.
... confused it with the idea that you could write code poorly ....
Clean Code is RequiredThe ability to pay back debt [...] depends upon you writing code that is clean enough to be able to refactor as you come to understand your problem.
YouTube.com ’09http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
Clean Code is RequiredThe ability to pay back debt [...] depends upon you writing code that is clean enough to be able to refactor as you come to understand your problem.
YouTube.com ’09http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
Dirty Code is a BAD IdeaDirty code is to technical debt as the pawn broker is to financial debt.
twitter ’09http://twitter.com/WardCunningham/status/3742903303
Don’t think you are ever going to get your code back.
Is It Technical Debt?
Is the code clean?Is the code tested?Is there a learning objective?Is there a plan for payback?Is the business truly informed?
Ask yourself ...
Is It Technical Debt?
Is the code clean?Is the code tested?Is there a learning objective?Is there a plan for payback?Is the business truly informed?
If you say no to even one...
... then you don’t have Technical Debt
You have a mess
Disorderly accumulation, heap, or jumble
A state of embarrassing confusionAn unpleasant or difficult situation
Mess (noun)
You have cruft
An unpleasant substanceThe result of shoddy constructionRedundant, old or improperly
written code
Cruft (noun)
Chill. It’s just semantics, man.
Technical Debt is Good
Just Semantics?
Chill. It’s just semantics, man.
Technical Debt is Good
Just Semantics?Quick and Dirty is Technical DebtQuick and Dirty
is Good
Chill. It’s just semantics, man.Just Semantics?Quick and Dirty
is GoodQuick and Dirty is Good
The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
“Let’s deploy and gather more information.”
Technical Debt in other fieldsConstruction
RECKLESS AND DELIBERATE
Technical Debt in other fieldsAutomotive
RECKLESS AND DELIBERATE
Technical Debt in other fieldsMedical
RECKLESS AND INADVERTENT
The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
“Let’s deploy and gather more information.”IRRESPONSI
BLE
INCOMPETE
NT
TECHNICAL
DEBT
DataSet aDs, qDs;aDs = _dbConnector.UpdateAgentList();qDs = _dbConnector.GetQueueList();foreach (DataTable aTable in aDs.Tables) { foreach (DataRow aRow in aTable.Rows) { foreach (DataColumn aColumn in aTable.Columns) { DataSet asDs = _dbConnector.GetAgentSkills(aRow[aColumn].ToString());//AgentId foreach (DataTable asTable in asDs.Tables) { foreach (DataRow asRow in asTable.Rows) { foreach (DataColumn asColumn in asTable.Columns) { foreach (DataTable qTable in qDs.Tables) { foreach (DataRow qRow in qTable.Rows) { foreach (DataColumn qColumn in qTable.Columns) { DataSet sqDs = _dbConnector.GetSkillsForQueue(qRow[qColumn].ToString()); foreach (DataTable sqTable in sqDs.Tables) { foreach (DataRow sqRow in sqTable.Rows) { foreach (DataColumn sqColumn in sqTable.Columns) { foreach (string skill in sqRow[sqColumn].ToString().Split(paramDelimStr)) { if (skill == asRow[asColumn].ToString()) { try { _dbConnector.SetAgentQueueSkill(aRow[aColumn].ToString(), qRow[qColumn].ToString(), skill); } catch { continue; } } } } } } } } } } } } } }}
Cruft or Debt?
http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
DataSet aDs, qDs;aDs = _dbConnector.UpdateAgentList();qDs = _dbConnector.GetQueueList();foreach (DataTable aTable in aDs.Tables) { foreach (DataRow aRow in aTable.Rows) { foreach (DataColumn aColumn in aTable.Columns) { DataSet asDs = _dbConnector.GetAgentSkills(aRow[aColumn].ToString());//AgentId foreach (DataTable asTable in asDs.Tables) { foreach (DataRow asRow in asTable.Rows) { foreach (DataColumn asColumn in asTable.Columns) { foreach (DataTable qTable in qDs.Tables) { foreach (DataRow qRow in qTable.Rows) { foreach (DataColumn qColumn in qTable.Columns) { DataSet sqDs = _dbConnector.GetSkillsForQueue(qRow[qColumn].ToString()); foreach (DataTable sqTable in sqDs.Tables) { foreach (DataRow sqRow in sqTable.Rows) { foreach (DataColumn sqColumn in sqTable.Columns) { foreach (string skill in sqRow[sqColumn].ToString().Split(paramDelimStr)) { if (skill == asRow[asColumn].ToString()) { try { _dbConnector.SetAgentQueueSkill(aRow[aColumn].ToString(), qRow[qColumn].ToString(), skill); } catch { continue; } }} } } } } } } } } } } } }
Cruft or Debt?
http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
DataSet aDs, qDs, asDs, sqDs;aDs = _dbConnector.UpdateAgentList();qDs = _dbConnector.GetQueueList();
foreach (DataRow aRow in aDS.Tables[0].Rows) { String agentID = aRow[“AgentId”].ToString(); asDs = _dbConnector.GetAgentSkills(agentID); foreach (DataRow asRow in asDs.Tables[0].Rows) { String agentSkill = asRow[“Skill”].ToString(); foreach (DataRow qRow in qDs.Tables[0].Rows) { queueName = qRow[“QueueName”].ToString(); sqDs = _dbConnector.GetSkillsForQueue(queueName); foreach (DataRow sqRow in sqDs.Tables[0].Rows) { foreach (string skill in sqRow[“Skills”].ToString().Split(paramDelimStr)) { if (skill == agentSkill) { try { _dbConnector.SetAgentQueueSkill(agentID, queueName, skill); } catch { continue; } } } } } }}
Cruft or Debt?
http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
AgentList agents = new AgentList(_dbConnector.UpdateAgentList());QueueList queues = new QueueList(_dbConnector.GetQueueList());
foreach (Agent agent in agents) { foreach (Skill agentSkill in agent.skills) { foreach (Queue queue in queues) { foreach (Skill queueSkill in queue.skills.Where(x => x == agentSkill)) { try {_dbConnector.SetAgentQueueSkill(agent.agentID, queue.name, agentSkill); } catch { continue; } } } }}
Cruft or Debt?
http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
if ((customer.state == “AL” && customer.type == CustomerType.GENERAL_AGENT && customer.revenue > 100000) || (customer.type == CustomerType.RETRO_AGENT && (customer.state == “WI” || customer.state == “IL”)) || (customer.type == CustomerType.FED_MANAGEMENT && customer.revenue > 150000)) { ... }
Cruft or Debt?
// If customer is Federally Regulatedif ((customer.state == “AL” && customer.type == CustomerType.GENERAL_AGENT && customer.revenue > 100000) || (customer.type == CustomerType.RETRO_AGENT && (customer.state == “WI” || customer.state == “IL”)) || (customer.type == CustomerType.FED_MANAGEMENT && customer.revenue > 150000)) { ... }
Cruft or Debt?
if (customer.isFederallyRegulated()) { ... }
Cruft or Debt?
double getSpeed() { switch (_type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; case NORWEGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException ("Should be unreachable");}
Cruft or Debt?
http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
class Swallow ... double getSpeed() { return getBaseSpeed(); }end classclass EuropeanSwallow ...end classclass AfricanSwallow ... double getSpeed() { return super.getSpeed - coconutLoad(); } double coconutLoad() { return getLoadFactor() * _numberOfCoconuts; }end classclass NorwegianSwallow ... double getSpeed() { return (_isNailed) ? 0 : getBaseSpeed(_voltage); }end class
Cruft or Debt?
Cruft is a bad decisionEvery Time
YOU ARE GOING TO CREATE UNINTENTIONAL CRUFT (You can’t help it. It’s unintentional.)
YOU HAVE TO CLEAN UP THE EXISTING CRUFT(Intent doesn’t alter Responsibility)
YOU ARE A PROFESSIONAL DEVELOPER(Professionals behave ethically)
The Cost of “Technical Debt”We did this
PER BUSINESS APPLICATION$1 Million
WORLD-WIDE TECHNICAL DEBT (INCLUDES HARDWARE) $1 Trillion (by 2015)
Grammy Doesn’tLoveMe!
It’s all about expectations
The Trap
Precedent for speed over qualityExpectation of increased velocityCruft slows you downMust write more cruft to keep up
Cruft begets cruft
Ask Permission to do your job correctly
Avoid The TrapThresholds set false expectations
http://blog.castsoftware.com/wp-content/uploads/2011/04/Technical-Debt-Software-Quality1.jpg
Avoid The TrapIncremental fixes fail
http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
Avoid The TrapIncremental fixes fail
http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
Avoid The Trap
Never make an intentional messMonitor your “Technical Debt”Follow the Boy Scout RuleRemember quality is your responsibility
Clean Constantly
NEVER Ask Permission to do your job correctly
Monitoring Cruft/Debt
Code CoverageCyclomatic ComplexityCouplingMaintainability
A few key metrics
Monitoring Cruft/Debt
Code exercised by automated testsMonitor test types separatelyDon’t set a coverage target100% coverage is a smellMonitor trends, not points
Code Coverage
Monitoring Cruft/Debt
Number of logical branches in codeDirect relationship with bugsTypically high in concentrated areasReduce conditionalsMonitor trends, not points
Cyclomatic Complexity
Monitoring Cruft/Debt
Interconnectedness of systemsHighly coupled is difficult to changeAfferent (Toward) and Efferent (Away)Dependency InjectionMonitor trends, not points
Coupling
Cruft/Debt Cards
VelocityScalabilityAvailabilityMaintainability
Tie it to Business Value
Review
Is a strategic design decisionRequires the business to be informedIncludes a pay-back plan
Technical Debt
HappensNeeds to be monitored and cleanedIs NOT Technical Debt
Cruft
Review
Is a strategic design decisionRequires the business to be informedIncludes a pay-back plan
Technical Debt
HappensNeeds to be monitored and cleanedIs (probably) NOT Technical Debt
Cruft
The Technical Debt TrapMichael “Doc” Norton@DocOnDev
Thank You!