Are JavaScript Comments Useless?

Should I write comments in my code? Should I avoid them at all costs? Should I use them sparingly? When developing software, all developers have their view on how and when to use comments. This article will reflect my opinion, not the ultimate truth.

I restrict formulating this opinion to software written in JavaScript using the principles of either functional programming or object oriented programming.

Comments and maintainability

This blog is all about writing maintainable code, i.e. code that is

  • easy to understand,
  • easy to extend,
  • easy to debug,
  • easy to test.

Does maintainable code need a lot of comments? If the code was written well, I seriously doubt it. Code should speak for itself.

Does maintainable code need any comments at all? Let's find it out by checking some examples.

Evolution towards mastering comments

Approach 1: JavaScript diluted with BS

Suppose a junior developer with nickname ByTheBook wrote the following code:

What's wrong with this approach?

First of all, a disclaimer. Never ever leave commented code in your application. It's just unprofessional. If the commented code serves the purpose of debugging, it's even worse. Clean up your commits. If it's too late, make a habit of committing locally and clean up your code later with interactive rebases.

Keeping commented code is just a small part of the big problem: technically, 90% of these comments just add noise. They don't add any value, they just serve as a tool for distracting the reader. For instance, after reading the above code segment, did you think about specifying what our function should do in case there are more than one participants with the same top score?

Approach 2: Self-documenting code

Flash is another junior developer with a lot of horsepower. Suppose he wrote the same code without any comments.

Technically, the solution is working. It is also evident that it returns null in case no participants show up. Yet, the code does not contain any explanation on how a tied first place is handled.

In addition, how would you know what the format of the participants object is without reading the whole function? You have to reverse engineer all information from the method: participants an array of objects, containing elements with a name and a score member of types string and integer respectively.

Approach 3: The Startup code

Startupper noticed the problem of ties. As he had thousand other things to do, he just placed a TODO comment in the code.

The problem with TODO items is that they tend to stay in the code. There are also todos placed on top of other todos. Some todos may get into conflict with each other. Others may be so badly described that no-one will know what they were originally about.

In this example, the TODO item grasps the essence of the problem. A solution is never provided though.

Also note that the type of the participants argument still needs some detective work.

Approach 4: Declarative head comments

The Declarator has the habit of writing declarative head comments containing

  • a short and precise explanation of what the function does
  • types of the argument list and return value
  • exceptions

This solution clearly documents what the getWinner method does. Comments mostly help and they don't distract the reader from the code itself. Inline comments don't exist at all. The tie is also addressed by the head comment.

Approach 5: Fix the cause, not the symptom

PickyPerfectionist is not a developer of compromises. He is proud of writing maintainable code and exercises the mantra: "a comment is only needed if the code is not good enough". His second mantra is that he never settles for code that's not good enough. This implies that PickyPerfectionist never writes comments.

Before writing the function, PickyPerfectionist clarifies requirements. In case of a tie, all names will be printed out, separated by commas.

The code is easy to read. The root of the problem has been fixed, no comments are required to explain the concept of the tie. Although the structure of the participants object is not defined, PickyPerfectionist went the extra mile and described the solution in a way that you get all information you need from the code. Even the name of the function changed. What can go wrong then?

Suppose that the decision of the stakeholders was that instead of enumerating the winners, they would change the game such that there can only be one winner. The cause of the problem is solved elsewhere. In this case, a comment-less approach would fall back to the code you have already seen:

One day a developer notices something weird: this function only returns the first participant with the highest score. Depending on which type of developer notices this problem, different solutions may be provided. Solutions may range between a TODO comment and a full clarification of expected behavior with the stakeholders. All possible solutions have two things in common though:

  • they take time,
  • they add noise on some level.

Would you consider using comments? Do you have an alternative solution to avoid wasting time? If yes, assume that looking at the documentation also takes time.

Technically, a decision making sure that there can be only one winner cries for an automated test. Guarding this behavior with a unit test helps developers not to commit changes that contradict the requirements. Tests don't point out the problem though in advance. In this special case, existing tests would not even mind if you changed the getWinner method such that it can handle multiple winners.

