98 comments

[ 3.7 ms ] story [ 86.3 ms ] thread
Then maybe those todos are not todos but just regular comments?
Agreed - there needs to be a space for known issues that are not worth tracking. Issues that need to be understood as real, but perhaps may never be viable to fix. Something you can ctrl-F for when you have time and are curious if there's something you can clean up.

It drives me insane that so many tools/processes treat TODOs as essentially code smells.

Not every TODO is technical debt waiting to be paid off
To me this brings the phrase to mind: "perfect is the enemy of the good."

Ideally tech debt or code-smell encountered like this would be captured/tracked/described better but often-times this means context switching or engaging in some kind of high-friction activity (like filling out a JIRA ticket) and that just discourages tracking it at all. At least inline TODOs are captured somewhere. And they can be for doing.

TODOs are a code smell.

If there's a known unhandled edge case there should be conditional logic guarding against it.

If the original author dislikes the idea of a refactor... well too bad it's not their decision anymore, but they should have at least been kind enough to write tests.

TODO: Remove the 'FillInData' function call after bug/<id> is fixed.
But the second example there shouldn't be a TODO then, but just a NOTE (or regular comment).
The example in the article:

> // TODO: If the user triple-clicks this button, the click handler errors because [xyz]

looks more like a comment than a real TODO to me. I agree that comments like those are useful, but shouldn't be a TODO.

A TODO implies a specific type of comment. One that implies a task, points to something that should actually be done (like TODO: This function should return another value with XYZ). And I agree that the proper place for that is a tracker, not buried in the code.

In the example just documents a bug. , there is no actual action.

In my experience, TODOs are often a way to get quick and dirty code approved in a PR. They usually never get done, they're just a way to push the responsibility onto some future developer who "will have more time" (which means it will likely never happen).

The example seems like more of a FIXME than a TODO.

It’s a clear error, but likely unimportant enough to bother addressing.

When I have a thought about how some piece of code could/should be improved, but it's not urgent, instead of

  // TODO: Refactor this by doing X, Y, Z
I'll say

  // Hmm: This seems brittle.  We might want to X, Y, Z this such that W.
My IDE will list all the TODOs and I don't like to clutter that list with stuff that isn't strictly necessary, but it is nice to have some string--"Hmm:", in this case--that I can grep for or recognize as indicating that I thought about this already.
Fwiw i’ve see far fewer todos lately since LLMs have gotten significantly better as of late. The todo documentation is often a perfect prompt.
I have a similar philosophy for low priority tickets. Some people say it's not worth filing a low priority ticket since we can't even do the medium priority ones. I think it's still valuable since (1) it let's you write it down to remove it from your mind, and (2) you can track repeated instances or anything else that might cause you to increase the priority.
I add and grep for the following:

- FIXME: this is clearly broken/wrong and highest priority

- XXX: this is “ugly” or assumes wrong things, probably higher than next

- TODO: at some point, implement a whole different approach/category/branch

- NOTE: code comment with a higher importance than just random comment

NOTE: I work a lot with old/unmaintained codebases where “code is truth”, so there is no “jira ticket creation” but amending things as you read.

I have often thought about doing exactly this, but one thing that always made me hesitate was the fact that nobody else seems to be doing it. Now that I finally see that others are actually using other labels than TODO I may actually start doing this, too.
I like this style. In a project I worked on we had CI reject any FIXMEs outright and any TODOs that weren't accompanied by an issue ticket[^1], so the hierarchy would be

FIXME: I am leaving a note to myself to not get distracted, but this code is not considered finished/mergeable until it's resolved

XXX: this needs fixing soon, but the code will still be functional without it

TODO: this needs revisiting but the code is perfectly useable without it - a lower priority XXX

NOTE: this does something unusual and you need to bear in mind while working on this code

[^1]: the value of doing (or not doing) this is a subject that has already been extensively rehashed in sibling comments

Absolutely. The ability to search for these flags before a commit, during a review or release is so valuable.
I have three levels:

1. An issue tracker, even if it's just a text file for some projects. These are things that need to get done over the long term.

2. TODOs. These are actually bugs or incomplete things. The code is not actually done. Something isn't handled, something isn't right. Big or small, but usually small.

3. XXXs. These are performance enhancements or refactorings. It's XXX because it's obscene that this code looks this way, because it's either ugly, slow, or gross. But the code works and is tested.

