[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)