How I Code
One of the things I like about the way the tech industry has changed since I cut my first production code is that even the senior guys and girls are expected to be able to roll up their sleeves and hack some code every once in a while. I don't get to code every day - sometimes there's too much running around keeping teams fueled with work and preventing fires from reaching their door - but every once in a while there's a thorny problem to solve and the best way through it is for me to jump in and start pair-programming.
So... 25 years of programming experience (14 of those getting paid for it) later, what does that look like?
Trade secret: These days, I'm a terrible coder.
I get bored easily. I've written too much code already. If I can't express my idea in about 500 lines of source (ideally under 100) then I'm not interested. If it takes more effort than typing docker pull
and docker run
to set up my stack, then I can't bring myself to care about it. Any time that I have to start dealing with fiddly OS issues like clipboards not sharing across a connection or SSH keys not being recognised then I rapidly get irritated with the computer and go off for a cup of tea instead.
There are whole classes of problems I can't be bothered with any more. I hate messy, side-effecting details like file I/O and persistent state. Clustering sucks, so I want everything I run to be read-only and immutable. Anything that involves touching a GUI for an operation is an extended yawn I could do without.
To cut it short, I am lazy, irascible and dislike any problem which can't be solved in one line by some variant of Array.filter().map(). So how the hell did I ever get to be in charge of telling people how to do this stuff?
The reason is that while I'm not so fussed about the nuts and bolts behind the scenes, I love solving problems. In fact, that's an understatement: when there's a problem in front of me, I have an almost single-minded dedication to fixing that problem and fixing it well.
This is what makes me a terrible coder. Self-professed good coders will constantly tell me about the things I need to be doing: "oh, you need DI for that problem", "you need a mapping layer", "everything should follow the decorator pattern", "you need 100% test coverage", and so on. Tickbox, tickbox, tickbox without really solving the problem at hand. I on the other hand don't care about something unless it's making my life easier. All I want is to solve my problem.
With that in mind, here's a short list of things that I've found are guaranteed to make my life easier no matter what I'm doing:
- Automated build and deployment
- Tests for complex and counter-intuitive behaviours
- Statelessness
- Immutability
- Monitoring and logging
Think about what isn't on the list. Most of these are not coding activities. There's nothing there like "use patterns" or "apply this framework" or "add a message bus" because those are only appropriate to some problems. I don't have "test everything" or "use IoC" because that's cargo-cult checkboxism. Maybe they solve today's problem, but then again maybe they just make it more complex.
What these things are is thought activity. How is my stack going to get set up? What am I going to do that has complex logic or interactions? How can I minimise the amount of state I have to deal with and keep it locked away in its own hive of scum and villainy? How am I going to know what's going wrong with this and why? These are far more important to me than deciding what design pattern I'm going to use today.
When I answer those fundamental questions I'll end up with maybe 2-3 nice things to build that each fit in my head easily, and one hairy bundle of state and nastiness. But wait! That big bundle is just state at this point, so chances are it fits into a class of problem someone's already solved and I can grab a relational DB, graph DB, key-value store or whatever off the shelf and glue it in. Ditto my messaging, and if my messaging is pretty standard then I've probably already got monitoring stacks kicking around that I can plug straight in... and now I'm writing a few services that are a couple hundred lines of JavaScript apiece rather than a 30kloc C# monster that reinvents several wheels along the way.
Of course, once I'm only dealing with a small amount of code I don't need all that DI and reflection-based mapping between dozens of different DTOs. Chances are I only have one or two things to stub or mock (remember, I want to test only the difficult bits that are challenging to refactor or might break downstream clients, not the "does JSON.parse() parse JSON?" nonsense I see strewn around in the name of 100% coverage) so my cognitive workload and execution time are best served by just newing these up rather than throwing in a huge framework to do it.
Now this kind of supposedly slapdash, cowboy stuff is no fun unless you can inflict it upon the world so I also want to deploy it. This is where my impatience really comes to the fore because I know that if I'm manually hacking a config file or typing a password on my first deployment, I'm still going to be doing it on the hundredth so I may as well get irrationally angry about it and make it all automatic right at the start.
By "automatic", what I mean nowadays is to containerise the hell out of everything and use environment variables to control the few things which change between development, production and whatever's in between. If I got my thinking about immutability right then I don't even have to worry about data volumes or other icky storage-related details - just run the containers wherever, wall it off from the Internet at large, figure out how to register them with a load balancer or service discovery layer, tweak your firewall rules to allow the appropriate traffic and you're done. Stuff is running.
The point here is that you don't need to get hung up on being a great coder and ticking all the boxes, because most problems don't actually need a great coder - they need someone who's able to think about what they're actually trying to solve, and what's actually going to be necessary to get that solution up, running, reliable and in the hands of the customer. Being lazy actually helps, because you think mainly in terms of what's going to be the least effort to code, deploy and support. (I will caution that you do need to be the more holistic kind of lazy where you look for the global minimum amount of effort, rather than the immediate goof-off.)
So yeah... how I code? I don't, really. Instead, I solve problems.