Developer Productivity for Humans: Software Quality
ieeexplore.ieee.org
ieeexplore.ieee.org
First that’s not always technically true because not all businesses have investors.
But assuming that the primary purpose is to make money, even that’s not precise since there’s a massive difference on optimizing for ROI tomorrow vs next quarter vs when you retire and hand your business over to others. Or different metrics altogether like market share or “engagement”. Those are all conflicting goals and have changed a lot just in a decade.
But even if you decide precisely which metric to aim for, there’s still a giant difference between primary purpose and only purpose. Simple things like a circuit breaker or a nail might be single purpose. But as soon as you step up almost everything is multi-purpose. A car, a house, even a hat have many degrees of freedom. A business has many unquantifiable components.
Anyway, the point is that giving carte blanche to decisions labeled with “business reasons” is at best lazy, and at worst legitimizes a sort of pseudo religious cargo cult worship of the “business truths” of the current year.
The truth is that nobody sits on magical predictive abilities, neither the 10x engineers nor the MBA grand poobahs. But it’s also clear that the companies with technical leadership and/or a high degree of engineering agency have been so successful in the last two decades, to the point of redefining the nature of business itself.
If I form a business and take no outside money, I am the investor, particularly in the context of GP’s point that “[businesses exist]…to make investors money.”
How much profit are nonprofits expected to make?
> But assuming that the primary purpose is to make money (...)
The difference is only how shitty it is. Internal software of huge corporations are total crap. Software which is facing paying customers is better.
IMO that's a super important point. Having accountability without control is probably the fastest way to burnout and dissatisfaction in my experience. It doesn't matter the amount of hours you put in, it doesn't matter how much vacation you have. It's the difference between a feeling of accomplishment vs the learned helplessness and Sisyphean feeling of endlessly pushing a stone uphill.
And productivity suffers the most. This situation negatively affects the whole system, naturally.
My manager: I want this in X days
Me: It is unlikely to finish in X days given x,y,z. It is also likely to cause outages.
My manager: If it causes outages, we will throw you on a PIP.
Me gets burned out.
Lesson learned. If a manager forces me ever again, I am going to let the project and the manager fail.
The game of Chinese Whispers of features (and deadlines!) is probably the most inefficient part of software development.
It goes like this:
1. "We need to improve how fast developers release features". Ok, so we throw out tests. Now they're shipping fast!
2. "We need to improve the quality of developers' code". Ok, so we add quality gates. Now they're shipping better code!
3. "The quality gates are slowing down productivity." Ok, so we'll introduce them at earlier stages, shifting left. Now they're shipping better code faster!
4. "The software works, but the customer is unhappy with the product." Ok, we'll focus on giving the customer regular updates and validating the results are what they expect. Now they're shipping better code faster that the customer likes!
5. "The software is now much more expensive than it used to be." Ok, so we...
...and on, and on. Each time, because nobody is focusing on the entire value chain, only a single thing is getting fixed, and it ends up having knock-on effects. It's not enough to perfect one link in the chain. The whole chain needs to be strong, and communication needs to go both directions, constantly.
And in that sense you cannot measure the productivity of a single person alone, you must measure what people are willing to pay for their output.
If you produce exactly the same as you did last month but nobody is buying it this month (or ever again) it means your productivity is zero. Is that true? Or does it mean your productivity is negative?
Or is it the case that when you work for someone else your productivity can be measured by the salary they are paying you? That would mean that "productivity is in the eye of the beholder". Your productivity as seen by you is different than your productivity measured by your employer.
No, your productivity has no connection to sales unless your job is in sales. And productivity for individual employees is measured all the time, across all industries.
Your time and output is being paid for by your employer, not the customer (except where they are the same person,) therefore productivity is loosely a measure of the value you create for your employer over time.
This is a class "the whole is greater than the sum of its parts". You're talking about productivity as a whole, everyone else is talking about productivity of the individual parts. The two are related but independent.
High Productivity = Spent effort results in progress towards the desired outcome (the product).
The question is: What is the product? I believe the issue is, that many (software) company are confused about that. Their product is the invoice. Everything else – especially the software sold, is just a means to an end.
Similarly in software development it is commonly understood that the lines-of-code is a bad metric for productivity. Some people write many lines while others may eliminate lines from it.
In general "productivity" is about economic activity and thus measured in monetary terms. But that doesn't make it any simpler.
Most people are completely unable to work with that, what includes a large majority of the managers on every level. Worse yet, it's never clear if a good or bad result happened because of somebody's work or despite it, so the feedback is completely unreliable and it's incredibly hard for people to improve.
And yet, I've never seen anybody teaching "management" to even acknowledging any of the complexity. (Including famous authors and professors.)
My thinking is, there's often enough people working for a business that know what the problems are, and can figure out how to solve them. But they can't solve them if they don't have the authority to do so, or their superiors stop them, or nobody cooperates with their attempts. I don't know how to solve that, but it must have to do with agency and cooperation.
* A sample of 9 developers, especially all working for the same company (in similar conditions) isn't much... but this seems to be a sore spot for most research on software development: very small, bordering on unrepresentative samples. Very hard to control for bias. Very hard to establish whether experiment subjects even have the relevant knowledge.
* I would very much prefer if code quality wasn't about people's feelings. There's nothing wrong with people's feelings... except I want a metric. It seems like the authors either don't believe it's possible to capture code quality "impartially" or that we are long way away from being able to do so.
* In the end of the day, the research behind the article doesn't have "action items". Suppose the reader didn't know about the complexities of measuring quality -- then they would've learned how hard it is. But the article doesn't as much as suggest what needs to be done to measure the quality (better). It's hard to fault the authors for not suggesting anything in this regard, and by their own admission, the metrics that they've found so far are kind of a snake oil... But, I really want a metric. That's why others keep pumping that snake oil.
Anyways, I still find the article useful in case anyone needs a brief explanation of the difficulties of assessing software quality.
On the subject of deep modules, as also recommended by John Ousterhout, I also enjoy a side effect of this approach: flatter dependency trees (internal dependencies). If you have deeper modules, you stop needing 10, 20 levels of modules to accomplish things. Not needing this makes it easier to debug and understand the big picture. IMO, "big picture code readability" is something of an afterthought. Things like Clean Code only care about the "small picture", individual classes and methods. Things that are rarely a problem in practice IMO.
Flatter hierarchies also reduces the number of things to maintain/understand: in the frontend, for example, a flat component hierarchy removes the need for components far away in the hierarchy to communicate, so no need for Redux (also no prop-drilling). It also makes things like DI containers not strictly necessary, as you can easily do it manually, if you have fewer layers.
Another important thing I realized is flatter hierarchies allow making that dependency graph closer to a tree, rather than a cyclic graph. This reduces cross-cutting concerns and minimizes incidences of "surprise code" that are often super deep into the dependency tree and a common source of bugs.
All IMO and IME, of course. But I'm curious if you also share my experience.
I'm a big fan of being able to read stack traces without scrolling, so my rules of thumb are to remove layers that pass data around without either providing a substantial abstraction or doing some computation with it (avoid ravioli code), and to collapse layers that were all doing the same sort of thing to the data, each a little bit at a time (avoid salami code).
My bet is that shallow modules originate via Conway's Law, then get cargo culted.
So much this. One of the things I absolutely hate seeing are the use of interfaces with a single concrete implementation.
context matters, it makes sense if you're authoring a library, it can make sense if you're working in something overly dynamic such as Ruby, Python, et al, but in a language like C#, Java, C++, et al, the compiler will assist you if you ever find yourself needing a second concrete implementation and most likely if you DO end up needing that second implementation, the interface is going to change anyway.
Distance between variable declaration and its use. But, oh, distances aren't simple either:
LoCs seem like a reasonable unit to count the distance between use and declaration, but are all LoCs equal? Should the metric penalize less for having long JavaDoc-style comments (which a lot of editors can simply collapse?) What about empty lines? -- seems even more contentious. Penalizing for lines of code regardless of contents of those lines will probably discourage programmers from adding empty lines even when they might make things better. Perhaps a better unit of measurement should be "statements"?
Now, why would using variables deep inside nested blocks be equivalent to using them same distance away but inside the same block? I'd say that probably declaring all your loop variables outside of the outermost loop sounds like a crime to me. Sure, the nesting level should be accounted for.
What do we do with class variables / struct fields though? Someone who wants to game the metric can simply decide that instead of using variables they'd store everything as a struct field. But, if we treat struct fields as variables... ouch, structs are meant to "transfer" bunches of variables from place to place, so, they will definitely score worse than function-local variables... How'd I find good ratio to balance struct fields against the variables? How'd measuring distance in LoCs or instructions coexist with mentions in different files, different directories even? What if it's like a define? Especially a popular one, like "TRUE" in C? -- That variable would pull out such a huge score...
----
I don't think these questions are impossible to answer. But I cannot even imagine the research plan to try to come up with some concrete numbers, ratios, functions to make this thing work...
I wrote "Nothing new of course." in the blog post itself, I am quite aware that it's a regurgitation of old stuff. Still, some of that old stuff is still being controversial, so I quite like giving it some theoretical backing.
> personally find the part about "Don’t waste vertical space" too far gone
Here's code I personally saw on the job, and it was mandatory, and the guy in charge of the silly rule that made it mandatory refused to change the rule, even though he admitted to my face the rule was silly:
/**
* Get the foo
*
* @return the foo
*/
int getFoo()
/**
* Set the foo
*
* @foo: the new foo
*/
void setFoo(int foo);
For something like 15 or more attributes, and this pattern was repeated across dozens of classes that I could see, and likely dozens that I didn't. Exactly like this, with comments that add zero information. And the rare times that it did, I kept missing it because it was drowned in a see of useless comments.Sometimes the code is too far gone.
Something being more reliable than something else is an absolute quality measure.
A piece of code may be reliable currently, but hard to modify.