SlideShare uma empresa Scribd logo
1 de 61
The Technical Debt Trap
Michael “Doc” Norton
@DocOnDev
Michael “Doc” Norton
Groupon
Director of
Technology
doc@groupon.com
@DocOnDev




Husband           Father
GrandFather
He’s SOOO Cute!!
What is Technical Debt?
Ward
Cunningham
Shipping first time code is
like going into debt.




                OOPSLA ’92
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
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
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
Technical Debt is a Good Idea
Technical Debt is a Good Idea




WTF?
Technical Debt is a Good Idea
Strategic Design Decision
  Allow for Rapid Delivery
  To Elicit Quick Feedback
  And Correct Design
Technical Debt is a Metaphor
Here Be Danger
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
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
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
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.
 http://www.youtube.com/watch?v=pqeJFYwnkjE&feature=player_embedded


                          YouTube.com ’09
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
[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 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
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
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
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?
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
You have a mess
Mess (noun)
Disorderly accumulation, heap, or jumble
A state of embarrassing confusion
An unpleasant or difficult situation
You have cruft
Cruft (noun)
An unpleasant substance
The result of shoddy construction
Redundant, old or improperly written code
Chill. It’s just semantics,
man.
Just Semantics?
Technical Debt is Good
Chill. It’s just semantics,
man.
Just Semantics?
Quick and Dirty is Technical Debtis Good
                   Technical Debt is Good
Chill. It’s just semantics,
man.
Just Semantics?
Quick and Dirtyis Good
          Dirty is Good
The Technical Debt Quadrant




        http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
The Technical Debt Quadrant
                                                “Let’s deploy and
                                                   gather more
                                                  information.”




        http://martinfowler.com/bliki/TechnicalDebtQuadrant.html
Technical Debt in other
fields
Construction
                                      TE
                                   R A
                               IB E
                            E L
                      D D
                 AN
           S   S
         LE
      CK
    RE
Technical Debt in other
fields
Automotive
                                      TE
                                   R A
                               IB E
                            E L
                      D D
                 AN
           S   S
         LE
      CK
    RE
Technical Debt in other
fields
Medical
                                     NT
                                  TE
                               E R
                            D V
                        IN A
                  N D
               S A
          ES
       K L
     EC
    R
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
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
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
Cruft or Debt?
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; }
          }
        }
      }
    }
  }
}




                                    http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
Cruft or Debt?
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; }
      }
    }
  }
}




                                    http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
Cruft or Debt?

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 Regulated
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.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");}




                   http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
Cruft or Debt?

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 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)
The Cost of “Technical Debt”
We did this
WORLD-WIDE TECHNICAL DEBT (INCLUDES HARDWARE)
              $1 Trillion (by 2015)
PER BUSINESS APPLICATION
              $1 Million
Grammy
Doesn’t
Love
Me!
Me!
Me!

It’s all about expectations
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
Avoid The Trap
Thresholds set false
expectations




       http://blog.castsoftware.com/wp-content/uploads/2011/04/Technical-Debt-Software-Quality1.jpg
Avoid The Trap
Incremental fixes fail




        http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
Avoid The Trap
Incremental fixes fail




        http://www.jacoozi.com/blog/wp-content/uploads/2007/01/refactoring_coc_big.jpg
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
Monitoring Cruft/Debt
A few key metrics
Code Coverage
Cyclomatic Complexity
Coupling
Maintainability
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
Monitoring Cruft/Debt
Cyclomatic Complexity
Number of logical branches in code
Direct relationship with bugs
Typically high in concentrated areas
Reduce conditionals
Monitor trends, not points
Monitoring Cruft/Debt
Coupling
Interconnectedness of systems
Highly coupled is difficult to change
Afferent (Toward) and Efferent (Away)
Dependency Injection
Monitor trends, not points
Cruft/Debt Cards
Tie it to Business Value
Velocity
Scalability
Availability
Maintainability
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
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
Thank You!



 The Technical Debt Trap
 Michael “Doc” Norton
 @DocOnDev

