Get things done instead of making your code perfect
For many years, I’ve been working mostly as a subcontractor, either forming an in-house team or extending one on the side of my client. I’ve had a chance to work with many teams, on various codebases — starting new projects or developing ones that have been existing for over 10 years. Some in good shape, others a bit rotten by the large amount of changes over their lifetime.
As with anything, experience is the best teacher. In programming, most of the time you get to work with other people, who (un)willingly shape your career and I was no different. Looking back, not everything had shaped me in a good way.
The beginning of my career was very fruitful when it comes to the amount of useful tools and tricks I learned, in what was a surprisingly short time — it’s amazing how fast getting to work on real projects provides you with very useful knowledge. This was no longer my own playground or school, but the real world, where things moved at their own pace and I had to adapt to survive — in other words, I needed to see through the not-so-useful stuff and acquire the very skillset required, in order to move things forward, or to keep them running at least.
Take git for example: before that, I would push my code to an FTP server. I still remember how the idea of version control applied to the code felt so complicated and very foggy to the newbie-me. Luckily, on my path, I met some people who did a very good job of guiding me or pointed me to great resources and that’s why a lot of things clicked back then. Every day or so, I felt myself having some sort of an a-ha moment. I learned how to write better code that would benefit the project. Every now and then I would pick up some “best practices”.
Speaking of best practices — while most of the time they were of great use to me, I believe other times I relied too much on them, which backfired on me. It all looked so great, reading “Practical Object-Oriented Design” by Sandi Metz as a newbie — but then the newbie landed on a project which was nowhere near the landscape the book promised. Sometimes, I would find myself paralyzed. The amount of time to complete a task was limited — and it usually revolved around adding more code. Very little of refactoring or removing it — not all projects had the luxury of doing that and not all clients appreciated it.
Very often I’d feel bad after having deployed a new thing, even though others, be it a business owner or his clients, loved it. In the back of my head, there was this image of spinning plates and me, just casually throwing another one on top. Right now, of course, I believe this was the right thing to do — I might have worsened the code quality but in the end, I kept the cogs turning. Yet, for a very long time, I would judge the “coder me” by the perceived quality of my code that made it to the production, instead of its usefulness — and it was possibly the biggest mistake during my career.
While these tools that are supposed to improve your code quality became part of my reality, I relied too much on them, which had a crippling effect on my productivity. Take static analysis tools, for example. Rubocop is one for Ruby which consists of dozens, if not hundreds of checks, which prevent you from doing some things with your code which are widely-accepted to be bad. For example, writing methods that consist of more than 10 lines of code. Or methods that are too complex, based on ABC metric and more. When I first learned about Rubocop, I was amazed. Finally, there was a tool, which would guide me, how to write good code, and even better — I could run it with a certain flag and it would fix most of the errors by itself.
Little did I know, time after time, I fell into a trap of trying to write the perfect code. I wasn’t happy if I’d written just some code — it needed to be perfect. And in my case, the perfectionism itself was very wrong (it rarely is good, by the way) — I aimed for things that were important to satisfy my ego, rather than what the business needed. My environment stressed writing clean code more often than getting things done, which made my brain pay more attention to the former. That doesn’t make it any less of my own mistake — I’m emphasizing on the fact that I was stuck in an echo chamber for a long time, which made it even harder to see things clearly.
Very often having a feature with an okay code became secondary to having it with the perfect code — no Rubocop errors, all sorts of automated tests and whatnot. Now, there is nothing wrong with tests — in fact, I encourage everyone to write them. The problem in my case was, that instead of consciously writing them I aimed for the numbers. It all became about them. Zero Rubocop problems, single responsibility, three-strikes, less than ten lines per method, as many as possible small, but not necessarily maintainable unit tests. I was so busy wasting my time on unnecessary things and all I needed was to step outside and take a look at the bigger picture I was missing back then:
No matter how much time you spend on polishing your code, in the end, all you get is a bunch of zeros and ones. Your client most likely won’t care about you adhering to the best coding practices or the fact that you used one of the 2 Hot Tricks 99% of Ruby Developers Don’t Know About (Number 10 Will Blow Your Mind) in your latest pull request. There is a chance that refactoring your code just so it passes all the checks, will actually make it less obvious to other developers working with it — and this should be far more important.
Since that realization, I have drastically changed the way I approach coding. The funny thing is that it was actually the ugly code seen on other projects that made me reevaluate what’s important. That code may be ugly, but last time I checked, it solved more problems and made more money than one of my side projects, abandoned because I could not decide on the code style and got stuck on setting up complex pipeline of bullshit. As long as people won’t be hurt or die because of my imperfect code, I’d rather fail fast. Failing means that at least I’ve taken an action. Perfecting code was good for the old “code artisan” phase of me — but not for getting things done, or finding the right balance between code readability and productivity, which is at the core of what I aim for.
The key takeaway is this: Don’t repeat my mistake and try to break your work habits regularly — make a conscious attempt to reevaluate how you work and whether you really are focusing on what’s important. No matter how fine things appear to be.