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