Mais conteúdo relacionado

Semelhante a THE TECHNICAL DEBT TRAP

Agile and Beyond :: The Technical Debt Trap
Agile and Beyond :: The Technical Debt TrapAgile and Beyond :: The Technical Debt Trap
Agile and Beyond :: The Technical Debt TrapDoc Norton
 
The Technical Debt Trap
The Technical Debt TrapThe Technical Debt Trap
The Technical Debt TrapDoc Norton
 
Virtual enterprise synthesys
 Virtual enterprise synthesys Virtual enterprise synthesys
Virtual enterprise synthesysVictor Romanov
 
Ports and Adapters Architecture
Ports and Adapters ArchitecturePorts and Adapters Architecture
Ports and Adapters Architectureofir attal
 
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudy
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudyJarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudy
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudyPalGov
 
Tackling Tech Debt with Rector
Tackling Tech Debt with RectorTackling Tech Debt with Rector
Tackling Tech Debt with RectorMichele Orselli
 
Government Interoperability Framework (Palestine Case) v5
Government Interoperability Framework (Palestine Case) v5Government Interoperability Framework (Palestine Case) v5
Government Interoperability Framework (Palestine Case) v5jarrar
 
Creating Responsive Experiences
Creating Responsive ExperiencesCreating Responsive Experiences
Creating Responsive ExperiencesTim Kadlec
 
Ports and Adapters Architecture - solid
Ports and Adapters Architecture - solidPorts and Adapters Architecture - solid
Ports and Adapters Architecture - solidofir attal
 
Deploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero DowntimeDeploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero DowntimeTwilio Inc
 
Stories Every Developer Should Know
Stories Every Developer Should KnowStories Every Developer Should Know
Stories Every Developer Should KnowThoughtworks
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
HTML5 Introduction
HTML5 IntroductionHTML5 Introduction
HTML5 Introductionbeforeach
 
A Lay of the Meta-land: A Systematic Approach to Dissect the Metaverse
A Lay of the Meta-land: A Systematic Approach to Dissect the MetaverseA Lay of the Meta-land: A Systematic Approach to Dissect the Metaverse
A Lay of the Meta-land: A Systematic Approach to Dissect the MetaverseCatrinaWang4
 
KSQL: The Streaming SQL Engine for Apache Kafka
KSQL: The Streaming SQL Engine for Apache KafkaKSQL: The Streaming SQL Engine for Apache Kafka
KSQL: The Streaming SQL Engine for Apache KafkaChris Mueller
 
Architecture in an Agile World
Architecture in an Agile WorldArchitecture in an Agile World
Architecture in an Agile WorldDon McGreal
 
AWS Stripe Meetup - Powering UK Startup Economy
AWS Stripe Meetup - Powering UK Startup EconomyAWS Stripe Meetup - Powering UK Startup Economy
AWS Stripe Meetup - Powering UK Startup EconomyAmazon Web Services
 
From CRUD to messages: a true story
From CRUD to messages: a true storyFrom CRUD to messages: a true story
From CRUD to messages: a true storyAlessandro Melchiori
 
Databaseconcepts
DatabaseconceptsDatabaseconcepts
Databaseconceptsdilipkkr
 

Semelhante a THE TECHNICAL DEBT TRAP (20)

Agile and Beyond :: The Technical Debt Trap
Agile and Beyond :: The Technical Debt TrapAgile and Beyond :: The Technical Debt Trap
Agile and Beyond :: The Technical Debt Trap
 
The Technical Debt Trap
The Technical Debt TrapThe Technical Debt Trap
The Technical Debt Trap
 
Virtual enterprise synthesys
 Virtual enterprise synthesys Virtual enterprise synthesys
Virtual enterprise synthesys
 
Ports and Adapters Architecture
Ports and Adapters ArchitecturePorts and Adapters Architecture
Ports and Adapters Architecture
 
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudy
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudyJarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudy
Jarrar.lecture notes.aai.2011s.ontology part5_egovernmentcasestudy
 
