DEV Community

What types of features typically lead to lots of tech debt?

Ben Halpern on October 18, 2018

What types of features consistently lead to technical debt in your world? Like, a manager or client asks for this and you just know it won't end well.

Collapse
 
cjbrooks12 profile image
Casey Brooks

Features that are completely unlike anything you've implemented before, because a lot of infrastructure needs to get set up to support that one feature, and you may not have time to plan it all out properly.

Alternatively, features that are nearly the same as an existing feature, but have a few significant differences. Either leads to lots of duplicated code, or else a bunch of hacks in the current code to make it also work for this edge case.

Collapse
 
rrampage profile image
Raunak Ramakrishnan • Edited

One-off feature requests which are of the form "We need this for today, nothing fancy, just a special check for X customer". The problems with these are:

  • Poor planning : These requests are a symptom of poor planning and often involve patchwork solutions to keep everything running fine (for now).
  • Permanence : Many requests which are a "hack" for today become accepted as part of daily flow. Even if they are stopped, code is often added but rarely removed. After a while, the programmer who implemented the feature would have left the team and even the people who requested the feature will not have a solid memory of the details.
  • Prevalence : Such special cases add up in codebase very quickly. Accepting even once sets a precedent and then the floodgates for these kinds of requests will burst open!
  • Emergent complexity : Such features are suggested in isolation and since it is an "easy" feature, no one pays attention to how these features interact with different parts of the system. It can lead to emergent complexity where combinations of small exceptions can lead to an unexpected behavior of the system.

IMHO, the best way to answer these kinds of requests (depending on how mature your company is) would be flat say no or ask for enough time to implement it in a sensible way.

A caveat for startups. Many startups are still experimenting with their core product when they launch. Such features are needed for fast iteration and feedback. Being ruthless in removing code for failed experiments is required to manage code base.

Collapse
 
kpollich profile image
Kyle Pollich

+1 to "Poor Planning" here. Technical debt is, as other users have mentioned, meant to be a conscious decision. Engineers need to make constant trade offs when developing software and technical solutions. Without proper planning, it's likely that engineers don't have all the information they need to make educated decisions about trade offs, leading to poorly implemented or short sighted solutions. If you're unable to consciously understand the trade offs you're making, you'll likely wind up with unintended technical debt or an inadequate solution.

Collapse
 
cjbrooks12 profile image
Casey Brooks

I've never really considered it that way, but you're totally right in that tech debt is exactly that: debt. Having a credit card isn't a bad thing if you can pay it off in a timely manner, just like writing "bad code" or rushing a feature for a timeline isn't necessarily bad if you take time to pay down that debt after release. But if you have a pattern of consciously choosing to add features and never pay it back, then you start to get in trouble.

Collapse
 
jfrankcarr profile image
Frank Carr

Tightly coupling features to particular things, such as customers, vendors, products, events or even hardware.

A real world example: A manufacturing company has made 12 different product lines for about 15 years. All software gets written around this fact. Suddenly, one day, there's a urgent need to expand it to more product lines because of a big contract with a certain big retailer. That's when things start to break all over the place because everything from the database to the front end is written specifically for 12 product lines. What the company did in this situation is to setup separate databases and apps for the new product line by making copies of the existing software. But there were other things tightly coupled so that didn't work. It almost sunk the company.

Collapse
 
phlash profile image
Phil Ashby

Similar thoughts here, once had to maintain a system that was stuck on SPARC hardware and Solaris 2.0 because of a binary blob we couldn't change. The least worst fix was to facade & isolate the blob on a separate system near the cause of it's existence. Still fugly..

Collapse
 
bgadrian profile image
Adrian B.G.

Anything that contains

  • urgency "URGENT", "ASAP", "tomorrow"
  • Diminutives "just a quick small tiny bit exception", it usually means that he does not understand or explicitly hide the complexity
  • excluding conditions: "we do not need to worry about X" where X is stability, performance, security usually. "We will worry about it later"
Collapse
 
kspeakman profile image
Kasey Speakman • Edited

I can nearly guarantee a feature will be technical debt, when a user has asked for it to meet organizational requirements that have nothing to do with the application's normal usage. When I implement it, I always know it is going to be a thorn in my side. Executives and managers are always coming up with new initiatives and policies. So then the code has to be reworked for non-functional reasons. Or it might just become unused cruft which is supplanted by another new org-overhead feature. And with every core-feature change I make, I must consider the impact to the org-overhead features even though it has no importance to the core use cases.

