The document discusses the concept of technical debt and how it differs from cruft. It explains that technical debt refers to strategic design decisions made to increase speed that require future work to pay back, while cruft is accidental messy or poorly-written code. The author warns that allowing cruft can lead teams into a trap where velocity is prioritized over quality, resulting in increasing cruft over time. The document provides suggestions for avoiding this trap, such as setting quality thresholds, making incremental fixes, and constantly cleaning code. It also recommends metrics for monitoring cruft and debt levels like code coverage, complexity, and coupling.
6. Ward
Cunningham
Shipping first time code is
like going into debt.
A little debt speeds
development so long as it is
paid back promptly with a
rewrite.
OOPSLA ’92
7. Ward
Cunningham
The danger occurs when
the debt is not repaid.
Every minute spent on not-
quite-right code counts as
interest on that debt.
OOPSLA ’92
8. Ward
Cunningham
The danger occurs when
the debt is not repaid.
Every minute spent on not-
quite-right code counts as
interest on that debt.
OOPSLA ’92
13. Metaphors Rock
We Reason By Analogy
Can’t keep
running at thisBUILDING ON
pace A WEAK
FOUNDATION
IT’S RAINING MEN
(HALLELUJAH)
Puts pressure
on our design
14. Metaphorphosis
When Metaphors Go Wrong
Return on Investment
SHORT-TERM Fraudulent Credit Card
Inadvertent Reckless
AUTO LOAN
Debt in the Third PYRAMID SCHEME
HIGH INTEREST
Intentional Quadrant Long-Term
HOME LOAN
Loan Shark
VOLUNTARY
Prudent
Pragmatic Leverage Student Loan OPERATIONAL
15. Metaphorphosis
When Metaphors Go Wrong
“CUT A LOT OF CORNERS”
JAMES SHORE
HTTP://JAMESSHORE.COM/BLOG/CARDMEETING/VOLUNTARY-TECHNICAL-DEBT.HTML
“QUICK AND DIRTY”
MARTIN FOWLER
“SLOPPY”
HTTP://WWW.MARTINFOWLER.COM/BLIKI/TECHNICALDEBT.HTML
DAVID LARIBEE “JUST HACK IT IN”
HTTP://MSDN.MICROSOFT.COM/EN-US/MAGAZINE/EE819135.ASPX
STEVE MCCONNELL
HTTP://BLOGS.CONSTRUX.COM/BLOGS/STEVEMCC/ARCHIVE/2007/11/01/TECHNICAL-DEBT-2.A
16. The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
17. 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.
http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
YouTube.com ’09
18. 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.
http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
YouTube.com ’09
19. [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.
21. Clean Code
is Required
The 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.
http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
YouTube.com ’09
22. Clean Code
is Required
The 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.
http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded
YouTube.com ’09
23. Dirty Code is
a BAD Idea
Dirty code is to technical
debt as the pawn broker is
to financial debt.
Don’t think you are ever
going to get your code back.
http://twitter.com/WardCunningham/status/3742903303
twitter ’09
24. Is It Technical Debt?
Ask yourself ...
Is the code clean?
Is the code tested?
Is there a learning objective?
Is there a plan for payback?
Is the business truly informed?
25. Is It Technical Debt?
If you say no to even one...
Is the code clean?
Is the code tested?
Is there a learning objective?
Is there a plan for payback?
Is the business truly informed?
... then you don’t have Technical Debt
26. You have a mess
Mess (noun)
Disorderly accumulation, heap, or jumble
A state of embarrassing confusion
An unpleasant or difficult situation
27. You have cruft
Cruft (noun)
An unpleasant substance
The result of shoddy construction
Redundant, old or improperly written code
28. Chill. It’s just semantics,
man.
Just Semantics?
Technical Debt is Good
29. Chill. It’s just semantics,
man.
Just Semantics?
Quick and Dirty is Technical Debtis Good
Technical Debt is Good
30. Chill. It’s just semantics,
man.
Just Semantics?
Quick and Dirtyis Good
Dirty is Good
31. The Technical Debt Quadrant
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
32. The Technical Debt Quadrant
“Let’s deploy and
gather more
information.”
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
33. Technical Debt in other
fields
Construction
TE
R A
IB E
E L
D D
AN
S S
LE
CK
RE
34. Technical Debt in other
fields
Automotive
TE
R A
IB E
E L
D D
AN
S S
LE
CK
RE
35. Technical Debt in other
fields
Medical
NT
TE
E R
D V
IN A
N D
S A
ES
K L
EC
R
36. The Technical Debt Quadrant
LE CA L
SI B N I
“Let’s deploy and
N H T
E C EB
PO
gather more
ES T information.”
IRR D
N T
PE TE
M
INCO
http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
37. DataSet aDs, qDs;
aDs = _dbConnector.UpdateAgentList();
qDs = _dbConnector.GetQueueList();
foreach (DataTable aTable in aDs.Tables) {
Cruft or Debt?
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; }
}
}
}
}
}
}
}
}
}
}
}
}
}
} http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
38. Cruft or 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; }
}
} } } } } } } } } } } } }
http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
46. Cruft is a bad decision
Every Time
YOU ARE A PROFESSIONAL DEVELOPER
(Professionals behave ethically)
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)
47. The Cost of “Technical Debt”
We did this
WORLD-WIDE TECHNICAL DEBT (INCLUDES HARDWARE)
$1 Trillion (by 2015)
PER BUSINESS APPLICATION
$1 Million
49. The Trap
Cruft begets cruft
Precedent for speed over quality
Expectation of increased velocity
Cruft slows you down
Must write more cruft to keep up
Ask Permission to do your job
correctly
50. Avoid The Trap
Thresholds set false
expectations
http://blog.castsoftware.com/wp-content/uploads/2011/04/Technical-Debt-Software-Quality1.jpg
51. Avoid The Trap
Incremental fixes fail
http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
52. Avoid The Trap
Incremental fixes fail
http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
53. Avoid The Trap
Clean Constantly
Never make an intentional mess
Monitor your “Technical Debt”
Follow the Boy Scout Rule
Remember quality is your responsibility
NEVER Ask Permission to do your job
correctly
55. Monitoring Cruft/Debt
Code Coverage
Code exercised by automated tests
Monitor test types separately
Don’t set a coverage target
100% coverage is a smell
Monitor trends, not points
59. Review
Technical Debt
Is a strategic design decision
Requires the business to be informed
Includes a pay-back plan
Cruft
HappensNeeds to be monitored and
cleanedIs NOT Technical Debt
60. Review
Technical Debt
Is a strategic design decision
Requires the business to be informed
Includes a pay-back plan
Cruft
HappensNeeds to be monitored and
cleanedIs (probably) NOT Technical Debt
61. Thank You!
The Technical Debt Trap
Michael “Doc” Norton
@DocOnDev
Notas do Editor
Design decisions that allow for more rapid delivery / illicit quick feedback / gather data necessary to correct design
- Plan to sell several different products. Starting with just one. Don’t extract interface yet.
Allows us to establish a simple understanding of a complex problem in common representational terms
"We incurred structural debt in order to meet your deadline. We should discuss that debt and set a plan for paying it back later."
"We incurred mechanical debt to stay in budget. We should get metrics around that and make sure we pay the debt down in the future."
"We incurred health debt during the surgery. You see, it is like we paid for the surgery with a credit card instead of a home equity loan..."
First, let’s get rid of the curlies for readability
Now, let’s assume we don’t have multiple tables in our DataSets nor do we need to iterate through multiple columns in cases where we’re looking for an AgentID or queueName
Now let’s introduce some abstraction. We’ll create some classes that receive DataSets and return collections of objects. We’re not showing these here. Our ORM could do this for us. And let’s not make the same series of calls for queue data for every agent.
Now we can see what this does. We get a list of skills for an agent, compare them to a list of skills for a queue and call SetAgentQueueSkill for all matches. Seems to me, this code shouldn’t exist. The AgentQueueSkill table should be a view in the dB.
Is this where this evaluation belongs? Probably not. What are we checking for here? Perhaps a comment will help us.
Better? Not really. But what if that comment was code?
What about this one?
Why is this NOT cruft? We clearly have more code.
1. Gartner Report in 2009 :: Includes Hardware 2. CAST Study in 2009 :: No correlation between size and debt; more modular == less debt
Ruby - churn => volume of changes git - gitswarm => visual history of changes Java - Cobertura or Sonar
Ruby - churn => volume of changes git - gitswarm => visual history of changes Java - Cobertura or Sonar