10 years of programming: Lessons Learnt


I wrote my first program around 2006 or thereabout – it was some toy program for the FORTRAN course at school. Ever since then, I have been given the opportunity to take on more challenging programming tasks. It’s been a heck of a journey for me and I am very grateful for the learning, the mentoring from rockstars and the chance to do exciting work.

Looking back, I have learnt a couple of lessons the hard way and wanted to share some of these so that other engineers know what to avoid. These are my rules of thumb currently (in no particular order). Enjoy and let me know your thoughts in the comments!

1. Write plain simple code

Code is meant to be read by computers. Computers and compilers could care less. So if you are feeling super smart then write in 0s and 1s; otherwise, please write extremely simple code.

When exceptions arise necessitating unorthodox or clever approaches; please do add comments and also create documentation. This would help the poor fellow who’s going to maintain it in the future (most likely you).

But why should we avoid clever code? After all, how else does a programmer show off his cool tricks?

if all you have is a hammer, everything looks like a nail – Abraham Maslow, 1966.

The problems associated with smart code are plenty –

  1. They require a higher level of concentration to understand
  2. They are prone to bugs since the smart fluff can hide bugs
  3. They can nearly always be simplified leading to smaller code and bug footprints

Suppose you have a pounding headache and your doctor orders you to buy any non-steroidal anti-inflammatory drug (NSAID). Imagine trying to decipher what NSAID stands for while coping with the raging headache. Not fun eh… What if the doctor told you to buy Panadol (substitute with Tylenol or Ibuprofen etc.)? That’s the similitude of simple vs smart code.

One way to simplify code is by avoiding surprises and establishing consistent patterns. For example, consistent naming patterns, predictable branching styles or standardized design patterns.

Why does this matter? Well it allows someone else to pick up your code, see the structural pattern and then extend it. There is a common language that everyone understands which makes deviations and buggy approaches easy to spot.

But writing dumb plain code is not so easy; so let’s go on.

2. Make it work then clean it up

While working on Odo, the JavaScript Stream library I wrote last year, I  agonized a lot over getting the perfect style. At times too, I catch myself trying to create a masterpiece at the first attempt.  The truth however is that this doesn’t happen often; maybe if you are Donald Knuth.

Most authors do free-flow writing while trying to get their thoughts together; afterwards, the editing and clean up occurs. Why do you think we have book editors? Coding is similar too; rather than rewrite that 3-line function 20 times, why not get the app working and then start refactoring? It’s much faster and code reviews would help catch coding issues you might have missed (just like editors with books).

Typically I just write and get a feature out, then I take a fine sieve to it. All the rules now come into play: DRY, YAGNI, code simplication etc. I do try my best to make it read like poetry (yes I am serious).

3. Never make the same mistake twice

Yes, once is good enough. Twice is bad.

You shouldn’t be shy of making mistakes, no human is infallible but what should scare you is making the same mistake more than once. Do a retrospective after completing each feature to learn what could have been done better and learn from missteps.

I recently took a long amount of time to implement some core software in an unfamiliar area, why? My initial assumptions about existing data structures were wrong and I found out a while later. It wasn’t so difficult to pivot to the right structures and then I ran into another issue – the helper functions I relied on didn’t behave as I expected they would.

Looking back, I could have written tests earlier (instead of later) to validate expected behaviours and also clarified assumptions with senior engineers. Lesson learnt.

A respected senior engineer explained it thus to me:

Junior developers might take a day to realize they are on a wrong path while senior engineers have enough experience to avoid such drains.

Good judgment comes from experience which involves making mistakes and learning. It’s OK to stumble and make mistakes, but please review each one and learn from that.

4. Know where you want to go

How do you get to China? Start heading east. Once you have a target, it is easier to calibrate your efforts and see if you are moving in the right direction. Unfortunately, most software developers never set goals and then get caught up.

The software engineering profession is remarkable for having rapidly changing and moving targets. Currently, the big areas include cloud computing, security, big data, artificial intelligence and AR/VR. Are your skills stagnating or positioning you to shine?

Having a general blanket target (e.g. I want to be a 10X programmer) doesn’t work; there has to be some specificity to it. So for the one who aspires to be a 10X programmer, the next question would be in what areas do you want to excel? Are there examples of such 10X programmers to copy?

Think again; do you want to extend the frontiers of computer science? Design the next Hadoop? Or author a widely popular book / open source software piece.

Know where you want to go and then start walking.

5. Task Breakdown and Estimation

You are to build a brand new calculator app; your manager wants it delivered as fast as possible. How do you estimate the amount of work required and when it’ll be ready for the customer?

How do you eat an elephant? One bite at a time…

The calculator project can be decomposed into modules like the core engine, the user interface and the data storage mechanism for calculation history. Each component should be broken down into smaller chunks. After breakdown, the engineer typically knows the pieces of work that needs to be done before he completes the project and can start implementing each phase.

This quickly becomes tricky when there are multiple people working on the same project and you need to coordinate integration efforts, release dates and project quality.

Always keep in mind the end goal of shipping the software and prioritize tasks accordingly. You want to maximize your return on investment so pick tasks that move you closer to the end goal.

6. Quality

Nope nope nope, testers shouldn’t find simple bugs in your code. You only want them to find bugs that occur when you press 10 buttons simultaneously while doing one-handed push ups standing upside down.

If you don’t find and fix your bugs; your customers will. And they won’t be happy.

Do the right thing; test the happy path first. Then, verify that there are no monsters lurking in the dark corners. Take some time, maybe 30 minutes, to rigourously exercise the code.

I typically write unit tests while completing the feature. Then once it’s ready, every discovered bug gets its own unit test. This helps to protect against regressions in the future. Aside, those unit tests provide active ‘documentation’ of the behaviour of the software.

Don’t compromise on quality – it’s the sign of good software and a great programmer.

tl;dr?

Have been writing programs for some time, made mistakes and learnt lots of lessons.

Do share your thoughts in the comments – would love to hear them!

Advertisements