Something that shocked me was working with junior programmers for the first time. For decades, I had either worked solo or with other experienced developers.
It was an eye-opening experience.
My style is influenced by Haskell and Rust, even when I program in, say, C# or PowerShell.
A simple example: I will extract the read-only logic into a pure function and minimise the size of the mutable procedure. This makes it trivial to test the logic in isolation without triggering any side effects. Similarly, the logic can have convoluted control flow but the imperative code can then wrap that with a single try-catch block, transaction, or retry loop.
For me this was such second nature that I didn’t even realise I was doing it until I saw the imperative spaghetti written by the juniors. I tried to explain with pair programming sessions what the benefits are of my approach.
Without fail, they would just “hack something” into the existing spaghetti, adding yet another mutable global variable to track some new state.
In every case they said they were in a hurry and that they would “fix it later”.
> In every case they said they were in a hurry and that they would “fix it later”.
This. We need to stop using time pressure as an excuse to do a bad job. Moving things out to a separate function might add 10 min but save 100x when everything comes crashing down.
Of course you shouldn’t overengineer but so much can be gained from spending a little time just thinking about how this should work.
This is my current struggle. I've enjoyed mentoring in the past, but right now I'm getting very exasperated feedback. It's hard because I don't have control of the environment to alleviate the deadline pressure, but I still want to help people learn. The end result seems to be a pile of tech debt for now. C'est la vie.
Something I observed very early on in my career is that bugs will have to be fixed no matter what. You can put them on the todo list and fix them later, or fix them right now. Either way, you're going to have to do the task.
It's like a conservation rule in physics, for every bug found, a bug fix must eventually be implemented. Bug in, fix out.
But... if you leave a bug lingering, then it can cause test failures for unrelated code development. It can trip up other developers. It can cause false positives until resolved.
So the only logical conclusion is that all bugs must be fixed ASAP, otherwise they have a "multiplier" factor dependent on how long they're allowed to persist. If left unchecked, this can blow out exponentially, until you're unable to efficiently fix bugs because you're tripping over thousands of other unfixed bugs while doing so.
You would think this kind of thing is logical, but no-one ever believes me. There's just slow blinking and then a slower repeat of the same old mantra: "We'll fix it... later?"
I agree. I think a zero defect mentality keeps things moving along smoothly. Unfortunately, people think I'm just being a perfectionist. I'm just trying to not trip on the treadmill. Every bug is another stumbling block.
It was an eye-opening experience.
My style is influenced by Haskell and Rust, even when I program in, say, C# or PowerShell.
A simple example: I will extract the read-only logic into a pure function and minimise the size of the mutable procedure. This makes it trivial to test the logic in isolation without triggering any side effects. Similarly, the logic can have convoluted control flow but the imperative code can then wrap that with a single try-catch block, transaction, or retry loop.
For me this was such second nature that I didn’t even realise I was doing it until I saw the imperative spaghetti written by the juniors. I tried to explain with pair programming sessions what the benefits are of my approach.
Without fail, they would just “hack something” into the existing spaghetti, adding yet another mutable global variable to track some new state.
In every case they said they were in a hurry and that they would “fix it later”.
I replied: “there is no later.”