13 ms·
Code only says what it does
- macintux 6y agoI’ve had similar arguments here once or twice. There’s so much context that isn’t deducible from code. You rarely need to document the “how” (that much should be evident if the code is well-written) but you absolutely should document the “why” (or, often as important, the “why not”: what code could be here but isn’t).
- throw1234651234 6y agoGive me an example, and I will write you code documenting the business context.
- Jtsummers 6y agoAnd then what? You throw away the example specification so that the why only continues on in the code? And after 10 years of maintenance, the code has drifted with each iteration so that the why is no longer clear in the code.
- mjw1007 6y agoI agree that you shouldn't document "how", but when I'm reading unfamiliar code, I find I what I miss is "what", not "why". To my mind, in well-written code each function should be documenting its contract: what it assumes, what it guarantees if that assumption holds. (And if it turns out that what you'd write is just the function's name and its parameter and return types with a few grammatical particles added, maybe it's OK to omit the documentation.) Then if you find that in order to do that you have to write a little essay, or you need terminology that doesn't correspond to a named thing in the codebase, or you're repeating yourself in multiple comments, that tells you something you need to put in higher-level documentation.
- gimboland 6y agoYes. Floyd-Hoare logic is worth learning about in this sense — a formal system for imperative languages where the rules essentially say "given preconditions X and code Y, if X is true before you run Y, we guarantee Z to be true afterwards". I've never ever ever proven code correct using this formalism, but that way of thinking permeates my every action as a programmer.
- lmilcin 6y agoWhether or not to document "how" will depend on the target audience. The code is written for people to read and only incidentally for computers to execute. From that point of view the target audience will matter a lot. I agree that in most cases, you expect the audience to be on level with the code and if you are writing code that is not on level with the audience (for example it is way too advanced) then you are doing something wrong (at the very least not considering who will be working with it). But not always. Example: I do with a lot of bright quants. With regards to code that does a lot of complicated calculations, they typically understand "why" but might need help with understanding "how". Another example: when your audience is mostly junior team you might want to explain "how". My current project starts using more and more reactive constructs and oftentimes I throw in an explanation of "how" when I, for example, get queries to explain during code reviews.
- deeg 6y agoWhen I teach coding I tell the students to document their code well but don't document what the code is doing it. That should be evident from the code itself (if it's not, then consider a refactor). Rather, explain why the code is doing it.
- keithasaurus 6y agoI agree with most of the points made here, though I think some of the bias toward up-front exhaustive documentation is probably not a good fit for most of the projects I've been a part of. Prototyping often reveals necessary changes due to resources constraints, or to unconsidered corner cases. Documentation needs to be a living thing as much as the code, and I think that pushes you toward documenting within the code more than externally. One of the more important points the author brings up is that authorial intent and the 'why's of comments are the most important. A corollary I'll bring up to that is that the 'what's should be encoded in tests. Tests can be great documentation, and they have the added benefit of informing developers when the goals of the software is being voided (when they fail). What has worked for me is conceiving of documentation this way: - Design Documents: Historical use only, not to be updated. - Readme: intro to project; why it exists, overview of how it's meant to function, how to edit, etc. Tends to be updated when big things change. - Code comments: why something exists, what considerations were made in that code's creation - Test descriptions and comments: binding goals of previous development to future development This approach has done a pretty good job of keeping documentation from getting too out-of-sync with code while enforcing basic business objectives, still tilting the balance toward development rather than documentation.
- jariel 6y agoThis is quite good actually. I would add that some elements of design are worth keeping up, like a general architectural overview and the details of some things, like state-machines or specific kinds of statefulness. It can be done in the comments, at the package level, that way developers can keep it up to date without much fuss.
- sosborn 6y agoThe marketing corollary is that metrics only tell you what happened, they cannot tell why. Yet somehow, entire companies have been built on the promise that they can answer the "why" by looking at the metrics.
- ChrisSD 6y agoA big issue with documenting what the code does is that the code and documentation can very quickly fall out of sync. As this posts says, it's much more useful to document the intent of the code, or why there's this mess of seemingly hacky code (see issues #80681, #82108, #66065). Also be wary of unit tests that are overly tied to the specifics of an implementation. These can be worse than useless when it comes to changing code. I.e. asking "why are my tests failing?" and finding out it's only because I breathed near the code.
- mrkeen 6y agoSystem tests too! The last code-base I worked on had do-everything system tests (with unexpectedly good coverage, I'll admit). They were so slow and passed often enough that I didn't immediately spot flakiness. I got suspicious when the tests started failing regularly when I added new unrelated code.
- otterley 6y agoA good way of avoiding this trap is to require updated comments as a condition of merging a pull request.
- voiper1 6y agoRelevant: Writing system software: code comments. from http://antirez.com/news/124 http://antirez.com/news/124 + https://news.ycombinator.com/item?id=18157047 https://news.ycombinator.com/item?id=18157047
- softwaredoug 6y ago“works as coded” My last job we used to say that if asked whether our code was correct or bug free ;). Often the devs get thrown under the bus if something doesn’t work “correctly” when in reality it might perfectly pass all unit tests based on the best understanding of the problem. Of course whether we could get any support to help define “correct” from anyone was another matter...
- xsmasher 6y agoThis fits my theory of programming, and theory of bugs - We take a problem, create a plan, and then write code that implements that plan. Defects can come from: * having/being given the wrong problem * right problem, but plan does not actually solve it * right plan, but your code did not correctly implement it
- webmaven 6y agoThen of course there are the maddening cases of accidental correctness. ie. a bug in your implementation of the wrong plan does the right thing.
- kevsim 6y agoI think the most reliable thing to see what quirks are load bearing is tests, particularly regression tests. You change something, you break expected behavior, you fix it and you write a test. Now the next person may wonder if some quirk is load bearing, but they'll know for sure when running the regression tests. Additionally, I'd say naming things, though one of the hardest things we have to do, can go a long way towards explaining the "why". Some programmers I've worked with have a knack for knowing just went to break a giant line into separate lines, giving local variables great expressive names, and all of a sudden the code reads a million times better. All that being said - I agree with most of the points of the article and do push my teams to do a lot of upfront writing down of designs. These things tend to go stale, but in the moment they're a great tool for fleshing out ideas and sparking discussions.
- trixie_ 6y agoIf I had a nickel for every programmer who thought their code was so good it didn't require comments... or thinks somehow that unit tests make up for comments... only to come back years later and have no idea why the logic is working how it is.
- baddox 6y agoIt seems to be fairly common for experienced programmers to point to unit test code as a way to explore or understand an open source software project. I don't doubt that this works for them, but it definitely doesn't work for me. When I'm trying to explore a new software project, the first thing I want to do is find the relevant "entry point," which is arguably the exact opposite end from the unit test code.
- henryfjordan 6y agoTests that target the surfaces of the project (public APIs, endpoints, etc) and code examples start to blend together at some point. "Here's a basic example that should do X" sounds a lot like "Do something basic and assert it does X".
- baddox 6y agoI think the biggest problem with using unit tests for this purpose is that unit tests tend to (rightfully) spend a disproportionate amount of lines of code on edge cases.
- dllthomas 6y agoWhere applicable, this is what doctests are for, and they're magical. ... where applicable.
- dfinninger 6y agoYes, this is how I use them as well. I’ll go to the unit tests after I have a decent understanding of the project and am looking for examples that aren’t covered in the README.
- dllthomas 6y agoCode is a mixture of what and how (and with IaC, sometimes who and where). I agree that "why" is the role of documentation. I've been experimenting with tying the two together with (machine checked, automatically surfaced) cross-references, so we can better know what bits of documentation a test supports, &c. I haven't yet gotten rigorous about it.
- corbins 6y agoThe counterexample here is the declarative style of programming. Most ideally this looks like an executable spec and is documentation itself.
- lmilcin 6y agoOnly for simple cases. When it becames complex enough the same problems show. Example: CSS.
- ativzzz 6y agoSure, but then you offload the complexity to the functions used as the declarative building blocks, so you do the documenting in a different place, though you will probably end up documenting complex declarative business logic anyway. (like why is process X that is so similar to process Y require Z different declarative blocks)
- client4 6y agoThis article fits nicely with the recent post discussing how Linus spends the majority of his time writing emails. For projects with n+1 contributors, inter-contributor communication is just as important as what code is being written. Emails, commit messages, code comments, docs, are all just different ways to communicate. I always think of the Underhanded C Contest[^1] as my favorite example of readable code that doesn't act as expected after a quick read. [1] http://underhanded-c.org/ http://underhanded-c.org/
- rawoke083600 6y agoJa to me the "rule-of-thumb" is still: "Code Is The How, Comments Are The Why"
- ris 6y agoSo many times this. "Clear code shouldn't need comments" - clear code can make it easy to see what but it can never say why. Let me know what corner cases you thought about when you wrote this. "The comments are in the commit messages" - almost nobody ever goes looking for them there, they're effectively invisible from `git blame` when they remove lines, people rarely make fine grained enough commits to be able to target specific lines or blocks sufficiently with context. "Nobody ever updates comments, so they're always out of date" - don't hire such people. It is an crucial task resolving the meaning of comments to make sure everything still makes cohesive sense. Neglecting to do this will often lead to commits that don't quite grok any subtleties of the original design. Don't make the reader of the code do the job of trying to piece together the scattered history of 5 different people's intentions. Of course, it's also useful to try to keep comments as close to the code in question as possible so that references which need updating are obvious to see.
- sanderjd 6y ago> almost nobody ever goes looking for them there I've seen this claim a number of times and it's always so odd to me. One of my most common activities each day - certainly more common than the activity of writing new code - is reading the commit history for different files. It's always surprising to me to hear that this is an uncommon thing to do. Edit to add: But I also think comments and documentation of all kinds are good. I don't advocate good commit messages instead of comments, but rather in addition to comments. The more documentation the better.
- Braxton_Hicks 6y agoAgreed. I think the "nobody ever goes looking for them" case is common for code bases where people are not writing good useful commit messages.
- phendrenad2 6y agoCommit messages are much harder to get to for a given line of code than a comment would be.
- ChrisMarshallNY 6y agoI comment my code[0]. I don't particularly care what people think about it. I will say that I have turned over a lot of code, over the years, and virtually never get asked about what it does. When people ask me about my code, I generally tell them where to look, and contact me if they need explanations. I don't get contacted, so I guess they could figure it out. I also tend to write a lot of supporting documentation. We do have to be careful, though. Documentation can easily become "concrete galoshes"[1], so things like header/auto documents are pretty important. [0] https://medium.com/chrismarshallny/leaving-a-legacy-1c2ddb0c8014 https://medium.com/chrismarshallny/leaving-a-legacy-1c2ddb0c... [1] https://medium.com/chrismarshallny/concrete-galoshes-a5798a55af2a https://medium.com/chrismarshallny/concrete-galoshes-a5798a5...
- bryanrasmussen 6y agoShould we be looking out for lying code? https://softwareengineering.stackexchange.com/questions/202352/should-we-be-looking-out-for-lying-code https://softwareengineering.stackexchange.com/questions/2023...
- foodigger 6y agomost people cant read it anyway so what does it matter?
- dkarl 6y agoThis is a major problem with code: You don't know which quirks are load-bearing. You may remember, or be able to guess, or be able to puzzle it out from first principles, or not care, but all of those things are slow and error-prone. This is a problem from both the negative (not breaking things) and positive (knowing how to add things) perspectives. The positive perspective was written about by Peter Naur in one of my favorite software engineering papers, "Programming as Theory Building," in which he describes how the original authors of a codebase have a mental model for how it can be extended in simple ways to meet predictable future changes, which he calls their "theory" of the program, and how subsequent programmers inheriting the codebase can fail to understand the theory and end up making extensive, invasive modifications to the codebase to accomplish tasks that the original authors would have accomplished much more simply. I highly recommend finding Naur's paper (easily done via Google) and reading it to understand why divining the "theory" of a codebase is a fundamentally difficult intellectual problem which cannot be addressed merely by good design, and not with 100% reliability by good documentation, either.
- mjb 6y agoThanks for sharing that, I'll read it! I do agree that comments, documentation, and other artifacts aren't sufficient to solve this problem. The closest I've come is with formal specification, where the intent of the program can be communicated very clearly. Multiple approaches are needed. One of those approaches is continuity: Keeping people around who are familiar with the code base and can pass on this knowledge to others.
- Jtsummers 6y agoThis is important to understand when moving through the early stages of a project. Many projects go through a clear prototype stage (where a lot of disjoint things are written, like a set of utilities to print out information on a file based on the format spec, make files with hardcoded content, etc.), then a system starts coalescing, and finally it's released. The problem I've encountered is when the prototype is too good. It's an 80% solution, it seems to do everything that's wanted, but the people who wrote it (contractors/consultants/too expensive older devs) aren't the ones who are tasked with finishing the last 20%. The original developers may have understood how to create that last portion with what they'd written, or they may have intended to throw it away [0]. The new developers don't know what's present (and so recreate a lot of existing capabilities), don't understand how to extend it properly (so a lot of copy/paste when the original devs laid out a nice extendable system with generics and or interfaces or whatever the language provides), and the whole thing turns into a mess. This communication between developers is critical, but usually absent. [0] "This is more of a proof of concept, it does everything you want for converting two file formats between each other, but doesn't scale yet because it's all 1-to-1 mappings, we are working on the intermediate representation now that we have a firmer grasp of what's needed." "Oh, that's fine, you guys can go work on the next project we've got a crack team that can wrap this up." "...Ok, thanks for the money." The crack team never makes that intermediate representation and just creates 1-to-n mappings between each format. The explosion in code size becomes unmaintainable, most of the mappings are the result of copy/paste, and bugs proliferate throughout because, while fixed in one section, they don't realize how many other places that same bug resides in. EDIT: For the record, [0] started off short enough to be a footnote then grew to be too long for it, and I forgot to edit it properly when I came back from getting a glass of water.
- phendrenad2 6y agoIt gives me no end to pain that "Comments are lies because they aren't code" is a fad that we're currently suffering through as an industry. For decades prevailing wisdom was that comments were a net benefit, and now in the last few years this trend has become prevalent. How much perfectly-good code is going to have to be rewritten from scratch in 10 years because no one remembers what it does?
- wanderr 6y agoIf no one understands what it does, it's not perfectly good code is it? Of course there are rare cases where code cannot be simplified, made more readable or self explanatory and in those cases comments are vital. But the aim should be for the vast majority of code to be easily readable by humans.
- phendrenad2 6y agoI mean it's "perfectly fine" because the people building it know how it works (because they were there when it was built), and think they don't need comments to help out future maintainers.
- Jtsummers 6y agoEssential versus accidental complexity. Perfectly good code can be unclear because of the accidental complexity included within it. Memory management, error handling (especially in languages with less expressive type systems), configuring hardware/database/network connections, etc. Those things are important, but they prevent the essential portion of the program from being expressed on its own. Type systems, a brief example: C versus Ada. Implement a network protocol where the data packet has specific n-bit sized fields with ranges less than the maximum for that size. You can easily do this in both languages. But in C, you'd either need to add bounds checking to all of those fields or risk letting errors propagate. That error handling obscures the essential portion of the program. In Ada, you make a type that is n-bits and only accepts values of the correct range. The errors can still exist in received packets, but the error checking is partially elided from the code because the type system itself can catch it. There's nothing wrong with the C code, and there's nothing wrong (many will disagree with that) with choosing C to implement the protocol. But it will increase the complexity due to factors beyond the inherent, essential complexity of the network protocol itself.
- cloogshicer 6y agoThe huge value that I see in a formal specification language like TLA+ is that we could have a precise way of communicating the problem in a way that is agnostic to the implementation language. Imagine something like StackOverflow, but instead of posting a question, you post a formal spec. Thinking even further, you could then find a way to combine/interface these specs and build something like a global database of computational problems. We're currently doing this already with StackOverflow, but we're focusing on the implementations, not the problems themselves. Please correct me if there's a mistake in this line of thought, I'd love to know.
- jackhiggs 6y agoWhat you're talking about there is a Model Repository. We're building one at the bank I work at, except because our modelling language (or meta model) is based on OMG's MOF we can generate artifacts (code) from our models. You can't do that with TLA+ as far as I know. It's pretty powerful - you can compose models together very easily, as well as generate loads of useful things for data-in-motion.
- cloogshicer 6y agoHey, thanks a lot for your response! It's really hard to search for abstract ideas like this if you don't know the terminology (like Model Repository), so this is super helpful. This is a very interesting topic for me, may I ask you a few questions? I sent you a request on LinkedIn.
- bobbane 6y agoAny thoughts on applying this article to... programming languages defined by a single portable implementation?
- rcshubhadeep 6y agoHere is little demo of codeBERT - https://youtu.be/oDqW1JHmaYY https://youtu.be/oDqW1JHmaYY codeBERT is trying to predict if a certain function and its docstring are associated or not. Thought about sharing it, I guess it is interesting in this context
- bob1029 6y agoIf you want your cake and also the ability to consume it, you might want to consider what functional programming can do for you regarding the ability of your codebase to self-document itself. Having type systems that are very closely aligned with the abstract business model is the best way to avoid frustration when you are trying to figure out why something is the way it is. The trick is understanding that functional vs imperative is a spectrum, and trying to force 100% on one side or the other is how you wind up killing any project. We find that keeping our business-level abstractions functional with the underlying infrastructure code imperative provides the best of both worlds. The code that is changing and analyzed most frequently is in the functional domain, whereas code that we touch maybe 1-2 times per month lives in an imperative domain (but sometimes functional wherever it makes sense here too).
- ajuc 6y agoI find functional code much shorter and cleaner, but also when you want to change something along a new axis you need to do a much bigger rewrite than with imperative/procedural/object-oriented code. OO code: "here's a detailed and long-winded description of what happens that's hard to understand. Ignore 95% of it and change that 1 little detail and hope for the best" Functional code: "here's a concise and easy to understand description of what happens, understand it fully, throw it away, and create a new, just as clear and concise description of what should happen from now on"
- aequitas 6y agoMy pathway into software development was through electrical engineering and embedded systems. So I don't know if this applies to other ways into software development as well. But what really stood out to me in the beginning was how useless code comment where. I would almost always see code like this: x = 1; // assign 1 to x y = x * 2; // multiply x by 2 I don't know if it was because they thought electrical engineers needed to be explained everything about code. Or if it was because all teaching material used this style and people just copied it. But I never understood why you would add comments like this, but had to do so anyways otherwise I would not pass my exams. It took me a while to learn that comments are the tool in which you can express your expectation of what the code should do.
- blt 6y agoThose samples were probably written by someone who had learned how to code in assembly language. In assembly, this kind of comment reminds the reader of the semantic meaning of what is in each CPU register. It could be very useful. Then the person learns C and never drops this habit.
- saagarjha 6y agoAbout the only time I use comments are to delineate a block of code that for whatever reason can’t be a method or because I am working around some bug and I think I might be tempted in the future to remove that code as “useless”. (Think “the dispatch_main here ensures that the code runs on the next runloop iteration, which is necessary for the animation to work”.)
- sktrdie 6y agoWhat I’ve noticed is that code is the only medium of communication that is non-ambiguous. Designers, product people, stakeholders, etc, all use ambiguous mediums. It’s impossible to understand just how pedantic and explicit you need to be when writing code versus, say, giving your human colleagues instructions. So it's 0% ambiguity for code. 100% ambiguity for the rest. In other words, communicating with the computer is overly pedantic, and code bares all the frustration. Can we make it more fair? 70-30 perhaps? Rather than concentrating on mediums that help with communication (as this post mentions: Design Docs, TLA+, comments…) I want a new medium that allows me share the burden of overscrupulousity with the rest of the people in my team, and not just developers.
- webmaven 6y agoPseudocode, perhaps?
- smitty1e 6y agoI'm looking at some ETL code from the dark past, and it uses low-level Db code to shovel in .csv files like a boss. I'm all' "Well, I guess that code that obtains the .csv files must be rock solid." Famous last words. A freshly done system later, I'm left to infer that there had been some other cleansing to to which I was never privy.
- AtlasBarfed 6y agoSo.. code is what it is?
- nardi 6y agoFalse. If we used only meaningless symbols like “A”, “B”, etc. for names, then it would be true. But if I have a method named “addItemToCart”, then I know what it ought to do. If it does NOT in fact add the item to the cart, then I’ve found a bug. It’s true that a short method name might not capture all of the subtleties, but usually the variable names within the method can give you an idea of what the intent of the programmer is as well. Obviously there are still things you should write comments for, but really well-thought-out names can get you surprisingly far.
- ThomasDeutsch 6y agoThe "why" can be expressed in code. Think of "Event Storming". A great way to talk about the "why" and to grow an understanding of how a problem can be solved. The result can be multiple "flows" that describe a series of events from the first command to the expected outcome. We have the option to directly translate a flow to code. And by keeping the flow in one place, we also keep a direct mapping from our code to the EventStorming-results. The "why" will not be lost. The code can contain multiple flows and every flow can have a scenario-like description like: "the user is able to select a product" This is what my passion is all about. To keep the "why" in one place. This also enables better collaboration between multiple disciplines (like UX <-> DEV) This is the idea behind scenario based programming. I am working on an open source project: https://github.com/ThomasDeutsch/flowcards https://github.com/ThomasDeutsch/flowcards Write me a line if you would like to get involved. Have you found other solutions for this problem?
- ellenafam33 6y agoHey, I am Ellena Faming I am a tech enthusiast and part time blogger. It would mean the world to me if you visit my website. I live with my brother in London United Kingdom, he is very friendly we both are good writers and gamer. Click the link and visit my website. https://www.eofoodanddrink.com/best-restaurants-paris/ https://www.eofoodanddrink.com/best-restaurants-paris/