As a perfectionist, by definition, something is only ‘good enough’ if it is perfect.
I really struggle to live with untested code, or shoddy code, or duplicated code. I come from a world where code can be beautiful, and code is the thing I have complete control over, something I understand and can make better through my own actions.
I seek to make the world a better place, one line of code at a time, even where the ‘world’ is often no more than a small bubble of half a dozen colleagues who will see the benefits.
I seek to optimise my world as much as possible. If there’s an element of manual labour to any of my work, I’ll try to automate it. Once I automate it to the point of just having to run a command, I’ll try to find a way of automatically triggering the command too.
I see technical solutions as beautiful things, especially when they make the right use of inheritance, of micro-service architecture, of scalability and of reusability; when modules are perfectly-named, comprising of small, discrete functions, throwing testable, well-defined and expected errors.
Any sub-par solution in this ecosystem sticks out like a sore thumb. My first reaction, my overbearing, immediate, overwhelming instinct, is to go in and fix it, whether the fix takes 20 minutes or 20 days to implement.
Lately, I’ve been trying to distance myself from this idealistic view of the world, and put my business hat on instead.
I need to remind myself that code does not exist in and of itself, and is not, in isolation, of any use. Code is written purely to fulfil a business requirement. Without the business, there would be no requirement and there would be no code.
I need to remind myself that the business has aims and objectives. It cares what gets delivered on the surface, and not necessarily what is happening beneath.
Obviously, the business cares that any technical solution is robust, performant and maintainable. There is an increasing awareness from non-technical stakeholders that these non-functional requirements are, indeed, requirements, and not merely some utopian whims from egotistical, precious, pretentious programmers.
But ultimately, the business will have a thing, or it may have lots of things. The thing is written in code. The thing works. People are using the thing. The thing is achieving its business purpose.
It may have the odd bug, in which case a fix will be prioritised. It may need the odd enhancement, which can be iteratively delivered. But ultimately, it’s a thing, it’s providing value to the business, and it’s good enough.
“But the controller has business logic in it! This needs a refactor!”
“I don’t like all these if-else statements – can’t we use the dictionary pattern?”
“In our new service X, we moved this authentication logic to its own module – shouldn’t we now update our old service Y to use the same module?”
Can the change be justified?
We hardly ever touch ‘service Y’ anymore. It’s still being used, it does its job, it’s not fallen over yet. It’s a legacy piece of software – we have new features we need to build. Do we really want to go ahead and start refactoring this old code which might be getting retired soon anyway?
Can we justify to the client that we should spend a sprint refactoring this stuff, addressing all the technical niggles, when really, on balance, taking a step back and looking at what we have… it’s not terrible.
I’m lucky enough to work in a place which gives more freedom than most to make refactor decisions which aren’t business critical. However, in my freelance work I am charging an hourly rate, and have to be constantly mindful of whether I’m developing for my client or for my ego.
In 2014 I built a WordPress site for a client, from scratch. It was my first WordPress site, and it grew to become quite complex, amounting to quite a bit of code.
In 2015 I was commissioned to create four more sites for the same client. These four sites had quite a lot of shared functionality, so I architected them in such a way that I could write the shared functionality once and all the sites would benefit from this shared ‘common’ theme, before developing four small child themes which override where necessary.
My dilemma: the perfectionist in me is crying out to refactor the original 2014 site, converting it into a child theme and inheriting from the common theme in the same way as the other sites. It feels like the right thing to do, saving me from duplicating fixes across two codebases and making for less of a learning curve for any new developer joining the project.
But undertaking this refactor would probably be a couple of weeks’ worth of work. By the end of the refactor, I may even have broken parts of the design or functionality, sacrificed for the sake of simplicity and consistency with the sister sites.
The truth is, this refactor would be of a benefit to me, but not the client. I can’t in this case properly justify what I want to do, even though it feels like the right solution. It’s really not so bad to duplicate the odd bit of code.
I need to keep telling myself: what I have is good enough.