61
The Technical Debt Trap Michael “Doc” Norton @DocOnDev

The Technical Debt Trap - AgileIndy 2013

  • View
    1.737

  • Download
    0

Embed Size (px)

DESCRIPTION

A visually updated version of the slide deck.

Citation preview

Page 1: The Technical Debt Trap - AgileIndy 2013

The Technical Debt TrapMichael “Doc” Norton@DocOnDev

Page 2: The Technical Debt Trap - AgileIndy 2013

Michael “Doc” NortonGrouponDirector of [email protected]@DocOnDev

Husband Father

Page 3: The Technical Debt Trap - AgileIndy 2013

GrandFatherHe’s SOOO Cute!!

Page 4: The Technical Debt Trap - AgileIndy 2013

What is Technical Debt?

Page 5: The Technical Debt Trap - AgileIndy 2013

Ward CunninghamShipping first time code is like going into debt.

OOPSLA ’92

Page 6: The Technical Debt Trap - AgileIndy 2013

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.

Page 7: The Technical Debt Trap - AgileIndy 2013

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

Page 8: The Technical Debt Trap - AgileIndy 2013

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

Page 9: The Technical Debt Trap - AgileIndy 2013

Technical Debt is a Good Idea

Page 10: The Technical Debt Trap - AgileIndy 2013

Technical Debt is a Good Idea

WTF?

Page 11: The Technical Debt Trap - AgileIndy 2013

Technical Debt is a Good Idea

Allow for Rapid DeliveryTo Elicit Quick FeedbackAnd Correct Design

Strategic Design Decision

Page 12: The Technical Debt Trap - AgileIndy 2013

Technical Debt is a Metaphor

Here Be Danger

Page 13: The Technical Debt Trap - AgileIndy 2013

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)

Page 14: The Technical Debt Trap - AgileIndy 2013

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

Page 15: The Technical Debt Trap - AgileIndy 2013

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

Page 16: The Technical Debt Trap - AgileIndy 2013

The Technical Debt Quadrant

http://martinfowler.com/bliki/TechnicalDebtQuadrant.html

Page 17: The Technical Debt Trap - AgileIndy 2013

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

Page 18: The Technical Debt Trap - AgileIndy 2013

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

Page 19: The Technical Debt Trap - AgileIndy 2013

