DEV Community

Cover image for Coding practices your future self will love you for
Arpit Mohan
Arpit Mohan

Posted on • Updated on • Originally published at appsmith.com

Coding practices your future self will love you for

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

  • Martin Golding

Here are 6 coding practices that I've adopted in the past 10 years to ensure that my future self has fewer sins to forgive.

1. Standardize code formatting

Any codebase is read a lot more than it is written. Code with consistent formatting is easily readable and comprehensible for everyone in the team. Standard formatting ensures that your eye, and your subconscious, can look for variables, braces, functions, etc seamlessly. Golang does a great job by providing the gofmt command in the standard library. This ended all formatting discussions that come up so often in code reviews in the Golang community.

2. Don't follow the DRY principle blindly 

DRY (Don't Repeat Yourself) is almost a mantra for developers. But if applied indiscriminately, it leads to abstract code that’s hard to read & understand. It also stops different parts of the code to evolve to their full potential. Do not follow the DRY principle blindly. 

It is a good idea to copy-paste the same function a minimum two times in the codebase. Only when you see the same requirement a third time, should you refactor the code and apply DRY. Doing this ensures that you are not prematurely assuming that two problems that looked the same initially, are still going to remain the same after a period of time. When you come across a similar requirement a third time, you have some data on what parts of the code are common. You also have three instances of repeated code to create a good abstraction. 

3. Debug code via logs 

Practice debugging code on your local machine via logs instead of a debugger. Debugging on your local machine ensures that logs are added at the right place. This, in turn, makes sure that you can debug production issues quickly because you would have gone through this cycle on your local machine before. Remember to not get too excited and add unnecessary logs everywhere. It will clutter your log file in production.

Too much logging == no logging.

4. Beware of premature optimizations

A primary goal of code optimisation is to improve performance. More often than not, performance issues are not where you think they are. Always benchmark your code before starting to optimize for performance. Without benchmarking, how will you ever know whether the code changes you make have any real impact on efficiency or not? Premature optimization, especially micro-optimization, is not a good idea because you don’t know whether you are working on removing a performance bottle-neck or not.

As a corollary, this doesn't give you the license to code like the wild west. Don't get the computer to do work that it doesn’t need to do just because you got lazy and didn't think of the most efficient way of solving a problem.

5. Don't complicate your codebase with unnecessary features

Don’t complicate the codebase with features that no user has asked for. This is a problem you need to avoid in early product lifecycles. Startup teams tend to assume that building more features will help them find product-market fit faster. This is an anti-pattern. Adding unnecessary features makes the code harder to read & debug. When new developers come on board, they will find it difficult to differentiate important code paths from the ones that were added on a whim. Eventually this technical debt slows the entire team down.

6. Setup a CI/CD pipeline early in the development lifecycle

Even if it’s a one-wo/man show, a CI/CD pipeline reduces the overhead of remembering (& doing) the build & deployment of a particular codebase. The common assumption is that CI/CD pipelines are important only in teams that are pushing a lot of code into production every day. In my experience, CI/CD pipelines are even more important for codebases that are rarely touched because you won’t remember how & where the code was deployed. This is especially true if you are updating the code only once a year. Plus, having a CI/CD pipeline ensures that you have a version-controlled script telling you exactly what you were thinking X months ago. 


What other practices have you followed to prevent your future self from hanging themselves? 😜


I share TL;DR versions of articles on software engineering that I read every weekday through my newsletter - in.snippets(). Sign up here if you want to learn something relevant every day.

Oldest comments (78)

Collapse
 
chrisachard profile image
Chris Achard

Nice post - definitely agree.

You mention gofmt for go (which is great); and for JS I'd recommend prettier: github.com/prettier/prettier , especially on teams. It allows the automatic code formatter to be the "bad guy", instead of having to talk about style during code reviews :)

Also definitely agree with number 4 - premature optimizations can kill code quality years later. It's always a terrible feeling when you get into an old codebase and realize that it's 4 levels of abstraction deep and you can't figure out what anything is doing :)

Collapse
 
mnivoliez profile image
mnivoliez

Rustfmt for rust.

Collapse
 
mohanarpit profile image
Arpit Mohan

We use prettier very heavily in our team and that has definitely reduced the number of bike-shedding arguments internally. I think more and more languages are realizing the importance of this and baking it into the standard library instead of an external library.

Collapse
 
peledzohar profile image
Zohar Peled

Love the quote you started with! Personally, I have this as a mantra:
When you write code, think about the poor bastard that's going to have to maintain it six months from now. It most likely be you.

Also, A solid set of rules.

Collapse
 
mohanarpit profile image
Arpit Mohan

I think that's a more accurate mantra. Be kind to your future self :)

Collapse
 
patricktingen profile image
Patrick Tingen

Another one here that had to laugh out when reading the quote. I forwarded it to my group of fellow-programmers. Oh and btw, love the set of practices

Collapse
 
nokiz profile image
Nando AM

Don't write stupid comments on code, but write comments.

Collapse
 
mnivoliez profile image
mnivoliez

I should add "do not write in comment what you could have write in code".
That include the name of function/variables, the types (if it's a typed language that is), the exception that can occur, any optional result, constant arguments.. etc...

Collapse
 
mohanarpit profile image
Arpit Mohan

Couldn't agree more. Comments should describe the "Why" and not the "How". The "How" is already present in code.

Collapse
 
afifsohaili profile image
Afif Sohaili

Don't follow the DRY principle blindly

Couldn't agree more. Was guilty of this before. Now I just duplicate first, often times more than three occurences and before refactoring and making them DRY.

Collapse
 
mnivoliez profile image
mnivoliez

You should go WET (write everything twice) first.
As always, do not follow that one blindly too.

Collapse
 
mohanarpit profile image
Arpit Mohan

I'm more biased towards MOIST these days. Walking that thin line between DRY & WET 😜

Thread Thread
 
mnivoliez profile image
mnivoliez

MOIST? Please enlighten me :p

Thread Thread
 
mohanarpit profile image
Arpit Mohan

Not too DRY, not too WET; just moist :)

Thread Thread
 
patricktingen profile image
Patrick Tingen

My Own Interpretation of Some Things 😉

Collapse
 
_ezell_ profile image
Ezell Frazier

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."

Wiser words have never been spoken. But your write-up comes pretty close.

Thanks 🙌

Collapse
 
mohanarpit profile image
Arpit Mohan

Thank you so much. Glad you found it useful.

Collapse
 
davidmm1707 profile image
David MM👨🏻‍💻

I'm guilty of the 4. Especially combined with 2. And 5.

Optimizing and trying to get 4 or 5 things done in a "clever" function has been the bane of me.

Then I had to scrap it as the client didn't ask for that (even if I thought we would like it and it would be nice).

But I'm learning... I hope.

Collapse
 
gayanhewa profile image
Gayan Hewa

Great points. Fourth one is my fav.

Collapse
 
wolfhoundjesse profile image
Jesse M. Holmes

WET: Write Everything Twice! 😜

Collapse
 
mohanarpit profile image
Arpit Mohan

These days, I follow MOIST. Not too DRY, not too WET. :)

