Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: How to Write Readable Code?
15 points by abhinav22 on Dec 22, 2020 | hide | past | favorite | 16 comments
A comment on a previous HN thread really stuck with me: It is easier to write code than to read it.

With this in mind, what are the tips and tricks the wise and experienced HN have for writing code that is easier to read by others and and the future us?

Tips I have been told to date are to use easy to remember function and variable names, to write in a way such that the code documents itself (ie minimal comments), to use quite a few relevant comments (this contrasts with the previous tip), and so on.

I’d be very grateful for your thoughts on what works well for you in your professional environments, but also the “why” aspect - why do you think your approach, that I’m sure you have fine tuned over many years, is effective.




From my experience:

1. Don't try to be clever. Unless there's a really good tangible tradeoff, do things the boring way. Ideally try to avoid language-specific features just to save a few keystrokes

2. Write as much stateless code as possible. Use function parameters instead of class members. If this results in too many parameters, it might be a sign that the function is too bloated


You are writing functional code mostly?


Currently, I'm mostly writing 2d/3d graphics code (C++)

I did briefly write some Haskell/Erlang in my undergrad programming language theory course and carried some of the functional paradigms into my professional career though trial-and-error and advice from my mentors


1. Add comments that explain why. This might be a technical reason (like, this query is structured in this weird way to convince Postgres to optimize it correctly) or business reasons (e.g. users outside the US sometimes put the street number at the end of the first line of the address)

2. Keep each method at a single level of abstraction. Don't mix high-level business logic like send_email() with low-level logic like constructing a SQL query.

3. Break out separate functions just to give a block of logic a name. This results in more context when reading the code, shorter functions, and better stack traces.

4. Don't work too hard to avoid duplication. A little duplication when two codepaths do something similar is much better than having a weird abstraction that exists just for the sake of deduplicating a few lines. (But do work hard to make sure that there is a single source of truth for important values and decisions!)

5. Prefer many functions to a few, configurable functions. When you have a function with, say, 5 boolean options, that's 2^5 = 32 cases you need to support. In reality, the function might only be actually called 6 or 7 different ways, so you don't actually need all those combinations. Having more functions that do one thing makes it much easier to tell what a particular piece of code is actually doing.

6. Start by explaining what needs to be done as though you are telling another person, and then transform that into code. It tends to result in more readable code than starting by explaining it to a machine.


Here's what I generally follow (there are exceptions, of course):

1. Functions can do 90% of what you need in terms of code organization and maintainability.

2. Don't try to get functions to do more than one job. Don't try to spread one job across multiple functions.

3. Name functions using concrete, unambiguous verbs. No: handleX, doX, processX, updateX. Yes: get/setX (from/to memory), fetch/sendX (over network), load/saveX (from disk), calculateX (and return value), findX (in list).


I’d recommend reading “clean code” by Robert Martin. It’s full of good tips, you don’t have agree with everything he writes but it is a great food for thought


And "Clean Coder".

Try to write the code in a way that it's easily readable. Depending on the language and compiler you may have an optimizer that helps you to write readable code yet performant byte code.


Group code files with feature, e.g "profile", "billing" instead of "controllers", "views", so that you don't need to jump into different folders when you work on a feature.


Think through naming of functions/modules one extra time.

Make your modules and function flow "tell a story". Ie make it readable like reading a literal short story.

Write quality unit tests that has realistic input data that explain your thoughts how the "module" should work. The happy path test is the most important one.


1. After you’ve finished implementation, make sure that your solution is the right one. If it’s not, it will never make sense or be readable by anyone

2. Use your favourite diff tool. Go over the diff and make sure first that the diff is readable for people to review it. Make changes accordingly

3. Quit diff and now read the whole thing. If you altered a function, read that function from the beginning. If you added/removed a function, read the class from the beginning. Make sure all make sense

4. Finally, ask for a review and pay attention. Don’t dismiss comments withou first considering them.

That’s what I do


Reading code of nice, successful, projects helps learn what good looks like, how the projects are structured, how each module minds its own business, etc.

I'm not saying the code is perfect, but the improvement is faster than to do it in a vacuum.

Writing the tutorial and documentation for a library and show it around to colleagues before you write the code has been helpful. "Would this make sense to you?"

I also used to give non coders a laptop and the documentation for a library I wrote and tell them to follow the documentation to do something.


I think the best test is to read the code yourself. If it's not obvious what it is doing, the side effects it may produce, or the assumptions made when executing it, then you probably need to add comments or refactor to answer those questions.

I try to keep in mind that the code I'm writing will eventually be maintained by someone else years from now, who never knew the context of why I'm writing this code or the function I am trying to achieve with it.


If you are writing a conditional block that tests complicated expressions, use the expressions to set Booleans with simpler, more descriptive names and use those instead.


Treat it like writing, there is such a thing as a first draft. It’s going to suck, but this is not the draft you put all your edits in. The draft is just a vision for what it should be.

Then, no matter the impulse to leave it alone and mark it as ‘working code’, go back and edit it.

This alleviates the pressure as it’s only your first draft, followed with a discipline to go back and fix your abstractions, organization, and elegance.


Choose good names

Keep functions small

Organize the code so it is easy to read

Write good tests, they serve as documentation

Write a Readme file to explain the overall purpose of the code and anything not yet implemented in the code


A big plus one on a good readme. So many projects lack this. At work, my team’s readme for each project has the super high level purpose; the basic flow and entry points; steps for building and testing; links to design docs, build pipelines, metric dashboards, runbooks; etc.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: