Mjanaging Tjechnical Djebt

What is technical debt?

  • [Technical debt] can be thought of as work that needs to be done before a particular job can be considered complete or proper. [citation needed]
  • Gene Kim: Left unchecked, technical debt will ensure that the only work that gets done is unplanned work!
  • Every line of code is technical debt
  • When you fix one bug only to create another
  • When you can’t deliver a feature because you don’t know what will break
  • If you’re using a rapid development framework and can’t rapidly develop
  • “it works for me”
  • Everything is on fire all the time
  • When you fix one bug only to create another
  • When you can’t deliver a feature or security patch because you don’t know what will break
  • If you’re using a rapid development framework and can’t rapidly develop
  • “It works for me”
  • Everything is on fire all the time

Tests. Do it.




When to test?

If you're making an assumption, you should test it.


def zipcode(s):
    """
    Get the 5 digit zipcode from any zipcode format.

    >>> zipcode('12345-6789')
    "12345"
    >>> zipcode('12345')
    "12345"
    >>> zipcode(12345)
    "12345"
    >>> zipcode(1337)
    "01337"
    >>> zipcode(None)
    ValueError: s must be a US postal zip code
    """
    return s[:5]
    

Don't have a single test?

Gotta start somewhere.


from django.test import TestCase

class HomeTests(TestCase):
    def test_homepage_loads(self):
        self.client.get('/')
    

blog.doismellburning.co.uk/2015/08/05/the-most-efficient-django-test/

