General Software Learnings

1. Writing good code is hard

Writing code/designing systems which are open to extensions and are flexible is hard, really hard, and losing sight of the bigger picture when implementing a small fix is super easy.

We can always put an if and get done with it, easy right? Or, we can handle it in a way which is consistent with the existing design. Doing things right takes time but be ready to put in extra time as the gains are much more.

It’s almost never worth adding hacks (yes, no one comes back to clean things up), a code is written once but read hundreds of times.

2. Bugs are never intentional

Most developers tend to ignore test cases while writing code as tests are extra effort right? Nope.

Over the time the original committer of the code isn't always the maintainer/reviewer so in that case its the test case which will prevents bugs on production. Extensive testcase driven codebase are always welcomed by new contributor as its pretty to mess things up.

Again, put in the extra effort as in my own experience putting X amount of time in writing testcases at least saves 10x developer time on finding/fixing bugs and saves company losses due to stupid bugs on production.

The cost of fixing things (if at all possible), almost always outweighs the tiny gain of not safeguarding.

3. Multiple knobs are dangerous

Guarding changes is good. Having multiple knobs is dangerous.

Ask, do I need to change things at multiple places to achieve a single objective?

For ex:/debug/pprof/* has two flags. One at application level (isCodeProfileEnabled) and one at ingress level (isProfilingBlocked)

So if isCodeProfileEnabled = true and isProfilingEnabled = false Next member will keep wondering why its not working? Not everyone in your team has all the context.

Have a single knob (extend it) for a single behavior. In case there has to be multiple touch points, document/enforce it at all the places.

4. Iterate fast

Initially never strive for perfection, If you do it will lead to no usable product coming out for months which generally isn't an option.

Always have a vision on the perfect way to implement something but it is equally important to iterate on the solution and keep getting new versions out, not blocking on a perfect system. Divide the project into milestones and welcome suggestions you get and incorporate them into your versions. This will actually lead to much better product than initial perfect system(as this time you know users opinion too).

Small iterations also relieve pressure of delivering so that is a huge plus.

5. Code is cheap

You might have heard "Talk is cheap, show me the code". This isn't true most of the time unless you are the guy who said it.

Think twice, code once. Before adding any hacky fix think of the developers who are gonna visit the same flow again.

First develop a clear picture in mind on how to approach a fix/feature before diving down into code.

In coding interviews, If you get a problem then spend 35-50% of time chalking the approach on paper, coding after that should be quite easy.

6. Don't predict

It is exciting to build something which is not needed right now to feel you gonna just move the task to done when that particular requirement will come and feel you are awesome. But in reality when that requirement will come your already written code will render useless. On top of that, your extra written code will add cognitive load on the project as its like a dead code which won't see the live traffic if it ever does.

Be lazy in these things, only add as per the requirement no less/no more.

7. Write welcoming code

Don’t make systems rigid to extension. As said on point 6 never add extra but don't make the code such that nothing can be added into it.

Design patterns we study in courses are a huge help here. I try to follow hexagonal patterns, S.O.L.I.D principles and lot others while designing services from scratch as they are most viable to extensions in future.

8. Simplify core use-cases

The most frequent use case should be the simplest possible even if it means making the rare use case a little harder.

For example: In rider assignment service, the assignment logic should be as easy and straight forward as possible. Always remember lesser the code, lesser the bugs.

If you are implementing something with lot of custom hacks, loopy code then that code will be the very first code you will end up refactoring in future.

Follow K.I.S.S (Keep it simple silly)

9. Welcome feedbacks

Always welcome constructive feedback with open arms, either we’ll know what we can improve on, or, we know there has been a gap in what we are doing and what it is perceived as.

Especially in code reviews, keep your ego aside and appreciate/discuss feedbacks of other people. Most of the times they will give you a different view to looking over a particular problem.

Needless to mention but try to become a listener. When you only say then you only say what you already know! Listening will make you learn new things.

10. Welcome the unknown

It is easy to get comfortable with learning a few things that are needed for day to day work and not explore other tools/frameworks or skills.

Try to explore BFS( breadth first search) manner as it will help to come up with alternatives when designing a solution. After that go DFS(depth first search) and learn the internals.


All above learnings were observed or realized over the time from different sources in person, experiences or through the internet shared by amazing folks. If you have something else to share pls do so by pinging me here.

If you like, do share with other folks.

Thanks!