The Sources of Friction in Legacy Django Projects

Whether months or years after launch, it can become increasingly painful to make changes to any application, Django-based sites included. An overview of some of the causes and an introduction to the series.

Today I want to talk to you about some of the reasons you may find it difficult and costly to make changes to your existing Django site.

Now let’s back up for a minute. Django, the web framework for perfectionists with deadlines, isn’t known for being difficult to work with, and in truth, it’s not. Any application running a long enough production, written in any framework or language, tends to become more difficult to make changes to, whether those are minor updates or new features.

What I want to do today is give you an overview of some of these reasons, so we can create strategies for assessing and cleaning up your codebase, making it easier to add the features you need on your site.

These challenges tend to group into four top level categories: technical debt, out of date software, tests or lack thereof, and necessary complexity. We’re going to walk through each of these in brief.

Technical Debt

You can’t talk about existing software or legacy software without talking about technical debt. There are a lot of descriptions and definitions of technical debt out there. From shortcuts other developers made that you have to live with, to careful trade-offs made to optimize for near-term business goals. It’s a little bit of both, but I’d summarize by saying that technical debt is manifested opportunity cost.

Some previous developer or developer team was faced with a decision to make. They had two options in front of them and they chose one. The cost of not choosing the other is now what you have to deal with. This isn’t necessarily bad programming. A lot of people confuse technical debt with bad programming, and it’s rare that bad programming is the cause of technical debt. By bad programming, think infinite loops. The kind of code you look at and think, “A team of drunken monkeys must have written this.”

Usually it’s because there was some sort of change to business strategy, or features, or some sort of use that the previous team couldn’t anticipate. They made the best decision with the information available at the time, and everything changed. The world around the application changed and now there are structural issues that you have to deal with. This is technical debt.

Out of Date Software

Out of date software like an older, third-party library or backing service makes updates to your site more difficult, because it creates an anchor against which you have to check every other requirement.

Let’s take a third-party library, for example. This library may make use of a Django API that has been since deprecated in newer versions of Django. If you update Django, you need to update this third-party library, as well. That’s well and good, and you probably should do that, but if this library hasn’t been kept up to date or newer versions have other changes that require you to make other changes to your application or to third-party libraries that that dependency requires, now the scope of your changes are magnified much beyond what you initially anticipated.

This is true also of backing services. If you have a part of your application or a third-party library that makes use of features in a database that may be reverse specific, you may have to upgrade the database in conjunction with updates to the application or your framework.

Tests

Tests, or the lack thereof, are another reason it can be difficult to make changes to your Django site. Tests come in four flavors: great tests, no tests, bad tests and slow tests. Any combination of the latter through will make it more difficult to make changes to your site.

No tests means you have no way of verifying whether any changes to the codebase break anything on the site. This is risky and it slows down development, as it probably should.

Slow tests mean that the test suite takes forever to run, for whatever reason. Now this has a tendency of slowing down development because you have to wait for the test suite to run for every, single change. This gets old and developers have a tendency of not running test suites that take a long time.

Bad tests can be bad for a number of reasons, but they could be bad because there are all kinds of errors in the test suite. That is, it isn’t really running successfully. Or it is running successfully, but the tests just aren’t meaningful.

Necessary Complexity

The last reason is necessary complexity. This comes in two flavors: computational and domain. In short, it means that some Django apps, or any program, have high degrees of complexity that are unavoidable because the problem they are trying to solve is unavoidably complex.

Now this could be because the problem that an application is trying to solve requires some algorithmic complexity.

More often than not, it’s a domain issue. An application models an industry, domain or business-specific process where the names and rules are predetermined outside of the application, are complex and may be opaque, especially to new developers.

I hope that wasn’t a lot of doom and gloom. In the next videos in this series, we’ll dive into each of these reasons in more detail, as well as some of the strategies you can take to make it easier and less costly to make changes to your existing Django site.