Using TODO For Everything
goldin.io
goldin.io
> the value of using a broader selection of terms is that you (and therefore all the other programmers you’re collaborating with), are able to be more descriptive about what it is precisely that you need “to do.”
But that's what the space after `TODO:` is for. To say what it is you need to do later.
The less complexity you add, the less you have to maintain. This mainly applies to things of a certain smaller scale, but I find I encounter `TODO` in my code when I am in a certain scope or just have some free time to refactor, fix things, etc., neither of which require anything beyond a searchable string, as you mentioned.
This reminds me of any note taking app that uses #tags. You start in earnest and tag things; you end up with twelve different tags for #cooking, #baking, #food, #recipes, etc. because you forgot which one was which when organizing; it falls into disarray; you are left with unusable cruft, so you end up just searching for "bread" in the search bar, anyway.
Edit: Really, in a zettel flow, you’re supposed to capture notes as fleeting thoughts that are processed and synthesized later into long form writing.
Each note should initially have few links (if any) until you’ve ruminated and expanded on that note in your own words. These are usually called literature notes in zettel workflows.
TODO-BUG TODO-OPTIMIZE TODO-FEATURE
Which other subcategories do you use?
Todo-incomplete Todo-refactor
Some others I imagine?
// TODO: Optimize this function
// TODO: Finish implementing this feature
I also label comments with BUG, NOTE and HACK, but not for unfinished items on a todo list.
Every benefit you listed is legit, yet not even the sum of them can compensate for the loss of fidelity and lack of human scalability which results from using 'TODO' for everything. Anyone competent enough to edit code can handle holding 'seven plus or minus two' types of comment tags in their head. Those who can't (or, more often, who can't be bothered to) aren't suffering from impostor syndrome. They might actually simply be impostors.
- DREAM tags let me focus on getting things shipped and avoid over optimizing/generalizing things that won't provide immediate value. When working in a professional context, they are always accompanied by a ticket. This adds a nice binding for whoever comes next to pick up the task.
- FIXME is also used to help maintain focus, but with the rule that no code ever gets merged with this tag still in place. For personal projects my branches tend to be quite large, so I'm comfortable accumulating some small number of these.
- HACKS calls out unintuitive behavior: breaks in abstraction layers, worst-practices that have better implementations than best-practices, or anything that smells "clever".
Everything else is just comments that future me/team can look back on and say "he must have been drunk when he wrote this, but thanks to these comments I can clearly understand the context and at least what was intended."
I much prefer either
- TODOs are resolved before merge (your FIXME)
- TODOs are moved (not copied) to the team backlog (maintaining in both places just gets them out of sync)
- TODOs are converted to documentation explaining the approach (e.g. HACKs)
I still tend to keep the "HACKS" thing though, simply because they localize the documentation right where you need to be aware of it.
- Create ticket in team backlog and add ticket number to TODO comment (and have CI pipeline check that ticket number is valid)
Say you do get past that hurdle, you've added friction to the process of managing the backlog because the code now needs to be updated when Issues are rejected.
The sad part? With almost 10 years on a 20-30 year old code base with many millions of lines of code that are littered with TODOs, I don't think the presence of a TODO was ever helpful when we decided to actually fix an issue.
Makes perfect sense. TODOs are comment, meaning they're as reliable as comments, meaning they often aren't (and the more time passes and code churns around them the less they are).
Clean the code, comment actualities later, etc. -- it helps with knowledge share to find ways to make you attend to cleaning things up.
I also sometimes include a stricter version that includes a test for the current behavior, on the theory that someone changing the current behavior might be in a good position to fix the ticket.
I don't understand that use case.
Do you mean that if you set the envvar, the test now becomes "normal" because the assumption is you're trying to fix the ticket, and thus make the test pass?
I guess that makes sense if your workflow is to "clock in" on tickets, to which you can hook env updates?
On the contrary; since they are right next to the thing that needs work you always encounter them Just In Time. And you can just delete them really easily if you decide they're truly stale. This may not lend itself to planning or management visibility, but for a small private project I prefer them to the overhead of separate tracking.
For a small private project there's no organisation which doesn't work.
I don't have anything resembling an issue tracker, but I've begun collecting brain dump style notes in either a gist or the Apple notes app.
Some of my side projects have more process around them than my work projects because the side projects will definitely get shelved at some point and resumed much later. Future me is always happier when the process was applied.
That means they become scenery, not something in the foreground. They are lost.
Is the use of HACKS just to highlight the importance of a comment? I tend to just stick those in a regular comment. Or if extra important NOTE at the beginning. For instance I refactored code the other day forgetting why it was the way it was, it didn't work, and then made a NOTE for it so I don't do it again.
For "DREAM" there is a ticket for proper tracking. For FIXME, code review prior to merge is sufficient. For HACKS, you really only need to care when you happen to be working in that space.
And yes, HACKS is to highlight the importance of a comment. It also signals an intentional deviation and an opportunity for someone to offer a suggestion on how to improve things.
Edit: I just added this into my editor but it's not highlighted by default. I wonder if there's a way to highlight it.
[1]: https://marketplace.visualstudio.com/items?itemName=ExodiusS...
There, fixed it.
- // STOPSHIP: the presence of this string anywhere in the codebase causes a production build to fail.
- // TODO: for everything else.
Once you're reaching 1.0.0, you know these can no longer be sliding through, and you can support all of this in CI.
// todo: todoThe article's goal is clearly to provide a quick categorisation of the TODO, rather than require reading the description to discover it: if I'm trying to debug something and reach a bit of code with a bunch of TODOs it's not going to help me much, if I see a FIXME or BUG I'm going to be a lot more interested.
Sometimes the TODO us sufficient through it context (e.g. a docstring empty but for a TODO stanza is obviously a missing doc), but often it's not and is the documentary equivalent of a goto.
Get yourself tools which are not hot garbage? All the ones I use let you customise markers however you want.
Customisation requires everyone who ever works on that codebase to also do the customization. Defaults are important
And they can go on the pile of all the others customisations necessary when you don't mandate all the tooling by fiat.
> Defaults are important
Defaults are a tool, when they hinder improvement you discard them.
Because of default highlighting support, I started using TODO. The most valuable part is the colored flag my tools generate to attract attention to code that needs it.
As far as the hundreds of #todo throughout my code, they are prioritized based on when I'm using the program and decide that I've had enough of a particular issue.
If I sit down to work and I can't think of anything to start with, I do a global search for #todo and pick a random one to work on.
THANK you. I only need a few concurrences to keep forging ahead with tools that work, but I do need a few.
I use the classic TODO, BUGBUG and my own (the last one is usually 'xxx' for brevity, and never in checked in to a public branch). That's it. Life is too short for needless complication.
The PM over there in the corner has just invented eight levels of TODO severity, and will soon multiply the truth by putting them in a database (somewhere), start a set of meetings to track them, and is already talking to tool vendors about building an Enterprise TODO Framework. Dry gulch that PM before you lose your sanity.
This is the most obtuse way of expressing a concept. I like it very much.
And if I need a better description: good news, you don't just write "TODO", you write "TODO: add cyclonavigatory imbobulator to fedonculate the explonizle" and you get to see that text so that it's perfectly clear what the task is. There's literally no need for a different keyword to more specifically bin "the kind of TODOs". One bin for "tasks" and one for "bugs" really is enough.
Anything more, and you should start using an issue tracker, not just more keywords. (and ideally all your TODOs are also issues already, of course)
If you disallow TODO comments, you will lose that context, or at least it won't be easily searchable anymore. Issue trackers are not a solution because:
- they create too much friction. A developer that is short on time might add two or three comments to suboptimal code rather quickly but would likely not bother dealing with a clunky UI like JIRA, having to write detailed descriptions referencing the exact place of the code, filling out 20 fields and then being hounded by a PM who (rightfully) doesn't understand what "implement foobar() in linear time" or "make Frobulator thread-safe" means.
- Comments are right next to the code, issues are not. I see people pointing out that comments can get out of date, but so can issues in an issue tracker.
- IMO, "refactoring tickets" tend to be the worst tickets, they're rarely fun to work on, they don't include the context for why the refactoring might be necessary or what the best way to evolve the code is, and if someone else is assigned to the issue than the author of the ticket, they might not even understand the intended refactoring. A comment is much more light-weight and optional and anyone who touches the code can read it and decide whether it makes sense to fix it. It's also almost impossible for a PM to know how to prioritise refactoring tickets. IMHO, unless we're really talking about refactoring entire systems, refactoring should preferably be done continuously whenever the need arises, i.e. "first make the change easy, then make the easy change".
- of course, code shouldn't be merged if there are glaring issues that don't implement the feature correctly / could break important things. It's the responsibility of the developer and the reviewer to make sure that this doesn't happen, regardless of whether there are "TODO"s or not.
The author is not saying TODO comments should be disallowed or stopped entirely, and explicitly states that he's not suggesting "use an issue tracker instead".
His recommendation is to use meaningful alternatives, e.g. FIXME, HACK, BUG, etc.
Dodging an issue tracker is, IMO, one of the clear benefits of TODOs (or FIXME, HACK, BUG, and family). Especially in low-trust teams or whenever there's a need to avoid the sorts of politics that can arise between roles.
Refactoring tickets are terrible for all the reasons you point out. PMs will essentially never prioritize refactor work over new features unless pressured to, and if so, the work more often than not gets assigned to newer hires and junior devs, whereas a TODO is actually more likely to get picked up by a curious and intrepid newcomer when they're actually ready for it. Should said newcomer stumble across it before they are ready, it can also be a signal that they ought to reach out to a more experienced developer to ask some questions. For devs, refactor tickets may be useless overhead: in time spent writing, time spent defending, time spent estimating, etc. And in return, there's little glory or praise achieved in working on them; tracking too much time on refactor tickets may even attract negative attention from management. Then good luck if your QAs and agile leads are suspicious of any unit of work that a new test plan can't be written for.
A good TODO is sometimes just how the sausage is made.
Sometimes I leave a TODO because a feature/fix must land before a certain date and I don't have the extra time to optimise the code before that. Customers prefer a slow feature over a nonexistent feature. Known bugs can be annotated with a FIXME and an issue number so that nobody will waste time on that part of the code if the bug isn't important enough to be fixed in the current sprint.
That said, "TODO: implement" should never ever reach merge requests or code review. Suboptimal implementations may be acceptable, but missing implementations are just bugs or incomplete code.
/JK
In our group we have the rule to add a task/story/feature ID when you add a //todo in the code. It helped us to prioritize and close todos. If the task was not prioritized for a long time (became overdue) or was rejected the todo is also removed from code. Apparently it was not deemed important enough to implement it and current code became the accepted version.
> you don’t want your project to end up like the Linux codebase with 3000+ TODOs dating back over a decade.
Why don't I? TODOs capture a lot of context that would otherwise be inappropriate or unseen in a comment. They're in all caps and they stand out and draw the reader's eye. They can be completely out of context, whereas comments are typically extremely contextual. They often help explain cases not covered, paths not supported, missing functionality or notes for future contributors. Splitting them into even more comments just makes them harder to find and reason about. When you're writing a TODO, you don't want to stop to smell the roses, thinking about what the future may hold, you just want to blot down the thought in your head and finish the task at hand.
Not to mention that in reality it's quite reasonable: https://livegrep.com/search/linux?q=TODO&fold_case=false®...
You be the judge.
HN is one of the best discussion sites out there now, but I wish that we weren't so formulaic and repetitive. So many things get over-pushed, simply due to the familiarity of popular structures such as "X Considered Harmful" or "Why I Don't X".
If you actually read this blog post, the thread here is taking this way more seriously than the actual author was.
Most tools support automatic aggregation and review of code comments starting with "TODO". Maybe some of these tools can be configured to support other prefixes as well. But they all support "TODO" by default, and it's pretty trivial to just put your shorthand descriptors after the "TODO".
Also, if you're pushing commits with a ton of "TODO"'s, then you're probably doing something wrong. Many tools will warn you by default, and many CI/CD pipelines will block your commits altogether. If something is small enough to be addressed right now, then you should address it right now. If it's large enough to require addressing later, then it should be a tracked ticket rather than a loose code comment.
> Why not just go straight to the issue tracker?
An issue tracker adds a lot of overhead. It's sitting on a different system, so you have to have a separate window open. It's public, so you have to spend time producing a comprehensible issue. Every action is a commitment. Internet access is essential.
Meanwhile, TODO is just a file, so it can sit right next to your code. Its private, so you can just stream thoughts right into it and move on. Adding an item is as simple as typing out some lines, and removing that item is as simple as deleting some lines. Need to search? Just grep it. It's fast, and it doesn't leave a mess in your code.
A practice I like to follow is to document "hacks" and create tickets for TODO items. In my experience, this has scaled better with the growth of the team and also allows for knowledge sharing and brainstorming when planning.
For TODO items I used the "eisenhower matrix" to decide if I should create a ticket for it or not. Where TODO items that are not "urgent" nor "important" are simply ignored until they reemerge again.
There are few phrases that I like to mention when I see devs add TODO comments:
- if in doubt leave it out
- every line of code is a potential liability that needs to be maintain and tested
- in the future requirements may be different or no longer relevant
I have no idea what the rationale for this is, especially considering the potential for corrupting the emphasis of the original headline, like in this case.
> Otherwise please use the original title, unless it is misleading or linkbait; don't editorialize.
So, "Stop using" could be considered "linkbait", which could be why it was changed to just "Using".
It's ironic that this has the effect of misleading the author's intent...
I haven't seen `XXX:` anywhere, but it's immediately disconcerting as the icon is meaningless. If I have to reach-out to you to discover the meaning of some word you use, it's a bad word.
Like others mentioned, it's not as an established convention as `XXX`. And it's much shorter and quicker to type, particularly convenient when you just want to rant about something, which is the usual use case for `XXX`. ;)
At the end of the day, these labels are meaningless unless the entire team is following the same conventions. So using whatever your team agrees with using is the most important thing.
I suppose if its defined somewhere as a standard for everyone working on the code it may make sense. Just doesn't feel very intuitive to me.
Visual Studio (not necessarily Code) will recognise TODO, HACK, NOTE and UNDONE, for example.
Java conventions mention XXX: https://www.oracle.com/java/technologies/javase/codeconventi...
10.5.4 Special Comments
Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken.
Using XXX in comments goes back to 1978, according to https://www.snellman.net/blog/archive/2017-04-17-xxx-fixme/I'm not a huge fan of XXX as a warning, there are more descriptive names in caps available that your IDE will probably even autocomplete after using them for a while. However, the practice is common enough that it's just a General Programmer Thing, kind of like how some people prefer /* */ over // because they're just more used to it.
usually to indicate some horrible hack which is required because we can't quite blow up the codebase to fix it all, and i'm not thinking of a simpler solution today.
it also exists to point out that even though the code looks maybe mindlessly overcomplicated that someone shouldn't just come in and refactor it to make it simpler because it'll blow up some edge condition if you do that. They're the long-term nuclear waste warning messages of a codebase.
TODO(username): blah blah
to almost-mandatory:
TOOD(bug#): blah blah.
Gonna write a TODO? Make a ticket for it, and follow up
// TODO ${username} $[date} (ISSUE) - message
Having a who and a when is very useful for quickly determining what it's about.The username is helpful for myself for quickly finding my own TODOs, the date is useful for others, as if the issue is so small nobody has bothered fixing it for years, then odds are it's probably not ever going to get fixed and then the TODO can probably be removed.
I just don't write TODOs in my code, as I have never seen a useful TODO in a codebase... The worst being "TODO: improve this". Sounds like a way to say "I wrote shitty code, I know it, please merge it anyway", which is completely useless IMO.
This is not a TODO issue, this is a merge criteria issue. TODO and its variants are only as useful as the process enforced surrounding their use.
If a dev team agrees that code can't be merged until certain types of TODO-variants are addressed, then the comment may be useful.
But of course, if no such process exists, they may not be useful. But that's a team/process issue, not a fundamental problem with using TODO comments.
"Just todo."
https://www.collinsdictionary.com/dictionary/spanish-english...
Honestly, the article has a very expensive proposition and a completely unsatisfying reasoning. If you want to add some explanation, well, add it after the tag. The tag is exactly that, a tag, not some part of your comment.
Personally, I try not to commit any TODO comments. They're sort of like warnings. Unless you're religious about clearing them out, they're just going to build up and be ignored.
I guess this is relevant if you're using TODOs in the main branch, but I see that as rare. There are very few times I've had someone else pick up a TODO I've written, or vice versa. In my current team, if we're passing a To-Do/bugfix/enhancement to someone, that becomes a ticket and/or a Slack conversation.
def my_fancy_function():
raise NotImplementedErrorThe exception is for runtime behaviour until the TODO is resolved: it's something you do mostly for yourself, not others. By the time others see your code, your TODOs have either been addressed, or they're acceptance criteria for follow-up work in your project tracker.
And that brings us to the third part that we _also_ need: the issue that the work the TODO talks about is for. Either as a checkbox task in a larger piece of work, or if it's big enough, taking up the entire issue. (because good project management means knowing what tasks are required/which work is outstanding, without opening a single file)
The date really helps because many times the TODO was written for an earlier design, and the todos haven't been updated. Many times a lot of time has been saved when trying to figure out the context of a todo.
Same for author. Helps to know who made the note, in case any additional context is needed. Though often it is you who made the comment and you've obviously forgotten...
It's kinda nice having it right there in the code though.
I prefer having the author out of the way and looking it up when I'm curious. I can see how others might prefer the opposite.
Before I ship something to production I try to get rid of all TODOs. Sometimes this means rewriting it as documentation of weird behavior, often it means moving it an external backlog, once in a while it is actually doing the TODO.
Once a TODO ships, it is effectively a WONTDO because nobody is going to want to touch that hairy code and if it works it works.
> Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken.
TODO is a linting error and should not exist when it’s final PR time. We use them for our own feature branch dev work.
Any item that’s a “do later” needs a URL for a ticket/issue in the comment. These are very rare and discouraged as usually the issue alone is enough. Don’t need to mention it in the code because even the location of the mention can basically be an opinion on how to solve the problem.
Tends to be the most useful in-code comment because if someone comes along and "helps" to refactor the "weird" code, they could accidentally undo the workaround and get stuck in the same loop the original author was in.
I don't want to remember a complete ontology of greppable signifiers. I would prefer to just 'grep -R "TODO" <dir>' or 'grep -R "TODO(zomglings)" <dir>' than use a more complex grammar as the author suggests. We can stuff those kinds of semantics in the TODO message.
If you're reading a sentence in a TODO you can decide what it wants you to do, it's bizarre to claim the reader will be less confused if the sentence was merely labeled differently. This reminds of using emojis in Github issues instead of using a universal up/down vote to count the usefulness of an answer like Stackoverflow.
Please don't ruin programming further.
Admittedly, I probably won’t adopt these new values since I tend to attach a Jira ticket and a few sentences to many of my TODOs; however, I can see how the concept would help some teams/individuals who tend to be less verbose with their comments.
TODO([person], [subtypes...]) [message]
Just as a catch all, in case w/e tool (or other people) don't grok the subtypes of TODO, or in case I encounter a new subtype I'd like to use. And at this point I think TODO is pretty ubiquitous.a) Suggestions for refactoring: TODO: move this to its own class
b) Known future work: TODO: remove this when legacy accounts are deleted
c) Warnings: TODO: this probably doesn't scale, suggest XXX instead
TODO(security, p1, blocking): login must be authenticated
TODO(perf, p3): update can improve to O(n) if needed
TODO(data, p1, blocking): this db insert should be retried on failure
Rather than entirely replace "TODO" (which would then require multiple searches when a single one now finds all instances), consider augmenting it instead.
E.g., TODO-FIX, TODO-DOCUMENT, TODO-ADDFEATURE...
(or, if you prefer, abbreviated versions of such tags)
Search TODO wins
"Conventional Codetags: a specification for structured TODO comments"
`TODO: can’t foo because bar. workaround with buzz. tracking: github.com/issue/1234` or whatever.
Every once in a while I go back through and clean up what I can. I think this is good.
I have hopes of one day being a more competent engineer and being able to go squash the todos.
TODO (never make it into `main`)
SHOULDDO (may have been TODOs in a previous life)
COULDDO (effectively pre-emptive strikes for code review)
I don't know whether this is a good thing or a bad thing.
This way you get all reviewers that write "any unit tests for that" covered and any brogrammer will know it is strong alpha male territory.
A more reliable approach is to:
1. File a ticket, and
2. Leave a comment in the code linking to it:
// This code does X, but it'd be better to do Y. At the time of writing
// fixing this doesn't seem to be an issue worth fixing.
//
// See: https://bugtracker.example.com/...
It's very difficult to write code that correctly predicts the future, but it's easy to write code that accurately describes the status quo at time of writing.This isn’t any different from filing a ticket. There’s merit to keeping all of your work in your issue tracker, but this isn’t part of it.