This a thousand times. Having empathy for future devs, maintenance, and bug fixes is so important.
This a thousand times. Having empathy for future devs, maintenance, and bug fixes is so important.
Very frustrating.
In fact, I think a third-party auditor would be a valuable service for dev teams to utilize at least once a year. Totally neutral party that can come in and say ‘We’re pretty sure the codebase is too complex and we noticed the commits came from so and so’. The business value here is you can root-cause velocity issues that can come from decent people who need to be reigned in (not necessarily fired).
I’m literally prepared to pay to have these people objectively assessed.
One challenging bit about this service would definitely be quantifying improvements. Since the problem is somewhat hidden by nature, you would almost need testimonials from other engineers on the team.
If a team was tasked to make a simple landing page for example, and it was oddly hard or time consuming for an average team member, it would be good to dig into why. If the answer is ‘you should see the boilerplate involved, or the deploy process ...’, then you can make a neutral analysis as to the cause.
This sounds like it'd reduce psychological safety on the team, to have someone without the project context come in and criticize your engineers. The morale decline of such a choice could outweigh the benefits.
It’s a tough one, so I don’t even know where to begin other than an independent arbiter. Anyhow, I agree with you that it is a delicate matter from an emotional perspective (even though the underlying can be a reasonably objective matter).
someone then removed all of my logging because it was ugly.
and then had to put it all back in when another bug was coming from the same terse beautiful code.
1. good logging is the most important part of the app. whatever the app is meant to do is secondary. the app should be a logging app first, and then a backend service to sell widgets second.
2. assume performance requirements for request latency and transactions per second will be at least 3x whatever the product owner tells you at the start of the project and plan accordingly. never trust any suggestion that you can 'ignore performance for now'.
3. the UI may be more important than logging
I think it happens because most measures of code quality are quite fuzzy, but brevity (which is valuable, other things being equal) is relatively objective. "Have I made the code shorter?" is a much easier question to answer than "Have I made the code easier to understand, modify and maintain?"
This is something that comes with experience though, and I think a lot of people don't truly grok this until they are trying to maintain their own terse/clever code written months/years earlier. Nothing is quite as humbling as doing `git blame` on some crappy code only to see your own name there.
"A picture is worth a thousand words.."
I noticed that they put a lot of their self-worth in the sophistication of their code, so it's difficult to criticise without making them feel bad. You need alternative methods of getting them to "see the light" and write code that's more understandable and maintainable by others.
Also on PRs try to point to their own work as sample of how to do things better. This doesn't hurt the ego much, because the role model is themselves.
Also, I feel like most of the time this is an impostor-syndrome/perfectionism issue that also happens with other workers too, so HR can give tips on how to deal with those issues in a more sensible way and tell you what you can or can't say.
I've noticed this too. One thing I've had mild success with is the concept that a particular programming document (especially in functional programming) is really a series of mini-documents. Each mini-document has function-level comments, a signature, body, and returns that tell part of the story of what that function does. The minute that the collective of those fail me and I find myself reverse engineering code, then we have failed the team and cost the company money.
Some complicated things must be done, especially at the size and scale of our products, but complex things are painted with a fine veneer of interfaces and documentation.
I think another exercise that can help is putting junior engineers front and center to architecture. Whether it's exposing them to review, the review process of a Senior engineers design, or putting them front and center to design implications. I've seen having to figure out the difference between a controller and a service cause some really positive abstract thinking that puts people on the order of thinking for the group rather than their own merits.
I think this is more prevalent for some languages/stacks than others, too; there's definitely a cultural aspect fostered the language owners or whoever the leaders are.
If these systems are not in place, and a senior developer can get away with writing overly complex code, then that is the fault of management, not the developer.
A first-year student is unlikely to understand C++ template metaprogramming, or just about any Haskell code, but that's not to say they should always be avoided in production code.
> The best code is no code at all
This can be interpreted as advice to avoid the 'inner-platform effect' anti-pattern. Good advice, but personally I'd rather express it in terms of the inner-platform effect.
Agreed. Comments have their place, and some code is unavoidably involved, just by the nature of unavoidable complexity. The solution isn't always to write simple code. If it were, we wouldn't bother studying clever and efficient algorithms.
Also, it's important to ensure comments are updated when code is changed. I don't know who originally said it: Stale and inaccurate comments are no longer comments, they're lies.
That blog post looks worth reading properly, I admit so far I've only skimmed it.
They're just the people to read a book on the topic and try to use it everywhere...
Don't apply corporate best practice designed to withstand turnover to personal programming - you're leaving abstraction and efficiency on the table.
The better code for your own projects is almost definitely inscrutable to a newcomer a lot of the time. It's okay for there to be prerequisites to understanding.
Sometimes the simplest solution also requires learning and building upon other concepts. Or sometimes, a simple interface is written around a complicated core.
For example: The OP's quote is used time and time again to argue against FP concepts in industry - a newcomer doesn't know the first principles, so by the OP's folksy razor[1], that code isn't as good as less abstract code that doesn't require learning a new concept or two once and for all.
[1] Folksy razors are the essence of every principle-ish-level engineer's methodology I've run into. Corporations value the ability to remove all human agency & decision-making from software development where possible.
Corporations value the ability to continue as an operating entity and make changes to the code after the proponent of Kleisli arrows and lenses has departed for greener pastures.
That said, it's hard not to play the game and buy in. I just write my vanilla Java, say right-sounding things in meetings, and somehow get Paid despite barely doing a thing.
Corporate software development is a great career tbh - instead of paying me to use Kleisli arrows for the company's gain, the company effectively pays me to use Kleisli arrows on my own IP lmao. Gotta love all that frothy waste that's produced by Worse is Better. Waste that the average dev can now reap thanks to the boom in remote work!
e.g. I'll understand my monad transformers in a year, but a new hire with no Haskell experience will not.
So I would say great code is code that:
1. Does its job well (robustly, performantly, etc. in whatever proportion is applicable)
2. Is maintainable by engineers with reasonable expertise in the tooling
in that order. If you can manage all that and make it accessible to your junior devs, that will of course make your code greater. But don't lose sight of what your customers care about. Your business isn't there to make you feel good about maintaining code, it's to provide customers with value.
How many entry level engineers come onto a project per year? 5? Is onboarding them onto the project is a deliberate and streamlined way such an undue burden that you must change your programming style to avoid it?
Then you'd be out of business.
Most likely the code I write has a bug in it. Or, at the time of writing, the customer requirement is fuzzy. Or, I have a limited grasp of the problem domain. Even if it is not any of the above, most likely there will be a change in a business requirement that impacts the code.
So whenever possible, I opt to write code that is either stupidly obvious, trivially testable, or easily replaceable.
What is better (A) a compiled bug free binary, or (B) well written source code that has a few bugs?
If you want to keep developing the software, the answer will always be (B).
There are code bases at my current employer that are entirely "ok" and still being worked on from before I was able to spell my name. Projects that have had continued development for >20 years by armies of engineers and the code is still readable and simple to understand.
In my experience, the easiest to maintain code is very often the most efficient and robust as well, because people haven't felt the need to hack around it at every corner.
Easy to understand code can be more quickly patched and repaired by anyone on the team. If you don't need to call in the senior who built it two years ago to repair it, and you can have someone do it right away, it is better for the customer.
That performant code that you wrote maybe at the expense of readability? It could very well become bad code when you leave the company and it falls to a junior engineer to modify it to fit some changing business requirement. Or, there’s a bug in the code and the amount of time it takes to fix it is a direct function of how quickly and completely that junior engineer can understand the code.
For me, the hard part is knowing when and how to make that trade off. I’ve definitely erred on both sides often enough.
I am not saying the code cannot be made better or more clear. But, it also depends on who you are writing to. Somebody who is not familiar with certain style of programming cannot easily read the code of certain level of complexity.
When I was hacking away my first big program, I could not write functions. Or find reading functions easy. The whole thing was a big wall of glorified assembly sewn together by labels. I am not sure why I was like that then, but I found concepts 'functions' and recursion or any other conceptual stuff really hard. My code was, in its own twisted way, 'most simple' and utterly unreadable.
I find the same sort of difficulties while reading some FP snippets. I confess it was a very short affair, but I had some difficulty reading it and even when I understood, I could not just write or think code in the same style.
There are ways to make your code better, your intentions clear but 'can be understood by a first year CS freshman' is bit abstract criterion.
It is kind of like, vocabulary and prose. You can make your prose clear. But, people have to work on the vocabulary on their own.
> The best code is no code at all.
This is completely agreeable.
Edit : Changed some poor word choices. Added an analogy.
Usually they end up thinking they can do a better job, decide to rewrite the thing from scratch, and take 10x longer to rewrite it than they thought it would take. And accomplish nothing in the end, because the thing they rewrote worked in the first place.
I real life working on a team with ever changing code, that is the barest rank minimum.
As a young programmer, I thought I was a master when I got the code to work. Now I know that is just the start. Making it readable and changeable is where real mastery lies.
This is very hard to convey to young fools as I used to be.
It works. I look at their code and think "that's neat", but you added 0 functionality while making it hard for the lowest half of the engineers to work with. You could have accomplished the same thing with hard-reference to a class.
codex bonus a discipulo prendatur
codex magnus a novo prendatur
codex optimus nullus est
Part of the problem is I couldn't find any good word for "code". "Codex" sounds cool but may not be the best fit here.
EDIT: Forgot a word. Also, I think "prendere" is better for "understood" here than "scire", which is more like "to know".
EDIT2: My friend suggested using the subjunctive for "comprehend" so that it's "may be comprehended" instead of "is comprehended". Also I got the tense wrong initially and I think that's fixed now.
EDIT3: "Ablative agents" are a thing. This is a rough language. Thanks, James.
EDIT4: prendar -> prendatur; aka "oops, should have used third person"
1) Readable Interfaces usable by juniors when parts of the code will be used by lots of devs and will almost certainly change
2) Higher complexity behind the interface for parts of the code that change less often and require more skilled engineers