Collapse
 
gypsydave5 profile image
David Wickes

Finally, five pieces of advice I can actually agree with.

💯

Collapse
 
mohanarpit profile image
Arpit Mohan

Thank you! Btw, which one didn't you agree with? 😜

Collapse
 
fultonbrowne profile image
Fulton Browne

Great post!

Collapse
 
mohanarpit profile image
Arpit Mohan

Thank you. Glad you found it useful!

Collapse
 
sebbdk profile image
Sebastian Vargr

I love that quote and frequently use it with my juniors. :)

Internally I like to add that, that sociopath is me, because that’s how I feel when I look at my old code...

Collapse
 
mohanarpit profile image
Arpit Mohan

Haha ... each time I look at my old code, I think "I don't think I'd be good friends with my past self. That guy was an idiot." :D

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

Great tips! I can attest to all of these.

I strongly agree with your statement about not following DRY blindly. I'd extend that out to any methodology or practice.

Additionally, I use commenting showing intent to leave my specification and intent inline in the actual code. The result is that, no matter how long I'm away from the code, I can always pick back up my thought processes where I left off; meanwhile, anyone else reading my code can pick up not just what I'm doing (which should be self-evident from the code itself), but why I'm doing it.

Collapse
 
mohanarpit profile image
Arpit Mohan

