The Technical Debt Trap - AgileIndy 2013

Preview:

DESCRIPTION

A visually updated version of the slide deck.

Citation preview

The Technical Debt TrapMichael “Doc” Norton@DocOnDev

Michael “Doc” NortonGrouponDirector of Technologydoc@groupon.com@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!

Recommended