The only constant is change. Generally true, even more so in software engineering. Shit changes all the time. Requirements, Milestones, Team Compositions, Technologies, Best Practices. Nothing is static. That’s probably the reason why I’m so intent on leading my teams to a state where they are primarily really good at adapting to change – regardless of its nature.
Being adaptable is the one true superpower a team can have. It’s of course much more than a set of behaviours and actions, it’s a mindset. The first step to getting there is to let go of the biggest obstacle on the way: the magical outcome. I’ve seen folks trying to build perfect systems. Like, really trying super hard. The problem is just – there’s no extra points for perfect, and there’s a risk of getting so committed to one specific outcome, a solution in a very particular shape, that it’s impossible to move in any other than the committed direction. Congratulations, you’re no longer able to react to change, at least not in an economical fashion.
Adaptability is about acknowledging reality. Things change all the time. Also, we learn more about the quality of our own decisions every day, with every line of code. Not all are awesome. That’s simply reality. It’s a small step from there to change the overall approach. Instead of building perfect, brilliant things, start by building small things that work. And then iterate. Incorporate learnings, undo mistakes. Change course, if needed. Be honest. With every move, make sure there’s a path to somewhere from where you’ll end up. Build small things – that can be changed. Optimise for functionality, then for changeability of a system.
Technically, there are a number of measures that can help to build systems that can be easily changed. Mature build automation, automatic checks and tests and a great developer experience are not nice to have, they are essential if your default state is, well, changing the thing. There’s also a ton of best practices to make sure you’re resilient to change – loose coupling, API versioning and so on are great strategies to make it easier to react to change on a technical level.
The bigger change is of an organisational nature. If you want to lose friends quickly in a leadership sync, suggest refactorings that are not tied to some business initiative. Reality is – the shape of our solutions need to change according to observed changes in the shape of our environment. If we learn that we’ve built something that’s hard to operate or prone to errors, this is where investments needs to happen. If the projected throughput increases by a factor of ten, but the thing is already reaching its limits now – what are you gonna suggest? Every shit system was enabled by folks completely misjudging on which side of the sunk cost fallacy they placed their bet. The best way to not get dragged down into an abyss of technical debt and sadness is to treat the status quo as nothing but a discardable snapshot. A snapshot that needs to be constantly evaluated if it’s still the right thing. Being overly attached to existing solutions, for whatever reasons, will prevent change. Even if that change clearly needs to happen.
Of course I’m not advocating for perpetual refactorings just to make stuff better. What I’m saying is: If you need to build something simple, but your current system is making that hard, your system needs to change first to make that change simple. You’ll have far more changes down the road. If all of them are hard, how’s that economical? Or fun?
Someone once said it’s not about the destination – it’s about the journey. I couldn’t agree more.