[HN Gopher] Code quality only matters in context (2019) ___________________________________________________________________ Code quality only matters in context (2019) Author : behnamoh Score : 83 points Date : 2022-05-28 04:39 UTC (18 hours ago) (HTM) web link (www.adamtornhill.com) (TXT) w3m dump (www.adamtornhill.com) | macintux wrote: | (2019) | fsociety wrote: | I'm coming up to almost a decade of programming and have 100% | bought into this mindset. Simple understandable code tends to be | easier to change and delete. Abstractions and fancy features | should have a high bar to introduce them. They can be useful, but | is the cost worth it? Usually not, but sometimes it pays off 10x. | | Perhaps if timelines for delivering software slows down this | mindset will be less advantageous. But in today's climate this | ensures you have more time for design and testing. | fswd wrote: | I accidentally discovered something similar 10 years ago in my | coding. At one point I had crippling procrastination. My mind was | protesting me. New frameworks, languages, etc were just becoming | "how many nuances can I remember", and I wasn't learning or going | anywhere. | | To get over the procrastination I would set up a Pomodoro timer | and set it to 20 minutes, and just write something, any code. I | made it a joke to write the crappiest code I could, to make it | fun, as long as it works. Inline copy pasta, etc. Later on it | turned into the goal of the most understandable code, over | everything. I would never have done this out of the university, | but this was 10 year later. Before I would come up with a "plan" | or "design", but at that point, I would just hack something up. | | What I found was with starting with an excellent blank CI/CD | project, and a good BDD end-to-end testing strategy, I could | write "dirty code first" to "just get it done" ... then once I | got into a OODA loop, refactor it into amazing products and | services while having fun. This reduced my cognitive load and | emotional overhead. Coding is actually 5% of the work, the rest | is QA, requirements gathering, meetings, UX/UI designs, and | overhead. | robert_tweed wrote: | I think the conclusion here is back-to-front. | | Code that never needs to be touched is fine. Although the odds | are that such code is either completely trivial or subtly wrong | (or both). | | Code that is touched every day is likely to be fine as well. It's | should get smoothed out naturally, like a pebble in a stream. If | not, you probably already have lots of alarm bells telling you | it's a problem without the need for any further analysis. It's | not the code quality that matters here so much as the test | coverage. | | The changes you really need to worry about are to code nobody has | touched for 3 years and whoever wrote it no longer works for the | company. Especially if that code was written with the mindset of | "nobody will ever care about this code". | | A better metric for deciding where you should focus the most | effort on code quality is not frequency of modification, it is | frequency of appearance in the runtime call-graph. Each call | probably also need a multiplier for how deep in the call-stack it | was, since that's where unintended consequences of a small change | are likely to have the biggest blast radius. | omegalulw wrote: | > A better metric for deciding where you should focus the most | effort on code quality is not frequency of modification, it is | frequency of appearance in the runtime call-graph. | | On th flip side, a lot of code that isn't common in the main | codepath often exists to fix edge case bugs that people have | lost context on. In my experience, this code is a landmine with | an unknown blast radius, only touch it with a 10-foot pole and | only when you absolutely must. | mro_name wrote: | everything only matters in context. In general. | twp wrote: | The author confused cause and effect. | | Author: because this code sees a lot of churn it is important. | Reality: this code sees a lot of churn because it is bad. | SPascareli13 wrote: | Even if that's the case the author's point still stands, | focusing the code quality in this code makes more sense, if | it's bad. | greymalik wrote: | > this code sees a lot of churn because it is bad | | That's one possibility. It's also possible that it changes a | lot because it's related to business rules, which are typically | more volatile than infrastructure code. | btbuildem wrote: | It's an interesting metric, the "churn" or "hot spots" in code. | Why do certain areas and not others exhibit high churn? | | I had a quick look through the codebases showcased on the | CodeScene site, and across them, the files with most churn tend | to have quite generic names (like core, daemon, helper, | internalEngine, etc). | | It sort of supports my intuitive take on the answer: the | "churniest" areas of the code are the ones that were initially | difficult to think of in specific terms, ie, the ones that don't | tend to implement one thing, but boundaries between things. | They're the catch-alls, the areas where our conceptual | abstractions don't fold together as neatly as we'd like. | giraffe_lady wrote: | This was a fun read for really personal reasons. The idea that, | basically, bad code no one ever has to touch again is in fact | good code, is in fact "better" in a true sense than carefully | engineered code accomplishing the same thing, has been a really | valuable guiding insight for me in my career. I couldn't remember | where I got it though, or if it even had one single source. | | Then when he shows the visualization I was like "hey that looks | like the d3 script I got out of some git analysis book years ago | and still use at every job I work." | | It's the same guy! Looks like he productized the scripts | distributed with that book, which nice. I'll definitely try it | and push for places I work to pay for that instead of the bundle | of customized scripts I've been dragging around for years. | | I really endorse that book too! I read it at the right time in my | career I think, where I had truly seen some shit and so had the | experience to understand the value of that approach, but not so | far in that I had become set in my ways. | pkolaczk wrote: | > The idea that, basically, bad code no one ever has to touch | again is in fact good code | | How do you know no one would ever have to touch that code | again, at the moment of writing it? | | Nevertheless, generally I agree that isolated complexity is | much better than complexity that spreads everywhere through | explicit or hidden dependencies (e.g. global state). So dirty | complex code hidden behind a simple API is actually not bad | code. | giraffe_lady wrote: | It's less a guideline for writing code than one I use when | deciding where to spend my efforts with existing code. I've | mostly worked in long-lived codebases of profitable software, | so nearly everything is a strong candidate for refactoring | off of "quality" alone. | | When you find something real blood-curdling but the last | commit in that file was three and a half years ago, you just | close it and pretend you didn't see. Better to spend the | effort somewhere it will definitely benefit someone soon, | rather than maybe some day. | Mr_P wrote: | This is literally the 'O' in SOLID. | | The key idea is to break code into "chunks" that each do one | thing. | | Then, if you have to add a new feature, it goes into another | chunk, instead of editing/modifying existing code. | | The same logic applies to system design at different scales, | whether fine-scale OOP or coarser-scale (micro)service | architecture. The ideal size of an individual "chunk" is | somewhat subjective & debatable, of course. | | It's like Haskell-style immutable data structures, but | applied to writing the code, itself. | Noumenon72 wrote: | So there is a script or something with the book that you can | run on your Git repo to see a chart of the hotspots? | giraffe_lady wrote: | It's not as neat as that unfortunately. You use this to | extract different data from the version control history: | https://github.com/adamtornhill/code-maat | | Then visualize it however. I have some d3 scripts that came | with the book that I've modified and you can track down | somewhere on github I'm pretty sure. I mostly use those for | demoing it to devs unfamiliar with the techniques though, | since it looks cool and is immediately obvious what it's for. | | For serious use I dump it into sqlite and use a mix of | different scripts and techniques to figure it out. It's been | kind of a language playground for me over the years so is in | a lot of different languages and is "learning code" in most | of them. Cleaning them up and sharing is one of those "maybe | some day" things though. | palata wrote: | "We developers mostly read code, so let's optimise the writing | part by writing bad code that will be slower to read." | | Am I the only seeing a problem here? | kbuchanan wrote: | While I'm extremely sympathetic to this idea, one question nags | at me: Long-tail code can also be long tail because _it was well- | written from the beginning_. The author is arguing that long tail | code lives in a stable, unchanging corner of the business. This | can absolutely be true, but it can also be true that a well- | written abstraction may service new needs without needing to be | changed. (In practice, this is hard.) | palata wrote: | This. | abnry wrote: | I wonder if you can formalize this a bit more. | | Let W(init,DC) be the initial cost (hours/effort) of writing | Dirty Code (DC). Let's assume that the code works for the | intended purpose and doesn't have any bugs. | | Let W(init,CC) be the initial cost of writing Clean Code (CC). | You'd expect it to be related to W(init,DC) by some proportion: | W(init,CC) = (1+alpha)*W(init,DC). | | Then there is a probability p that you will want to / extend the | code. | | Let W(ext,DC) be the amount of effort required to extend the code | if the initial code is dirty. | | Let W(ext, CC) be the amount of effort required to extend the | code if the initial code is clean. I'd expect W(ext,CC) = | (1-beta)*W(ext,DC). | | Then you can compute E[W(total)|CC) vs E[W(total)|DC]. This will | define some trade-off curve based on alpha, beta, p, W(ext,DC) | and W(init, DC). | | Lots of assumptions here, but I wonder if thinking this through | will provide any insights. Obviously, if the probability of | extending the code is low, then it always makes sense to write | dirty code. If the probability of extending the code is high, | then you'll want to write clean code. | bumby wrote: | I would also include a probability of an bug being introduced | while extending the code. Code quality tends to be harder to | track as the number of system interfaces expands. Particularly | when it coordinates efforts between physical systems, even | "clean code" can cause coordination failures because the | context has changed by the extension. The example my mind | always goes to is the Ariane V failure; it was a failure of | 'clean code' in new context.[1] | | Then there is the severity of the potential failure. So the | additional risk should also encompass both the probability of | failure when extending code and the severity of that failure. | | [1]http://sunnyday.mit.edu/accidents/Ariane5accidentreport.html | gabereiser wrote: | I was let go once for having too many commits in a PR. When we | squash merged... I've come to the same conclusion about code | quality. If it's something that others interact with, make it | polished. If it's something only you interact with, make it | commented. | defen wrote: | > I was let go once for having too many commits in a PR. | | You were fired for having too many commits in a PR? That seems | like an extreme overreaction unless there's more to the story. | otagekki wrote: | There definitely has to be, on the other end of the commit | count spectrum I've seen people being reprimanded for having | too few commits. Looks like they had bad management anyway, | he might have dodged a bullet there | j7ake wrote: | This mindset is also true for many researchers who code. | | Professional programmers make fun of research code but actually | the dirty way is desirable considering that research is about | prototyping, tweaking, and in small groups. | diarrhea wrote: | To that I say: there's dirty code -- then there's researchers' | code. It can be a whole new level, far beyond just copy-paste | and other superficial sins. | salawat wrote: | Research code has different priorities. | | I have a set of repos I pull down for vivisecting software | projects. | | They would be horrific to anyone else. I do horrible things | to other peoples' code. Idioms clash, the style and messaging | and comments can seem schizophrenic, and you'll run into | things that'll send professionaal coders running like custom | instrumented versions of the language runtime. Everything | that can be done wrong in them, generally is, and it's tuned | for one thing. | | Figuring out how to read it, why it works, and where to poke | it to change it. I'm one of those people who'll sit down with | an entire rcosystem of code and go Dr. Moreau on it. | | ...Then I turn around and push the well documented, polished, | minimum viable changeset into the professional repo, and lock | away the horrible atrocities I have wrought far from the eyes | of Man, hopefully well enough that only God will eventually | pass judgement. | laserlight wrote: | > Or maybe I decide to squeeze in an extra if-statement in | already tricky code. | | And that's how the long tail becomes long tail. Nobody touches | that part of the repo, because you have made it untouchable. | People find working around easier than understanding and | modifying existing code. Mess becomes messier. | | Writing clean code is not about introducing big abstractions, | large refactors. It's about leaving the place better than you | found it. | xupybd wrote: | Sometimes you have a root cause deep in the architecture. As | long as that cause exists you will have to work around it. Each | work around will have to be removed if you ever fix the root | cause. | | I saw this as a developer and had thought it was better to just | leave the architecture alone and keep the work arounds as tidy | as possible. Then I started working in manufacturing, a | production line has many similarities to a running program, and | saw the true cost. We fixed a root cause at the beginning of | the line and all the work we put into working around the | original problem was more of a mess to clean up than fixing the | root cause. | | I'm now a believer in trying to fix the source if possible. | | That said a legacy code base with no tests is less likely to | get a structural change from me. | shkkmo wrote: | If you are implementing a workaround, then that is a | potential opportunity to solve a root problem deep in the | architecture. | | The point being made is that going in to fix that root cause | because you think that there will be a need for workarounds | in the future is premature and can cause problems and | unnecessarily break working code. | thaumasiotes wrote: | > Each work around will have to be removed if you ever fix | the root cause. | | Do they? I feel like many workarounds will just hang around, | checking for situations like inconsistent state that no | longer arise. You might be better off removing checks for | conditions that no longer occur (or not...), but it's not | exactly urgent. | ramesh31 wrote: | >Writing clean code is not about introducing big abstractions, | large refactors. It's about leaving the place better than you | found it. | | Writing clean code and leaving the place better than you found | it requires time. Time we generally just do not have. There | comes a point where things just have to _work_ , and all of | your ideas about what is "right" and "clean" have to be set | aside to make that happen. | karatinversion wrote: | This seems a very short sighted attitude to me, like saying | that there is no time for testing, there are too many bugs to | fix. | xupybd wrote: | If the business fails because it couldn't get to market in | time who cares if the code quality was good? | | Context is critical to knowing when to invest in quality. | liotier wrote: | At an ISP, when I was much younger, at the coffee machine | I asked the Technical Director why we didn't invest in | some technical cleanup. He replied that any available | finances are much more profitably spent in advertising, | which was directly correlated to sales, which were | critical to survival. I guess that's why there are two | sorts of companies: those that survived, and those with | great code quality ! | salawat wrote: | There are two types of programmer. | | There is a programmer that reads, absorbs the system as a | whole and deals with it as it is. | | Then there is the programmer who just wants shit written | that can get them most of the way there and he'll fix the | other shit to do as he wants eventually. | | The software industry is generally run by the latter. | | The former are those that see the most value in high | quality code, because quality only matters when you can't | reerite the thing without applying a cost function. | | Context is not critical to knowing when to invest in | quality. That is paying lip service to the fundamental | nature of what business programming is. | | Running a business staffed with programmers is all about | balancing onboarding, spin up, time to contribute, etc, | etc. | | With high quality architecture that business loop is far | more efficient. Costwise, time or money, all of that | meta-businessy crap dwarfs the actual implementation of | new features. | | ...And you can never rely on the person you need to be | there when the chips are down to stay there when it | happens, because Murphy finds a way, no exceptions. | | You do it right from the beginning, or you write shitty | software. There is no middle. | ramesh31 wrote: | >This seems a very short sighted attitude to me, like | saying that there is no time for testing, there are too | many bugs to fix. | | It is. The priority for a programmer goes: make it work -> | make it fast -> make it clean. And you either have time for | all three of those, or you don't. Generally in reality | though, when dealing with business needs and product | managers, the pipeline becomes: make it work -> alright now | make this work -> alright now also make this work. | epgui wrote: | I would argue that for most code, making it clean should | be a priority over making it fast (optimizing for | simplicity and readability over algorithmic performance). | | It obviously depends on the application. | arinlen wrote: | > _This seems a very short sighted attitude to me, like | saying that there is no time for testing, there are too | many bugs to fix._ | | This is not true at all. The definition of "clean code" is | highly subjective and context- and experience-dependent. | Your personal opinion and feelings towards a code style are | not the same as bugs, nor is a lack of compliancd with your | personal taste a potential liability similar to not adding | a test. | IshKebab wrote: | Nonsense. You have to spend that time, either once now or 9 | times later. You just need to be more firm about using it. | arinlen wrote: | > _And that 's how the long tail becomes long tail._ | | Not really. | | Developers should only touch production code if there is a good | business reason to touch it, whether fixing a bug or adding a | feature. If there is no good reason to touch a bit of code, you | should not be touching it. Otherwise you're just adding noise | to the audit trail, perhaps along with bugs in otherwise | perfectly fine code, without any justification. | | The long tail is a long tail because there are no bugs not | reasons to mess around in those parts of the code. Feeling | adventurous is not a good reason to mess with it. If you have | to implement a feature or fix a bug, complaining that it's old | code won't make things go away. | mobjack wrote: | There comes a point where impossible to leave code in a better | state without a major refactor. | | The choice is between writing a few ugly if statements making | the code a little worse or spending 10x the time refactoring | hoping you don't introduce any regressions. | WesolyKubeczek wrote: | There are five questions I like to ask about any codebase I'm | given to work with: | | 1) suppose I have a bug to fix, how deep should I, on average, go | to get to the cause? How many files do I need to jump through to | determine a trivial flow of data from a to b? | | 2) there's a straightforward feature or edge case, how easy is it | to add it? | | 3) (for dynamic languages) is it possible to get the full list of | usages for a particular function/method I'm changing? | | 4) is it possible to correctly identify and eliminate a portion | of code that has been unused for a while? | | 5) are there areas no one knows how they work and everybody is | afraid of touching because nobody is sure what would break and | how? | | I use these things to determine the code quality. Perceived | cleanliness doesn't affect the quality. ___________________________________________________________________ (page generated 2022-05-28 23:00 UTC)