DEV Community

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

Coding practices your future self will love you for

Arpit Mohan on September 18, 2019

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 ...
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
 
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
 
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
 
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
 
poncianodiego profile image
Diego Ponciano

Loved CSI! Thanks for sharing.

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
 
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
 
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
 
mnivoliez profile image
mnivoliez

Rustfmt for rust.

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
 
mortoray profile image
edA‑qa mort‑ora‑y • Edited

It is a good idea to copy-paste the same function a minimum two times

No. I'm steadfast against this. The first copy-paste is already reason to abstract the code. If you don't you'll have already duplicated bugs, and limited the functionality of the app. You'll also be encouraging yourself, and team-mates to copy it a third time -- since realistically, how will you know somebody has copied it once before?

Abstracting code in a clean way can be challenging. This is not a reason to avoid it. If you constantly avoid doing this you will never learn how. Creating an abstract form from two functions is easier than from three related functions. Do it right away. There's absolutely no reason this should result in less clean code.

Collapse
 
mohanarpit profile image
Arpit Mohan

That's the whole point of premature abstraction. In my experience, just because 2 things look the same initially doesn't necessarily mean that they will evolve to be the same. Obviously there are tiny functions such as "add 2 numbers" which will still remain the same and hence can be abstracted early.
As with any rule, apply with care and don't over-stretch it. The answer to most questions in programming (and life) are "It depends" :D

Collapse
 
gthomas2 profile image
gthomas2

I'm also strongly against the WET principle. Having good unit tests and code coverage is important. If you go with the WET principle you are making it harder to write tests for your code. If you go with DRY and then you later find a function doesn't meet your requirement, don't use that function and rewrite the code - simple!

Collapse
 
patricktingen profile image
Patrick Tingen

This article explains it well why WET is better than DRY:
dev.to/wuz/stop-trying-to-be-so-dr...

Collapse
 
gthomas2 profile image
gthomas2

I had to go through some WET code in a project I'm working on today (code by a peer) and nearly threw up. Copied and pasted an entire method from one place to another. The code was tripe in both places and needed to be fixed twice. And you know what? I had to spend time going through the code to make sure it was exactly the same before I could be sure that the fix would work in both places. WET does not save you time if you follow it blindly. That's why it isn't better than DRY and that article does not say it's better than DRY. It says that sometimes (with small bits of code) it's fine to repeat it.

Thread Thread
 
patricktingen profile image
Patrick Tingen

I think you are 100% correct; following principles blindly does not sound like a good plan. The only absolute rule in programming is that there are no absolute rules

Collapse
 
elmuerte profile image
Michiel Hendriks

Tests, tests, and more test.

That should be right after code style. Without tests your CI is useless. With a useless CI your CD is worthless.

Without tests you waste more time on debugging.

Without tests you cannot optimize at all.

Collapse
 
mohanarpit profile image
Arpit Mohan

I agree wholeheartedly. Testing is super important. I've seen projects debate long & hard about unit-testing vs system testing vs integration testing. What's more important is that you are testing at some level or the other. Something is waaay better than nothing!

Collapse
 
elmuerte profile image
Michiel Hendriks

That's a simple debate. You need all of those tests. Because they test different things.

Unit tests are fast, they can be executed on every build, maybe even before every commit.

System tests are used to test the result of the combination of units. As it requires the system to be running it takes more time. You run this maybe every hour, or once a day.

Integration tests are slow and depend on external systems. But they test things you cannot/should not do with unit tests or system test. You run these maybe daily or weekly depending on how much effort it takes reset states.

Then there's also the end-to-end test, or UI test, which sits between system- and integration-tests. This can easily be skipped if your system has no UI. But otherwise you do need it. It is also rather slow, and might even need a testing matrix to run the same tests for different clients (e.g. browsers). So you probably run this once a day, or every other day.

The less of these things you have in place, the more dangerous changing your software will be. The longer it takes to find out something broke, the longer it takes to find out why. That's why your first line of defense should be unit tests. That unit tests might touch the same code as the other test suites is irrelevant. The time to feedback is much shorter.

The above is more or less Chapter 7 and 8 of the book Continuous Delivery in a nutshell. Get the book in physical form, because if anybody challenges you, you can use it as a weapon too :)

Collapse
 
mohanarpit profile image
Arpit Mohan

Yes! Very important aspect!

Technical writing has always been very under-rated, but very critical. Documenting any workflow, API or algorithm helps us reason with our own assumptions and removes inconsistencies and biases.

In the open source world, documentation has the added benefit of getting new contributors interested in the project. It's also much easier to raise your first PR for a documentation fix than for an actual bug.

Collapse
 
poncianodiego profile image
Diego Ponciano

