Left unchecked, technical debt will ensure that the only work that gets done is unplanned work!
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]
Gotta start somewhere.
from django.test import TestCase class HomeTests(TestCase): def test_homepage_loads(self): self.client.get('/')
Consider regression testing should be mandatory.
You will sleep better at night with good test 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.
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
“Any task you do at least once a month should take less time than it takes to get a cup of coffee” †
>>> 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]
Make yourself obsolete
Pretend you're training your replacement
Could you go on vacation without your laptop?
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
Sleep on it
Practice with others on open source projects
As iron sharpens iron, so one person sharpens another.
The rule is: one pull request = one change
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.
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.
The best way to up code quality and share knowledge
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
Get faster feedback loops
Embrace failure (high trust)
Learn how to say “NO”
Write up concrete plans to reduce technical debt as actionable items
|Reduce homepage query count||┬──┬|
|Fix inconsistent migrations||┬───┬|
|Refactor Polls views to CBV||┬─┬|
|Upgrade from Django 1.5 to 1.8||┬─────┬|
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
<a class="twitter-timeline" />
Writing tests is easy
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:
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)
Is it greppable?
Name variables (especially in tests) so they read like English
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())
$ ./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
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
Mixins and Base classes
Hurts readability and performance
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!
docker run --rm -p 8000:1947 crccheck/tech-debt