[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.

Page 20: The Technical Debt Trap - AgileIndy 2013

... confused it with the idea that you could write code poorly ....

Page 21: The Technical Debt Trap - AgileIndy 2013

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

Page 22: The Technical Debt Trap - AgileIndy 2013

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

Page 23: The Technical Debt Trap - AgileIndy 2013

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.

Page 24: The Technical Debt Trap - AgileIndy 2013

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 ...

Page 25: The Technical Debt Trap - AgileIndy 2013

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

Page 26: The Technical Debt Trap - AgileIndy 2013

You have a mess

Disorderly accumulation, heap, or jumble

A state of embarrassing confusionAn unpleasant or difficult situation

Mess (noun)

Page 27: The Technical Debt Trap - AgileIndy 2013

You have cruft

An unpleasant substanceThe result of shoddy constructionRedundant, old or improperly

written code

Cruft (noun)

Page 28: The Technical Debt Trap - AgileIndy 2013

Chill. It’s just semantics, man.

Technical Debt is Good

Just Semantics?

Page 29: The Technical Debt Trap - AgileIndy 2013

Chill. It’s just semantics, man.

Technical Debt is Good

Just Semantics?Quick and Dirty is Technical DebtQuick and Dirty

is Good

Page 30: The Technical Debt Trap - AgileIndy 2013

Chill. It’s just semantics, man.Just Semantics?Quick and Dirty

is GoodQuick and Dirty is Good

Page 31: The Technical Debt Trap - AgileIndy 2013

The Technical Debt Quadrant

http://martinfowler.com/bliki/TechnicalDebtQuadrant.html

Page 32: The Technical Debt Trap - AgileIndy 2013

The Technical Debt Quadrant

http://martinfowler.com/bliki/TechnicalDebtQuadrant.html

“Let’s deploy and gather more information.”

Page 33: The Technical Debt Trap - AgileIndy 2013

Technical Debt in other fieldsConstruction

RECKLESS AND DELIBERATE

Page 34: The Technical Debt Trap - AgileIndy 2013

Technical Debt in other fieldsAutomotive

RECKLESS AND DELIBERATE

Page 35: The Technical Debt Trap - AgileIndy 2013

Technical Debt in other fieldsMedical

RECKLESS AND INADVERTENT

Page 36: The Technical Debt Trap - AgileIndy 2013

The Technical Debt Quadrant

http://martinfowler.com/bliki/TechnicalDebtQuadrant.html

“Let’s deploy and gather more information.”IRRESPONSI

BLE

INCOMPETE

NT

TECHNICAL

DEBT

Page 37: The Technical Debt Trap - AgileIndy 2013

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

Page 38: The Technical Debt Trap - AgileIndy 2013

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

Page 39: The Technical Debt Trap - AgileIndy 2013

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

Page 40: The Technical Debt Trap - AgileIndy 2013

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

Page 41: The Technical Debt Trap - AgileIndy 2013

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?

Page 42: The Technical Debt Trap - AgileIndy 2013

// 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?

Page 43: The Technical Debt Trap - AgileIndy 2013

if (customer.isFederallyRegulated()) { ... }

Cruft or Debt?

Page 44: The Technical Debt Trap - AgileIndy 2013

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

Page 45: The Technical Debt Trap - AgileIndy 2013

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?

Page 46: The Technical Debt Trap - AgileIndy 2013

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)

Page 47: The Technical Debt Trap - AgileIndy 2013

The Cost of “Technical Debt”We did this

PER BUSINESS APPLICATION$1 Million

WORLD-WIDE TECHNICAL DEBT (INCLUDES HARDWARE) $1 Trillion (by 2015)

Page 48: The Technical Debt Trap - AgileIndy 2013

Grammy Doesn’tLoveMe!

It’s all about expectations

Page 49: The Technical Debt Trap - AgileIndy 2013

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

Page 50: The Technical Debt Trap - AgileIndy 2013

Avoid The TrapThresholds set false expectations

http://blog.castsoftware.com/wp-content/uploads/2011/04/Technical-Debt-Software-Quality1.jpg

Page 51: The Technical Debt Trap - AgileIndy 2013

Avoid The TrapIncremental fixes fail

http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg

Page 52: The Technical Debt Trap - AgileIndy 2013

Avoid The TrapIncremental fixes fail

http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg

Page 53: The Technical Debt Trap - AgileIndy 2013

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

Page 54: The Technical Debt Trap - AgileIndy 2013

Monitoring Cruft/Debt

Code CoverageCyclomatic ComplexityCouplingMaintainability

A few key metrics

Page 55: The Technical Debt Trap - AgileIndy 2013

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

Page 56: The Technical Debt Trap - AgileIndy 2013

Monitoring Cruft/Debt

Number of logical branches in codeDirect relationship with bugsTypically high in concentrated areasReduce conditionalsMonitor trends, not points

Cyclomatic Complexity

Page 57: The Technical Debt Trap - AgileIndy 2013

Monitoring Cruft/Debt

Interconnectedness of systemsHighly coupled is difficult to changeAfferent (Toward) and Efferent (Away)Dependency InjectionMonitor trends, not points

Coupling

Page 58: The Technical Debt Trap - AgileIndy 2013

Cruft/Debt Cards

VelocityScalabilityAvailabilityMaintainability

Tie it to Business Value

Page 59: The Technical Debt Trap - AgileIndy 2013

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

Page 60: The Technical Debt Trap - AgileIndy 2013

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

Page 61: The Technical Debt Trap - AgileIndy 2013

The Technical Debt TrapMichael “Doc” Norton@DocOnDev

Thank You!