Lovely totally agree. I'd say human-to-human comments explaining things does not hurt at all also. Well, after you know how to write a proper comment/doc block, create it so that other human can easily pick up, even provide an example if necessary. Comments are for humans not for computers. Also write your code as if you were having a human conversation as far as possible, writing function names and classes so that they make sense and are rather elegant during usage. Some storytelling never hurt no programmer ;) if you know what I mean. Have a conversation while you program, even vocalize it.

Collapse
 
therealkevinard profile image
Kevin Ard • Edited

The one I'd add is (for my purposes) to the same end: docs, ideally, should be written in the same cadence as the code - update code, update doc, update code, update doc.
This is insanely turbulent for me.

Instead, I've adopted something between TDD and plain through-as-crap testing.

I can run the specs and flip through the its and get a complete understanding of what the code should (and should not) do, and how to make it do it.
Doc-by-test is much easier for me because I don't have to switch gears to keep it moving.

The "honest" benefits of testing are just byproducts lol.

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
 
dirtycode1337 profile image
Dirty-Co.de

"Too much logging == no logging." - cannot agree more on this one! I use logs a lot especially when writing JavaScript code and when I find myself filtering in my own logs I know, I've logged too much and I start cleaning up my logging :)

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
 
sprzedwojski profile image
Szymon Przedwojski

Good points, Arpit!
About loggind I'd add that it's a good practice to introduce different log levels, e.g. ERROR, INFO, DEBUG, TRACE. This way you can have different amount and detail of logs on different environments and possibly you can also just change an env variable to change the log levels on production if you have issues there.

Collapse
 
mjsarfatti profile image
Manuele J Sarfatti

Love it! And it's a good reminder not just for beginners!

I would add a number 7:
Write test, just a few, for the most complex parts.

Collapse
 
mohanarpit profile image
Arpit Mohan

Thank you!

Testing is definitely required! Not just for the complex parts, but for the simple ones as well. You never know when the simple part becomes complex :)

Collapse
 
mjsarfatti profile image
Manuele J Sarfatti

I agree, but if testing is not part of your routine starting with "test absolutely everything" will result overwhelming and you may just give up entirely.

A good approach is to start where it hurts. Then add tests for every bug you find. Then if you still have time and budget feel free to go all in!

It also depends if you are building a library (I'd test as close to 100% as possible in that case) or a Gatsby website (I'd maybe only test a few UI components)

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
 
darcrux profile image
Gaurav

Really love this post Mohan

Collapse
 
marcospy profile image
Marcos Costa Pinto

Thanks for the great tips!

I'll try to debug locally using logs, I'm sure that will help me ship code more observable to production.

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
 
blindfish3 profile image
Ben Calder

Also do regularly look back at code you wrote 6 months ago; even if you don't have to. It will help you maintain this mindset ;)

Collapse
 
mohanarpit profile image
Arpit Mohan

I always shudder each time I look at my code from 6 months ago. There's a constant sense of "I was such a dumbass back then" :)

Collapse
 
ferricoxide profile image
Thomas H Jones II

Violent psychopath or someone like me. Either way…

Bad Time

Collapse
 
yabaud profile image
yabaud

Good article! Beware of the copy paste function though... I've been programing for 15 years and observe it as one regular source of bugs in code.

Collapse
 
akshaymadhan_99 profile image
Akshay Madhan

Super article

Collapse
 
fultonbrowne profile image
Fulton Browne

Great post!

Collapse
 
mohanarpit profile image
Arpit Mohan

Thank you. Glad you found it useful!

Collapse
 
vasilypoet profile image
Asamoah-Ojugbana Jeffrey

Love this!

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
 
damindo profile image
Damindo • Edited

Good share, thank you.
So now "best practices" are adopted in fear of "the violent psychopath" joke :)

What happened to "We don't negotiate with terrorists" ?

Collapse
 
enriqueedelberto profile image
Edelberto Enrique Reyes

Thanks for the article.

Collapse
 
gthomas2 profile image
gthomas2

I almost was guilty of number 5 today until my teammates wised me up in scrum.

Collapse
 
jsmccrumb profile image
Jacob McCrumb

I stopped in because title looked promising, read on with a chuckle because of that initial quote, and stayed til the end cause it was all good content. Thanks for the write up!

Collapse
 
hasii2011 profile image
Humberto A Sanchez II

Unit test, unit test, unit test.

Collapse
 
theweeappshop profile image
Tony Ross

Absolutely SPOT-ON! Thank you for this.

Collapse
 
martinakuzniecowa profile image
martinakuzniecowa

thank very usefull

Collapse
 
rzprrtkgolyd4ug profile image
veterant

Take advantage of goormIDE.
goormIDE is a fantastic cloud based IDE and it's free!

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.

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? 😜