Comments driven by common sense

According to my opinion, comments are useful if they add value. There is no ultimate right or wrong approach.

Banning comments from the code is very much like basing your diet on counting calories. They may help up to a certain extent, as eating 2000 kcal per day is significantly better for you than eating 8000 or 300. The big picture is more complicated though. Some calories are more useful for you than others. Eating a salad should benefit you more than drinking a soft drink with sweeteners and gas. Similarly, banning comments from the code may force you to write better code. However, when the code cries for a comment, denying it is quite harmful in the long run, creating confusion and reducing maintainability.

When are comments useful? First of all, JavaScript does not allow you to specify the types of the argument list and the return value. Therefore, information on type definitions help. These type definitions are there in the signature of methods in many other languages. JavaScript development environments may give you some type data on hover, but an overview still saves time. If you know the difference between == and ===, and you prefer using ===, then types should be important to you. Declaring these types should be equally important, otherwise type-safety would lose its purpose.

An example signature looks like this:

The types are clearly specified. The name of the arguments is enough next to the type as all 3 names are described in one sentence above the types.

It is not clear whether the type of the return value should be left out or not. It is perfectly fine to agree on leaving it out for the sake of writing or generating less comments.

When it comes to defining classes and methods, I am a big fan of head comments. One sentence can describe the one and only responsibility of a class. The same holds for its methods. If you write programs in functional style, head comments also help.

Many developers write a head comment before implementing a method. Head comments increase the quality of the code by focusing the developer's effort into implementing exactly the required functionality, nothing more, nothing less.

Other extensions can be added to head comments such as:

  • optional arguments: sometimes the last couple of arguments may be left undefined
  • mixed types: sometimes types are mixed. In JavaScript, it is not possible to define multiple functions with the same name. Instead of polymorphic overloading of methods, all variants of the method is realized in by the exact same method. This implies that the same function is sometimes called with arguments of mixed types
  • composite types: see Approach 4 for an example. Normally, the type of participants is array, but for the sake of understanding the structure, more data are provided
  • information about thrown exceptions
  • preconditions of calling the method informing other programmers about the conditions under which the method is supposed to work
  • side effects

Decide on what information you need and omit everything else. Simplicity is important. A weekend-project or a prototype should have different commenting requirements than a web application that will be developed and maintained for 5 years.

Writing excellent head comments is an art, but writing head comments that are good enough can be based on common sense. Common sense dictates that head comments should be informative. This is an example for a bad head comment:

This is somewhat better:

A well written head comment makes 99.99% of inline comments obsolete. Regardless of the complexity of the method, I mostly agree with opinions that say that inline comments just add noise and distract developers instead of helping them.

Head comments also help you enforce the single responsibility principle. Regardless of the level you are looking at code, each building block has to have one and single clearly defined responsibility. Therefore, similarly to function comments, I also suggest adding head comments to classes. If you have a hard time defining what your class is about, it is a good sign that you are violating the single responsibility principle.

Whenever a head comment is hard to write, it often indicates that it's time to think about decomposing the method into multiple ones or shift responsibilities of your object somewhere else. Therefore, thinking about head comments may result in better code.

From the point of view of code maintenance, head comments are useful because of at least two purposes:

  1. head comments save time in case the reviewer just needs a brief overview of what the method is for
  2. in case of a faulty method, the reviewer has access to the original intentions the implementation was based on

In exchange for this information, head comments have to be maintained. This is not a hard task as long as developers know what they are doing.

Should I write comments or not?

It is up to you, do whatever helps you. Some projects require no comments at all. Others cry for at least some head comments. Unlike languages with strict typing, JavaScript comments give you valuable type information on the arguments and the return value. Compact head comments may also make your code more understandable. In addition, compact comments make you think about your code, sometimes resulting in changes that make the code more maintainable.

For all these reasons, I don't think that all comments are useless. The world is not strictly black or strictly white. While extreme opinions often attract more debate, a balanced approach evaluating both points of view is often more helpful in the long run.

Learn ES6 in Practice

Sign up below to access an ES6 course with many exercises and reference solutions.