Users tend to not be able to differentiate between what features they need to accomplish their work and what things are just organizational cruft. So they always ask for (or outright demand) features like this. Nowadays, I try to determine what use case is driving a feature request. If it is not the main purpose of the app, I look for alternative ways to help the user meet those organizational requirements without generating tech debt for me. For example "What if I give you a CSV of the data so you can play with it in Excel?" Or "How about using X product to accomplish that?" Or "Does this really need to integrate with BizTalk?"

Answers like these help the user solve their problem and also avoid writing code that will be a grief to me in the future.

Collapse
 
rhymes profile image
rhymes • Edited

I can nearly guarantee a feature will be technical debt, when a user has asked for it to meet organizational requirements that have nothing to do with the application's normal usage. When I implement it, I always know it is going to be a thorn in my side.

The magical words you hear too often in consulting are "the customer asked for this".

They make you wonder if PMs are doing their job or just saying yes to whatever the customer asks them for :D After a few "yeses" veering off the core product you tend to accumulate a lot of debt already.

Maybe PMs should be UX designers or UX designers should be the ones talking to the customers and let PMs run the day to day of the project.

Collapse
 
ben profile image
Ben Halpern

A couple things that come to mind for me:

  • A/B testing. Whether additional scripts on the client, complexity on the backend or anything in between, it rarely seems to end well.
  • "Example" versions for potential customers.
Collapse
 
rhymes profile image
rhymes

"Example" versions for potential customers.

Also "prototypes" that become the final version :D

Collapse
 
andrewmsboyd profile image
andrewmsboyd

As a super beginner dev, I'd like to know a little bit more about why A/B testing might qualify as a practice that leads to tech debt.

It seems like something that giants like Google and FB do all the time. Is A/B testing not a practice intended to prevent tech debt?

Collapse
 
ben profile image
Ben Halpern

A/B testing is, in my experience, usually an attempt to improve some business metric like landing page conversions and engagement etc. They're great if done right, but they inherently add a lot of complexity and coordination that can cause holes that are hard to dig out of.

Big orgs do a lot of A/B testing, but they devote the resources to making it work, and I'm sure they still have their issues. Smaller engineering orgs get in trouble trying to add split testing into an already rigorous workload.

Thread Thread
 
picocreator profile image
Eugene Cheah • Edited

There is also a stats issue involved. And how many misunderstand stats.

Seen way too many startup spending way too much time trying to use A/B, as a means to try find a magical 10x conversion rate improvement through it. With sample size of under a thousand.

Over simplifying, my rule of thumb, until one reach over a million hits per month, or a team of 50, one should never consider A/B. Till then incremental improvement and feedback is good enough.

Collapse
 
elmuerte profile image
Michiel Hendriks

Technical debt isn't just about bad code. It is about the price you have to pay for going back to that code to make changes.
Bad code, and even bad architecture can have zero technical debt when it works, and does not require change.

Collapse
 
davepacifico profile image
davepacifico • Edited

I don't think you have to consciously decide to take on debt in code. First of all, you could just not realize you're making a bad decision. Maybe you are inexperienced. Second, and I think more importantly, you can do everything right based on the information you have at that moment and then it becomes debt later as you get more information, understand more about new use-cases, etc. This is an oldie but a goodie by Martin Fowler - martinfowler.com/bliki/TechnicalDe...

Collapse
 
nestedsoftware profile image
Nested Software • Edited

I don’t know if this helps, but I think there are three factors that can all contribute to technical debt:

  • Hastily adding features
  • Having a limited understanding of the kind of programming one is doing
  • Adding a source of complexity where it may be avoidable (e.g. A/B testing)
Collapse
 
thejessleigh profile image
jess unrein

Any time someone wants to get an ad hoc notification as a result of some action. Whether this is a user getting a push notification for an isolated action, or the dev team getting an email under certain conditions. There are definitely ways to build out a robust notification and reporting solution, but often times I see a request to tack on a notification to a piece of functionality, and it can lead to noise and frustration. Paying down the debt of cleaning up noisy notifications, or debugging notifications that aren't firing properly, can be incredibly painful.

Collapse
 
ben profile image
Ben Halpern

Yeah definitely. I think you can get ahead of this with a really good observer pattern setup and general observability excellence, but building that is burdensome on its own. Fat chance implementing the perfect architecture to handle arbitrary last-minute notification needs unless it's already a true core competency.

Collapse
 
offendingcommit profile image
Jonathan Irvin

"Let's focus on stability later."

Collapse
 
thomkrillis profile image
Bobby Yankou

This is an excellent point. I'm going to start advocating for this interpretation.

I think I generally use the term as you described, choosing what feels like a hack or shortcut over a properly engineered solution because of the time costs.

Collapse
 
eljayadobe profile image
Eljay-Adobe

Relevant book recommendation: Clean Code, by Robert Martin.

Collapse
 