Tackling Tech Debt with Rector
Tackling Tech Debt with RectorTackling Tech Debt with Rector
Tackling Tech Debt with Rector
 
Government Interoperability Framework (Palestine Case) v5
Government Interoperability Framework (Palestine Case) v5Government Interoperability Framework (Palestine Case) v5
Government Interoperability Framework (Palestine Case) v5
 
Creating Responsive Experiences
Creating Responsive ExperiencesCreating Responsive Experiences
Creating Responsive Experiences
 
Ports and Adapters Architecture - solid
Ports and Adapters Architecture - solidPorts and Adapters Architecture - solid
Ports and Adapters Architecture - solid
 
Deploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero DowntimeDeploying Next Gen Systems with Zero Downtime
Deploying Next Gen Systems with Zero Downtime
 
PHPUG Presentation
PHPUG PresentationPHPUG Presentation
PHPUG Presentation
 
Stories Every Developer Should Know
Stories Every Developer Should KnowStories Every Developer Should Know
Stories Every Developer Should Know
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
HTML5 Introduction
HTML5 IntroductionHTML5 Introduction
HTML5 Introduction
 
A Lay of the Meta-land: A Systematic Approach to Dissect the Metaverse
A Lay of the Meta-land: A Systematic Approach to Dissect the MetaverseA Lay of the Meta-land: A Systematic Approach to Dissect the Metaverse
A Lay of the Meta-land: A Systematic Approach to Dissect the Metaverse
 
KSQL: The Streaming SQL Engine for Apache Kafka
KSQL: The Streaming SQL Engine for Apache KafkaKSQL: The Streaming SQL Engine for Apache Kafka
KSQL: The Streaming SQL Engine for Apache Kafka
 
Architecture in an Agile World
Architecture in an Agile WorldArchitecture in an Agile World
Architecture in an Agile World
 
AWS Stripe Meetup - Powering UK Startup Economy
AWS Stripe Meetup - Powering UK Startup EconomyAWS Stripe Meetup - Powering UK Startup Economy
AWS Stripe Meetup - Powering UK Startup Economy
 
From CRUD to messages: a true story
From CRUD to messages: a true storyFrom CRUD to messages: a true story
From CRUD to messages: a true story
 
Databaseconcepts
DatabaseconceptsDatabaseconcepts
Databaseconcepts
 

Mais de Doc Norton

Tuckman Was Wrong
Tuckman Was WrongTuckman Was Wrong
Tuckman Was WrongDoc Norton
 
A Practical Guide to Cynefin
A Practical Guide to CynefinA Practical Guide to Cynefin
A Practical Guide to CynefinDoc Norton
 
Building Blocks of a Knowledge Work Culture - NDC London 2016
Building Blocks of a Knowledge Work Culture - NDC London 2016Building Blocks of a Knowledge Work Culture - NDC London 2016
Building Blocks of a Knowledge Work Culture - NDC London 2016Doc Norton
 
Codemash pre-compiler - Collaborative Decision Making
Codemash pre-compiler - Collaborative Decision MakingCodemash pre-compiler - Collaborative Decision Making
Codemash pre-compiler - Collaborative Decision MakingDoc Norton
 
Experimentation Mindset
Experimentation MindsetExperimentation Mindset
Experimentation MindsetDoc Norton
 
Switching horses midstream - From Waterfall to Agile
Switching horses midstream - From Waterfall to AgileSwitching horses midstream - From Waterfall to Agile
Switching horses midstream - From Waterfall to AgileDoc Norton
 
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps Culture
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps CultureAutonomy, Connection, and Excellence; The Building Blocks of a DevOps Culture
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps CultureDoc Norton
 
Creative Collaboration: Tools for Teams
Creative Collaboration: Tools for TeamsCreative Collaboration: Tools for Teams
Creative Collaboration: Tools for TeamsDoc Norton
 
Experimentation mindset
Experimentation mindsetExperimentation mindset
Experimentation mindsetDoc Norton
 
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014Doc Norton
 
