Almost everyone has heard of Technical Debt by now, but Functional Debt exists too.
Let me tell you about Functional Debt, what it can do to you if you’re not careful, and how to keep it at bay.
What is Functional Debt?
Because this isn’t something wildly talked about yet, the definitions may vary, but I’ll share mine here:
Functional Debt is the direct result of previous business decisions that causes a degraded ability to address current or future business goals.
– Matt Eland
Let’s unpack this definition.
By degraded , I’m referring to anything that slows or prevents the business from making improvements or changes in the way they’d want to.
By direct result I’m talking in particular about intentional choices made by the business in some point in its existence. Additionally, choosing to “go fast” and not make drawn out choices can be a choice in of itself as this can constrain future changes as well.
Let’s give a hypothetical example:
Let’s say you’re a software startup with a small web application. You’re growing a user base and starting to get low levels of payment and usage. Your sales team finds a big opportunity, but you need to add some new features to your entity handling that will satisfy their business needs.
You make the changes, take the money, keep the lights on, and implement the feature. In doing so, you’ve made a few decisions about how your software should work and behave as well as your general strategy for handling customer-specific needs.
Most companies don’t understand the impacts of the functional debt they take on through early decisions, but let’s follow this company further.
The Consequences of Functional Debt
We fast forward a few years in our scenario and the company is growing and doing well. There’s a decent user count and variety, but you’ve yet to truly “hit the big leagues”.
Suddenly, sales announces a large potential customer is interested but wants a significant change to how the software works. Their change conflicts a little with some of the decisions you’ve already made and how your business rules work.
Forced Choices
This is where your past decisions are converted from risk to actualized functional debt. Here you are forced to make one of a few different choices:
- Rework the old logic to work how the big customer wants it, potentially displeasing your user base in the process
- Make your logic more and more configurable to meet a variety of usage scenarios
- Fork your codebase and offer a dedicated version just for the large customer
- Walk away from the sale (and likely any other sale like it)
The Reality of Debt
Every single one of these choices has negative consequences.
If you adapt an existing system to work in a way contrary to its initial design, you could forget to adapt critical pieces of logic and introduce subtle bugs. That is to say, revising the purpose of a feature incurs a quality risk.
If you add configuration options, your system becomes harder to use and maintain. This is because you have to maintain database columns for configuration choices, maintain the UI to configure these settings, and maintain code that can handle things in a number of different ways. Testing all paths becomes exponentially tricky as you add to the configuration options the system has.
Forking or branching a codebase is a viable solution. However, this can be something you regret as you now need to implement new features in two codebases. If you want to pay down tech debt, you now have to pay it down in multiple places.
Walking away from a sale may make the developers cheer, but it also doesn’t pay the bills and can represent a huge missed opportunity to explore new market segments related to that customer’s needs. That said, it’s still often worth doing.
Missed Opportunities
Another way that functional debt can impact a business is if you want to innovate new capabilities. For example, let’s say a new competitor adds a minimalist user interface and very flexible and dynamic capabilities. Your product that serves a wide variety of users may not be easy to modify to offer the same degree of flexibility.
Here’s the hard to accept part: the reason it becomes hard to adapt an old product is at least partially because of the business decisions you made in adding functionality in order to get to the point where you are today.
Preventing Functional Debt
So, what can we do differently?
Well, first of all, start saying no. I’m not saying you say no to most sales opportunities or even most feature requests.
I’m saying that when entertaining new features to add to the software, you default to saying no.
You should not add a feature unless the short and long-term benefits outweigh the estimated short and long-term costs.
This no can be to external customers or potential customers or to internal employees advocating for features.
For example, say a designer wants to make the application support themes other than a dark theme. Her justification for adding these is that people will like them and the time required is very low.
Let’s say your designer doesn’t have a lot else on her plate at the moment. She should make those changes, right?
Well, possibly, but let’s look at the longer term. Adding the ability to theme the site as a whole puts new theme support work on designers and developers as they add new pages and controls. Additionally, quality assurance must test using the different styles.
Finally, the styling support is another feature that a replacement system will also need to make if they want to stay in parity with the current logic.
Repaying Functional Debt
Okay, so what if you haven’t said no? Is all hope lost?
Probably not, but it might be time to retire a feature or two.
Specifically, what you can do is introduce a newer system of doing things – one that has lighter rules and more flexibility, but less initial features. You design this new system with your new needs in mind as well as your old needs (if you want to continue to support the old system) and a way for people to try out the new motif and potentially migrate their data over.
For example, let’s say you have an editor component that you offer to end users. People are used to the original editor, they can work with its functionality, and they have some content written using it.
You need to add on new functionality that’s just not possible given the choices made in the original editor, and so you create a new editor type and allow users to choose which editor to use when creating new content.
Over time you develop a pipeline that will automatically convert users to use the new editor instead of the old one. You then give people that path for awhile until all functionality from the old editor is now present in the new editor as well.
Once the new editor is ready to replace the old, you announce a cut-over date some time in the future. Once that date arrives, you convert to the new model, and then get rid of the old model.
Hopefully the replacement implementation will be built based off of a more mature understanding of the organisation’s needs and prospects and will represent a smaller functional risk to the organization.
Learn More
Functional Debt is a term I mistakenly thought I had coined a number of years ago.
It turns out that I am not the only person to have thought about this topic and come up with this term.
Here are a few articles by others that I would recommend looking into if you’d like a second or third opinion on this topic:
- Every Feature Considered Harmful – Michael Dubakov
- Functional Debt vs Technical Debt in Software Development – Roman Predein
If you have a different definition or criteria than mine, I’d love to hear your take, especially if you can provide examples of functional debt to support it.
The post Functional Debt: The Price of “Yes” appeared first on Kill All Defects.
Top comments (7)
I'm finding this exact situation with a legacy API I'm working with at the moment. It's currently a monolith, that a single client has driven a lot of the functionality for.
We are now in a tricky situation in that some clients want slightly different functions, but not enough to warrant a completely different application.
My long term plan, is breaking the monolith into microservices but that takes team. But I'm feeling the functional debt pain right now.
Love your writing by the way Matt, keep it up :)
Thanks for the encouragement! That means a lot.
As for your specific case, I can empathize to some extent as a manager managing an API development team.
Breaking a monolith into microservices is a good plan. You might want to consider Bob Martin's strangler application pattern on that journey.
Thankfully, API developers have more options in introducing new endpoints or versions as needed and are less tied to user interface concerns.
I've read about the strangler pattern before, and it's exactly how I'll manage it I think.
Agreed on the options for API developers though, it's a nice place to be. The API itself has versioning in the URL string, so it should be extremely easy for me to migrate.
Thanks for the response!!
Thanks Matt!! I am in my first couple of years in my career. But I am already seeing projects carrying technical and functional debts.
I think that those debts take some time to be felt. They always like creep in. And i am wondering what options do we have if the debts are too much?
The most effective way I've seen to handle severe functional limitation / debt is to launch a new product line and reuse as much infrastructure and supporting logic as possible. Really it's something I think you have to design around where your product needs to go. If you didn't do that you need to look at how to pivot into parallel offerings or add on configurability.
Nice. I hadn't heard it that way, but back when I had a startup, we coined the phrase, "Every asset is also a liability."
This is why startups can compete with established companies. They're typically built on older stacks, struggling with tech debt and functional debt, and have a lot more oversight and goals they have to hit vs being able to pivot and innovate new product lines. It's essentially like using judo to fight a larger opponent.