I didn't know about CSI. Thank you so much for a pointer to the article. #TIL

Being able to re-create the program in any other language using just the comments is a great north-star to have; obviously really hard to follow (especially in the beginning)

Collapse
 
codemouse92 profile image
Jason C. McDonald

Glad you find it helpful! I should have also included the link to my article about how it works in practice.

Collapse
 
peledzohar profile image
Zohar Peled

I can't agree with you more! About two year ago I had to re-write an implementation of am algorithm I wrote 7 years earlier. Lucky me, I originally commented everything that the customer needed right next to the specific part of the code that did it. Saved me days. Literally days of work.

Collapse
 
lieryan profile image
lieryan • Edited

I came with an open mind but after reading the CSI guide, it looks to me like a very stupid idea.

A clean, well written code should reveal intent from the code itself, from the variable and method names, and its structure; and the test, the function interface, and pre/postcondition/assertions should reveal the detailed specification and contracts, in which case nearly all CSI comments as exemplified in that guide will be redundant.

Reading clean code should feel like reading CSI. The CSI comments then becomes redundant.

If you write your code, tests, and assertions with the same care that you write CSI, then you will get an executable and self-checking CSI without the comments; and your reader won't have to read twice and they will never be misled by outdated or quickly phrased comments.

The CSI guide you linked encouraged commenting the intent on each line, IMO this is very ridiculous. If you write intent revealing code, the intent should almost always be fairly straightforward to read from the line itself. If it's hard to read an intent from the line, then it may be ok to add comment as a crutch, but much better would be to rewrite the lines so the intent of that line and how that line relates to other lines becomes clear from the code itself.

The hard part of reading code, and where intent revealing comments can definitely help, is deriving intent from a large piece of code. On the contrary, the CSI guide you linked discouraged such commentaries. A few strategically placed comments can help summarise the grand intent that's not immediately obvious from reading individual lines. Intent revealing comments should be reserved for these grand schemes, not for individual lines. Individual lines should be clear enough without comments, and line comments are used sparingly when the line cannot be made clearer otherwise.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

That "stupid idea" has saved my company countless hours. Others have reported the same. If the proof is in the pudding, it must not be so stupid.

Not every practice is right for everyone, and CSI might not work for you, but based on your comments, I can safely say you either skimmed or grossly misunderstood the standard. I'm as much of an advocate for self-commenting code and proper tests as is humanly possible, but in practice, they don't make up the difference in the specific (common) situations where CSI fits in.

If anyone is interested in understanding how this actually works, I did write this article up. It addresses all of the aforementioned misunderstandings.

Thread Thread
 
sinewalker profile image
Mike Lockhart • Edited

mmm

I've been flip/flopping between comments are a last resort, okay and these specific kinds are actually good. And then there is literate programming which seems to be something along the lines of CSI, which I'd not heard of before.

But certainly, no "rule" should be followed religiously (that is, without question or thought). Which is a common thread among the OP's other rules, and my own Rule 0.

Thread Thread
 
chekote profile image
Donald Tyler • Edited

Calling it a "Stupid Idea" is a little harsh. But I do agree with the more positive sentiments expressed in Lieryan's post. The example I've attached from the CSI, in particular, seems to illustrate the point well. It's literally just repeating the code in English:

thepracticaldev.s3.amazonaws.com/i...

I'd argue that you should take Lieryan's suggestion as far as you can go, and then only when you still have ambiguity should you resort to CSI. Even then, you'd need to make sure that your comments are truly adding value and not just repeating what's already evident from the code (as with the attached example).

Thread Thread
 
codemouse92 profile image
Jason C. McDonald • Edited

The only trouble with deciding whether a comment is "useful" or not while you code is that, during the process, everything you do seems obvious. The non-obvious intent only becomes apparent upon revisiting.