When to test? (cont'd)

Consider regression testing should be mandatory.

You will sleep better at night with good test coverage.

Coverage

Coverage is just a tool to help you figure out where you're missing tests.

100% coverage isn't useful if you have crappy tests.

Signs your tests are crappy

  • Can other people read and extend them?
  • Are tests getting maintained? Or are they a source of frustration?
  • Do your tests describe the problem in a way where someone could throw away the code and use the tests as a spec?

Bitrot / Software entropy

 

If you're not touching something, it's getting worse

If you don't have the manpower to continously touch all your code and documentation, that's a smell

Improvement Kata - Mike Rother

Applications age like fish, data ages like wine

Automation

“Any task you do at least once a month should take less time than it takes to get a cup of coffee”

Original: Any system that must be deployed more often than monthly does so faster than you can get a cup of coffee.

xkcd/1205
xkcd/1319

Code quality

  • Practice makes perfect. Always be iterating.
  • Keep things simple. Code that requires less context to understand is more readable.
  • Keep things short. Every LOC is debt.
  • Know your audience.
  • Choose readability over performance.
  • import this

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
...
    

from operators import attrgetter

friends = [
    aquacorg,
    corgnelius,
    stumphery,
    gatsby,
    scout,
    tibby,
    winston,
]

# Which is better?
accounts = map(attrgetter('instagram'), friends)

accounts = [x.instagram for x in friends]
    

Pizza Story

Code Silos Specialist Unicorns

Avoiding code silos

Make yourself obsolete

Pretend you're training your replacement

Could you go on vacation without your laptop?







Related topics

  • #nocomments – Do comments help or hurt readability?
  • Cyclomatic complexity – quantify readability
  • McCabe
  • PEP8
  • PyFlakes

Code review

This is the single most practical way to get better.

  • People take too much time to review
  • I'm the boss
  • We need to push this hotfix for production ASAP






No one to review your code?

Sleep on it

Practice with others on open source projects

As iron sharpens iron, so one person sharpens another.

Pull requests

The rule is: one pull request = one change

Boy scout rule

Leave this world a little better than you found it.
– Robert Baden Powell

If you have to touch a test to clean something, leave it alone for now.

Code review is more than reviewing code

  • Repeatable?
  • Documentated?
  • Maintainable? (Does the feature justify the technical debt?)

Raymond Hettinger - Beyond PEP 8

Technical debt note

A fiscal note is a written estimate of the costs, savings, revenue gain, or revenue loss that may result from implementation of requirements in a bill or joint resolution. It serves as a tool to help legislators better understand how a bill might impact the state budget as a whole, individual agencies, and in some instances, local governments.

Pair programming

The best way to up code quality and share knowledge

 
  • tmux + vim
  • Driver + Navigator
  • Pair
    Programming
    Ping
    Pong
    Pattern

Teams

Guess what? Software teams are just like other teams

The team should care about controlling technical debt

Robots can help

Past you is the worst coworker ever

Culture

Get faster feedback loops

  • Sprints
  • Code review
  • CI/CD
  • Reduce friction
  • Release early, release often
  • Use analytics

Culture

Embrace failure (high trust)

Learn how to say “NO”

Write up concrete plans to reduce technical debt as actionable items

Task
Reduce homepage query count ┬──┬
Fix inconsistent migrations ┬───┬
Add CSRF ┬─┬
Refactor Polls views to CBV ┬─┬
Upgrade from Django 1.5 to 1.8 ┬─────┬

Trading technical debt

  • Deciding up front what you're optimizing for
  • Technical debt is a deliberate design decision






Now what?

Single responsibility principle

Do one thing, do it well

UNIX philosophy, Docker images, Microservices, OOP

Document how it works:
Throw away the code, reuse the interface

Kill babies

Taco Bell Future

  • Froze content with wget
  • Old stuff still worked and looked the same
  • Deleted all the things
  • New stuff was easy to write

The TweetWire

PHP

Django Models

Cron Job

Streaming Client

No Admin

<a class="twitter-timeline" />

Django is great

Writing tests is easy

Less boilerplate

Great community

Don't customize the Admin

The admin is a developer interface, not a CMS

Writing your own seems like it's more technical debt, but you'll end up with a better user experience

Admin customizations == tight coupling

A partial list of admin packages you can use instead of coding your own:

Clean as you cook

Delete code! That's what source control is for.

If you think you'll need to toggle something, don't use comments, use a feature switch.

Open tickets for things you find (see boy scout rule)

Naming things

 

Is it greppable?

Find/Replace friendly?

Name variables (especially in tests) so they read like English

Readable tests

Keep boilerplate out.


class ArticleManagerTests(TestCase):
    def test_stuff(self):
        a = Article(active=True,
                    title='Corgi Beach Day',
                    slug='corgi-beach-day',
                    text='Corgs got sand on their stumpers'
                    pub_date='2015-09-31')
        self.assertIn(a, Article.objects.active())

    def test_active_returns_only_active_articles(self):
        article = ArticleFactory(active=True)
        self.assertIn(article, Article.objects.active())
    

Use unique names


$ ./manage.py shell_plus
# Shell Plus Model Imports
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import Group, Permission, User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from tx_elevators.models import Building, Elevator
# Shell Plus Django Imports
from django.utils import timezone
from django.conf import settings
from django.core.cache import cache
from django.db.models import Avg, Count, F, Max, Min, Sum, Q, Prefetch
from django.core.urlresolvers import reverse
from django.db import transaction
>>> Elevator.objects.count()
51952
    

Avoid the test client

Don’t use it! For unit tests.

Do Use it! For integration tests

urls
request middleware
views (dispatch/get/get_context_data)
response middleware
context_processor

Avoid model inheritance

Mixins and Base classes

Hurts readability and performance

Stay fresh

requirements.txt:

Every pull request, if a version can be bumped, bump it.


$ pip list --outdated
$ bundle outdated
$ npm outdated
    

This only works if you have test coverage!

Reading

  • Docker and DevOps by Gene Kim, Dockercon ’14, 38m45s
  • Inheriting a Sloppy Codebase by Casey Kinsey, 42m04s
  • Simple Made Easy by Rich Hickey, 61m26s
  • Implementing a Strong Code-Review Culture 37m48s
  • Reading (for real)

       

    Similar discussions

    • Microservices vs Monoliths
    • Not invented here syndrome
    • Feature creep
    • Insert product development buzzword here *

     

     

     
    • Get frustrated
    • Get lazy – Automate away routine tasks
    • Faster feedback loops
    • Always be touching
    • Treat fixing technical debt as a feature
    • Clean as you code
    • Foster a good coding culture
    • Single responsibility principle
    • Everything must be repeatable
    • Plan ahead for the whole lifecycle

    Thanks!

    github/crccheck/tech-debt-talk

    
    docker run --rm -p 8000:1947 crccheck/tech-debt