[HN Gopher] Maybe comments should explain 'what' (2017)
       ___________________________________________________________________
        
       Maybe comments should explain 'what' (2017)
        
       Author : zahrevsky
       Score  : 177 points
       Date   : 2026-01-04 10:43 UTC (12 hours ago)
        
 (HTM) web link (www.hillelwayne.com)
 (TXT) w3m dump (www.hillelwayne.com)
        
       | awesan wrote:
       | I feel like no one serious uses the uncle Bob style of
       | programming anymore (where each line is extracted into its own
       | method). This was a thing for a while but anyone who's tried to
       | fix bugs in a codebase like that knows exactly what this article
       | is talking about. It's a constant frustration of pressing the "go
       | to definition" key over and over, and going back and forth
       | between separate pieces that run in sequence.
       | 
       | I don't know how that book ever got as big as it did, all you
       | have to do is try it to know that it's very annoying and does not
       | help readability _at all_.
        
         | ngruhn wrote:
         | I know plenty of Java/C# developers who still suffer from this
         | mind virus ;P
        
         | embedding-shape wrote:
         | > where each line is extracted into its own method
         | 
         | Never heard of "that style of programming" before, and I
         | certainly know that Uncle Bob never adviced people to break
         | down their programs so each line has it's own method/function.
         | Are you perhaps mixing this with someone else?
        
           | troupo wrote:
           | > I certainly know that Uncle Bob never adviced people to
           | break down their programs so each line has it's own
           | method/function
           | 
           | There's a literal link to a literal Uncle Bob post by the
           | literal Uncle Bob from which the code has been taken
           | verbatim.
        
           | eterm wrote:
           | This is from page 37 of Clean Code:                 > Even a
           | switch statement with only two cases is larger than I'd like
           | a single block or function to be.
           | 
           | His advice that follows, to leverage polymorphism to avoid
           | switch statements isn't bad per-se, but his reasoning, that 6
           | lines is too long, was a reflection of his desire to get
           | every function as short as possible.
           | 
           | In his own words, ( page 34 ):
           | 
           | > [functions] should be small. They should be smaller than
           | that. That is not an assertion I can justify.
           | 
           | He then advocates for functions to be 2-3 lines each.
        
             | embedding-shape wrote:
             | > to leverage polymorphism to avoid switch statements [...]
             | was a reflection of his desire to get every function as
             | short as possible.
             | 
             | That's both true, but long way away from "every line should
             | have it's own method", but I guess parent exaggerated for
             | effect and I misunderstood them, I took it literally when I
             | shouldn't.
        
               | eterm wrote:
               | I've edited my comment to add more context to that quote.
               | He absolutely advocated for the most minimal of function
               | lengths, beyond what is reasonable.
        
             | zephen wrote:
             | He has expressed admiration for lisp, and he comes from a
             | time before IDEs. These may color his desired level of
             | complexity.
        
         | xlii wrote:
         | _Haskell enters the chat_
         | 
         | Haskell (and OCaml I suppose two) are outliers though as one is
         | supposed to have a small functions for single case. It's also
         | super easy to find them and haskell-language-server can even
         | suggest which functions you want based on signatures you have.
         | 
         | But in other languages I agree - it's abomination and actually
         | hurt developers with lower working memory (e.g. neuroatypical
         | ones).
        
           | danielscrubs wrote:
           | It's because maths are the ultimate abstraction. It's
           | timeless and corner cases (almost) fully understood. Ok maybe
           | not, but at least relative to whatever JavaScript developers
           | are reinventing for the thousand time.
        
         | Scarblac wrote:
         | Turns out writing a book and getting it published with the
         | title "Clean Code" is great marketing.
         | 
         | I have had so many discussions about that style where I tried
         | to argue it wasn't actually simpler and the other side just
         | pointed at the book.
        
           | __s wrote:
           | Cult think loves a tome
        
           | hamdingers wrote:
           | > and the other side just pointed at the book
           | 
           | One of the most infuriating categories of engineers to work
           | with is the one who's always citing books in code review.
           | It's effectively effort amplification as a defense mechanism,
           | now instead of having a discussion with you I have to go read
           | a book first. No thanks.
           | 
           | I do not give a shit that this practice is in a book written
           | by some well respected whoever, if you can't explain why _you
           | think_ it applies here then I 'm not going to approve your
           | PR.
        
             | rasmus-kirk wrote:
             | Yeah, and any of these philosophies are always terrible
             | when you take them to their limit. The ideas are always
             | good in principle and built on a nugget of truth, it's when
             | people take it as gospel I have a problem. If they just
             | read the book and drew inspiration for alternative,
             | possibly better, coding styles and could argue their case
             | that's unequivocally good.
        
           | bluecalm wrote:
           | It's like with goto. Goto is useful and readable in quite a
           | few situations but people will write arrow like if/else tree
           | with 8 levels of indentation just to avoid it because someone
           | somewhere said goto is evil.
        
             | Scarblac wrote:
             | A colleague recently added a linter rule against nested
             | ternary statements. OK, I can see how those can be
             | confusing, and there's probably a reason why that rule is
             | an option.
             | 
             | Then replaced a pretty simple one with an anonymous
             | immediately invoked function that contained a switch
             | statement with a return for each case.
             | 
             | Um, can I have a linter rule against that?
        
         | zimpenfish wrote:
         | > I feel like no one serious uses the uncle Bob style of
         | programming anymore (where each line is extracted into its own
         | method)
         | 
         | Alas, there's a lot of Go people who enjoy that kind of thing
         | (flashback to when I was looking at an interface calling an
         | interface calling an interface calling an interface through 8
         | files ... which ended up in basically "set this cipher key" and
         | y'know, it could just have been at the top.)
        
           | mannykannot wrote:
           | Hardcore proponents of this style often incant 'DRY' and talk
           | about reuse, but in most cases, this reuse seems to be much
           | more made available in principle than found useful in
           | practice.
        
             | zimpenfish wrote:
             | There's also the "it makes testing easier because you can
             | just swap in another interface and you don't need mocks"
             | argument - sure but half of the stuff I find like this
             | doesn't even have tests and you still tend to need mocks
             | for a whole bunch of other cases anyway.
        
         | falcor84 wrote:
         | I wonder how hard it would be to build an IDE "lens" extension
         | that would automatically show you a recursively inlined version
         | of the function you're hovering over when feasible and e.g.
         | shorter than 20 lines.
        
         | falcor84 wrote:
         | I wonder how hard it would be to have an IDE extension that
         | would automatically show you a recursively inlined version of
         | the function you're hovering over when feasible and e.g.
         | shorter than 20 lines.
        
         | WillAdams wrote:
         | For an example of what happens when he runs into a real
         | programmer see:
         | 
         | https://github.com/johnousterhout/aposd-vs-clean-code
         | 
         | _A Philosophy of Software Design_ is an amazing and under-rated
         | book:
         | 
         | https://www.goodreads.com/en/book/show/39996759-a-philosophy...
         | 
         | and one which I highly recommend and which markedly improved my
         | code --- the other book made me question my boss's competence
         | when it showed up on his desk, but then it was placed under a
         | monitor as a riser which reflected his opinion of it....
        
           | onionisafruit wrote:
           | Each page in that book serves its purpose. That purpose is
           | raising the monitor 0.1mm.
        
           | hyperman1 wrote:
           | That's a really interesting read. I felt myself being closer
           | to John about the small method part, but closer to UB for the
           | TDD part, even if in both cases I was somewhere inbetween.
           | 
           | At the very least, you convinced me to add John's book to my
           | ever-growing reading list.
        
           | jcranmer wrote:
           | That entire conversation on comments is just wildly insane.
           | Uncle Bob outright admits that he couldn't understand the
           | code he had written when he looked back on it for the
           | discussion, which should be an automatic failure. But he
           | tries to justify the failure as merely the algorithm just
           | being sooooo complex there's no way it can be done simply.
           | (Which, compared to the numerics routines I've been staring
           | out, no, this is among the easiest kind of algorithm to
           | understand)
        
         | lucketone wrote:
         | It was written in different times, different audiences. (When
         | variable names t,p,lu were the norm)
         | 
         | It was useful for me and many others, though I never took such
         | (any?) advice literally (even if the author meant it)
         | 
         | Based on other books, discussions, advice and experience, I
         | choose to remember (tell colleagues) it as "long(e.g.
         | multipage) functions are bad".
         | 
         | I assume CS graduates know better now, because it became common
         | knowledge in the field.
        
         | ekjhgkejhgk wrote:
         | Great, that's exactly how I feel with any style that demands
         | "each class in its own file" or "each function in its own file"
         | or whatever. I'd rather have everything I need in front of my
         | eyes as much as possible, rather than have it all over the
         | place just to conform with an arbitrary requirement.
         | 
         | I said this at a company I worked and got made fun of because
         | "it's so much more organized". My take away is that the average
         | person has zero ability to think critically.
        
           | frozenlettuce wrote:
           | If those demands made any sense they would be enforced by the
           | languages themselves. It's mostly a way of claiming to be
           | productive by renaming constants and moving code around.
        
         | TZubiri wrote:
         | It's an extremism to get a strong reaction, but the takeaway is
         | that you should aim when possible to make the code
         | understandable without comments, and that a good programmer can
         | make code more understandable than a newbie with comments.
         | 
         | But of course understandeable code with comments simply has
         | much more bandwidth of expression so it will get the best of
         | both worlds.
         | 
         | I see writing commentless code like practicing playing piano
         | only with your left hand, it's a showoff and you can get
         | fascinatingly close to the original piece (See Godowsky's
         | Chopin adaptations for the left hand), but of course when you
         | are done showing off, you will play with both hands.
        
         | jffhn wrote:
         | >where each line is extracted into its own method
         | 
         | As John Carmack said: "if a lot of operations are supposed to
         | happen in a sequential fashion, their code should follow
         | sequentially" (https://cbarrete.com/carmack.html).
         | 
         | A single method with a few lines is easy to read, like the
         | processor reading a single cache line, while having to jump
         | around between methods is distracting and slow, like the
         | processor having to read various RAM locations.
         | 
         | Depending on the language you can also have very good reasons
         | to have many lines, for example in Java a method can't return
         | multiple primitive values, so if you want to stick to
         | primitives for performances you inline it and use curly braces
         | to limit the scope of its internals.
        
       | rokkamokka wrote:
       | I agree wholeheartedly - I've fought against refactors like this
       | for the same reason. In the end readability is king, and jumping
       | through 6 methods instead of one decreases readability quite a
       | bit.
        
       | eterm wrote:
       | I wouldn't take the examples from Bob Martin as gospel, see also:
       | "Don't refactor like Uncle Bob":
       | https://theaxolot.wordpress.com/2024/05/08/dont-refactor-lik...
        
         | JanNash wrote:
         | Thank you! Taking that refactoring advice at face value when I
         | still was quite junior led to me writing an immensely over-
         | abstracted framework that bit me in the butt for years
         | afterwards when trying to debug or add a new feature. Wasn't
         | easy to unlearn...
        
           | rasmus-kirk wrote:
           | Thank God you did. I hear of seniors who still do this shit
           | with no real sense of style because they just assume that
           | over-abstracting everything is always the correct thing to
           | do. You're learning, not unlearning!
        
       | jbreckmckye wrote:
       | Sometimes I want to use comments because I'm doing something
       | vaguely algorithmic, and I know some readers won't follow the
       | code.
       | 
       | I'm trying to think of a good example, maybe something like a
       | pointer window based function (off the top of my head)
       | 
       | (This isn't real code. Don't get hung up on it)
       | func DedupeStrings(ss []string) []string {           if len(ss) <
       | 2 {             return ss           }           ss =
       | strings.Sort(ss)                u := 1 // index of end of
       | "uniques" set           for i := 1; i < len(ss); i++ {
       | // Consume until new value             if ss[i] == ss[i-1] {
       | continue             }             // Put new value in 'uniques'
       | set             ss[u] = sorted[i]             u++           }
       | // Final state: all unique items are positioned            //
       | left of 'u' index           return ss[:u]         }
       | 
       | People will quibble, but
       | 
       | - I'm not convinced you could change the variable names without
       | harming clarity. Would a name like uniquesEndIndex really be any
       | clearer? It adds noise to the code and still doesn't satisfy a
       | confused reader
       | 
       | - I don't want to use function calls for documentation, eg
       | putInUniques(). I'm doing it this way because I want it to run
       | really quick.
        
         | toxik wrote:
         | I'll be honest, this code is easier to read for me without the
         | comments. Also sorting feels like it's going to be slower than
         | having some kind of set structure? You don't need ordering,
         | just collocation of duplicates. If not or if it's a wash, that
         | is also a good thing to comment. Also I'm not sure about the
         | semantics of Go but it seems this mutates the argument AND
         | returns a value, something I consider dangerous.
         | 
         | Otherwise I agree, people have a weird hang up about short
         | variable names. Somehow not a problem in mathematics...
        
           | jbreckmckye wrote:
           | There's probably a better example. The point is sometimes the
           | What needs explanation, and finding a better What isn't
           | practical.
           | 
           | I have slightly unorthodox opinions about short variables. I
           | used to hate them. Then I posted a question on one of the PL
           | design forums - it might have been Reddit
           | r/programminglanguages - why is there are history of single
           | letter names for type variables? ie T, U, etc for generics.
           | The answer I got back, was, sometimes you want code to focus
           | on structure rather than identities. That stuck with me,
           | because it helped me understand why so much C code (including
           | Linux) code uses similar naming practices. Names can lie, and
           | sometimes expressing the structure is the absolute critical
           | thing.
        
             | alembic_fumes wrote:
             | Back when I programmed in Haskell, I also had a similar
             | question about the extremely terse variable names that pop
             | up everywhere. I'd wonder, why is this "x" and "xs" instead
             | of "item" and "items" or "businessName" and "businessNames"
             | or whatever. Eventually I found this (paraphrased) answer
             | that made it all click:
             | 
             | The specificity or abstractness of a (variable) name
             | relates to the values that it can hold. So when you have a
             | _very_ abstract function whose inputs can be of almost any
             | type, naming those inputs in an overly-specific manner is
             | an exact inverse of the failure of giving an overly generic
             | to name highly constrained parameter.
             | 
             | Examples of correct naming:                 func
             | firstWord(s string) string { ... }            func
             | bidShortcodePrefix(businessId string) string { ... }
             | 
             | Examples of incorrect naming:                 func
             | firstWord(strWithOptionalSpaces string) string { ... }
             | func bidShortcodePrefix(s string) string { ... }
             | 
             | All this said, I do agree with your original take on the
             | comments. I much prefer having human-readable explanations
             | inline with anyhow non-trivial code. If nothing else, they
             | really make it easier to correctly fix the code if a bug is
             | found much later.
        
         | Bootvis wrote:
         | I agree this is easy enough to follow but I'd like to quibble
         | about something else:
         | 
         | Comments should answer the question why you are not using some
         | kind of hash set and do a single pass over the data and why
         | it's OK to reorder the strings. One could reasonable expect
         | that Dedupe shows first occurrences in order.
        
         | CuriouslyC wrote:
         | What is ss supposed to mean? Also, I only know what "u" means
         | because of your "uniques" comment.
         | 
         | Those comments also don't really help me quickly understand the
         | code. I'd do a small doc comment along the lines of "Removes
         | repeated elements from the supplied list, returning the
         | remaining items in original order"
        
         | 1718627440 wrote:
         | Where is the `sorted` array coming from?
        
       | croes wrote:
       | Isn't the purpose of comments to make code understandable?
       | 
       | If that needs a why it's a why-comment.
       | 
       | If it needs a what it's a what-comment. Especially if clever
       | programming tricks are used. 6 month later you already forgot
       | what the trick is and how it works.
        
         | jbreckmckye wrote:
         | Yes, but some people have a Jihad against "what" comments -
         | believing these should be elevated into the structure of the
         | code itself, eg veryVerbosePainfullySpelledOutVariableNames or
         | thisFunctionNameExplainsAWholeDomainConcept()
        
           | croes wrote:
           | I would like to see their version of
           | https://en.wikipedia.org/wiki/Fast_inverse_square_root
        
         | Scarblac wrote:
         | Yes, but there are other ways to make it more understandable
         | (like good names, idiomatic code, units that are neither too
         | long nor too short) that are often preferable, because comments
         | always have a danger of going out of sync with the code.
         | 
         | The "why" is the part of the explanation that can't be deduced
         | from the code.
        
           | croes wrote:
           | Sometimes good names etc. don't help. Think of this
           | 
           | https://en.wikipedia.org/wiki/Fast_inverse_square_root
           | 
           | That definitely needs a what comment.
        
             | Scarblac wrote:
             | Yes of course, sometimes there is no understandable way to
             | write the code and comments are the best way.
             | 
             | But there's also the case to be made that the comments that
             | particular code needs are "why" comments. I can see what
             | happens, but why does it work?
        
               | croes wrote:
               | Why does it work or why was the code written?
               | 
               | The article mentions the reason for the code which I
               | would expect in the commit message
        
       | jph wrote:
       | These examples could both be much better IMHO with a top comment
       | block that describes the purpose of the functionality and shows
       | good usage examples. Something like this below, and ideally using
       | runnable doc comments to help keep the comment correctly
       | explaining the code.
       | 
       | Replace symbol placeholders in the input string with translated
       | values. Scan the string for symbol placeholders that use the
       | format "$foo". The format uses a dollar sign, then optional ASCII
       | letter, then optional word characters. Each recognized symbol is
       | replaced with its corresponding value.
       | 
       | Symbols are only replaced if the symbol exists i.e.
       | getSymbol(String) returns non-null, and the symbol has not
       | already been replaced in this invocation.
       | 
       | Example:                 - input = "Hello $name, welcome to
       | $city!"            - output -> "Hello Alice, welcome to Boston!"
       | 
       | Return the string with symbol placeholders replaced.
        
         | Signez wrote:
         | I think the argument against this kind of top comments is that
         | it makes easier to forget to update them if you change the code
         | it refers to.
         | 
         | A single line comment is easy to parse, read and spot as having
         | to be changed when you patch something.
        
       | aquafox wrote:
       | I'm a data scientist and a lot of my R code are dplyr-chains a la
       | data |> select(features) |> filter(low_quality) |>
       | mutate(feature=...). It just saves time to comment on what those
       | chains do instead of having go through them every time I want to
       | change something.
        
       | jackfranklyn wrote:
       | The "what" vs "why" distinction breaks down when your code
       | encodes domain knowledge that readers can't infer from context.
       | 
       | I build accounting software and half my "what" comments are
       | actually explaining business rules that would be impenetrable
       | otherwise. Something like:                 // Bank transfers
       | appear as two transactions - a debit here and credit elsewhere
       | // We match them by looking for equal-opposite amounts within a
       | 3-day window
       | 
       | That's explaining "what" but also implicitly "why" - because
       | that's how double-entry works and that's the tolerance banks
       | allow for settlement delays. You can't really extract that into a
       | method name without it becoming absurd.
       | 
       | The Uncle Bob approach of
       | extractNameMatchingTransfersWithinSettlementWindow() doesn't
       | actually help - now I need to know what settlement windows are
       | anyway, and I've lost the context of why 3 days.
        
         | coffeebeqn wrote:
         | I also do that but I'd argue that business rules/quirks count
         | as a "why"
        
           | troupo wrote:
           | They are often a "why" in the form of "what the hell" :)
        
           | gbin wrote:
           | I agree it is about "what the code is technically doing" vs
           | why which is "what external factor you need to understand to
           | read this"
        
           | mashally wrote:
           | I agree with that as well, the "why" explains the business
           | logic and that makes much more sense to me. Otherwise, I
           | might end up explaining the algorithm (the "what") instead of
           | the business behind it.
        
           | bostik wrote:
           | While I agree, I think that's still incomplete. To me good
           | comments have always been about "what is being done AND why".
           | 
           | Or to put it another way: to provide the necessary context
           | for figuring out why a particular piece of code is written
           | the way it's done. (Or what it's _supposed_ to do.)
        
         | wizzwizz4 wrote:
         | > _and that 's the tolerance banks allow for settlement delays_
         | 
         | This is missing from your comment. While I'd probably be able
         | to pick that up from context, I'd have to hold "this is an
         | assumption I'm making" in my head, and test that assumption
         | against all parts of the codebase I encounter until I become
         | certain: this'd slow me down. I'd recommend including the "why"
         | explicitly.
        
         | tyre wrote:
         | Does the caller of the method need to know the three days? Why?
         | What if you update to FED Now and it changes?
         | 
         | It seems like the caller only needs to know that it's checking
         | within the window, which is then likely a constant (like
         | SETTLEMENT_WINDOW_DAYS) that gives the context.
         | 
         | If you need to, you can add a comment to the constant linking
         | to whatever documentation defines why three days.
        
         | antonymoose wrote:
         | I always use "what" comments for regular expressions, in
         | addition I provide examples of before and after transformations
         | so that future developers know immediately what's going on
         | without having to first stop, context-switch, and decipher
         | hieroglyphs.
        
           | epgui wrote:
           | This is probably one of the best use cases for "what"
           | comments... however in my opinion a much better way to go
           | about this is to have example-based tests (and maybe a decent
           | function name) serve as your documentation.
        
         | tetha wrote:
         | > That's explaining "what" but also implicitly "why" - because
         | that's how double-entry works and that's the tolerance banks
         | allow for settlement delays. You can't really extract that into
         | a method name without it becoming absurd.
         | 
         | That's why I've also started to explicitly decompose constants
         | if possible. Something like `ageAlertThresholdHours =
         | backupIntervalHours + approxBackupDurationHours +
         | wiggleRoomHours`. Sure, this takes 4 constants and is longer to
         | type than "28 hours".
         | 
         | However, it communicates how I think about this, how these 28
         | hours come about and how to tweak them if the alerting is being
         | annoying: It's easy to guess that you'd bump that to 29 hours
         | if it throws false positives. But like this, you could see that
         | the backup is supposed to take, say, 3 hours - except now it
         | takes 4 due to growth of the system. So like this, you can now
         | apply an "obviously correct" fix of bumping up the approximate
         | backup duration based on monitoring data.
        
           | dijksterhuis wrote:
           | i personally prefer this kind of version -- if i want to do
           | the maths to work out tweaks i can, but i'm not forced to do
           | maths in my head to know/tweak the end value
           | // a total of          // - backup interval = 24         // -
           | approx backup duration = 2         // - "wiggle room" = 2
           | ageAlertThresholdHours = 28
           | 
           | yes lazy devs are lazy and won't want to or just won't update
           | the comments (be pedantic in review :shrug:). it's all
           | trading one thing off with another at the end of the day.
           | 
           | edit -- also your version forces me to read horizontal rather
           | than vertical, which takes longer ime.
           | 
           | sorry, i've basically done an unprompted code review. i feel
           | like a bit of a dick now.
        
             | Joker_vD wrote:
             | const int backupIntervalHours = 24         const int
             | approxBackupDurationHours = 2         const int
             | wiggleRoomHours = 2         const int
             | ageAlertThresholdHours = backupIntervalHours +
             | approxBackupDurationHours + wiggleRoomHours;
             | static_assert(28 == ageAlertThresholdHours);
             | 
             | It's a shame more languages don't have static asserts...
             | faking it with mismatched dimensions of array
             | literal/duplicate keys in map literals is _way_ too ugly
             | and distracting from the intent.
        
               | pwdisswordfishy wrote:
               | Mmm...                   ageAlertThresholdHours = 24 + //
               | backup interval                                   2 + //
               | approx backup duration
               | 2;  // "wiggle room"
               | 
               | No static assert needed, no need to pre-compute the total
               | the first time, and no need to use identifiers like
               | `approxBackupDurationHours`, the cognitive override about
               | the possibility of colliding with other stuff that's in
               | scope, or the superfluous/verbose variable declaration
               | preamble.
        
               | feffe wrote:
               | I'm a believer in restricting the scope of definitions as
               | much as possible, and like programming languages that
               | allows creating local bindings for creating another.
               | 
               | For example:                   local             val
               | backupIntervalHours = 24             val
               | approxBackupDurationHours = 2             val
               | wiggleRoomHours = 2         in         val
               | ageAlertThresholdHours = backupIntervalHours +
               | approxBackupDurationHours + wiggleRoomHours         end
               | 
               | Then it's easier to document what components a constant
               | is composed of using code without introducing unnecessary
               | bindings in the scope of the relevant variable. Sure
               | constants are just data, but the first questions that
               | pops into my head when seeing something in unfamiliar
               | code is "What is the purpose of this?", and the smaller
               | the scope, the faster it can be discarded.
        
               | zephen wrote:
               | Mentally discarding a name still takes some amount of
               | effort, even if local.
               | 
               | I often write things the way you have done it, for the
               | simple reason that, when writing the code, maybe I feel
               | that I might have more than one use for the constant, and
               | I'm used to thinking algebraically.
               | 
               | Except, that I might make them global, at the top of a
               | module. Why? Because they encode assumptions that might
               | be useful to know at a glance.
               | 
               | And I probably wouldn't go back and remove the constants
               | once they were named.
               | 
               | But I also have no problem with unnamed but commented
               | constants like the ones in the comment you responded to.
        
             | tetha wrote:
             | > sorry, i've basically done an unprompted code review. i
             | feel like a bit of a dick now.
             | 
             | That's all fine.
             | 
             | Just note that this was one of the easiest examples I could
             | find. For example, for reasons out of my control, the
             | individual network configuration on a linux host is
             | positively nuts. The decision whether to deploy routes,
             | static DNS servers and such depends on 3-5 facts about the
             | datacenter and the provider it's on.
             | 
             | In such a case, it is more maintainable to separate the
             | facts about the provider, or the thing we are looking at
             | (e.g. "Does this provider allow us to configure routes in
             | their DHCP server?", from the computation/decision making
             | ("Can the system rely on the routes from the DHCP
             | servers?"), and all of that from the actual action based
             | off of the decision ("Deploy routes statically if DHCP
             | provided routes are not correct").
        
           | ulbu wrote:
           | we tend to talk about type composition, but values too are
           | composed. this suggestion makes the composition clear and,
           | imo, is strictly better that a hardcoded resulting value.
           | even more so if we assign it using some blocks-with-returns
           | feature, if the language has it: we can clarify that the
           | value's components are not used elsewhere and thus reduce
           | complexity of the namespace. without such feature, I'm not
           | sure complicating the namespace is worth it, and a comment
           | may actually be better.
        
           | peheje wrote:
           | I don't necessarily disagree with providing context, but my
           | concern is that comments eventually lie. If the business rule
           | evolves (say the window moves to 5 days) the comment becomes
           | a liability the moment someone updates the code but forgets
           | the prose.
           | 
           | The comment also leaves me with more questions: how do you
           | handle multiple identical amounts in that window? I would
           | still have to read the implementation to be sure.
           | 
           | I would prefer encoding this in an Uncle Bob style test. It
           | acts as living documentation that cannot get out of sync with
           | the code and explains the why through execution. For example:
           | test("should_match_debit_with_credit_only_if_within_three_day
           | _settlement_window", () => {           const debit =
           | A_Transaction().withAmount(500.00).asDebit().on(JANUARY_1);
           | const creditWithinWindow =
           | A_Transaction().withAmount(500.00).asCredit().on(JANUARY_4);
           | const creditOutsideWindow =
           | A_Transaction().withAmount(500.00).asCredit().on(JANUARY_5);
           | expect(Reconciliation.tryMatch(debit,
           | creditWithinWindow)).isSuccessful();
           | expect(Reconciliation.tryMatch(debit,
           | creditOutsideWindow)).hasFailed();       });
           | 
           | This way, the 3 day rule is a hard requirement that fails the
           | build if broken rather than a suggestion in a comment block.
        
             | sbuttgereit wrote:
             | Until someone changes the test to be four days, or two, but
             | doesn't update the test name.
             | 
             | Ultimately disciplined practice requirements rely on
             | disciplined practices to succeed. You can move the place
             | where the diligence needs to taken, but at the end the idea
             | that comments can lose their meaning isn't that different
             | to other non-functional, communicative elements also being
             | subject to neglect. I don't mean to suggest that a longish
             | test title wouldn't be more likely to be maintained, but
             | even with that long name you are losing some context that
             | is better expressed, person-to-person, using sentences or
             | even paragraphs.
             | 
             | I had first hand experiences with this, oddly enough, also
             | working on an accounting system (OK, ERP system... working
             | the accounting bits). I was hired to bring certain
             | deficient/neglected accounting methodologies up to a
             | reasonable standard and implement a specialized inventory
             | tracking capability. But the system was 20 years old and
             | the original people behind the design and development had
             | left the building. I have a pretty strong understanding of
             | accounting and inventory management practices, and ERP
             | norms in general, but there were instances where the what
             | the system was doing didn't make sense, but there was no
             | explanations (i.e. comments) as to why those choices had
             | been taken. The accounting rules written in code were
             | easier to deal with, but when we got to certain record
             | life-cycle decisions, like the life-cycle evolution of
             | credit memo transactions, the domain begins to shift from,
             | "what does this mean from an accounting perspective", where
             | generally accepted rules are likely to apply, to what did
             | the designers of the application have in mind related to
             | the controls of the application. Sure I could see what the
             | code did and could duplicate it, but I couldn't understand
             | it... not without doing a significant amount of detective
             | work and speculation. The software developers that worked
             | for the company that made this software were in the same
             | boat: they had no idea why certain decisions were taken, if
             | those decisions were right or wrong, or the consequences of
             | changes... nor did they care really (part of the reason I
             | was brought in). Even an out-of-date comment, one that
             | didn't reflect the code has it evolved, would still have
             | provided insight into the original intents. I know as well
             | as you that code comments are often neglected as things
             | change and I don't take it for granted that understanding
             | the comments are sufficient for knowing what a piece of
             | code does.... but understanding the mind of the author or
             | last authors does have value and would have helped multiple
             | times during that project.
             | 
             | When I see these kinds of discussions I'm always reminded
             | of one of my favorite papers. By Peter Naur, "Programming
             | As Theory Building"
             | (https://pages.cs.wisc.edu/~remzi/Naur.pdf). In my mind,
             | comments that were at least good and right at one time can
             | give me a sense of the theory behind the application, even
             | if they cannot tell me exactly how things work today.
        
             | tetha wrote:
             | This however misses an important point: 3 is not in our
             | control. 3 in general is controlled by math-people, and
             | that 3 in particular is probably in the hands of a
             | legal/regulation department. That's a much more important
             | information to highlight.
             | 
             | For example, at my last job, we shoved all constants
             | managed by the balancing teams into a static class called
             | BalancingTeam, to make it obvious that these values are not
             | in our control. Tests, if (big-if) written, should revolve
             | around the constants to not be brittle.
        
               | peheje wrote:
               | I like the idea of using a LegalConstants namespace or
               | Code Owners to signal that we don't own those values.
               | 
               | However, I'd argue that being 'out of our control' is
               | actually the main reason to test them. We treat these as
               | acceptance tests. The goal isn't flexibility, it is
               | safety. If a PR changes a regulated value, the test
               | failure acts as a tripwire. It forces us to confirm with
               | the PM (and the Jira ticket) that the change is
               | intentional before merging. It catches what code
               | structure alone might miss.
        
         | dijksterhuis wrote:
         | ime summaries/details of the "business what" are the most
         | important part of "why the code exists/is written this way" --
         | it's the overarching problem that section of code aims to solve
         | / needs to work around!
         | 
         | they can also be a good defence against newer seniors on the
         | team refactoring willy nilly -- can't argue with business
         | rules, but can argue over uncle bob. ;)
        
         | locknitpicker wrote:
         | > The "what" vs "why" distinction breaks down when your code
         | encodes domain knowledge that readers can't infer from context.
         | 
         | Your comment is a poor example because you unwittingly wrote
         | "why" comments, not "what".                 // We match them by
         | looking for equal-opposite amounts within a 3-day window
         | because bank transfers appear as two transactions - a debit
         | here and credit elsewhere
         | 
         | If anything, you proved the importance of clarifying why things
         | must be the way they are.
         | 
         | > The Uncle Bob approach of
         | extractNameMatchingTransfersWithinSettlementWindow() doesn't
         | actually help - now I need to know what settlement windows are
         | anyway, and I've lost the context of why 3 days.
         | 
         | You are also completely off in here as well, and I think that
         | your comment shows a deeper misunderstanding of the topic. What
         | you tried to frame as "Uncle Bob approach" actually means
         | implementing your domain in a clear and unambiguous way so that
         | both the "what" and the "why" are clear by looking at the code.
         | Naming conventions are one aspect, but the biggest trait is
         | specifying an interface that forces the caller no option other
         | than doing the what's because of the why's.
         | 
         | Without looking too hard into it, whipping out something like
         | this in a few seconds would match the intent
         | GetMatchingTransfers(TransferAmount, SettlementWindow)
        
         | epgui wrote:
         | What you describe really is describing the "why", not the
         | "what".
         | 
         | The line between the two is not _that_ blurry: assume your
         | reader has total knowledge of programming, and no knowledge
         | whatsoever of the outside world. Comments about what the code
         | does to bits are the  "what"; comments about how the code
         | relates to the outside world are the "why". The rest is a
         | matter of taste and judgment.
        
           | lukan wrote:
           | Just curious, you advice against "what" comments?
           | 
           | "assume your reader has total knowledge of programming"
           | 
           | Because if I know my fellow programmers have like me not a
           | total knowledge of programming, what comments before footguns
           | seem useful to me.
           | 
           | Or when there was a hack that is not obvious.
           | 
           | To me it mostly is not a question of taste, but context. Who
           | will read the code?
        
             | seba_dos1 wrote:
             | If you're writing a coding tutorial, you'll want to comment
             | on the "what" indeed. Otherwise it will most likely end up
             | being more distracting than useful, and sometimes even
             | misleading. Exceptions exist, but by virtue of being
             | exceptions there's no catch-all rule for them, so just use
             | your judgment.
        
             | epgui wrote:
             | I almost (?) always advise against "what" comments. I have
             | rarely (if ever?) encountered any cases where "what"
             | comments didn't have a better (and practical/cheap/easy
             | enough) solution.
             | 
             | In my experience, when I review junior contributors' code
             | and see "what" comments, it's usually caused by 1) bad
             | naming, or 2) abstractions that don't make sense, or 3)
             | someone trying to reinvent maths but incorrectly, or 4)
             | missing tests, or 5) issues with requirement gathering /
             | problem specification, or 6) outright laziness where the
             | contributor doesn't want to take the time to really think
             | things through, or 7) unclear and overcomplicated code,
             | or... any number of similar things.
             | 
             | At the very least, any time you see a "what" comment, it's
             | valuable to take notice and try really hard to think about
             | whether the problem the comment tries to solve has a better
             | solution. Take it as a personal challenge.
        
               | lukan wrote:
               | For sure, bad code exists. But if I have to work with bad
               | unclear code, "what" comments are very helpful.
               | 
               | Like something really bad
               | 
               | x=y //triggers method xyz
               | 
               | So I would agree that under controlled conditions, they
               | should not be necessary.
        
         | Xss3 wrote:
         | GetNameMatchedTransfersWithin(int Days)
         | 
         | Gives a good idea of what but not why and if anyone considers
         | that method name too long they can get back in their cave, tbh.
        
         | zephen wrote:
         | > The "what" vs "why" distinction breaks down when your code
         | encodes domain knowledge that readers can't infer from context.
         | 
         | Yes, there are multiples levels of knowledge, and the required
         | level of commenting depends on the minimum knowledge expected
         | of a reader in each of several dimensions.
         | 
         | In point of fact, the only thing that almost always can do
         | without documentation is a different question, "How."
        
         | mgkimsal wrote:
         | The 'comment becomes a lie' is because you've got magic number
         | there in the comment.
         | 
         | If the comment was                 // We match them by looking
         | for equal-opposite amounts within an X-day window defined by
         | BANK_TRANSFER_MATCH_WINDOW_DAYS
         | 
         | the comment is more evergreen, until the actual logic changes.
         | If/when the logic changes... update the comment?
        
         | zahlman wrote:
         | > The Uncle Bob approach of
         | extractNameMatchingTransfersWithinSettlementWindow() doesn't
         | actually help
         | 
         | Sure it does. You've isolated the "what" to the name, and the
         | comments can focus on the "why".
         | 
         | (Although I think _some_ of the XP advocates would go off the
         | rails and try to model a settlement window as an object....)
        
         | carlmr wrote:
         | The within settlement window might still be a good addition to
         | the method name. Since that is something I can at least Google.
        
       | reactordev wrote:
       | Should stick a (2017) on there as this is almost a decade old.
       | 
       | Comments should explain. If it's why, it's why. If it's what,
       | it's what. The point of comments is to explain, to the
       | reader/editor, what the intent of the code is and how you chose
       | to approach it. That's it. No need to fight over what, why, how,
       | who, etc.
       | 
       | If you have domain knowledge that helps support the code, maybe a
       | link to further reading, by all means add it to comments please!
        
       | meindnoch wrote:
       | "Uncle Bob" is a bad programmer, simple as.
       | 
       | Change my mind!
        
         | michaelcampbell wrote:
         | Did he actually ever write anything substantial, other than
         | that book?
        
           | meindnoch wrote:
           | None which I'm aware of.
        
         | xorcist wrote:
         | He was very successful in establishing that nickname.
        
       | frumiousirc wrote:
       | The article is about comments. But, more generally, I think the
       | issue here is about naming things.
       | 
       | Names capture ideas. Only if we name something can we (or at
       | least I) reason about it. The more clear and descriptive a name
       | for something is, the less cognitive load is required to include
       | the thing in that reasoning.
       | 
       | TFA's example that "weight" is a better variable name than "w" is
       | because "weight" immediately has a meaning while use of "w"
       | requires me to carry around the cumbersome "w is weight" whenever
       | I see or think about "w".
       | 
       | Function names serve the same purpose as variable names but for
       | operations instead of data.
       | 
       | Of course, with naming, context matters and defining functions
       | adds lines of code which adds complexity. As does defining overly
       | verbose variable names: "the_weight_of_the_red_ball" instead of
       | "weight". So, some balance that takes into account the context is
       | needed and perhaps there is some art in finding that balance.
       | 
       | Comments, then, provide a useful intermediate on a spectrum
       | between function-heavy "Uncle Bob" style and function-less
       | "stream of consciousness" style.
        
       | xlii wrote:
       | I'm all against commenting gatekeeping. IMO this is an anti-
       | pattern.
       | 
       | Even in stupidest cases, like:                   // add two and
       | two         let four = two + two
       | 
       | The rationale for this is that if you start to mute developer on
       | case of "this is not comment-worthy" you start to actually losing
       | context for the codebase. Sure, maybe "add two and two" is not
       | contextful enough, but "add same account twice" might be signal
       | for appropriate code.
       | 
       | Maybe that's me, but I rarely saw teams which over-document,
       | under-documenting is usually the case. So if we ever meet in
       | professional environment - comment away. Worst case scenario -
       | I'll skim over it.
        
         | panstromek wrote:
         | > Maybe that's me, but I rarely saw teams which over-document,
         | under-documenting is usually the case.
         | 
         | This is a good point, although this recently changed with LLMs,
         | which often spit out a ton of redundant comments by default.
        
           | chuckadams wrote:
           | Claude Code in particular seems to use very few redundant
           | comments. That or it's just better at obeying the standing
           | instruction I give it to not create them, something other
           | assistants seem to blithely ignore.
        
       | drivingmenuts wrote:
       | Here's a thought, and I'm just spitballin' here: maybe they could
       | do both? Sure, writing an encyclopedic tome about three lines of
       | code is probably a bit out of bounds, but overexplaining is only
       | bad when it's your wife or girlfriend. It might be a good idea to
       | be absolutely clear about things.
        
       | mgaunard wrote:
       | bug workarounds don't need to be justified if instead of working
       | around the bug you just fix it instead.
        
         | panstromek wrote:
         | Sure, but you can't always fix the bug if it's not in your
         | system.
        
           | mgaunard wrote:
           | Fork it, you should have ownership of your whole stack.
           | 
           | If you have the spare time, you can try and submit your
           | patches upstream; in the meantime, you just maintain your own
           | version.
        
             | panstromek wrote:
             | No, you can't always do that. We have workarounds for
             | platform bugs that were even fixed, because we get users
             | with old devices that can't upgrade. You cannot fork a
             | phone of a random person on the other side of the world.
             | Once a platform bug is out, it can stay out in the wild for
             | a very long time.
        
       | Scarblac wrote:
       | Nowadays my rule is "the comment should contain enough about the
       | why and the how so that the LLM generates the next few lines
       | mostly correctly."
        
       | shevy-java wrote:
       | I use a lot of comments, for many reasons.
       | 
       | While it leads to more things to read, which thus may take time,
       | I feel that the benefits of using comments far outweighs the
       | negative sides. This is even valid when comments are outdated
       | usually. To me, adjusting and updating comments often was much
       | easier and faster than describing something de-novo.
       | 
       | In the ruby land this is quite problematic because many do not
       | use any comments. The result is a horrible code base. Getting
       | people who wrote that code to use comments is often too late, as
       | they already abandoned ruby in favour of another language, so I
       | never buy the cop-out explanation of "the code is self-
       | explanatory" - not even in ruby it is. Everyone can write
       | horrible code.
        
       | oweiler wrote:
       | His first "what" example actually explains "why" clear is called
       | two times. The code perfectly captures the "what".
        
       | willtemperley wrote:
       | I like to see comments for external information that can't be
       | derived from the code or API documentation.
       | 
       | For example, for some reason padding bytes are allowed in
       | variable length integers (LEB128) for reasons I still do not
       | understand:                   // Allow padding bytes that do not
       | affect the value         let expectedBits: UInt8 = (result < 0) ?
       | 0x7F : 0x00
        
       | epolanski wrote:
       | I like antirez' style of comments.
       | 
       | He starts implementing any module or function by first writing
       | the documentation for it and let's it guide both the
       | functionality and structure.
       | 
       | Makes Redis also extremely easy and enjoyable to read.
       | 
       | Random example:
       | https://github.com/redis/redis/blob/unstable/src/aof.c
        
         | boredemployee wrote:
         | Really nice, we would have a better world if comments like that
         | were the standard.
        
         | CuriouslyC wrote:
         | This is a great practice. I used to do it when writing complex
         | algorithms, I'd do pseudo-code comments to outline
         | functionality, then basically implement the comments line by
         | line.
         | 
         | Now I sometimes use this practice when working with agents, if
         | I need something done just a certain way. It's time consuming,
         | but it produces good results.
        
       | panstromek wrote:
       | I also find that phrase super misleading. I've been using a
       | different heuristic that seems to work better for me - "comments
       | should add relevant information that is missing." This works
       | against redundant comments but also isn't ambigous about what
       | "why" means.
       | 
       | There might be a better one that also takes into account whether
       | the code does something weird or unexpected for the reader (like
       | the duplicate clear call from the article).
        
         | matt_kantor wrote:
         | I like this framing, but might add to it: "comments should add
         | relevant information that is missing _and which can 't easily
         | be added by refactoring the code_".
        
       | rossant wrote:
       | I like to use comments extensively, even if it's just to visually
       | separate blocks of code in my IDE. A bit more spacing simply
       | feels cleaner to me.
        
         | matt_kantor wrote:
         | Why not use blank lines? (I suspect the answer might be "my
         | code formatter deletes them", which is a damn shame.)
        
           | bonesss wrote:
           | .Net languages have 'regions' that can collapse & nest,
           | providing a high level narrative of file organization (and,
           | in practice, display most files in a clean collapsed view).
        
       | locallost wrote:
       | People (and I'm one of them) usually say why instead of what
       | because in general the what can be understood if you can read
       | code. But obviously no hard rules, if I write something twisted
       | because I had no idea how to do it better or had the time, then
       | I'll write what it does. It's not perfect, but nothing is.
       | 
       | Same goes for comments vs commit messages. It's a fact comments
       | get outdated and then you have an even bigger problem whereas a
       | commit message is always correct at the time it was made. But
       | obviously again, no hard rules. Sometimes I feel it's better to
       | write a comment, e.g. if it's something that is really important
       | and won't change a lot.
        
       | KaiserPro wrote:
       | I have changed my commenting style now, since the rise of LLMs.
       | 
       | I used to comment in a similar way to claude/chatgpt, as in both
       | the what and why. (although the why in LLMs is often lost. ) I
       | used to comment as if it was for someone who didn't know the
       | libraries very well. (ie me in two years time. Documentation at
       | the previous place was utterly shite, so it was effectively a
       | journal of discovery)
       | 
       | However, my commenting style is both what and why. My variable
       | names can be longer than my FANG peers, mainly because I know
       | that English not being a first language means that half arsed
       | abbreviations are difficult to parse.
       | 
       | But effort is placed on not using fancy features, python mostly,
       | so avoiding lambdas and other "syntactic sugar", unless they
       | absolutely make sense. If I do use them, i have a comment saying
       | _why_ I'm doing it.
       | 
       | Some of my colleagues were dead against any kind of commenting.
       | "my code should be readable enough without it". They had the
       | luxury of working on one bit for a few months, then throwing it
       | away.
        
       | DiabloD3 wrote:
       | My favorite genre of comments: it warns you not to touch it, and
       | if you do, you must add to the list under the comment how many
       | hours you wasted and got nowhere.
        
       | broken-kebab wrote:
       | IMO the example shows exactly that splitting code in smaller
       | pieces is way better than just commenting it.
       | 
       | It makes it easier for dev's brain to parse the code e.g. to
       | understand what _code really does_ , while fattier but commented
       | version makes it harder but tries to replace it with information
       | about original coder's intentions. Which is maybe important too
       | but not as important as code itself.
       | 
       | Not to forget that it's too easy to change code and leave
       | comments obsolete.
        
         | BoorishBears wrote:
         | Splitting example is way too much indirection, but capturing
         | what the code does in the code itself is a preference for me.
         | In any high level language don't know why the middleground
         | wasn't explored:                   var hasSymbol =
         | getSymbol(symbolName) != null         var replacementPending =
         | !alreadyReplaced.contains(symbolName)              if(hasSymbol
         | && replacementPending){
         | alreadyReplaced.add(symbolName);           stringToReplace =
         | stringToReplace.replace("$" + symbolName,
         | translate(symbolName));         }
         | 
         | Technically this performs worse because you lose short-
         | circuiting, but in performance-sensitive contexts code styling
         | is less a concern anyways. And I also wouldn't rely on short-
         | cutting alone to avoid a _really_ expensive operation or side-
         | effect: at some point someone _will_ fail to notice it.
        
           | 1718627440 wrote:
           | As for the comments, I would probably write it like this:
           | /* Symbol actually exists */         if ((NULL != getSymbol
           | (symbolName)         /* and still to be added */         &&
           | (!alreadyReplaced.contains (symbolName))         {
           | ...
           | 
           | Although in this specific case the comments seem like noise
           | to me.
           | 
           | > Technically this performs worse because you lose short-
           | circuiting
           | 
           | Not really, because optimizing compilers are a thing, when
           | this thing is parsed into SSA, there won't be a difference.
        
             | BoorishBears wrote:
             | The compiler would have to determine that these are pure
             | calls which I wouldn't rely on if performance actually
             | matters
             | 
             | I just tested a recent gcc at -O2 with a contrived example
             | using strings in an unordered_set: a look-up always occurs
             | if not relying on short-circuiting
        
           | broken-kebab wrote:
           | I like your version, and it's certainly possible to split too
           | much without any practical result just for the dogma. But wrt
           | the particular example I can see what's going on with a
           | glance over the split part, while I have to focus at the
           | commented one. Comments themselves can be helpful, but they
           | can also be misleading cause code and coder's thoughts are
           | not guaranteed to be in harmony all the time.
        
       | mattacular wrote:
       | Explain "why not what" is good general advice. My further advice
       | for comments is: even bad comments can be useful (unless they're
       | from LLM output maybe...) therefore when in doubt, write a
       | comment. Write it in your own words.
       | 
       | Had to add the last sentence for the circa 2020s developer
       | experience. LLM comments are almost never useful since they're
       | supposed to convey meaningful information to another human coder,
       | anything your human brain can think of will probably be more
       | helpful context.
        
         | falcor84 wrote:
         | I strongly disagree. If you're using something like Claude Code
         | to generate the code, it has significant context about the
         | task, which from my experience provides very useful (albeit
         | overly verbose) comments. I sometimes edit/rewrite its comments
         | (as I might with the code itself), but I would never ask it to
         | generate uncommented code.
        
         | 3371 wrote:
         | I always think LLM comments are more about helping themselves
         | to stay on track.
        
           | yen223 wrote:
           | Same goes for human comments tbf
        
         | CuriouslyC wrote:
         | AI comments are fine for high level summaries of the what/how.
         | They fail at the why, which is where we come in.
        
         | bonesss wrote:
         | > even bad comments can be useful
         | 
         | Bad comments aren't just less helpful than possible, they're
         | often harmful.
         | 
         | Once you've hit a couple misleading comments in a code base (ie
         | not updated, flatly wrong, or deeply confusing due to term
         | misuse), the calculus swings to actively ignoring those lying
         | lies and reading the code directly. And the kind of mind
         | resorting to prose when struggling to clarify programming
         | frequently struggles with both maintenance and clarity of
         | prose.
        
       | StellarScience wrote:
       | Ignoring the git commit message strawman (those can include
       | "what/why the change", not "what/why the code") and the Uncle Bob
       | strawman, the final code block looks fine. But notice:
       | // translate will replace all instances; only need to run it once
       | 
       | This is a "why".                 // Replace all symbols
       | 
       | This is a "what". It's better conveyed by improving the function
       | name rather than by a comment:                 String
       | replaceAllSymbols() {
       | 
       | Ultimately this article buttresses conventional wisdom about
       | comments.
        
       | jarek83 wrote:
       | I think the benefits of either clean code (sepearate methods) and
       | commenting "what" are of different kind:
       | 
       | - clean code one, for me it just reads easier, specific bits of
       | the larger operation are not surrounded with noise coming from
       | other bits like it is in the commenting "what" one. I can focus
       | more on each step, and that can make it easier to spot a bug or
       | to refactor/adjust/extend, as now I'm more like on a given page
       | of Lego set instructions
       | 
       | - the commenting of "what" one - yeah, this obviously makes it
       | quicker (but probably not easier) to see the larger picture. It
       | has benefits, but I believe this helps more hacker/scripter kind
       | of people than programmers
        
       | CuriouslyC wrote:
       | Comments should explain everything, but via links. Large comments
       | cause context rot, so keep your comments tight and focused, and
       | provide links to details as needed.
        
         | chrisweekly wrote:
         | Agreed... IFF you're linking to something immutable (Jira
         | tickets probably qualify in many enterprise scenarios).
         | Otherwise linkrot is at least as big a problem. Meaningful
         | commit messages surfaced in-IDE via git blame can serve a
         | similar purpose.
        
       | okonomiyaki3000 wrote:
       | We need to differentiate between a "What this is" comment and a
       | "What this does" comment. "What this does" is a lot closer to
       | "Why" than it is to "What this is". I would hope "What this is"
       | is rarely needed but "What this does" can certainly be helpful
       | pretty often.
        
       | akabalanza wrote:
       | I'm glad LLMs will make these conversations obsolete, just like
       | linters did to tab-vs-spaces
        
         | matt_kantor wrote:
         | Care to elaborate? It's not obvious to me why/how that would
         | happen. In fact, my experience so far tells me that code with
         | tons of "why" comments (and possibly some "what"s as well)
         | makes LLMs less likely to break stuff.
        
       | d-lisp wrote:
       | As I am involved in more low level stuff, I prefer to read the
       | source than the man pages, and I am very happy with people
       | overcommenting their code as a user of e.g. a lib. On the other
       | hand, it is unbearable to me to see comments on a codebase I am
       | working on. Fortunately, emacs show/hide comments exists, so I
       | find myself overcommenting things.
        
       | antirez wrote:
       | I made a point here https://antirez.com/news/124 that comments
       | are needed at the same time for different reasons, and different
       | comments have differente semantical properties that can be
       | classified in classes you very easily find again and again, even
       | in very different code bases.
        
         | commandersaki wrote:
         | This is a great post and meshes with how I like to comment as
         | well. I like to break the so called rules and get a bit _dirty_
         | when it comes to writing code and comments. My opinion which
         | you state, is to remove the effort from the reader in needing
         | to figure things out a second, third, or n-th time.
         | 
         | Here is one I wrote just to talk about iterating a loop in
         | reverse:                   /*          * We iterate the v6
         | prefixes in reverse from longest prefix length          * to
         | shortest. This is because the ipv6 address is a sequence of
         | bytes,          * and we want to perturb the address
         | iteratively to get the corresponding          * network address
         | without making a copy for each perturbation as that          *
         | would be expensive.          *          * For example take
         | address: abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd.          *
         | * With masks /112, /64, /8 we want to create the following
         | network addresses          * to lookup as follows:          *
         | * Lookup abcd:abcd:abcd:abcd:abcd:abcd:abcd:0000 in /112 bucket
         | * Lookup abcd:abcd:abcd:abcd:0000:0000:0000:0000 in /64 bucket
         | * Lookup abcd:0000:0000:0000:0000:0000:0000:0000 in /8 bucket
         | *          * In any other order aside from most specific to
         | least, we'd have          * to create copies of the original
         | address and apply the mask each          * time to get each
         | network address; whereas in this case we can take          *
         | the same address and clear lower bits to higher bits as we go
         | from          * most specific to least specific masks without
         | incurring any copies.          */         for (auto it =
         | m_v6_prefixes.crbegin(); it != m_v6_prefixes.crend(); ++it)
         | 
         | Or here is another for masking a v4 address, but also
         | explaining why a uint64 is used (this is calculated in a hot
         | loop [same as the previous comment example], so I felt it was
         | imperative to explain what is going on as there is very little
         | room otherwise to optimise):                   for (const auto
         | & [ mask_len, bucket ] : m_v4_prefixes)         {
         | /*              * Example:              *              *
         | netmask 255.255.128.0 (/17) or 0xffff8000:              *
         | *   0xffffffff ffffffff << (32-17)              *
         | --------------------------------              *   0xffffffff
         | ffff8000 (shifted left 15)              *              *
         | Applying against address 192.168.85.146 or 0xc0a85592:
         | *              *      (converted to uint64_t due to implicit
         | integer promotion)              *              *
         | 0x00000000 c0a85592              *       &              *
         | 0xffffffff ffff8000              *      -------------------
         | *      0x00000000 c0a80000              *
         | -------------------              *               0xc0a80000
         | (after conversion to uint32_t causing              *
         | lower 32-bit truncation)              */
         | std::uint64_t mask = (~0ULL) << (32 - mask_len);
         | std::uint32_t network_addr = addr & mask;
         | const auto itt = bucket.find(network_addr);
        
           | Karliss wrote:
           | Except your giant comment doesn't actually explain why it
           | used uint64. Only place mentioning uint64 is integer
           | promotion which only happens because you used 64bit integer,
           | thus no explanation of why.
           | 
           | Was it done because shifting by amount equal or greater to
           | integer width is undefined behavior? That would still not
           | require storing result in 64bit mask, just shifting (~0ULL)
           | would be enough. That would be a lot more valuable to explain
           | than how bitwise AND works.
           | 
           | The first one also seems slightly sketchy but without knowing
           | rest of details it's hard to be sure. IPV6 address is
           | 128bits, that's 2 registers worth integers. Calculating base
           | address would take 2 bitwise instruction. Cost of copying
           | them in most cases would be negligible compared to doing the
           | lookup in whatever containers you are searching resulting
           | address. If you are storing it as dynamically allocated byte
           | arrays (which would make copying non trivial) and processing
           | it in such a hot loop where it matters, then seems like you
           | have much bigger problems.
           | 
           | For my taste it would be sufficient to say "Iterate in
           | reverse order from most specific address to least specific.
           | That way address can be a calculated in place by
           | incrementally clearing lowest bits." Having 2 paragraphs of
           | text which repeat the same idea in different words is more
           | distracting than it helps.
        
             | commandersaki wrote:
             | Sorry, I didn't explain uint64 was used. I wrote this many
             | years ago so my memory was foggy, but I went through a few
             | iterations using uint32 only to use branches for the masks.
             | This was the only branchless way I could come up with at
             | the time after a few attempts. I think the example was more
             | to demonstrate that the algorithm was correct and I wasn't
             | going to unit test it at that scope.
             | 
             | As for the 128-bit addresses, we used boost ip::address_v6
             | to_bytes() as it appears there was no masking option.
             | 
             |  _For my taste it would be sufficient to say "Iterate in
             | reverse order from most specific address to least specific.
             | That way address can be a calculated in place by
             | incrementally clearing lowest bits." Having 2 paragraphs of
             | text which repeat the same idea in different words is more
             | distracting than it helps._
             | 
             | Ah apologies, too late now, should've mentioned it in the
             | PR. But I expected it would ruffle some feathers, I don't
             | care for conventions or other people's quibbles. As long as
             | it improves understanding for the reader, regardless of how
             | "redundant", then mission accomplished.
        
       | onion2k wrote:
       | If you need a comment to explain 'w' means 'weight' then you
       | should remove the comment and rename the variable 'weight'.
        
       | ivanjermakov wrote:
       | I noticed that when I write code that is not trivial to
       | understand I tend to extract intermediate values into variables
       | with meaningful names.                   applyDrag(): void {
       | const { quad: quadConfig } = settings             const quad =
       | this.getRigidBody()             const quadVel =
       | vec3ToTwgl(quad.linvel())             const dragMag =
       | aerodynamicDrag(quadConfig.dragCoefficient, v3.length(quadVel),
       | quadConfig.frontalArea)             const dragDir =
       | v3.negate(v3.normalize(quadVel))             const dragForce =
       | v3.mulScalar(dragDir, dragMag)             const dragImpulse =
       | v3.mulScalar(dragForce, dt)
       | quad.applyImpulse(vec3TwglToRapier(dragImpulse), true)         }
       | 
       | This way code gets more natural language anchors which helps
       | understanding what it does.
        
         | necrotic_comp wrote:
         | I appreciate this way of programming - also, if I may, in the
         | age of auto-complete I think it's okay to have verbose variable
         | naming. Imho, it's perfectly fine to have quad, quadVelocity,
         | dragMagnitude, etc.
         | 
         | I see this a lot in the wild, though - as an honest question
         | (not trolling!) why do people still shorten their variable
         | names in place of having a terse descriptor ?
        
           | ivanjermakov wrote:
           | I tend to have shorter names for function scoped variables.
           | Wider the scope - more descriptive the name. Short names are
           | good to have more concise code and more logic fitting into a
           | line width.
        
         | codemonkey-zeta wrote:
         | I find that Lisps encourage this behavior more than other
         | languages. Many (most?) of the lisp functions I read have the
         | exact same structure:                 (fn some-function [args]
         | (let [binding (transform args)]           (an-expression
         | binding)))
         | 
         | I find that this makes skimming lisp code much easier, because
         | I can usually skip reading the bindings and just read the
         | function name and ultimate expression and usually get the gist
         | very quickly.
         | 
         | You might wonder how this is different than the example you
         | provided, and the answer is because you could sneakily
         | intersperse anything you wanted between your imperative
         | bindings (like a conditional return statement), so I actually
         | have to read every line of your code, vs in a lisp `let` I know
         | for a fact there is nothing sneaky going on.
        
           | ivanjermakov wrote:
           | It's the same for many FP/pure languages, where function is a
           | single expression.
        
         | TZubiri wrote:
         | Funny how even in this very verbose code (which is perfectly
         | fine btw), there's still a need to use shorthands (quadVel).
         | It's like completely explained code requires so many words, but
         | we need to fit the code into a certain character window.
        
       | filoeleven wrote:
       | The bigger point I take from this is that the purpose of comments
       | and good names are all attempts to help the developer grasp "the
       | context of this code". The article uses "context switch"
       | repeatedly, and in fact never uses the word "context" any other
       | way. Since the author acknowledged they're starting a friendly
       | flame war, I'll go ahead and add that the biggest problem with
       | the example code is that it's object-oriented and mutable, which
       | forces a sprawling context on the developers working with it.
       | 
       | When I read the replace() method, I was immediately confused
       | because it has no arguments. stringToReplace and alreadyReplaced
       | are properties of the class, so you must look elsewhere (meaning,
       | outside of the function) for their definitions. You also don't
       | know what other bits of the class are doing with those properties
       | when you're not looking. Both of these facts inflate the context
       | you have to carry around in your head.
       | 
       | Why is this a class? In the replace() method, there is a call to
       | translate(symbolName). Why isn't there also a
       | SymbolNameTranslator class with a translate() method? Who decided
       | one was simple enough to use a function while the other warrants
       | a class?
       | 
       | SymbolReplacer surely could also be done with a function. I
       | understand that this is illustration code, so the usage and
       | purpose is not clear (and the original Bob Martin article does
       | not help). Is there a reason we want these half-replaced strings
       | made available every time we call SymbolReplacer.replace()? If
       | there is, we can get the same data by using a reduce function and
       | returning all of the iterations in a list.
       | 
       | A plain, immutable function necessarily contains within it the
       | entire scope of its behavior. It accepts and returns plain data
       | that has no baggage attached to it about the data's purpose. It
       | does one thing only.
        
         | commandersaki wrote:
         | The translation from function to class Martin Bob style makes
         | it become literal spaghetti code.
        
       | scottlamb wrote:
       | This is tangential to the article's point, but that `replace`
       | function is a complete WTF in a way both authors completely
       | ignore. Because it replaces things in the entire string in a
       | loop, it will translate symbols recursively or not depending on
       | ordering. Imagine you have the following dictionary:
       | a=$b         b=oops
       | 
       | if your input string just has one of these, it will just be
       | translated once as the programmer was probably expecting:
       | input:  foo $a bar         output: foo $b bar
       | 
       | but if your input string first references $b later, then it will
       | recursively translate $a.                   input:  foo $a bar $b
       | output: foo oops bar oops
       | 
       | _Sometimes_ translating recursively is a bizarre behavior and
       | possibly a security hole.
       | 
       | The sane thing would be to loop through building the output
       | string, adding the replacement for each symbol as you go. Using
       | String.replace and the alreadyReplaced map is just a bad idea.
       | Also inefficient, as it and throws away strings and does a
       | redundant search on each loop iteration.
       | 
       | Feels typical of this whole '90s-era culture of arguing over
       | refactoring with Java design patterns and ornate styles without
       | ever thinking about if the algorithm is any good.
       | 
       | Edit: also, consider $foo $foobar. It doesn't properly tokenize
       | on replacement, so this will also be wrong.
        
         | shiandow wrote:
         | The insane thing to do would be to implement a variant of loeb
         | so it works regardless of order.
        
           | scottlamb wrote:
           | That'd still be less surprising!
        
         | scottlamb wrote:
         | > The sane thing would be to loop through building the output
         | string, adding the replacement for each symbol as you go.
         | 
         | As follows:                   // SYMBOL_REF should be a class-
         | level static final to avoid recompiling on each call.
         | int pos = 0; // input[..pos] has been processed.
         | StringBuilder out = new StringBuilder(); // could also guess at
         | length here.         Matcher m = SYMBOL_REF.matcher(input);
         | while (m.find()) {           String replacement =
         | symbols.get(m.group(1));           if (replacement == null) {
         | continue; // no such symbol; keep literal `$foo`.           }
         | out.append(input, pos, m.start());
         | out.append(replacement);           pos = m.end();         }
         | out.append(input, pos, input.length());
         | 
         | (Apparently there's also now a Matcher.replaceAll one could
         | use, but it's arguably cheating to outsource the loop to a
         | method that probably didn't exist when the Uncle Bob version
         | was written, and it's slightly less efficient in the "no such
         | symbol" case.)
         | 
         | Coding style must serve the purpose of aiding understanding. If
         | you have strong opinions about the coding style of `replace`
         | but those opinions don't lead to recognition that the
         | implementation was incorrect and inefficient, your opinions are
         | bad and you should feel bad. Stop writing garbage books and
         | blog posts!
         | 
         | </rant>
        
       | shiandow wrote:
       | If we're doing hot takes then I propose the following guideline
       | taken from mathematics.
       | 
       |  _Only comments should explain what, variable names should only
       | hint_
       | 
       | The first example is perfectly fine, nobody has the time to
       | derive or read a verbose formula involving the words 'weight',
       | 'radius' and 'price'.
        
       | tangotaylor wrote:
       | "What" comments can be quite nice to quickly parse through code.
       | 
       | But I don't think they're worth it. My issue with "what" comments
       | is they're brittle and can easily go out of sync with the code
       | they're describing. There's no automation like type checking or
       | unit tests that can enforce that comments stay accurate to the
       | code they describe. Maybe LLMs can check this but in my
       | experience they miss a lot of things.
       | 
       | When "what" comments go out of sync with the code, they spread
       | misinformation and confusion. This is worse than no comments at
       | all so I don't think they're worth it.
       | 
       | "Why" comments tend to be more stable and orthogonal to the
       | implementation.
        
       | TZubiri wrote:
       | The maybe is the strongest part of this article.
       | 
       | In my early days I read a lot of "you should" "this is wrong".
       | But code is an expressive medium, you can do things one way, or
       | do it the other, you can write "amountOfEmployees" or you can
       | write "ne" with an "#amount of employees" comment, either way is
       | absolutely fine and you can use whichever depending on your
       | priorities, tradeoffs or even your mood.
       | 
       | Also I used to obsess over code, (and there's a lot of material
       | that obsesses about code), but after you become profficient at
       | it, there's a cap on the returns of investing time into your
       | codebase, and you start to focus on the product itself. There's
       | not much difference between a good codebase and a marvelously
       | polished codebase, so you might as well use the extra focuse on
       | going from a bad UX to a neutral UX or whatever improvement you
       | can make to the product.
        
       | drob518 wrote:
       | I agree with the OP, but, unfortunately, posts like this generate
       | more heat than light. Like a lot of things, what and how to
       | comment code comes down to "do the right thing," not a list of
       | rules, where everyone will always find counter examples. Do
       | whatever you need to communicate effectively with "the next guy,"
       | who could very well be you.
        
       | kayo_20211030 wrote:
       | Love it. Particularly the "correct" refactoring at the end. The
       | future maintainer will thank you. (BTW: that future maintainer
       | might be you). To a first approximation one should write "local"
       | code i.e. the bits that are important should be right in front of
       | you in the editor. It shouldn't need too much navigation, with
       | all the overhead of context switches, to understand what you're
       | looking at.
       | 
       | Of course, be sensible and use good judgement :-)
       | 
       | But, that's what we're paid for, right?
        
       | ImPleadThe5th wrote:
       | I really do not like working with uncle bob hardliners
       | 
       | There have been so many times where I have commented _why_ I
       | think some uncle bob-ism made the code unclear and the response
       | is always:
       | 
       | > *Sends link to Clean Code, maybe you don't know about this?
       | 
       | No, I do, and I am allowed to disagree with it. To which they
       | always clutch their pearls "How do you think you know better than
       | uncle bob!?", this is a Well Established Pattern TM.
       | 
       | I don't think I know better than Uncle Bob, but I don't think
       | Uncle Bob works on this codebase nearly as much as you or I.
        
       | zephen wrote:
       | There are five canonical questions: What, When, Where, Why, and
       | How.
       | 
       | "When" is occasionally a good question to answer in a comment,
       | e.g. for an interrupt handler, and "Where" is also occasionally a
       | good thing to answer, e.g. "this code is only executed on ARM
       | systems."
       | 
       | The other three questions typically form a hierarchy: Why -> What
       | -> How.
       | 
       | A simplistic google shows that "code comments" are next to "what"
       | and "how" at about the same frequency as they are next to "why"
       | and "what."
       | 
       | This makes some amount of sense, when you consider the usual
       | context. "Why" is often an (assumed) obvious unstated business
       | reason, "What" is a thing done in support of that reason, and
       | "How" is the mechanics of doing the thing.
       | 
       | But with multiple levels of abstraction, _maybe_ the "What"
       | inside the hierarchy remains a "What" to the level above it, but
       | becomes a "Why" to the next level of "What" in the hierarchy. Or
       | maybe the "How" at the end of the hierarchy remains a "How" to
       | the level above it but becomes a "What" to a new "How" level
       | below it.
       | 
       | Is it:
       | 
       | Why -> What/Why -> What/Why -> What/Why -> What -> How
       | 
       | or
       | 
       | Why -> What -> How/What -> How/What -> How/What -> How
       | 
       | In many cases the intermediate nodes in this graph could be
       | legitimately viewed as either What/Why or as How/What, depending
       | on your viewpoint, which could partly depend on which code you
       | read first.
       | 
       | In any case, there are a few hierarchies with final "Hows" that
       | absolutely beg for comments (Carmack's famous inverse square root
       | comes to mind) but in most problem domains that don't involve
       | knowledge across system boundaries (e.g. cache optimization,
       | atomic operations, etc.), the final "How" is almost always
       | adequately explained by the code, _if_ the reader understands the
       | immediately preceding "What."
       | 
       | If I see a function "BackupDatabase()" then I'm pretty sure I
       | already know both "Why" and "What" at the highest levels. "How" I
       | backup the database might be obvious once I am reading inside the
       | function, or the code might be opaque enough that a particular
       | set of lines requires explanation. You could view that
       | explanation as part of "How" the database is backed up, or you
       | could view that explanation as "What" the next few lines of code
       | are doing.
       | 
       | Again, this viewpoint might even partly depend on where you
       | started. If you are dumped inside the function by a debugger,
       | your question might be "What the heck is this code doing here?"
       | but if you are reading the code semi-linearly in an editor, you
       | might wonder "How is BackupDatabase() implemented?"
        
       | nooee wrote:
       | Also note, that after Uncle Bob's refactoring, you now have six
       | additional functions floating around, which may or may not make
       | sense outside of the context of their original caller. This can
       | make the API surface of your class (even if it's just the
       | internal one) harder to grasp and it invites other devs to reuse
       | code that was never intended for reuse, creating unintended
       | couplings. That's mainly a problem for languages that don't allow
       | nested functions though. But in Java, I am sceptical of excessive
       | function creation for the sake of self-documenting code, unless
       | maybe it's in the context of a command pattern, where the whole
       | class only has one obvious function anyway.
        
       | xg15 wrote:
       | The "don't explain variable definitions with comments because
       | people won't see the comments at usage sites" argument also seems
       | obsolete in the face of modern(?) IDEs.
       | 
       | If I look through code and see a variable I don't know, I want to
       | see its definition anyway, so I know the type, scope, initial
       | value, etc. And it's trivially possible to do that with
       | everything that has a "jump to definition" command.
        
       | programmertote wrote:
       | One thing I learned from programming since the early 2000s, there
       | is no such thing as one size fits all advice. You do what is best
       | for future folks--as I like to call the unfortunate folks who
       | would have to maintain the code I wrote--by providing them
       | helpful hints (be it business rules, assumptions related to
       | code/tech) along with as simply and clearly written code as
       | possible (how do I know if my code is simple and easy to
       | understand? Have a junior teammate review my code and have
       | her/him leave comments wherever she has to spend more than 10-15
       | mins reading an area in the code).
       | 
       | I hope not of a lot of the future folks hate me for leaving them
       | with ample context and clear/dead simple code.
        
       | scoofy wrote:
       | I feel like a complete weirdo when it comes to comments and
       | variable names. I've never worked professionally as a coder, but
       | I've been working with python and a bit of js for like 15 years
       | now. I strongly believe that variable names should be long, and
       | explain what they are, and that comments should be long, and
       | explain what's happening.
       | 
       | I have no idea why people want to "save time" to write short
       | comments and short variable names. I just CTRL+C, CTRL+V my
       | variable name anyway. They compound on each other, and that ends
       | up adding an unnecessary level of complexity, and the possibility
       | for errors.
       | 
       | When I come back to a piece of complex code after a year or two,
       | I'm very, _very_ happy that I 've used a variable name like
       | "three_tuple_of_weight_radius_price" instead of "tuple" or "t".
        
         | rasmus-kirk wrote:
         | I think it's a leftover before proper LSP's, if you had to
         | type/paste everything, that would be fairly tedious, but now-a-
         | days everyone uses LSP's with autocomplete that have all the
         | variables in scope.
         | 
         | I do think very long names can hurt readability though so it's
         | still a balancing act, but variables like "t" (often used in
         | Haskell, ugh) is awful in my opinion.
        
         | crazygringo wrote:
         | I prefer a middle ground like "product_info".
         | 
         | It has nothing to do with saving time, and more to do with
         | readability.
         | 
         | Variables like "t" impede readability because you have to keep
         | the meaning of each one in your head.
         | 
         | But variables like "three_tuple_of_weight_radius_price" take up
         | too much horizontal space, which leads to so much line
         | wrapping.
         | 
         | You want each name to communicate just enough to convey the
         | basic purpose/meaning, and clearly distinguish from other
         | variables, _but no more_.
        
       ___________________________________________________________________
       (page generated 2026-01-04 23:00 UTC)