Who wrote this shit?
heltweg.org
heltweg.org
I learned a great deal of humility and compassion in that moment.
I've subsequently noticed that those who are quickest to talk trash about nuanced engineering decisions and minor bugs are often the ones with the most fundamentally-indefensible coding practices (5000-line source files that throw innumerable compiler warnings, using deprecated frameworks, explicit silent failure modes, etc). Latent insecurity is a very real phenomenon.
I say this in jest, mostly...
A few months later I came across the same chunk of code... "Who wrote this shit?", and off we go again. I must have gone through this loop 4 or 5 times with the same piece of code.
I mean... that could happen... hypothetically... to... someone.
So much code to do pretty simple stuff… but it worked…
The thing is---I know the developer (he left our company over a year ago) and is a great guy (former jazz musician), but let's just say he had some questionable coding practices.
Say you track down a bug, find a line of code that makes no sense, and `git blame` it, to discover that you wrote it yourself, 2 years ago. If the commit message is "bugfix flaky builds", good luck figuring it out.
If the commit subject rather, is "bugfix flaky builds", followed by a message that explains what the flakiness was, why you think the change will fix it, what other bugs or limitations you were working around, and what upstream changes you might be waiting on that prevented further work, you're in a much better position. Suddenly you have a lot more context on what you were doing, why you were doing it, why you didn't do it better at the time, and in some cases it can even catch you from making an obvious but subtly-wrong mis-step.
Similarly, if someone's confused by your code during code review, that's a great opportunity for either in-line comments, or commit messages, as appropriate.
Unlike PR discussions, tickets, emails, slack threads, wiki pages, or photos of whiteboards, commit messages + git blame has an uncanny ability to be exactly the documentation you need exactly when you need it. Good git history practice can be one of the highest returning investments.
What has gotten me the most value is having either the branch or the commit message tie back to a ticket somewhere. -That- has the original bug, the comment thread that led to the decision around why this particular fix, any additional comments around tradeoffs we were aware of, and what other options we dispensed with, etc.
A well written commit message might explain what the issue was, but it won't have anywhere near the context the ticket and resulting comment thread should have.
That works until the bug tracker goes down or the company decides to use a different bug tracker and the import doesn't preserve information, or the link in the commit message doesn't resolve to the corresponding ticket in the new bug tracker. This is far less likely to happen to the git history given that it's distributed.
That being said, adding information to the merge commit message linking to the discussion or actually summarizing it in the commit message itself would definitely be an improvement. The merge commit has references to the commit the branch is based off of and the head commit of the branch, so you can limit git log output to just commits in the branch long after it has been merged.
Fair that it can disappear eventually if you change ticket trackers or whatever; that's a risk of changing ticket trackers. Hopefully you maintain both for a bit, and once you're six months out or whatever and retire the old, you don't need as much context since things have moved on (and there's a generational effect in tickets akin to that in garbage collection; you tend to need recent things more often than old things, and the older, the less likely you are to need it).
But just in terms of "what would I rather have", a link to the ticket every time. And in terms of "what am I more likely to provide", a link to the ticket every time as well (since all the communication on the ticket came about out of need; writing a thorough commit message is out of preparation, and I, and everyone else, am WAY better at consistently doing things that I need to do than preparing for possible future things)
In practice over the past 20+ years, I've had to rely on commit messages far more than tickets, but a well-written ticket is defnitely awesome to have. When I ran Engineering for a startup, one of the things we invested a lot of time in was making sure commits had good messages, tickets had good writeups, and the two were linked. We required a pull request to close a ticket, and our CI system would automatically append a link to the ticket to the PR when it was merged. It was such a level of awesomesauce.
I went through 5 different CVSs and the history was gone forever in each migration - but actually JIRA is still the same after 16 years )))
In any case, I think the "correct" answer is proper commit messages AND solid issue tracking. My preference for commit when looking in the past was more around trying to understand particular changes to specific files or lines of code, which are more easily navigated in source control. A good commit message helps narrow down things when there is a long history, but a link in that message to the actual ticket would be a dream since that would likely have the larger context.
All that said, I have spent some time at a FAANG and neither commit messages nor tickets were useful at all there. Commit messages were usually along the lines of "fix a bug" or "add a feature" and the tickets rarely had more detail than "fix X" or "add Y". That was more of a symptom of the "go forward" culture there. Little time was spent making it easier for the next person since that wasn't really rewarded in the performance process.
What if VCSs used a single file or a folder, like .gitcommits, where anyone could append any sort of info in the same commit, so it could be a part of it. Then, when you commit a feature, you add to this file(-s):
@@ @@
+---
+added websocket support to the server
+ /ws - main socket
+ /ws-events - events socket
And few commits later you decide to extend it, editing the same record: @@ @@
+---
+added json-rpc over websockets
+ /ws-json-rpc
And VCS would then extract these records at `git log`: ...
4509812 added websocket support to the server
0732691 <no .gitcommits message>
8712389 added json-rpc over websockets
Few commits later @docsguy expand on json-rpc: @@ @@
---
-added json-rpc over websockets
+added lifetime-related json-rpc over websockets
+task: ./tasks/1873.md
+supports 'start' and 'stop' methods: ./doc/ws-lifetime.md
/ws-json-rpc
@@ @@
+---
+enhanced commit descriptions
A tasks/1873.md
A doc/ws-lifetime.md
4509812 added websocket support to the server
0732691 <no .gitcommits message>
8712389 added lifetime-related json-rpc over websockets
6034007 enhanced commit descriptions
Full commit messages would then be just diffs. Also, one could write a commit message gradually, with the sources they are modifying. Or write two commit messages at once (because we all do commit two+ changes sometimes): @@ @@
+---
+refactored foo bar heavily, @docsguy please expand
+---
+fixed a bug in baz, didn't care to backport
...
0923423 refactored foo bar heavily, @docsguy please expand
fixed a bug in baz, didn't care to backportI ended up writing https://github.com/vatine/sressays/blob/main/change-requests... to try to clarify to myself what I thought a good change request ("PR", "CL", "CR", whatever you want to call them) needs.
(It was a personal project.)
Sometimes the best documentation is seared into your soul as a mark of shame. I think I’ll wake up a few times wincing about it.
Should someone inherit your project and end up fixing another bug in that part of the code they may be benefit from any information you share.
Shame is temporary, public repos are not.
(I say this as someone who has a track record of being too hard on myself!)
// BOGUS: assuming 'x' will never be greater than 1024.
Sort of tells future engineers, yeah, I know it's shit.
A comment I left that I am sometimes reminded of by ex-coworkers still at that company.
Those are very different needs.
"Why?" belongs in code as a comment. "How?" only sometimes belongs in a comment--generally if the code is "clever".
"What?" generally belongs in the commit message as it can touch multiple files and subsystems.
"Who?" and "When?" generally belong in your ticketing system.
Then I realized I wrote the comment. I didn't address the <niche> things because I was looking for it then and I'm stilling looking for it.
Let's submit ideas! I'll start
He wanted to learn about using Machine Learning to predict how often his pet dog would need to go to the bathroom
(1) Niche book writing software (2) Dumbphone hacking
And, to my surprise, it was not _that_ bad.
Sure, it was full of naively implemented stuff that could have been implemented way better. But, even a decade and a half after, it was pretty clear to read, and it was decently organized.
And, in some ways, I preferred this code to the one I'm writing professionally. I was honestly prouder of myself as a teen than myself as a professional programmer.
The difference, I think, is that I had a clear idea of what I wanted to achieve for this project to be considered as definitely finished. Since I started working on code (for money) I've always been working on never ending projects. This industry (and me, as a professional) is obsessed in writing code for long term maintenance and evolution instead of effectively finishing products.
So, to get back on topic, I'm not sure you really write better code with time. I mean, yes, you totally do, but it's not as important as learning how to code for others to be able to understand and modify it with constraints you can't even imagine.
And I saw a lot of people writing super nice open source side project and then, when you work with them on some professional level, well, they still write the same shitty code as everyone else.
Like when you learn a natural language's vocabulary, but you still need to figure what conjunctions of words are not intelligible or natural phrases to fluent speakers. Phrases that have ambiguous meanings or otherwise generate confusion.
I think there's a comparable notion of fluency in programming that goes what most people mean they say they're fluent in a programming language.
If you are actually improving then there should be some good in there (you got better from two years ago right?). If you can't identify that good, then either you are just chasing fashion (that perfectly good construct from two years ago is now out of fashion so it is "bad"), or you haven't improved your ability to tell good code from bad and just calling it bad because you are unfamiliar with it.
If you want to actually get better at code then you should do a real review of the code you wrote a year ago. Where did bugs occur in the code you wrote? Is there something that you could have done to make it less error prone? Is there code you wrote that is easy to understand? What design choices can you make so that more code ends up in the good code camp? How were the bugs detected? Can I integrate that in to what I do for testing? Then actively practice moving your code in the good direction and away from the bad.
Anything less is chasing fashion and using familiarity as a good and unfamiliarity as bad. "As is" it is a pithy blog post for Coding Horror, but won't get you there. Pursuing greatness requires directed improvement
Do you only feel this motivation when you look back at old projects? Perhaps the improvement could be in organization (code-level or otherwise) such that you do not feel lost or confused looking at your old stuff.
I would go as far as to say that it's a negative signal, because instead of improving code quality you are just changing things that don't really matter.
In the end I think it's actually kind of fun to look back through the code though, and think "surely I should have known about X back then... Why didn't I just do that instead."
EDIT: Actually I feel like an aging chess GM -- better than younger at strategy, worse than younger at tactics.
I had an issue, last week, where a bug was caused by an omission I left from an SDK that I wrote, maybe, eight years ago. It was a simple thing. I didn't add a "RefCon" to a server interaction, so I couldn't attach a reference context to a callback. This is a classic pattern, that I've used for decades, and I have no idea why the hell I didn't add it to this SDK. I suspect that it might be that the SDK was for a fairly wide audience, and I probably thought that they wouldn't understand it. So here I am, paying the price for underestimating my user base (which, so far, is Yours Truly).
Anyway, the "fix" was to implement a semaphore, and treat the call as blocking, which is awful. I really need to go back and change the SDK, but that's a fairly fundamental change, that I can't afford, right now (the SDK tofu is rock-hard).
Such is the life of a shipping developer...
The trick is to give them easily defuseable bad ammunition when they "sneak" around to collect. If you disassemble all their arguments and have emails were they were informed, you can trash them thoroughly.
Unpayed though. Cause even good arguments cant help broke little shops.
And if you don't consult a lawyer to prepare for small claims court, you stand a decent chance to be blindsided by that or something else.
If the initial action costs nothing, you have nothing to lose, but they will almost certainly lose something. If you do nothing it will cost you nothing also, but you have no chance of gaining anything at all.
They don't need to hire a lawyer to determine it, the junior paralegal in the in-house counsel’s office with a checklist will do just fine, since all the information needed to make the determination will be on the papers they are served with.
> If the initial action costs nothing, you have nothing to lose
Not at all true; one of the other standard techniques for getting things out of small claims court is for the defendant to find anything about the interaction in question that they could countersue for that would raise the amount in controversy above the small claims limit (since the requirement for linked counterclaims to be handled in the same case and the small claims limit interact to requiring moving the case when this happens), even if it is something that they wouldn't sue over otherwise.
We pine for the perfect green field where all things are good but there are probably zero companies where all developers are expert, where the solutions are all unique and unambiguous, where the trade-off between maintainability/performance and speed of coding are all completely set in stone, where nothing has ever changed in strategy, framework, etc. where no framework update has ever broken something and needed some dirty hack to work around it, where you don't have managers come and go who are not 100% helpful or useful.
So better to look forwards always. Don't try and fix what is there unless it needs changing to move forwards. A lot of the code I have wanted to rewrite in my current company will be toast in the next 2 years as we are writing new apps so just don't lose sleep over it.
A comment explaining "why?" A quick refactor of your patch to make it easier to understand. A small README update. Those kind of little things add up and pay dividends.
Best write code with empathy for those that come after you -- including your future self.
Developers like you are few and far between. I find it painful when others devs constantly re write working code, instead of moving forward. It’s so easy to trash what is there. Very few have the maturity to work with existing code without complaint.
That implies, code never is perfect. Not even good. But clunky, cobbled together, expermental or just plain stupid. But always just about 'good enough' to solve the issue at hand.
I just would add, that the urge to refactor things whenever possible, definitely introduced bugs for me, because also refactoring has to be done with consideration and some things were weird for a reason, you do not see at first glance.
And refactoring can also hurt you, or another person just used to that code in its old shape. And then missunderstanding things.
I'm an avid TDD developer. Red-green*refactor*. The latter, often overlooked, is IMO by far the most important part of TDD. But the refactor is only possible because of the tests you wrote, asserted, and tested (testing the tests) in the red-green phase.
It gets hairy when a refactor needs to also refactor the tests - often a sign that the tests were lacking in the first place (and the more reason to refactor them). In which case I try to refactor them not in lock-step but decoupled: first refactor the tests without touching the SUT. Then refactor SUT (and then, most likely, another round of this)
There is no fool-proof way. There will be bugs. There will be regressions. But that is a artifact of "change", not of refactoring. I'm also a believer in "never fix something that ain't broken". Which, unfortunately, only works for software that is not ever upgraded, has no dependencies, runs on hard- and software stacks that never change and has no changing business-needs ever. I.e.: non-existing software.
I think this is context dependent. I generally agree with this statement on relatively low-risk projects. The problem with "good enough" is that it often becomes a rationale for our cognitive biases to take the easier route. I don't want someone doing that on, say, safety-critical code. Maintaining high standards is a way of buffering against those cognitive biases.
Isn't that by definition what good enough means? That on safety critical code "good enough" is a very different level than on a throwaway-script?
It really comes down to understanding why the goalposts have moved. Is it because you have more information to reduce the uncertainty about the risks that standards are meant to be mitigate? If so, great! If not, it's a red flag you may be responding to something else that increases risk, like schedule or cost pressure.
For example, NASA has different standards depending on risk categorization and the predefined threshold of quality gradually gets higher as the use gets riskier. A business application is held to a much lower level of quality than software for a robotic mission which is lower than a human rated development effort.
We are laying out an approach to software development, refactoring, and a model for how to view old code that you some acroas that seems bad.
You seem to be stuck on the term "good enough" and arguing semantics that don't make sense. Yes, sometimes there are standards. that you need to meet. Sometimes just meeting the offical standard is not "good enough", and you need to do more. "Good enough" is inherently contextual, and you seem to agree with this, but seem still be arguing against using that term?
Good enough is usually an excuse for vague and ill-defined practice. If you don't have a well-defined "good enough" you probably don't have a mature process. If you don't have a mature process, you probably shouldn't be writing critical code. Hence my original comment that it's not a good mindset for high-risk applications.
Well defined "good enough" often looks like a standard. Those standards should be risk based so that one person's biases don't result in a different level of risk mitigation than another person's. That risk is what contextualizes what is "good enough". I'm sure if you asked the Boeing managers, they felt their CST-100 software was "good enough", but the relevant safety standards say it wasn't "good enough". Since both sides can use the term, it makes the term somewhat useless. Like you say, there is no singular "good enough" so the question becomes: Good enough...for what? Good enough to meet schedule, or good enough to not risk crashing into the ISS? My main issue is that "good enough" often means "undefined". When people say "good enough", I've found it often means "we don't know what we need, but I'm sure we'll know it when we get there." I think that can be a bad approach to software development when the risks are high because it opens one up to cognitive biases that lead to subjective and poor decision making.
If you're saying "good enough" is precisely defined and based on risk, then I agree. But that is not how I've ever seen the term used in practice. It's almost always a nebulous term which means you've only vaguely defined the risk. Poorly defined, subjective judgement belongs more to art than engineering, especially not safety-critical engineering. "clunky, cobbled together, expermental or just plain stupid" as the OP said, just doesn't cut it on critical applications, even if the developer claims it's "good enough" and doesn't strike me as a professional mindset.
Indeed, blind adherence to standards is bad as standards are not perfect and are designed to fit a general use case. You need your developers/engineers to think about the full context and asses whether their design will hold up under real life conditions and not just those that were prevalent when the standards were created.
Look at the actual wording of the post I originally responded to:
>"But clunky, cobbled together, expermental or just plain stupid. But always just about 'good enough' to solve the issue at hand."
Can you imagine a discussion about relevant risks and priorities that uses that definition of "good enough"? I can't, especially with safety-critical code.
I'll give another example: The NTSB report of the uber autonomous driving accident gives a good breakdown of events. Through that report you can see the developers programmed a delay (they call it an "action suppression") due to nuisance braking etc. It's hard for me to imagine a code engineer programming a delay on a static delay time-sensitive safety critical system if they understood the risks (even if the mitigation was the human driver, they didn't seem to have a good understanding of human factors engineering). Yet someone along the way thought the software was "good enough" for production. It's speculation on my part, but I doubt you'd find a good FMEA or hazard analysis on that system. This is my big worry as SV mindsets get into safety critical systems: the general "move fast and break things - because it's 'good enough'" doesn't translate well to systems where lives are at stake. That is what I was responding to: the over generalization that clunky code (in the OPs words, not mine) is 'good enough"
That's not a definition, but a description. It was pretty clearly not an description of "safety-critical code".
You've inserted a context of safety-critical vehicle control systems into a comment responding to an anecdote about writing PHP4.
You say things like:
> Poorly defined, subjective judgement belongs more to art than engineering
That only seems true if you are extremely lucky and/or early in your career. It is extremely common for software engineers to face poorly defined, nebulous problems that you simply don't have the information to solve in an objective manner. The frequency with which this happens is why the approach described by the top comment is so effective. It is a process of continual improvememnt where you try to avoid making unnecessary decisions until you have better information to make them with.
What changes with safety critical code is how you gather that information (and what other processes to build to supplement developer judgment). You try to gather that information with as little risk as possible. Experimental clunky and cobbled together code has a place in this process, but not as a part of live, uncontrolled testing. You run it against models as you prototype solutions and then you refactor or rewrite that code to be good enough to test in riskier situations.
The quality of the assessment matters, but there is really no problem with people making an assessment of whether the code was "good enough" for it's context. In fact, I would refuse to work with a developer who refused to make such assessments. Standards and outside analysis are important, even in non-safety critical systems, but they ate no substitute for a developer making careful assements of if code is good enough.
This is part of the point the article and top comment are making. You can assume that the person who "wrote this shit" is an idiot and mock them, but you will learn more instead if you try to understand the context that drove that person to make the decision, how well that decision worked out, what it cost them and what it gained them. This is how you avoid cognitive biases, not by refusing to accept code that is truely "good enough" in some quixotic pursuit of impossible to achieve perfection.
> That is what I was responding to: the over generalization that clunky code (in the OPs words, not mine) is 'good enough"
I think you are tilting at windmills here. There is no such broad generalization. Clunkly code is often not good enough, which is why it needs to be refactored, "the moment that it starts becoming messy" (which is, I'm sorry to tell you, a context dependent subjective judement call.)
But clunky code can be fine or even great. I'll take a defect free clunky code base that solves a stable problem over an elegant rewrite that adheres to the latest coding standards any day.
In my experience they are meant to mitigate risk. Now maybe that risk is not credible on a particular project which means that standard doesn't apply. But in all other cases, not adhering to standards means you are incurring additional risk, by definition.
Now maybe you're just saying, "Yeah, but those are acceptable risks" in which case I don't really think we're saying anything different. My experience working on safety-critical code uses standards that explicitly state what risk is acceptable so there isn't much wiggle room for wishy-washy statements like "good enough". They aren't esoteric, abstract standards of practice (and maybe that's where our personal experience diverges). It becomes relatively clear, with a good testing plan to maps to said standards, whether that risk threshold was met.
It's easier to illustrate with hardware, but the same principles apply. Say there's a standard that states each critical component must have a specified reliability level. You could either install a single component that meets that reliability level or design redundancy so the overall reliability meets the standard requirement. What you can't do is install a lower-reliability component and claim it's "good enough" unless you change the definition of critical. And that's what sometimes happens in practice; people get through a design/build and realize they didn't meet the pre-defined/agreed upon standard and so they perform mental gymnastics to convince themselves and others that the component isn't reaaalllllly critical as originally defined. And that discussion shouldn't be based on subjective judgement. As the sign above my old quality manager's office said "In God we trust, but all others must bring data."
>I'll take a defect free clunky code base that solves a stable problem over an elegant rewrite that adheres to the latest coding standards any day.
This might be part of where our opinions diverge. My experience in hearing "good enough" seems different than yours. It sounds like you're using it as "it solves the problem, so it's good enough". My usual experience is more along the lines of "it doesn't meet the standard, but it's good enough." The issue in the latter case is that I think there's some hubris that one fully understands the problem. If you do, then you should have no problem bringing data to support that claim and we'd have no qualms. But if you can't, one thing standards are good at is helping to make you pause to consider all the aspects of the problem you didn't think of. Part of that hubris is the assumption that it's a stable problem. Standards capture the lessons learned when people realized it's not so stable. So clunky code may good enough to solve your conception of the problem, but that still may not be good enough if your conception of the problem diverges from reality (see: 737MAX MCAS, uber, CST-100, etc. as already brought up).
I've seen people adhere blindy to standards and I've seen people ignore standards without a good reason. Both are failure modes that can increase risks.
I also think you are grossly simplifing what caused the engineering failures you mention. They have a lot more to do with systemic pressure and misplaced priorities than they do with engineers making contextual assements of risk beyond what is stipulated in the standards.
>I also think you are grossly simplifing what caused the engineering failures you mention.
I don't know how you arrived at this conclusion? I am in no way simplifying. I said those types of systems are complex to the point that subjective determination of good enough isn't adequate and how standards help fill those gaps of understanding. I've literally worked on some of those systems and have had listened to people at the highest levels of some of those organizations about the nature of those failures. I've withheld approving plans of one because I witnessed firsthand how the nature of external pressure corrupts what is meant by "good enough". If you know more intimate details on any of those examples, I'm all ears.
>They have a lot more to do with systemic pressure and misplaced priorities than they do with engineers making contextual assements of risk
This is the exact point I've been making but I think the two are interwined. Those competing pressures make fertile ground for rationalization and cognitive bias to influence decisions to change the definition of good enough more in-line with the verbiage of the OP (again, there was no discussion of risk in that post, you shoehorned that into your interpretation. There was only discussion of clunky, stupid code which was blessed as good enough). You seem to imply risk understanding occurs in an objective vacuum and I disagree. That's why I think subjective determination of good enough falls short in some scenarios. I'm not sure if you've been so focused on being right that you've ignored that central point, or if I'm just not communicating it effectively but it's not really worth belaboring further.
Which I did not do. I don't think you are doing it deliberately or I would have ended the conversation long ago.
> You seem to imply risk understanding occurs in an objective vacuum and I disagree.
Not at all, where do I imply that? It is actually the opposite. I am arguing against your position that risk assements should happen in a vacuum and be based purely on standards with no need or room for subjective reasoning.
> again, there was no discussion of risk in that post, you shoehorned that into your interpretation
While the top comment did not explicitly mention "risk", the comment or did reply to you saying:
>> Isn't that by definition what good enough means? That on safety critical code "good enough" is a very different level than on a throwaway-script?
> That's why I think subjective determination of good enough falls short in some scenarios.
I've repeatedly said that subjective risk assessment is usually not enough:
>> Standards and outside analysis are important, even in non-safety critical systems, but they are no substitute for a developer making careful assements of if code is good enough.
>I'm not sure if you've been so focused on being right that you've ignored that central point, or if I'm just not communicating it effectively
I think your communication issues or on the listening side as you keep projecting a strawman onto people rather than actually listening to what people are saying.
But since we both appear to feel that the other one is not listening, that is probably a clue this conversation should end. I do encourage you to take some time carefully re-reading the thread to see if you can figure out why you seem to misinterpret so much of what people say.
I understand your point. What you seem to be missing is that we're talking about two different things. I agree that decisions should be made in the context of the risk of the engineering application. That's trivially apparent to the point where it's almost confusing that you would feel the need to bring up up (ad nauseum). It's also not particularly interesting because just about everybody will agree with that. What I'm talking about is when people fall prey to cognitive biases to the point where they can no longer make accurate risk assessments. That's a much more interesting problem because the engineering world is full of cases where otherwise smart engineers make terrible judgement calls, all the while telling themselves that they understand the risk. I literally brought up cognitive biases in my first post and instead of responding to what I'm actually discussing, you just keep underscoring a trivially simple point.
I think you're reading your own interpretation into what I'm trying to say and then somehow twisting it into being a miscommunication on my part. When I'm saying subjective judgement can lead to bad decisions, I am not saying "we take all the unique and contextual facts into consideration and arrive at a reasonable subjective risk assessment for this scenario". I'm saying people's cognitive biases can lead to them discounting risk without good evidence because it results in a decision they are emotionally attached to. E.g., "I don't want to miss schedule and look bad, so let's rationalize away this risk that really wasn't mitigated." That is not an objective risk-based decision, it's a biased emotional one. They may think it's "good enough" to get the job done, until it's not (as in the cases I specifically brought up).
While I already explained it but it didn't seem to sink in, I'll reiterate one last time:
You seem to say your definition of "good enough" is based on good, risk-based judgement. I already said if that's the case then we don't disagree. But I also said that is not the context that the term "good enough" is generally used in practice. In my experience, it's used to justify a sub-standard effort and I've given you concrete examples of that. That point of digression between what I'm saying and what you're interpreting seemed to fly right by you because you're more concerned with arguing, and there's some irony in you pointing out that someone else isn't listening.
Not at all. I said that "good enough" is a contextual, subjective judgement and is a critical part of software engineering. The idiom "good enough" says nothing about quality of that subjective judgment, despite your insistence that it does.
> I'm saying people's cognitive biases can lead to them discounting risk without good evidence because it results in a decision they are emotionally attached to
Of course cognitive biases (and all sorts of other things) can degrade judgment. That doesn't mean that we should try to get by without it. We seem to be in agreement on this.
> that is not the context that the term "good enough" is generally used in practice.
Here you are simply wrong. "Good enough" means " adequate but not perfect, not "sub-standard". While it is possible you have been operating in a cultural bubble where that term is only used to mean "sub-standard", in this context the meaning of "good enough" that is being used has been clarified repeatedly but you insist that only your experience with the term matters and thus everyone must use your definition. Instead of working to understand what people are saying, you assume that they are using your definition. Perhaps this sort of assumption explains why you somehow missed out on noticing everyone who uses that term in the normal way. Seriously, go look as some definitions and try asking people what they mean when they use the term.
> That point of digression between what I'm saying and what you're interpreting seemed to fly right by you
Another example of you not really listening. I've repeatedly pointed out this exact divergence.
Let me try a different tack to see if we can get off this pedantic merry-go-round. You've agreed that cognitive biases affect decision-making. So let's say as a developer you are working on safety-critical code that is in danger of being over schedule and over budget. Their manager says if the project isn't successful, your company will lose future work to a competitor and that might leave you out of a job. But if it is delivered on time, you're company will get a massive windfall in terms of future contracts and profits, and likely lead you to a big promotion. What do you do to ensure those cognitive biases do not influence you to incorrectly discount risks and ship the software early before the risks are properly addressed?
(Btw, it's a really bad method of communicating to use absolute terms like 'everyone'. For one, it makes it look like you think you're smarter than you are and more importantly, it's easily falsifiable. That type of communication belongs more on r/iamverysmart than HN)
I've seen this approach really bite teams that only focus on the cost of implementing application behaviors rather than the long-term costs in terms of maintenance and systems complexity. If too many poor design decisions are made when a project is greenfield under the premise of "good enough" it can create technical debt so bad that the devs can't extricate the debt from core product features further down the line.
Me too. But that is typically a problem with how they define "good enough". And how that evolves over time. If "good enough" means "what we decided on 7 years ago" or "It works on my machine" then certainly that term is not covering what it seems to cover.
"Good enough" should, obviously, take future maintainability, security, new hires, evolving standards, moving business-cases and changing markets into consideration: i.e. overall complexity, reusability, consistency, maintainability etc.
Or, to put it differenty: if your "Definition of Done" is not evolving or changing over time you can be sure that the "quality" part in that DoD is sub-par in a few years and your project development will grind to halt somewhere in the next years surely. (edit: that, or it is so vague and up to intepretation that any new hire or insight can change it already. Which may be a good thing, IDK)
We had an excel spreadsheet that was used for at least a decade to process some measurements. There were a lot of magic numbers shoved in the equations to handle some issues with the equipment along with math that I'm surprised Excel can handle. The results would be correct but it was a total black box but the steps to get to them were nearly incomprehensible. A coworker decided to spend some time upgrading it to Matlab to allow for some better interfacing with new test equipment we were buying. She thought it would take a week, it took months. Talking to the original author was useless as he couldn't remember how he built any of it. Finally she got it working with both the old and new test equipment and now has properly documented everything so it explains the use of any magic numbers. I did not envy that job at all.
Part of the reason I like to write as little code as possible is that anything over a year old has some antipattern that I've come to loathe. I can't hate code that didn't get written in the first place.
Or at least, it's a lot harder to do so.
I don't know. I tend to remember what code I wrote, and recognize my own code when seeing it, even years later.
My code from 6 months ago looks good to me. My code from 10 years ago looks "reasonable, if a bit messy". I remember what I was trying to achieve with what level of knowledge I had, and often what I had in mind at this moment (sometimes including unrelated feelings).
I'd probably write this code differently today and it's clear I learned things in the meantime, but a little bit of linting helps turn this code into "reasonable, if a bit less messy" (mainly limiting line length). I definitely find my way in this code and even find it kind of enjoyable. Sure, there are some details I don't remember but things are mostly here.
Do I have an exceptional memory, an exceptional tolerance to execrable code or both?
Re: the article, I've definitely felt "who wrote this shit" but I'm past it. Most surprising things have an explanation and this explanation should be sought before the final verdict… which is often not needed anyway. It's just a negative feeling that achieves nothing.
For example, I wrote a javascript image editor that stored images as hex strings internally, and saved them to file by screenshotting them. Completely mad design. But that was ~23 years ago, long forgotten by everyone except me, and I was age 14 at the time.
This is a young and growing industry; someone who coded like a 14-year-old ten years ago might simply be a 24 year old today.
If I found my code from a year ago bad despite all these years of programming, I'd be worried I'm not in fact any good. The whole point of taking care to write good code is that it will still be readable and maintainable (i.e., good) in a year and more, and I'm sure I can achieve this, and could back then.
I'm also able to recognize good code from other people from years ago, if I systematically thought my code from one year ago was bad, that would mean I'm consistently bad too.
It just does not compute.
Who knows, maybe you're a better coder than I am and you just "got" it instantly! It's immensely important for me to keep growing, so I guess it's a good thing I may be so much worse than you?
Few more years than you (it depends when to start counting), definitively in the same range.
If one can’t write good code after several years of experience, then they’re in the wrong profession.
I suspect it's having to work around teammates' styles and integrate it my own into it that causes friction at the edges, but I'm not really sure.
The usual process was install osCommerce, add some extras, zip it all up and manually deploy it to a VPS and transfer the credentials to the owners.
The work was mostly found by word of mouth so it wasn't unusual to get emails asking for assistance/to do work out of the blue.
Had one such email to change an existing shop up a bit. Probably no more than a few days work. Received their credentials and ssh'd to the host machine to take a look. Scanning the source files of the plugins had me head scratching in a couple of places, decided this was compiled by someone terrible. Scrolled some more and saw the author's details. Oops. So that's how they got my email address.
"I did not."
If I don't then the comments either have the effect of a) scaring future me, or b) getting ignored because I think that I can do better now.
There are objective good code that are timeless, implementations that does not need another look or left few/no space to improve.
Granted, it's a lot harder to do at larger scale.
What he said humbled me and I basically never said anything like that ever again.
I also had the opposite experience. Two years in, wrote some code for a library that I thought was pretty clever. One day I got pulled into an online chat with a couple principal devs -- phenomenal engineers, respected the hell out of them -- and one was asking the other about this piece of code. He said something like, "Who wrote this shit? It's so complicated, I can't figure it out."
So from that moment I understood that you have to be careful not to be too clever when you write code. Changed my life.
To this day I'm so grateful to have had such amazing, patient mentors early in my career.
— Tom West, quoted by Tracy Kidder in The Soul of a New Machine (Modern Library, 1997). ISBN 0-679-60261-5
Previously cited on HN, but it’s a classic quote so worth citing again.
However asking "what is this shit" is a perfectly valid thing to do.
There are good developers producing crap due to constraints.
There are also other developers producing crap because they can't produce anything else or just don't give a damn.
Being able to differentiate between the two is often helpful, hence the "what" question.
My current project was started in the middle of 2021. The same people have been working on it for 6 months. I've been working on a related project and shifted over at the beginning of the year. I know the constraints and there haven't been deadlines.
The staff engineer decided to pick technology by what's cool. They haven't invested in development workflows. The infrastructure is held together manually by those who have admin access. Subsystems that need to communicate don't.
I have much sympathy for legacy projects, but those projects got to where they are because people made poor decisions. My current project is well on it's way to being a legacy project in just 6 months.
The team I'm on today doesn't say no to requirements and scope creep. They are too invested in tech and aren't adjusting. They don't cultivate truth about how parts of the project aren't coming together.
I blame problems on leadership much more than I do on individual contributors. I wish the commit log included the tech lead and managers on the project when code was written.
And even that critical mass won't be enough if leadership implicitly or explicitly reward shiny visible progress and ignores structural work and integrity.
The experiences we've probably all seen of new buildings going up quickly and then looking like trash just a couple years later are great examples. The problem is that approach "works" during boom years because everyone can move on fast enough to make the problem someone else's.
FWIW, I did write atrocious code when I was 16. But I'm in my 40's now.
1. It's nobody's fault
2. It could be my fault
3. It's my own damn fault
https://news.ycombinator.com/item?id=6478121Sometimes it may however still be the best solution but your future self was unable to figure out why because your former self was too lazy to properly document the code.
This seems like a really sane thing to do!
In addition, if you want to keep track of the commits and the context behind them, i've found that merge/pull request descriptions are also really nice for this!
Back when i had to struggle with an Eldritch DB schema that someone wrote and had to patch in new functionality, i ended up painstakingly mapping out how it corresponded to the business concepts/objects (which was pretty loosely) and threw that diagram into the merge request, because sadly otherwise the schema still wasn't all that clear...
...just to have that very same diagram save my hide when i had to go back to it months later to update some of the code, which necessitated rediscovering how everything works.
Now, whether things belong in the issue tracker or somewhere that's more close to the code repo is probably just a cultural question, but i'd say the main thing is to have some place to store information like that.
Code-bases grow through different phases along with the company - there's the "we need to ship the MVP, so just comment that out" codebase, then there's the "we're starting to understand the problem domain better" phase, followed by the "I just read a book by Martin Fowler/Uncle Bob, and I'm going to fix all the things", then the "wait, the problem domain is hairier than we thought, let's iterate on this", then perhaps, depending on company dynamics, the "a charismatic senior developer convinced enough people to use <technology X>, so we started moving towards it" followed somewhat later by "well, the senior dev left, and everyone decided that X was bollocks" moving away...
Or perhaps the entire model of the system changed. Your batch ETL pipeline delivered yesterday's data in time for start of today's business, and that was fine for a few years, but now the sales team want today's data refreshed twice a day, hang on actually, we want it updated every hour, now we want it updated within five minutes.
Code written for old paradigms always look crap when all you know is the new paradigm.
Think a back-end that concatenates XML into a big global string over the span of thousands of lines of code, then passes it to a function that parses it and outputs it again as JSON. Think functions spanning a thousand lines with triple-nested switch/case and if/else blocks Think a front-end where JS is used to concatenate HTML, CSS and more nested JS together into a string Said front-end will save and reload the currently active page on change of any form field, and there's dozens of form fields across dozens of dialog screens.
When I joined I was given free rein to rewrite it in the technologies I thought would suit best. It's been two years, at a stretch I'm about 20% of the way there. It's a project that needs one or two fully staffed development teams, but we have the budget for two people because our management resists faster growth or investments.
If you squint hard enough this is cgi-bin
This is the danger of rewrites (assuming this was not actually greenlit as a 10 year project)!
Debugging is like a murder mystery where you're simultaneously the investigator, the victim, and the murderer.
Code as if the next guy is a violent psychopath who knows your address.
I am the main consumer of most of my legacy code, so I make sure to do the best job possible.
Nevertheless, I always end up, wanting to rewrite it from scratch.
I don't, and do the best I can, to make sure the product is of as high a quality as possible, and ship it.
That way once you realize it's someone else's fault you feel slightly relieved and less prone to talk poorly about them.
It's self-deprecating sure, but I've never been a believer in the whole "believe in yourself"/pro-self-esteem mindset, if you are mentally strong enough it really doesn't have an impact on how you operate or think. There's always something more brilliant, and more stupid then you are; that poor deadline based decision has been made by both you and the person who wrote that piece of crap code. We are all the same (barring some exceptions).
Though I will say, I hate what modern program "design" has become, anytime someone mentions "sprints" you know that any maintenance you do on that codebase will be a fight uphill the whole way, there's no excuse other then an exec wanted something in half the time, just to have the poor sods that come after to be doomed to poor progress reports for months after trying to fix that garbage code they are tasked to maintain.
Unfortunately I found that it’s a hard work institutionally. Even where I found gratitude and respect of my people whose quality of life working with the software in question improved, I still was plagued by the problems of blame-assignment and career-making but futile huge rewrites orchestrated by people for whom destroying my work and denying its value was highly beneficial. I don’t know, I burnt out on this last time so hard I’ve been taking kind of a vacation.
As much as I love sustainable software development, it’s a losing battle and probably a futile goal in most of the industry. I’m just trying to accept this and move on.
Sure enough, a few years later, I was diagnosing a bug in this software, and realized it only happened in documents with some utf-8 in them. After digging a while, I found that comment.
And that probably made me actually grow as a developer. Because I write good code. I write bad code. Depending on the time of day, my mental condition and external pressures. The same like everyone else.
And I also was once placed in front of a half finished but abandoned PHP project, for me to finish it. That surely was no fun. That code was not good. And I was stressed and angry with it. But today I would no longer direct my anger at that actual person. He also just did, what he could with the given ressources. And venting anger might be therapeutic in some instances, but I am not sure, it helps get stuff done. And it definitely makes for a bad social dynamic.
So anyway, related dilbert comic:
If you have an example on github of something commented the way you think is 'correct' please post it. I hope you're not confusing high level app documentation with code comments.
"People like you are the reason why code becomes unmaintainable."
So ... what do you think, I could say of people like you and something with the internet?
In any case, I use comments in code btw. But way less often nowdays. Because comments have a tendency to be ignored and still remain there, despite the code for that comment changed long ago or was even removed. That can happen with any documenation, sure - but comments are notorious for it.
No comment is way better, than a wrong, missleading comment.
Those two statements combined is your justification (excuse) for never writing comments and why the code you and people like you write is unmaintainable.
Just write the damn comment. You're code isn't as good as you think it is. And no one can read your mind as to your intent when you set upon writing the code.
To which you just made a strawman argument of
"Those two statements combined is your justification (excuse) for never writing comments and why the code you and people like you write is unmaintainable."
You do not know me, nor my code - yet you judge about it, claiming it unmaintainable. Well, what more is there to comment on? Probably nothing.
Your attitude in infectious. It causes new developers to have the same now unfounded opinions and not write comments themselves. The cycle of unmaintainable code continues.
Otherwise, sure:
"Is it because YOU ignored them and didn't update them with code changes? Or others did so and it got past a code review? "
Both happened. And I doubt this never happened to you. And if it really never happened to you - then you either are a superhuman - or never had to ship lots of code with a tight deadline.
A few weeks later a senior engineer saw the code in passing, proceeded to rewrite all of it, submitted a PR with a 2 page description tearing into the original code. Explaining why it was terrible and unacceptable and then posted the PR into our it into our team's slack channel with some comment like:
"@here everyone please read this PR as an example of terrible engineering"
The code was indeed quite poor, and the lessons were valuable, and I took them to heart. I also spent the next 18 months actively avoiding requesting feedback, in fear of this happening again.
I think as a senior, this kind of behavior tends to really leave a lasting impact on starry eyed juniors.
Something to keep in mind.
The first few editions were snippets of my own code. I got a few token lols from other devs.
I then saw a senior had committed what looked like a gem... something obviously contorted but fairly short and understandable for if they were coding on autopiliot
`if day.isWeekday() && !day.isWeekend() && day.isMonday() { // this is a monday`
The day I posted that to slack was the day I learned never to criticize in public, even non-personally and even in jest.
If I was their manager, they'd be forced to apologize for how it was handled to the person with myself and HR on the call, and then I'd force them to read a productive feedback book.
I'd also expect they quit. I usually find people overly cruel at work are especially insecure and in need of counseling. Usually something else driving that behaviour. Most people aren't just assholes.
10 years from now, I'll be saying the same about the code I write now. And that's okay.
It was a pain but all the collective griping and work to improve it made us stronger as a group and also made us way better excel designers.
I tell the junior developers to “Write code like you have to come back in a decade with no context”
When mentoring I also suggest the most important quality is a “think skin and an open mind”.
Your code always sucks. It’s a time -vs- constraint issue as the author mentions. As context changes, code must adapt. That’s why I’m not worried about AI any time soon.
HOWEVER, sometimes we see things that no mess of external pressure and crazy circumstance could have produced. No, these gems are born out of individual madness (maybe I've even been lucky enough to produce some myself, one can hope).
Example, no. But here's a clue: they are usually accompanied by an equally insane commit message. "Magic." "Kill me." "Why not?" or the ultimate "".
One technique that helps me keep myself sane: every commit message should describe "why", everything else is in code. I like to think it prevents a lot of future problems.
1. It becomes an impulse and ends up cropping up in places where code is not just perceived as shit, but also misunderstood. And once devs aren’t taking the time to fully understand code before judging it all is lost.
2. It takes mental resources to form the useless judgment and clouds the vision with its bias once it is made. Suddenly it’s more difficult to see the nuanced angles in the code since you’ve got a useless judgement taking up mental space and resources.
3. Again it’s habit forming and becomes a barrier to thinking freshly and creatively when faced with new code.
4. It’s negative.
5. As seen here in all the comments it is rediculously faulty.
6. ALL old code gets to be shit with varying degrees of speed. ALL code bases get old. If you want to work on an old codebase, it comes with the territory. You can be a grumpy old man about it, you can be a grumpy old man about anything, but the net effect is just making you a grumpier shittier developer.
In a similar way I have some coworkers who I know do not code as well because they don’t have the patience to be detail-oriented or pursue optimal solutions by any measure from code efficiency to maintainability. That’s about the worst thing I can think of to say about another programmer… and here’s the thing, they still occasionally write solutions borne of their own perspectives that I can learn from, their code still needs to be maintained, they sometimes do improve etc. If I let the author factor in I’m still going to miss things even if the prejudgment is right 90% of the time.
Finally, I think it is healthy to like people and find the good in them even if they are paddling against the boat, if you can’t lift them up or fire them it’s making the best of the situation. If you can understand that they are humans with their own things going on, that other humans could look at you exactly the same way, I think it lifts us all up.
This is my first HackerNews comment.
EDIT: Formatting. See previous line.
Unfortunately, I was still warned that this may portray an atmosphere of non-acceptance when done in "public" channels since readers might not be aware that this was my code and that I am making a self-deprecating remark.
Honestly, I am not sure whether to keep doing it or not. I like the relaxed and jovial atmosphere that comes out of it (it's more of a joke that all of our past code is shit, and ultimately, that what we are writing today is the shit of tomorrow), but I struggle to come to peace with the PC crowd. Am I really messing it up for someone else?
The most prolific writer of absolutely shit legacy code, in my experience, was always me. I was happy I had evolved to at least be able to recognize it as shit. Sometimes I didn't yet have a better idea!
Sometimes I knew it was shit when I committed it, too. Deadlines, frustration, tip-toes, and maybe even imposter syndrome contribute to that.
It's a good reminder, and I appreciate others taking care to build others up.
But not at the code, I fully understand how code can become hairy, deadlines can be tight, etc. No. I'm pissed at my team (I'm new) who didn't have time in the past 5 years to even attempt to clean this shit up.
I found that usually code written around and after 4pm tends to be like that and generally try to avoid more serious stuff in late PM.
legacy software or shit software? The two are not the same. So be clear with your statement, to circle it back to your intro, you're the creator of the _shit software_ -- right? That's what this is about? See how difficult it is to admit it. You couldn't even do it and you're writing the blog post about it. The ego is strong. But, I guess you're on the path towards this acceptance, you kinda semi-admitted to it. You have much more work to do but one day you'll finally understand this distinction and it'll be good for you and all the folks that have to maintain your shit. Keep improving your critical thinking and software engineering skills. The buck ends up with you. It's your choice what you produce and your standard of excellence. And you know what, it may be the case that the sooner you become a manager the better for everyone. That may also be a tough pill to swallow but fear not, you'll be happier... and also some content for a future blog post!
However my moment of realization was when, two years into my career, I asked the question and found out it had been me.
Here are my own personal views on the subject matter:
I am not my code, and my code is not me.
As time progresses, so will I.
To become better.
Never perfect.
In both my personal and professional lives, when this comes up or I have the thought, way too often the answer is:
I did.
Sorry for the attempt at humor (though I certainly find it both tragic, upsetting, and amusing, it's also 100% true).Edit: To add more to this, feeds train our brain to consume content which we don't even need. Search on other hand is inherently required when we are working on something cool.
Having said that, cussing is a rite of passage in our house. We all cuss like sailors.
I'd suggest that if you don't want kids to read the word "shit" you keep them off the Internet entirely for life rather than running around trying to impose your morality on everyone else.
Does it make our whole environment less professional? Does it influence us to be unprofessional in other parts of our craft? Do outside observers view us as less a profession because of it?
I don’t know the answers but I certainly worry about it. Though perhaps I’m just aging out of this audience.
This is a post on someone's personal blog with some reflections on something they saw at work. I'm not sure why we should expect him to write professionally (leaving aside the question of whether swearing is acceptable in professional writing or not).
I also wouldn't necessarily expect HN to only carry professional content - although some of what's shared here might be interesting from a professional viewpoint, it's not a portal for professionals (what even is 'hacker' as a profession? What percentage of the HN community are amateur hackers rather than professional hackers?).
Ultimately, it's a discussion forum on the internet, where self-proclaimed hackers share things they think are cool, and if others think it's cool too, then it gets shown to more and more 'hackers' until not enough new people think it's cool enough, at which point it gets shown to fewer and fewer people.
That said, we're all adults here, mostly liberal leaning, and we all grew up with the internet; a bit of potty mouth won't hurt anyone. I mean you can take the moral high ground and consider anyone using swear words as immature and move on, I guess.
I wouldn't consider the word "shit" to be inappropriate for a reader that I felt mature enough to expose to HN content and conversations.
There are existing software and methods to get around this problem of accidental censorship. Someone mentioned maintaining a professional vocabulary, and I am inclined to agree: The more you read people writing with crude language, the more likely you are to accidentally let it slip around your parents, or someone like a small child.
Anyway, on the subject of the actual post, comments are you and your future self's mutual friends.
Whether we spell "shit" or "s**t", you say the same word in your head.
Software quality cannot be pinned to a single individual. Software quality emerges from your software development process.
So, for me, it is more: "Who approved this shit?"
I once had a complicated codebase and had a extremely friendly and downright great person walking me through that. There was some things that bothered me (of course - entry level and dunning kruger). But I never uttered a word, the dev was so technically competent and overall personable guy, I tried my best not to be a jerk. He might have his reasons because we sometimes get lazy yet the contribution we make goes beyond that day and stays forever in the codebase.
That day I learned that, soft skills is the most important thing when it comes to interacting in a team. Suppress your feelings and think of the other guy. See beyond the code.
I feel like a well paid janitor.
At some point we all figure out that if every line of code was perfect, the computer wouldn’t do very much at all.
Indeed a good point, the constraint of laziness and stupidity :P
Do they never read their own code?
Or maybe they never see their own code?
if current you is always considering future you, then previous you will no longer be the bad guy when future you becomes current you.
tl;dr: pay it forward to your future self.
https://notoriousbfg.com/building-software-sharing-knowledge
https://notoriousbfg.com/code-and-context
TLDR: I don't think that poorly written code is as common as devs like to thing it is. Context is just as important in our general perception of how well some code has been written/designed. There are several ways we can and should document our code including descriptive variable and method names, commit messages, tests and PR comments.