This is why CSI advocates commenting everything now, and then refactoring the comments once the code isn't as fresh in your mind. It's easier to drop a comment that isn't useful, than to try and figure out what intent-comment you SHOULD have included, but didn't.

None of that should be in lieu of any other component of clean coding, mind you. The code's "what" should still be self-evident, without comments. Comments are only for why, and I have never come across a single production-level code base where the intent was even sufficiently suggested by the self-commented code.

Usually, the people who say that intent-commenting is redundant to clean code are those who have never actually put intent-commenting into practice; it's dismissed because, as clean code likes to declare in its limited, but somehow magically all-seeing manner, "comments are always a failure."

I use both, and one can't even pretend to replace the other.

Thread Thread
 
codemouse92 profile image
Jason C. McDonald • Edited

I just realized (and this isn't aimed at any particular person here), but I think that from a psychological perspective, one reason people seem to be so uncomfortable with the idea of commenting intent traces back to imposter syndrome...

There are those coders who write "clever" code that the average programmer is simply awestruck by. Even when it's completely "clean", the cerebral nature of the code is just too incomprehensible to any but the most senior developers...yet nothing particularly clever is actually being accomplished. The developer in question is trying to be Mel, and the moment they actually admit what the intent ("why") of their code is..."Oh, I'm just searching for a value in an array"...the smoke is cleared away, exposing their Cleverness as mere Overengineering.

I'm far from suggesting this is a common reason for opposing intent-commenting, but I have no doubt it is one of the reasons.

On a broader scale, however, I think it isn't unreasonable to assume that there are plenty of coders who naturally fear code critique by their peers, and if they're entirely up-front about their intent, they'll be subject to feedback along the lines of "Why are you doing this the hard way?"

By keeping our intent to ourselves, we feel like we can hide behind our (otherwise clean) code. Most of our peers won't bother to read it in light of what it's intended to be doing, so we're more likely to get "LGTM" code reviews and glaze-eyed pats on the back. Intent commenting exposes our inner thought processes to the open source world for public scrutiny, and I think that scares the Dickens out of a lot of people.

Thread Thread
 
sinewalker profile image
Mike Lockhart

Yes. Emphasis on adding value. Repeating code in English (or another human language) is one of my pet peeves, but if it adds value, then I'm for that.

Thread Thread
 
codemouse92 profile image
Jason C. McDonald

Precisely! Intent-comments only work if they add value: a clear expression of the intention apart from the code itself.

That's one of the major reasons I wrote the standard: to differentiate between junk comments and useful ones, and to encourage the latter.

Thread Thread
 
sinewalker profile image
Mike Lockhart • Edited

+1 for mention of Mel

I feel my future self will disown any gratuitous 'cleverness', so for me personally, a comment on some clever code is more likely to be an admission to Future Self of being too much clever, and not enough smart :-)

Also, it's a little like explaining the punch line of a joke. One either feels that the joke has failed, or else being condescending to explain it. Another form of imposter syndrome

Collapse
 
poncianodiego profile image
Diego Ponciano

Loved CSI! Thanks for sharing.

Collapse
 
tomavelev profile image
Toma

When debugging via logs, log levels are great feature to be using. Too much design patterns without past personal experience of it is also an anti pattern. Loved the idea of ci/cd as early as minimal MVP is implemented. So when adding new features, you could verify /tests/build/deployment is still working.

Collapse
 
mohanarpit profile image
Arpit Mohan

Log levels are god-send. God bless the person who thought of this first. :)

In production, there have been cases where we enabled debug logs for a brief period just to get more information on a bug. Tuning the log levels also affects performance in a big way (especially in a high throughput scenario).

Collapse
 
ferricoxide profile image
Thomas H Jones II

Violent psychopath or someone like me. Either way…

Bad Time

Collapse
 
pavelloz profile image
Paweł Kowalski

Good stuff.

I would add, write tests, so you will learn how to write testable code, which at the end, will result in better code.

Collapse
 
mohanarpit profile image
Arpit Mohan

Oh ya. TDD for the win! It's a muscle that needs some practice to be developed. But after a period of time, you feel like there's no other way that you can write code in.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.