My whole thing here is that this is just as effective of a comment without the todo prefix.

Lint the TODO part before merging, then TODO becomes a nice thing you can grep for on your own branch, like a note to yourself.

As a proponent of "TODOs should always point to a concrete issue", you have 3 ways to resolve a TODO before merging:

1. Just file the issue. If it's something you should actually do, you can take 20 seconds to write it down and track it. 2. Just do it. If it seems like too small of a thing to file an issue for, fix it before you commit it. 3. Turn it into a comment. If it's not worth fixing and not worth tracking, but you want to remember it, that's a fine thing for a regular code comment.

Eat your broccoli. Track your todos.

I have a single rule: Every todo needs the ticket number included.

// TODO: improve the routing https://jira.com/whatever/TIX-1234

This rule is important because comments can get orphaned. Just leaving a comment is a recipe for a comment nobody knows why it’s there. Just make a ticket or do it now.

When forced to point to a concrete issue by tooling, I often just end up rewording it - "Ideally this should X, but it Y". Comments are fine, lower overhead and don't require re-triaging later, and have all the context to immediately understand.
> If it's not worth fixing and not worth tracking, but you want to remember it, that's a fine thing for a regular code comment.

In my mind, every todo in code is of this type - worth fixing (someday, maybe) but not worth tracking. If it needs to be tracked, put the details in the ticket and just link to the code, don't put a commment in there.

To me, the point of the todo comment is to see it if I am working/touching/utilizing that bit of code. That is the time it should be worked on, not when someone finally gets to a ticket in the ticket tracker.

It's all about the method of action - if the task is something that should be prioritized against other work, put it in a ticket. If it is a task that should only ever be done if I touch this bit of code, then put it in a TODO comment.

Todos can also serve as a direction where you want the code to go to. Leaving this in the code ensures everyone working on it sees it, and every change they make can take this direction in mind.

Maybe THIS change finally warrants implementing foo, or at least refrain from implementing bar.

Any MBA in the comments- those issue growths will make me look bad in front of my superior- we should delete all those issues once a year.

Thus introducing the ToDODOs - which is a attempt to hold memory of important tasks facing extinction through cooperate dementia, which those who hold idealistic views of the stakeholders while engineering processes have no living memory of due to job hoping.

Sometimes the value is just in capturing that thought in situ, even if it never gets acted on. It's less about task management, more about code archaeology
4. Take a look at TODOs while maintaining the code, and promote them to the issue tracker if you feel like their time has come or have time to fix them. Take note that it's being actively worked on, on the codebase.

Eat your veggies. All veggies matter. Be flexible.

P.S.: This is what I do. My IDE gives a nice list of them.

I disagree.

In each practical project, there is an order of magnitude more things than you could do. One of the crucial job is to prioritize things well, knowing the context.

Regular tasks trackers put things outside of context. Low-priority things might go better in code. That is, you don't need to care about performance of a particular function as it does not matter. But when it starts to matter, and you see "TODO: cache results to speed up", you see an easy win.

Issue trackers are often politicized. You get projects where they auto-close stale issues. Or where they're resistant to creating issues that they know that realistically nobody is going to work on this in the foreseeable future.

TODOs are an excellent place for developers to describe where they'd like to go with a given pile of code if they had the time, and realistically that kind of work isn't suitable for every issue tracker depending on who has access to that issue tracker and who has opinions about what goes in there.

It’s worth noting that 1. is not mutually exclusive with writing a TODO.

In fact, on my team, all TODOs must have a bug in parentheses immediately afterwards to satisfy the linter. So not only not mutually exclusive, but the opposite.

// TODO(<issue-tracker-id>): <Short description>

This format allow for quickly finding the place where the thing needs to be done, while keeping track of the issue in the issue tracker.

I often write the issue tracker ID's in my code to add additional context. It works especially well for bugs which are reproducable in programatic tests. Then I name the test specification after the ticket, so that it's known that this bug doesn't resurface as regression.

I also use a tiered strategy and FIXME for things that really need to be fixed or I have a solid idea what the next step would be to fixing it.

TODOs are something less solid than a FIXME and are also just about getting it out of your head so you can devote more mental energy to something else or just relax.

Maybe the idea is not fully formed yet, maybe you are not sure you really want to do it, maybe it is waiting on something else, but it needs to be captured or you will have to keep thinking about it lest you forget.