Teamwork Ain't Easy - RailsConf 2014
Teamwork Ain't Easy - RailsConf 2014Teamwork Ain't Easy - RailsConf 2014
Teamwork Ain't Easy - RailsConf 2014Doc Norton
 
Creating a Global Engineering Culture - Agile india 2014
Creating a Global Engineering Culture - Agile india 2014Creating a Global Engineering Culture - Agile india 2014
Creating a Global Engineering Culture - Agile india 2014Doc Norton
 
Doc That Conference Keynote
Doc That Conference KeynoteDoc That Conference Keynote
Doc That Conference KeynoteDoc Norton
 
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013Doc Norton
 
Velocity is not the goal code palo-usa
Velocity is not the goal   code palo-usaVelocity is not the goal   code palo-usa
Velocity is not the goal code palo-usaDoc Norton
 
Teamwork Ain't Easy
Teamwork Ain't EasyTeamwork Ain't Easy
Teamwork Ain't EasyDoc Norton
 
Velocity is NOT the Goal - PNSQC
Velocity is NOT the Goal - PNSQCVelocity is NOT the Goal - PNSQC
Velocity is NOT the Goal - PNSQCDoc Norton
 
Growing into Excellence - PNSQC
Growing into Excellence - PNSQCGrowing into Excellence - PNSQC
Growing into Excellence - PNSQCDoc Norton
 
Velocity is not the Goal
Velocity is not the GoalVelocity is not the Goal
Velocity is not the GoalDoc Norton
 
Do I have a role?
Do I have a role?Do I have a role?
Do I have a role?Doc Norton
 

Mais de Doc Norton (20)

Tuckman Was Wrong
Tuckman Was WrongTuckman Was Wrong
Tuckman Was Wrong
 
A Practical Guide to Cynefin
A Practical Guide to CynefinA Practical Guide to Cynefin
A Practical Guide to Cynefin
 
Building Blocks of a Knowledge Work Culture - NDC London 2016
Building Blocks of a Knowledge Work Culture - NDC London 2016Building Blocks of a Knowledge Work Culture - NDC London 2016
Building Blocks of a Knowledge Work Culture - NDC London 2016
 
Codemash pre-compiler - Collaborative Decision Making
Codemash pre-compiler - Collaborative Decision MakingCodemash pre-compiler - Collaborative Decision Making
Codemash pre-compiler - Collaborative Decision Making
 
Experimentation Mindset
Experimentation MindsetExperimentation Mindset
Experimentation Mindset
 
Switching horses midstream - From Waterfall to Agile
Switching horses midstream - From Waterfall to AgileSwitching horses midstream - From Waterfall to Agile
Switching horses midstream - From Waterfall to Agile
 
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps Culture
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps CultureAutonomy, Connection, and Excellence; The Building Blocks of a DevOps Culture
Autonomy, Connection, and Excellence; The Building Blocks of a DevOps Culture
 
Creative Collaboration: Tools for Teams
Creative Collaboration: Tools for TeamsCreative Collaboration: Tools for Teams
Creative Collaboration: Tools for Teams
 
Experimentation mindset
Experimentation mindsetExperimentation mindset
Experimentation mindset
 
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014
Agile Metrics : Velocity is NOT the Goal - NDC Oslo 2014
 
Teamwork Ain't Easy - RailsConf 2014
Teamwork Ain't Easy - RailsConf 2014Teamwork Ain't Easy - RailsConf 2014
Teamwork Ain't Easy - RailsConf 2014
 
Creating a Global Engineering Culture - Agile india 2014
Creating a Global Engineering Culture - Agile india 2014Creating a Global Engineering Culture - Agile india 2014
Creating a Global Engineering Culture - Agile india 2014
 
Doc That Conference Keynote
Doc That Conference KeynoteDoc That Conference Keynote
Doc That Conference Keynote
 
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013
Agile Metrics; Velocity is NOT the Goal - ScrumGathering 2013
 
Velocity is not the goal code palo-usa
Velocity is not the goal   code palo-usaVelocity is not the goal   code palo-usa
Velocity is not the goal code palo-usa
 
