Download EPUB

Indentation And Alignment Can Help You πŸ”Š

fagnerbrack.com 6 min read Original article
Summary
The article argues that code indentation and careful alignment help teams collaborate, while objecting mainly to alignment used inside function calls. Indenting function arguments, array items, and object properties makes version control diffs show only the relevant changed lines instead of highlighting whole blocks. Adding a trailing comma to the last item makes diffs even cleaner, a trick Axel Rauschmayer described in 2013, though it does not work for function parameters yet. These habits also improve git blame traceability and atomic commits.

The author warns against alignment used for micro-optimizations, citing premature optimization and the Pareto principle. Code that needs heavy alignment may signal a design problem, so better abstractions and naming beat lining things up for looks.

Indentation And Alignment Can Help You πŸ”Š

A ring buoy on the beach, leaning on a stick and ready to help

There is a thin line between what makes the application succeed and what makes the application fail. No one knows all the criteria to make it succeed, but everyone knows one criterion to make it fail, and that is blindly following everything you read on the internet.

Last time, I wrote an article called Why Aligning Statements Will Haunt You. The text tried to be as objective as possible in presenting the bad parts of code alignment for certain kinds of statements. Still, it sparked some opinions and a few misunderstandings.

To be clear. This is not about making claims that the code can be "more beautiful" or "less beautiful" using certain styles, it is about pointing out real problems, the decision if that problem is worth worrying about or not depends on each team on each project.

There are people who believe that code alignment can hurt legibility, others don’t. There are people who believe that spaces between parenthesis can hurt legibility, others don’t. We need to agree that "theoretical legibility" is subjective, and that is a fact. Therefore, when arguing about anything related to software development, we can't focus in "theoretical legibility", we need to focus on practical, demonstrable and objective issues.

That said, not every code alignment can pose problems for the collaboration of a team, only some of them, like the arguments for the require example in the previous article. Other types of alignment, like indentation, can actually do the opposite and objectively help collaboration.

Function arguments and Literal constructs are some of them. Take the snippet below, for example:

Three code snippets in separate lines showing a Function, an Array Literal and an Object Literal. They are not indented.

In the examples above, if we add a new argument, item or property, the S.C.M. will highlight the whole line in the diff, it doesn't matter if one is using some mechanism to ignore whitespace or not, there will be 3 lines removed and 3 lines added anyway:

The same code snippets as before shown in a diff with a new function argument, array item and object property added. Each of the snippets are simultaneously highlighted as changed and added.

There are tools that make this better, highlighting with a darker color only the offending characters that were changed in the line. However, if we indent it, the diff will highlight only the relevant lines that contain the arguments, items or properties that were changed, instead of highlighting all of them. It doesn't matter which tool is being used:

The same code snippets as before, shown in a diff with a new function argument, array item and object property added. Now they are all indented. Only the relevant line for the argument, item or property is marked as removed. The two other lines are marked as added due to the lack of trailing comma.

The problem now is that the SCM fails to expose the intent of a single change, and instead shows 3 lines removed and 6 lines added, when in reality what we want is 3 lines added, and that is it. To fix this, it's possible to make a step further and leverage JavaScript's trailing comma for Literals to make the diff highlight exactly the changes that are relevant:

The same indented code snippets as before, shown in a diff with a new function argument, array item and object property added. There's only one change of one line for each snipped representing an added line.

This is a useful technique that was explained by Dr. Axel Rauschmayer in 2013. Unfortunately, as shown in the example above, this technique doesn't work for function parameters, although there is a proposal (still open at the time of this writing) to make it work.

A similar benefit can be achieved using the comma-first approach.

Another way to get the benefits without always having to add comma last is to add a new argument, item or property in the beginning instead of in the end. Unfortunately, this messes with the order and therefore might change the desired behavior of the code, that is why this technique is not useful for all cases. Even for an Object Literal, where the order is assumed to be irrelevant, it can break because it is possible that the code relies on the order of the properties by using the definitions of ES2016:

The same indented code snippets as before, shown in a diff with a new function argument, array item and object property added in the beginning. There's no trailing comma. There’s only one change of one line for each snipped representing an added line.

This kind of benefit is not restricted only to diffs for code review. By changing only the parts of the code that is relevant, we make sure that the line is properly traceable through the "git blame", and assuming we understand how to make atomic commits, the only commits that will touch that line are the ones relevant to a single specific purpose (something that would be hard to do if we had the same line being touched over and over again for several different reasons).

Logging changes that are relevant only to a specific purpose allow efficient traceability.

Despite the benefits of indentation, one might argue that aligning statements can be useful for certain languages and parts of a system that heavily relies on micro optimizations (like a reusable library or the core engine of a game) and therefore cannot build a lot of inner abstractions.

However, I would advise strong caution about this line of thought because premature optimization is the root of all evil, and Pareto teaches us that we should focus on the 20% of the code that leads to 80% of the bottleneck before even thinking about changing anything to increase performance. Ideally, or at least for most of the time, the compiler or the interpreter should be able to deal with optimizations instead of leaking that to the developer.

There is another important benefit of alignment, which is to spot a potential code smell. If the code is in a state that requires some sort of alignment, it is a very good reason to take a step back and see if it can be improved through efficient decoupled abstractions and good naming, instead of trying to align everything in a potentially useless attempt to make it more legible.

Aligning the code might be an indication that the code is not as legible as it seems, and therefore the best solution could be improving it instead of aligning it.

Indentation and alignment have the potential to force the improvement of the architecture.

Use efficient architectural practices instead of aligning and indenting code to increase maintainability, unless there is a very good reason not to do so.

There are probably more important problems to worry about, but maybe those important problems could have been prevented by caring about small things that have the potential to cause a bigger impact in the long run.

If you liked this, you might like readplace.com, built for exactly this kind of reading.

Thanks for reading. If you have some feedback, reach out to me on LinkedIn, Reddit or Github.