As soon as I write down a TODO (code or other) that was only in my head, I can relax a little more, because now it's captured for future reference.

In my code these days, I have:

TODO

SHOULDDO

COULDDO

The TODOs generally don't make it to main, the others sometimes get picked up eventually.

I couldn't disagree more. TODO is basically an action list you search with grep. When I'm looking for things that could be done, the last thing I want to do is to have to mentally filter out the things that aren't actionable. That just makes the process use a lot more mental energy than necessary. It also leads to unproductive conversations like "we have 147 TODOs, but 18 of them actually need doing at some point, which is an improvement from last month's 123 TODOs with 22 real ones".

No, please, do not do this. As notes, those are wonderful things to add. They're the sort of comments I want to see in the code I'm reading! Keep them! But don't label them as TODOs, for the same reasons that you wouldn't use Reminders as your combined actions and notes app.

Edit: In addition to the mental energy, your brain eventually gives up and becomes blind to them. Then you tend not to see them at all, even the actionable ones, unless you step back and dedicate even more mental energy to mindfully going through them one at a time to give them a fair reassessment. This gives me more ADHD-fueled anxiety than I can describe.

The most frustrating thing to find is a TODO for a half baked thought about some inconsequential logic. Delete!
I like the idea presented by the author. This is because, in my opinion, classic TODOs have no place in the main branch. You can do whatever you want in your feature branch or on your local machine, but not in the shared codebase. If something is not ready, you are not done, and you should not commit or merge it.

In my opinion, the author describes more of a NOTE, such as, "Currently, we support X because of the requirements in TICKET-X. If you want to support X and Y..." or "This was done like this because of X. The better solution is Y and it make sense to do the better solution when ...". I like the idea of helping my future self quickly understand why something was done in a specific way and how I can refactor it now. Also this indicates that how ever added the NOTE, is a good software engineer, that does not implement features or functionality that is not needed yet.

I have never seen TODOs being cleaned up in enterprise environment. Therefore our team would not approve PR with TODOs: either fix them yourself or open a separate ticket for it.
This is a great example of a practice that is pragmatic and smooths the way for future polish if the software grows in usage by 100x, without investing a bunch of effort now that won't make sense if it doesn't grow (and might stop you from doing the things that will enable it to grow.)

If usage takes off by 100x, someday somebody will be tasked with clearing up errors in Sentry (or whatever) so bugs and regressions are easier to spot, and this comment will save them hours of debugging.

However, I think using TODO to flag it is a poor choice. Good luck explaining to your teammates, "We use TODO to communicate that we aren't going to do something." I doubt you're going to get consistent adherence to such a counterintuitive convention. Instead, I would prefix the comment with "KNOWN ISSUE."

I love this TODO approach not just for what it does for future readers as Sophie notes but also for the mental release it gives me when thinking about edge cases that I don't want to commit to fixing.

PS Hi Sophie!

Replace the not-TODOs with NOTEs.

For example, this TODO:

   //todo: factor this out in case X
…is a NOTE, albeit a gratuitous one.

Because if X ever happens, the note won’t matter anyway, since you will have had to grok all the related code to refactor. You will see this note while you’re refactoring the surrounding code and smirk, “yep, that’s right”, or “no, it doesn’t really fall out that way.” Either way, most TODOs/NOTEs like this just get in the way.

They capture information you have when writing the code that communicates something useful about it.
Strongly agree. I think of TODO as a task that might be interesting for the next person who stumbles over this code. "This logic is not great. If you happen to refactor this entire feature consider changing this thing as well". The TODO can even have an associated ticket but because it's right in the code it's more discoverable. Otherwise, the next person to change the code might even complete the ticket without knowing it.
Second todo isn't a todo, should be a trade-off comment. Something like "Technically, this will raise an error if the user triple clicks the button, but most people ain't that fast, so screw it"
This is just going to lead to things not being done as nobody knows whether or not the TODO is resolved or not.

Personally, I tag my comments in one of two ways:

1. // TODO: <task> (if multiple things, I do a multiline comment with Markdown-style checkboxes next to each item in the list).

2. // NOTE: <explainer>

The former is what you'd expect (I routinely search for these to make sure I'm not missing minutiae) and the latter is for code that can't be refactored to make it clear and requires some explanation.

Doing this consistently has really saved my bacon over the years (both in terms of keeping track of tasks and remembering why I had to use that ridiculous chunk of code to get something to work).