Teamwork Ain't Easy
Teamwork Ain't EasyTeamwork Ain't Easy
Teamwork Ain't Easy
 
Velocity is NOT the Goal - PNSQC
Velocity is NOT the Goal - PNSQCVelocity is NOT the Goal - PNSQC
Velocity is NOT the Goal - PNSQC
 
Growing into Excellence - PNSQC
Growing into Excellence - PNSQCGrowing into Excellence - PNSQC
Growing into Excellence - PNSQC
 
Velocity is not the Goal
Velocity is not the GoalVelocity is not the Goal
Velocity is not the Goal
 
Do I have a role?
Do I have a role?Do I have a role?
Do I have a role?
 

THE TECHNICAL DEBT TRAP

  • 1. The Technical Debt Trap Michael “Doc” Norton @DocOnDev
  • 2. Michael “Doc” Norton Groupon Director of Technology doc@groupon.com @DocOnDev Husband Father
  • 5. Ward Cunningham Shipping first time code is like going into debt. OOPSLA ’92
  • 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
  • 9. Technical Debt is a Good Idea
  • 10. Technical Debt is a Good Idea WTF?
  • 11. Technical Debt is a Good Idea Strategic Design Decision Allow for Rapid Delivery To Elicit Quick Feedback And Correct Design
  • 12. Technical Debt is a Metaphor Here Be Danger
  • 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.
  • 20. ... confused it with the idea that you could write code poorly ....
  • 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
  • 39. Cruft or Debt? 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; } } } } } } } http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
  • 40. Cruft or Debt? 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; } } } } } http://thedailywtf.com/Series/2010/3/CodeSOD.aspx
  • 41. Cruft or Debt? 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)) { ... }
  • 42. Cruft or Debt? // If customer is Federally Regulated 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)) { ... }
  • 43. Cruft or Debt? if (customer.isFederallyRegulated()) { ... }
  • 44. 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");} http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
  • 45. Cruft or Debt? 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
  • 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
  • 54. Monitoring Cruft/Debt A few key metrics Code Coverage Cyclomatic Complexity Coupling Maintainability
  • 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
  • 56. Monitoring Cruft/Debt Cyclomatic Complexity Number of logical branches in code Direct relationship with bugs Typically high in concentrated areas Reduce conditionals Monitor trends, not points
  • 57. Monitoring Cruft/Debt Coupling Interconnectedness of systems Highly coupled is difficult to change Afferent (Toward) and Efferent (Away) Dependency Injection Monitor trends, not points
  • 58. Cruft/Debt Cards Tie it to Business Value Velocity Scalability Availability Maintainability
  • 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

  1. Design decisions that allow for more rapid delivery / illicit quick feedback / gather data necessary to correct design
  2. - Plan to sell several different products. Starting with just one. Don’t extract interface yet.
  3. Allows us to establish a simple understanding of a complex problem in common representational terms
  4. "We incurred structural debt in order to meet your deadline. We should discuss that debt and set a plan for paying it back later."
  5. "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."
  6. "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..."
  7. First, let’s get rid of the curlies for readability
  8. 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
  9. 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.
  10. 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.
  11. Is this where this evaluation belongs? Probably not. What are we checking for here? Perhaps a comment will help us.
  12. Better? Not really. But what if that comment was code?
  13. What about this one?
  14. Why is this NOT cruft? We clearly have more code.
  15. 1. Gartner Report in 2009 :: Includes Hardware 2. CAST Study in 2009 :: No correlation between size and debt; more modular == less debt
  16. Ruby - churn => volume of changes git - gitswarm => visual history of changes Java - Cobertura or Sonar
  17. Ruby - churn => volume of changes git - gitswarm => visual history of changes Java - Cobertura or Sonar
  18. Java - Cobertura, Clover, EMMA .NET - NCover Ruby - rcov / metric_fu
  19. Java - Cobertura, Clover, EMMA .NET - NCover Ruby - rcov / metric_fu
  20. NDepend JDepend