10x Engineer: Pivoting out of bespoke solutionsSunday Jun 6, 2021 | Series 10x Engineer
Ever felt like your team isn’t able to deliver the flexibility you would really like? You’ve put in a lot of time to make sure you’re resilient, you barely have down time, the agile process is highly optimized. Still the new feature requests are piling up and it is getting harder and harder to keep all the happy flows straight.
It might be time to shift who your customer is and treat your services as a product instead of a bespoke software solution.
We as engineers have all these wonderful guidelines about how to keep codebases easy to understand and maintainable. However the real world tends to want to interfere and it usually wins. There is a tight deadline for a new feature. This one change is only for this part of the flow. This edge case only applies when the stars align… I’m sure we’ve all experienced them.
A few months later the request comes up to add a new flow and some of the previously mentioned edge cases apply. But not all of them of course and a slightly different mix compared to any other flow, right?
At this point you realize you need to do some refactoring but where are you going to get the time? Let’s have a look at how we can make small steps to a more configurable situation and possibly offer self service solutions.
The business case
Let’s go back for a second to my remark about guidelines. One that I’ve seen repeated and actually like myself too is the ‘rule of 3’. The third time you have to implement something you should make it generic or ensure the code is shared.
The same case can be made for a lot of refactoring cases. On the business side it is a hard sell though. “Why would it take more time to implement X when you did it before in less?"
Which is a fair question, here it becomes important to have a bit of an overview of your domain. These are my go to questions to keep in mind for that.
- Do we expect more of these kind of changes in the future?
- Do we open up more possibilities if we make this change?
- Do we empower others to do things themselves without IT support?
These all fall in the category of ‘what is the impact of this change’. Even if it is only a day or so of work, if it comes back often enough it is worth it to invest 5 (or so) extra days now to allow others to do it themselves. It will get done quicker as the work doesn’t need another party to plan. Your own team can focus on other things. And future small changes to the way we configure things can open up more possibilities. For example maybe a/b testing.
How to prepare
The business case is very dependent on the exact situation so that is an excerise that you have to do on your own. However we can look into a few ways to make sure we don’t end up in as deep of a hole as could be the case.
While we shouldn’t overengineer our solutions there are a few things I keep in mind to make sure I can pivot when it makes sense.
- Keep as much of the code as generic as possible and isolate case specific logic and load that dynamically.
- Make things configurable when possible
- Stay informed about the direction the business wants to go and how they work or want to work
- What is the workflow
Separate generic and specific code
This one is probably the most well known ones but also easily forgotten when focussing on delivering a story. We have a lot of tools in our arsenal to make sure that we separate the two. For example I like to use the strategy or visitor pattern in some form.
Or in earlier stages I like to keep things separated with functions, so later I can easily extract that to its own class once I have a second variant of something. Where the third would make me rewrite it a bit further into some pattern.
You do have to keep a sharp eye on it and possibly a good memory to remember that somethings are being repeated.
Making things (capable of being) configurable
My mind usually immediately goes to some configuration in a database. But that is not where you want to start for obvious risk of overengineering. No, configuration can start as small as putting some values in variables instead of inlining them in code branches.
After that try to group them in configuration classes. No need to load them from file or database yet, they can be hardcoded. Later we can turn that configuration data class into a serialized file, table or whatever framework you like. At least we already have it centralized and portable, so when the time comes to pivot to a full on configuration we don’t have to refactor the entire code base.
Where are we heading
Next point is probably the most challenging one. Staying informed of where the business wants to go. In an extreme example, if you’re about to add a third variant of some code branch but it’s 100% certain that there will never be more. Then there really is no need to ensure that you can configure that for the future.
But something that takes the team a few days every 6 months gets interesting to make easier. It could very well be that the business really would like to do it once per month, but without consulting the team decided that it isn’t worth the investment. All because neither side could see all the options and wishes.
What is the underlying workflow
A component of the question ‘where are we heading?’ is ‘what do we need to support?’. What kind of work and results are those that use our software trying to accomplish. This should and can influence what parts of the sofware are likely to be subject to ‘frequent’ change. Or what parts would enable others to do more without needing to align with the roadmap. Or maybe even make it usuable for more people.
A small example
A few years back my team was working on extracting our e-mail system from the monolith into our new microservices architecture. This meant pretty much a complete overhaul of all the mails we had. There were 10s of different templates and counting those that really should be owned by other teams it was over a 100 if I recall correctly.
We worked closely with a designer and business analysts, the first couple of emails we treated standalone. But the further we got along it became clear to me that we could reuse quite a few elements between templates. The design principles were the same after all.
On top of that the design had to get some tweaks and keeping those small tweaks aligned between all templates was already becoming a nightmare to keep straight.
So I decided to build some tooling, divide the design up into reusable components so we could compose instead of build new templates. The components were a mix of structural components (e.g. single column vs 2 columns) and visual components (e.g. icons, calendar, banner). All of them were made nestable and thus composable.
Now a few years later we added a workflow on top of it and have 10 to 15 teams manage their own templates. They have no need to know about the details of e-mail html (oh boy…) or have to bother us aside from a merge request and an introduction if they’re starting out with their first. Without that tooling and making those templates composable/configurable my team probably wouldn’t be able to do any other work.