Necessary complexity in existing Django apps

Simplify to improve; but sometimes it's not possible or reasonable to simplify difficult to understand code. Understand why this can be the case in your Django project and some strategies for mitigating these issues.

In the last two videos we talked about tests and technical debt, rather no tests, bad tests, slow tests, and then what it means to have technical debt in a Django project.

Today we’re going to talk about the third reason, which is necessary complexity. So, before we start, let’s talk about what it means for software to be complex.

It means, you know, it’s difficult to understand. It could mean that it’s difficult to work with. It could mean that it’s difficult to test in some way. There’s something about how it works which is just a little bit counterintuitive perhaps or there’s just too much there.

Now, often, this can be technical debt itself and that’s probably the first thing that comes to mind when you think about complexity in your projects, but there’s a type of complexity that really there’s no way to get around. And that can still make it difficult to work with your Django project.

So, we’re going to look at what types of necessary complexity there are and some solutions to, at least make it easier to work with.

So the first type is algorithmic complexity and the second type is domain complexity. Algorithmic complexity is probably the easier to understand.

Basically, think about an algorithm you might have or some calculations in your project that are maybe just necessarily complex to do the thing you want to do. There’s no way around it. You can’t just chain a couple of quick functions together, and you know, there’s extra queryset method you can add, and you really, you’ve got to go through a lot of steps to do the work.

And maybe there’s a simpler way of writing the algorithm, but it’s not as performant. And, so, there’s this tradeoff that you’ve made and it’s a necessary tradeoff based on your priorities and it leaves you with more complex code.

It’s a little bit harder to understand for anyone new to the project, or even for yourself if you come back to it after a little while. And it could also be a little bit more difficult to test. That’s the first type.

The second type is domain complexity. And this arises from software that works in a domain, it’s solving a problem in a business domain, and has some sort of level of complexity to it by itself.

This is usually the case in regulated industries or it could be specialized industries. It’s the case in finance education policy, healthcare. You’re going to run into some sort of domain knowledge that needs to be applied to the project, whether that’s names, rules, or any combination thereof.

This is, again, far more common in Django projects or any web project. So, how do you solve for these? For algorithmic complexity, really what you want to do is just have really solid documentation.

You want to make sure that someone else, even yourself in the future, isn’t coming in and maybe trying to make changes that don’t need to be made and that you’ve setup the testing as well as it can be set up and that is documented, too.

So you can come in and hopefully improve this in the future, if need be, but you’ve documented this to the greatest degree possible. And, this may be obvious, but you want to have as many entry points as you possibly can.

So, yes, bring it down to the bare, you know, only to the level of complexity that is absolutely necessary and then stopping there.

With domain complexity, again, documentation is often the answer. One of the issues you run into with complicated domains, or you know, we’ll call them technical domains, is you need specialized names.

So, you might have, there’s all kinds of names that define things in this business domain and you want to translate those somehow to the Django project. Now, you could rename these things, whether they are models or fields, otherwise, in a way that is very intuitive to you.

But, what happens is you risk losing the connection to what it actually means in the real world, or at least the business domain world. So, it’s often much better to keep those names, even if they are a little bit confusing at first to a new developer or, again, to yourself coming back to the project.

So, the key here is document. Understand why you have these fields here. And then adding in interfaces in the form of model methods, or properties, so that you can expose things that make sense to a developer coming in, but maintain all of the properly named business relationships in the application itself.

The other thing you can do is make sure you have lots of references to the business domain. So, you can explain to yourself or a new developer, why? What does this mean? Not just why did someone name this this way.

Oh, it’s because we thought it did a really good job of representing the way these two things should interact. No, this was named this way because of this thing named in this document. This official document. Maybe it’s uh, you know, a US federal government document. Or maybe it’s some soft of industry regulatory document. Or something else like that.

But, explaining what that is so someone knows. Oh, okay, this has meaning here. And, if need be, they can actually refer to that to extract more information about why this is named.

Now, this may seem counterintuitive to you, hey, the software really should be self-documenting. It should explain everything.

But, again, in a really technical domain it’s important, it’s critical, to maintain this connection to the business domain because there is a greater risk of losing that and having the program do something or rather changing it to do something that it’s not supposed to than there is in having to deal with a name that maybe isn’t immediately intuitive to a new developer.

So, there are, there are all kinds of other methods you can use that are more applicable to technical debt, I think, or to solve your technical debt, to make some of the code simpler as far as how you break it apart but the solution here is basically just really thorough documentation.

And making sure that every developer understands that these things are named not just for you know, for your convenience, but for the convenience of mapping out the technical domain. The domain that this application is solving, to the application itself.

That’s probably not the most satisfying answer, uh, but eventually what happens is, when you have this all documented, it’s still going to be a little bit slow to make changes, it’s not going to be, it’s not like working on a blog engine where okay we have a post and comments it’s a little bit more complicated than that.

But, you will reduce the risk of error and you know, the confusion as you go through and develop. And that has a significant speed up factor in and of itself.

So, again, I hope that’s helpful. The next episode we’ll talk about the last reason, which is out of date software. And you can click through in the description to sign up for our newsletter, This Old Pony, which is the Django newsletter devoted to legacy Django.