cess11 profile image
PNS11

The security later philosophy. Badly implemented auth, relying on exact input for stable execution, no systematic testing, all such things will be hard and costly to implement at a later time.

This isn't exactly features, rather it's about whatever features get precedence.

Collapse
 
nerkmind profile image
Lewis Clarke

Normally its things that involve big data, that is coming from a 3rd party.

When you have no control over how the data comes and just have to work with what you're given...that tends to cause problems

Collapse
 
theredspy15 profile image
Hunter Drum

Any major addition to your project will add lots of debt. Simply because a lot of work will go into making it works well with the rest of the project. Especially when the feature is very different from anything else already incorporated

Collapse
 
elmuerte profile image
Michiel Hendriks

A transaction is an atomic sequence of executed features. (This as a whole would also be a feature.)

To use a bad car analogy. A SUV would be a feature that tries to do two things. And neither of them it does great. Trying to change either feature would also impact the other feature. While it all may work the effort for change/maintenance is higher. There is of course the hope that if work needs to be done on both features the total amount of work is less than when work on those features would need to be done independently.

Collapse
 
mshel profile image
MikhailShel

I'd say it something trivial which has a lot of "and's or also's" in definition and strict timeline, so if you hear something like:

"we want to have emailing functionality which will also send text messages and keep track of all the emails in salesforce in 3 days." <-- that would be a clear sign to me that at least a week of refactoring should be allocated to detangle it.

That would happen because pretty much any engineer knows how to do it and tight timeline pushes engineer to cut corners

Collapse
 
elmuerte profile image
Michiel Hendriks

Features that try to do more than one thing.

Collapse
 
darkain profile image
Vincent Milum Jr

1) Any time you add "todo" notes
2) any time you don't add unit tests with new features
3) any time you don't add documentation with new features
4) any time you don't test for edge case input

For #4, I'm currently working on a document, at least for PHP (but can apply to others), that shows a ton of different data types and values that can be passed into a function which are generally overlooked or the developer simply doesn't know about them. Is great to unit test edge cases like these to help prevent bugs. I'll have more on this when the document is live!

Collapse
 
apastuhov profile image
Aleksey Pastuhov

I noticed two popular types of problems:

  • Mostly we have debt when we develop software in a hurry. It is easy to forget some stuff and as result - big debt with lots of minor issues, which are not critical, but can take a lot of time if we won't do it.
  • When we use Proof of Concept as a source base for Production development.

Also, here I wrote an article how I prefer to do manage technical debt, maybe you can find something useful there.
dev.to/apastuhov/how-to-manage-tec...

Collapse
 
jannolii profile image
Janno Liivak • Edited

I seem to get into trouble almost every time I start using some new language/framework/concept/etc I haven't used before ... in a tight-scheduled project :)
I know I shouldn't, but I can't help myself ... want to learn new things all the time. And so I spend the nights trying to get back on track :P

But about features ... I think that features changing physical processes (or how people use the software) tend to have too many iterations because people discover (too late) that they "forgot" to mention how they "really" want to use the system and that what they meant (when they described the problems) was actually something different than what I understood :)

Collapse
 
david_j_eddy profile image
David J Eddy

human input validation, time zones, "multi-cloud"

Collapse
 
nebojsac profile image
Nick Cinger

The type of feature that needs to be done yesterday!

Given enough time, any feature can be done properly, with minimal debt incurred.

Collapse
 
johnson_cor profile image
Corey Johnson

Social media integrations. Every time I've integrated some kind of 3rd party social media integration I end up having multiple bugs that I have to go back and deal with.

Collapse
 
wolfhoundjesse profile image
Jesse M. Holmes

Modernizing a 20-year-old codebase. Not such a big deal for a 100 users, but as soon as you scale … .

Collapse
 
eezing profile image
Eric Zingeler • Edited

“consciously decided on some tradeoff” - This is deliberate technical debt according to Martin Fowler’s Technial Debt Quadrant

Collapse
 
revskill10 profile image
Truong Hoang Dung

everything which needs an ORM , of course.

Collapse
 
theodesp profile image
Theofanis Despoudis

Feature flags and Integration points to start.

Collapse
 
perttisoomann profile image
Pert Soomann

When developers last question to stakeholder is "Are you absolutely sure this is what you want me to do?"

Collapse
 
gabeguz profile image
Gabriel Guzman

Any feature that has to be delivered faster than it should be delivered.

Collapse
 
swizzard profile image
sam

I've worked at a lot of places with a lot of tech debt and after some close analysis I think I can definitely say that the feature most strongly correlated with tech debt is capitalism.

Collapse
 
lukewestby profile image
Luke Westby
  1. Drag and drop
  2. Image carousels