It's ironic to me that the "Hammer Factory Factory Factory" post was recently doing the rounds again.
I have recently been working with a client whose "senior" dev swallowed some books with opinions on "quality" wholesale and uncritically.
Thus in the simplest project, implementations that could literally be a lambda function (on receive message, write row into DB) are a festival of multiple tiers of objects, mappers, mediators, IoC frameworks, wrappers, Nuget packages, etc., etc.
Everything is in multiple projects. Simple constants (like: API routes - '/api/foo/bar') are indirected into files containing those strings, so there's a huge cognitive overhead and much clicking around to make sense of it. God help you if you don't use an IDE.
This isn't quality. It's the antithesis of quality. Devs have to understand a whole load of abstractions just to get simple things done. But the author is proud of his tower of 'best practice' - blissfully unaware that adding the simplest feature is now hundreds of lines of code, where one would suffice. This is burning through, literally, thousands of euros of dev time.
Coming from Spring or Java EE:
> implementations that could literally be a lambda function (on receive message, write row into DB) are a festival of multiple tiers of objects, mappers, mediators, IoC frameworks, wrappers, Nuget packages, etc., etc.
Spring or Java EE is a strong convention, so IOC is one automatically as well (both make use of that heavily). Hibernate would be the next strong convention, therefore mappers are, therefore we will have multiple tiers of objects. Wrappers will also be needed in a language like Java. About the rest of this list I can't say much now, but I would argue that lots of what this person is doing is based on strong conventions in the enterprise world. And it goes on:
> Everything is in multiple projects. Simple constants (like: API routes - '/api/foo/bar') are indirected into files containing those strings, so there's a huge cognitive overhead and much clicking around to make sense of it. God help you if you don't use an IDE.
Coming from Java again, everything won't be in multiple projects, but in multiple Maven modules instead. AFAIK that is good practice, or, if you want: a strong convention. Stuff like API routes will indeed not be saved in a code file, but in an openapi file instead.
IMO then, what this person was doing was actually following strong conventions. Yes, these are often also specific patterns, but what is the difference, specifically for these things listed here?
It seems to me much more that the person was probably "limited" more by the language. I think there are fairly good reasons for all of these, especially when working with more than ten people - in a language like Java. And in this case you will have to use Java (or something similarly famous) because otherwise you won't find a replacement very quickly that is fairly cheap. Now, maybe the person would not have needed all this in such a small project that is just for one person. But who knows, maybe the project grows. Or maybe this person was simply familiar with this and could get this down fastest. All in all, I think there are many good reasons to decide to make a project with patterns/conventions like this.
probably you meant to say "hours"? :-)
And thousands includes hundreds of thousands, which is indeed the case here.
Like ... it was two orders of magnitudes off of what you're stating the reality is. It makes sense that people would try to reinterpret the statement.
From a business perspective, investing in architecture quality buys a lot more optionality than investing in code quality, and so prioritizing the former is almost always the right decision.
I consider focus on code quality everywhere a form of premature optimization. Only focus on quality where it hurts... But if it hurts (f.e. you had to change it 3 times and it got messier each time), be very disciplined about refactoring to a better model: whiteboard, brainstorm etc and don't start refactoring until you found a better model.
I'm more worried about low quality code that takes the form of an api or object that everyone in the entire codebase has to use. Something where if it has a bug or if it needs to change, it will impact huge swaths of code.
Meanwhile, the code that takes a double and returns a double ... yeah it can be full of spiders and work by literal earth magic and as long as the unit tests are stable, I'm not losing any sleep.
If you have to change it just rewrite it from scratch and reseal away the evil.
No, it's much harder for technical leadership. Technical leadership operates on opinions, fads, cargo-cult, etc., like you said.
Non-technical leadership can always fall back on business fundamentals.
You mean like opinions, fads, cargo-cult, etc?
Non technical leadership is just as susceptible to this. They’re just influenced by different people.
For little good it'll do them. Any input to their calculations that references the software part of their business will still come with a big "shmaybe?" attached to it, making the results just as bad.
Code quality is your new feature rollout average time.
If it's a steep rising curve it is abysmal, if it's mostly flat you have an excellent team.
If it was flat but exponentially grew after you went on a hire spree, you know where to look at.
Initially, one could churn out a lots of features quickly accumulating the technical debt. The increasing time can be rather more about the past, then new people you hired.
It takes time for new hires to get familiar with the code and for seniors to help them get up to speed, so I'd be surprised if a hiring spree didn't end up sharply rising curve for feature rollout time.
You won't have high code quality without a motivated and competent team for instance. Same if they can't correctly scope their features or engage in long unplannable projects, etc.
I'd make a parallel with clean natural water: you can't have it in isolation, the rest of your environment needs to be functional to preserve it.
https://www.pri.org/stories/2012-08-25/amateur-restoration-b...
I think a big part of this is the tech industries failure to grasp the value of experience. Experience teaches you to pick out the fads from the fashions and the values of various opinions. It helps develop your code smell and your ability to discern the quality of a work. All other trades value experience and trust it to help measure these things. If you wanted to judge the quality of work done by a junior plumber you'd bring in a master plumber to evaluate it.
While it's indeed hard to get objective measurements looking at the codebase alone, telling a manager things like
"look, this is going to take 5x the amount of time it should because the current code is a complete mess so I have to be extra careful not to break things and it takes way longer than it should to figure out where I have to put the new feature in order to mimimize the amount of extra chaos created"
or
"I cannot do anything sensibly without refactoring this first but it will pay off in the next couple of months and years to follow"
should make it pretty clear the quality isn't where it should be. If management doesn't grasp that, or doesn't want to hear it, then management quality is probably at the same level as the code's. I know I'm in a position not every developer is, but when needed I ask and get extra time for things like this. Because I've seen what happens when you try to build a trainwreck on top of existing ones: that stuff is exponential, at least.
That is a fair, so I guess that is the point where trust in experience kicks in, like the sibling comment mentions already.
But nobody ever does such a test since it would be prohibitively expensive.*
And also rather hard to do. You cannot reliably use the same developers to do it because both tests would influence each other. Using different developers would raise questions about whether both are at the same level. Etc.
Yet I do think some aspects might be easier to prove than other. Has perhaps been done already but say you take a bit of code with formatting completely off and inconsistent, and the same piece where it looks uniform. Have people read it a couple of times, then ask questions about it. Or something like that, I'm not into that research but you get the point: should be doable to objectively measure which one has the least cognitive overhead and gets understood the fastest. Assuming it's the uniform one, that would then open the door to saying it's worth spending time now to apply project-wide formatting vs continuing with a mix of styles as-is.
"historically, a code modification like the one you've requested has taken 5n units of time. After refactoring, such a change will take n units of time."
You wouldn't perform an A/B test to prove your claim. The managers would simply have to trust you for the reputable engineer that you are, and hopefully observe substantially increased velocity after the refactoring.
Yeah, that is my point. You can make up any bullshit number, and there is no way to prove of disprove it.
"Hey boss ... this code the other vendor handed off to us is really bad code quality. We'll need to rewrite it or it's going to take 10x as long to do the feature than what we initially estimated."
"Hm, that's not good. I'll talk to the customer."
<later>
"So that's how long it will take without a rewrite."
"That doesn't sound right. I'll ask the other vendor how long it will take them to implement the feature."
<later>
"The other vendor did it in two days. Your team is fired."
<later>
"We've got another round of bug reports from the field. Also a class action law suit from angry customers. Also the product killed someone."
"Someone died? It's a website how is that even possible?"
"One of the many bugs causes the screen to flash wildly. Someone viewed it who was sensitive to flashing lights and had a violent seizure that ultimately claimed their life."
-----
Without a separate objective code quality metric, you can't determine between two parties who argue about what the code quality is. It could be someone isn't willing to spend some time learning something new. It could be that someone is just unfamiliar with the code. It could be that someone is cutting corners and writing dangerous code.
All you can do is to pick the people with the best track record and hope that you don't find out you choose wrong after spending millions of dollars and burning a lot of customer good will.
Because of this, it would be really nice if we had a different way to measure code quality besides: "The software developers are complaining about it."
I've seen at least two perfectly good code bases get refactored badly because the dev didn't understand how they worked, or they were in a language the dev didn't want to work in [0].
[0] One of them was me, and in my defence it was PHP.
More often than not I see "code quality" as an excuse for being lazy or generic blanket argument that you cannot refute because "code quality".
> - Code quality is quite subjective and the field is driven by opinions and fads.
Agree. In almost every team I have been part of, when discussing code quality there was almost never consensus regarding what's good and bad.
Besides, in almost every company I have worked for, modules (or products) were usually refactored after 3 years or so (as in: the code that deals with retrieving data from the DB remains almost intact, but everything else is moved out to its own repository: the frontend as microfrontend and a new in-between layer (call it a proxy or "backend for frontend"))... so there was never a huge motivation to write quality code, just to write "good enough" code.
FWIW, I've found that the best way to approach dragging a team in a new direction is to not focus on what "quality" is at all, but see if everyone can agree on what the problems are.
I think if you can get people aligned on the problems -- specifically high level 'above the code' ones like "X keeps breaking" or "X is really hard to change" -- you can sneak quality into the discussion without it being an attack on any individual developer's code. "why is X hard to change" can become a conversation about loose coupling, cohesion, state, etc..
From management and customer point of view, "it works" is the only quality measure.
No one cares about opening the box and the less one knows about how the sausage is made the better.
Actually there is: Tech debt materializes in all measurable metrics of the project. Project Deadlines continuously are missed and the time at which they overshoot increases.
A project needs "exponential" people. The quit rate among the developers constantly increases, with experienced devs quitting first.
All these signals should allow actually easily to create a metric for code-quality. Its a signal that bounces from the code through the system to you.
We have ways of computating the original value after it has bounced through the develop teams system.
https://en.wikipedia.org/wiki/Convolution
The problem is rather- nobody wants to know how much debt they own, or to speak bluntly, whether the situation one is in, is actually a tech-debt bankruptcy.
When we dug in and improved the architecture, we could support 3+ clients with one engineer and add any new data source to less than a week.
I don't attribute it only to code quality but a combination of better architecture, good development practices(proper linting, proper conventions etc) and good product road map.
Focusing only on code quality without context may not be useful. Saying that it doesn't take more than a few minutes to set the core tenets of the project even for a small one time project.
This is a question of the quality of estimates and unrealistic deadlines. This is a separate problem from code quality. E.g. if you have really bad code but you know how bad it it, then this is factored into the time estimate.
Software tend to get more complex over time. Even if code quality is optimal, software will get more requirements added over time - especially if it is successful. If you allocate resources rationally, you will start by solving the "low hanging fruit" in the problem domain. So you cant really compare tasks at different stages in development.
Like a endless papyrus scroll, and medieval scribes, modifying a copy and pasted atrocity for a month.Code this bad, usually never makes it to HN of course.
I have to disagree with you on this point (and your third point)
I've seen so many examples where developers DID improve Code quality (CQ) from of the numerous automated/personal quality checks available. (Though what follows is from a Frontend dev perspective)
- CI is CQ
- Code Review is CQ
- IDE w/ Linters is a form of CQ
- `tsserver` is an real-time type CQ
- Immutability is a passive CQ
Idk, maybe Frontend-space is a world away from what you're working with every day, but CQ in my domain has both technological and cultural tools available before code ever reaches the end-user.
> So for non-technical leadership, it is hard to know if "extra time" spent on code quality actually improves anything or is a waste of time and money.
This is really interesting to me as a problem statement: how can devs unfold/make known the value of CQ as a critical function in this math? (I don't have an answer, but I think about it a lot). What are we not sharing – or, worse, what methods/language/etc. are we using that don't fully translate between teams?
I feel it's the job of the org to be able to identify this kind of bottleneck. What position within an org is responsible for explicating the properties of this kind of issue? (Again, I don't know)
Code reviews and linting is just applying some opinions to code. How do you show empirically these opinion are valid?
> But how do you know these things actually improves code maintainability? How do you quantify it's effect?
Trends. Trends in Client retention, trends in fewer user-submitted bugs. Trends in error rates garnered from logs. Trends in employee retention. Simply stated, Statistics. Imagine: you code a Minimum viable product (MVP) and get to market! Then you're inundated with user-submitted and computer monitor-submitted issues (i.e. AWS alarms) – you have a "shit show" of a product. So, how do you improve this MVP to reduce the Trends of failures? The solution is expressed in the ways I outlined above (but with vigor): CI, Tests, utilizing language linters such as TypeScript's tsserv, etc. (and so much more).
> Code reviews and linting is just applying some opinions to code. How do you prove these opinion are valid?
It's not an "opinions on code", it's a culture which is predetermined by the org (assuming the culture is healthy enough to understand its necessity and/or recognize its deficiency of the same). EVERY org needs to "scale". Orgs asked themselves: how do we effectively "scale" and what is "scale" org-wise? The tenets vary, but the history has painted a portrait of domains: SRE, DevOps, Data Analysts, Frontend, Backend, Product, Systems, Networking, SDET, etc. Each is not encumbered by the need for tests/CI/pre-deploy shtuff (arguable), but is released from "toil" because they recognized scale went beyond "opinions on code."
Validity of code is tests and there are many, many, expressions of tests: End-to-end, Integration, Regression, Smoke tests, Unit, etc.
> How do you prove empirically that immutability is not just a fad like so many others?
I look back on the time before I was cognizant of the concept of Immutability and every larger FE app I wrote feels now indistinguishable from disorder and turmoil. I hope the YC community can expand on the necessity of immutability from a maths perspective (as I cannot), but it's eminently scalable (read: understandable and practicable from an FE dev perspective).
(It's late and I gotta cut off here, hopefully someone can expand and/or redact everything I've said).
Cheers
Good for you, but this is not very objective. People were saying the same things about OO inheritance and and a bunch of other stuff which the industry have later become more skeptical towards. I'm not saying you are wrong about immutability, just that you cant show any solid empirical evidence that immutability improves long-term maintainability.
Immutability is taking it a step further and provide a mechanism where scope does not matter. If you have an immutable object you can always expect the values to be what they are and not changed by some other path of code. You can freely pass around the immutable objects because they cannot be changed.
In other words, it's a mechanism that you can use to ensure that no matter what is changed, it's not the value of you immutable objects. I'd argue that it lowers the surface of things to consider and with any decent tooling also prevents you from trying.
In my experience this is the usual adoption curve of new practices (not necessarily best practices). They come as a shiny new solution for an annoying problem, it gets absorbed by early adopters that then become evangelists. More people start using these patterns/practices and start encountering the issues and obstacles with it, some get disheartened, frustrated and become outspoken against it.
These practices then evolve with time, becoming more nuanced, having "best applications" and "non-use cases" to better judge its applicability. And then becomes mainstream and a expected practice for modern software development/engineering.
I've seen this with multiple trends: OOP-isation of everything, UML (birth and death, kinda superseded by C4 diagrams these days), NoSQL, microservices/SOA, Kubernetes, Dockerisation, and so on and on.
FP and immutability are getting into the maturing phase of this, I remember a few years ago when it started making inwards on FE development, it was adopted, kinda overused and now I see it trending towards more cautious adoption.
I believe it's all a matter of understanding, all new shiny things will always have early adopters that can cope with the pain points. These are addressed when getting more mainstream and with that comes the knowledge of what actually these pain points are in the real world after years of adoption.
I don't see this pattern changing anytime soon, I've seen it repeat too many times the past 15 years.
The measurements these businesses are looking at are (by definition) disjointed from reality as experienced by their customers and employees.
I think what's confusing to me about this and your previous point, is you mentioned this inability to access objective reality outside our own subjective experience, but now appeal to a shared human experience (i.e., there's a general human accomplishment we should all be working towards that goes beyond our subjective experience). I can understand one or the other, but it seems there's some tension between those 2 views.
- There is no way to measure code quality
- There is no way to measure developer productivity
- Code quality is quite subjective and the field is driven by opinions and fads.
I have seen many examples where developers thought they were improving code quality by implementing some pattern or architecture but actually made it worse.
So for non-technical leadership, it is hard to know if "extra time" spent on code quality actually improves anything or is a waste of time and money.