JavaRush /Java Blog /Random EN /Code rules: the power of proper naming, good and bad comm...

Code rules: the power of proper naming, good and bad comments

Published in the Random EN group
Rules for writing code: the power of correct naming, good and bad comments - 1 How often have you had to understand someone else's code? When, instead of a couple of hours, you spend days just to understand the logic of what is happening. The funny thing is that for the person who wrote this code, everything is clear and very transparent. And this is not surprising: after all, perfect or ideal code is a very vague concept, because each developer has his own vision of the world and the code, respectively. More than once I came across a situation where my colleague and I looked at the same code and had different opinions about its correctness and cleanliness. Rules for writing code: the power of correct naming, good and bad comments - 2It's a familiar feeling, isn't it? However, there are some time-tested points that should be adhered to, which will ultimately work to our advantage, because if you leave your code in the state in which you yourself would like to receive it, the world would be a little happier and cleaner. Rules for writing code: the power of correct naming, good and bad comments - 3In our last article about the rules of writing code (or rather, a small guide), we touched a little on the recommendations for writing the system as a whole and its elements such as objects, their interfaces, classes, methods and variables. There I briefly mentioned the correct naming of certain elements. Today I would like to talk about exactly this, because correct names make code readability much easier. We will close the topic of correct code with the help of reflections and small examples of comments in the code - is this good or not so good. So let's get started.

Correct naming

Correct names improve the readability of the code, accordingly saving time on familiarization, because it is much easier to use a method when the name roughly describes its functionality. Since everything in code consists of names (variables, methods, classes, file objects, etc.), this point becomes very important when creating correct, clean code. Based on the above, the name should convey the meaning of why, for example, a variable exists, what it does and how it is used. I will note again and again that the best comment for describing a variable is its correct name. Rules for writing code: the power of correct naming, good and bad comments - 4

Naming Interfaces

Interfaces typically use names that begin with a capital letter and are written in camel case (CamelCase). It used to be good practice when writing an interface to prefix it with an I to designate it as an interface (eg IUserService), but this is quite ugly and distracting. In such cases, it is better to write without it (UserService), and add -Impl (UserServiceImpl) to its implementation. Well, or as a last resort, add the prefix C (CUserService) to its implementation.

Class names

Just like interfaces, names are capitalized and use camel style (CamelCase). No matter what kind of apocalypse is happening, no matter how fast the deadlines are, but never, remember, the name of a class should never be a verb! Class and object names must be nouns and their combinations (UserController, UserDetails, UserAccount, and so on). You should not provide the name of each class with the abbreviation of this application, as this will only add unnecessary complexity (for example, we have a User Data Migration application, and we will add a UDM to each class - UDMUserDeatils, UDMUserAccount, UDMUserController).

Method names

Usually the names of methods begin with a small letter, but they also use camel style (CamelCase). Above we talked about the fact that class names should never be verbs. Here the situation is diametrically opposite: the names of the methods must be verbs or their combinations with verbs: findUserById, findAllUsers, createUser, and so on. When creating a method (as well as variables and classes), to avoid confusion, use one naming approach. For example, to find a user, the method can be written as getUserById or findUserById. And one more thing: do not use humor in the names of methods, because they may not understand the joke, as well as what this method does.

Variable names

In most cases, variable names begin with a lowercase letter and also use Camelcase, except in cases where the variable is a global constant. In such cases, all letters of the name are written in uppercase and the words are separated by an underscore - “_”. When naming variables, you can use meaningful context for convenience. In other words, when there is a variable as part of something larger - for example, firstName, lastName, status - in such cases you can add a prefix indicating the object of which this variable is part. For example: userFirstName, userLastName, userStatus. You also need to avoid similar names for variables when they have completely different meanings. Common antonyms for variables:
  • begin/end
  • first/last
  • locked/unlocked
  • min/max
  • next/previous
  • old/new
  • opened/closed
  • visible/invisible
  • source/target
  • source/destination
  • up/down

Short variable names

When we have variables like x or n or something like that, we don't immediately see the intention of the person who wrote the code. It's not obvious what method n does: it requires more thoughtful thinking (and that's time, time, time). For example, we have a field - the id of the responsible user, and instead of some name like x or just id, we will call this variable responsibleUserId, which immediately increases readability and meaningfulness. However, short names like n have their place as local changes to small methods, where the block of code with that change is just a couple of lines of code, and the method name perfectly describes what happens there. A developer, seeing such a variable, understands its secondary importance and very limited scope. As a result, there is some dependence on the length of the variable name: the longer it is, the more global the variable is and vice versa. As an example, a method to find the last saved user by date:

public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
Here we use short names x and y to set the stream sorting, and forget about them.

Optimal length

Let's continue the topic of name length. The optimal name length is somewhere between the maximumNumberOfUsersInTheCurrentGroup name length and n. That is, too short ones suffer from a lack of meaning, and too long ones stretch the program without adding readability, and they are simply too lazy to write them every time. Not taking into account the above case, for variables with a short name like n, you need to keep the length to approximately 8-16 characters. This is not a strict rule: more of a guideline.

Small differences

I can’t ignore subtle differences in names, because this is also a bad practice, since you can simply get confused or spend a lot of extra time noticing minor differences in names. For example, the difference between InvalidDataAccessApiUsageException and InvalidDataAccessResourceUsageException is difficult to spot at a glance. Also, misinformation can often arise when using small L and O, because they can easily be confused with 1 and 0: in some fonts the difference is more obvious, in others less so.

Semantic part

We need to put the semantic part into the names, but not overplay with synonyms, since, for example, UserData and UserInfo actually have the same meaning, and we will have to dig a little deeper into the code to understand what specific object we need. Avoid uninformative words, for example, firstNameString: why do we need the word string? Can a name be a date type object? Of course not: therefore, simply - firstName. As an example, I would like to mention boolean variables, for example, flagDelete. The word flag does not carry any semantic meaning. It would have been more reasonable to call it - isDelete.

Disinformation

I would also like to say a few words about incorrect naming. Let's say we have the name userActivityList, and the object named so is not of the List type, but some other container or custom object for storage. This can confuse the average programmer: it would be better to call it something like userActivityGroup or userActivities.

Search

One of the disadvantages of short and simple names is that they are difficult to find in a large amount of code, because what would be easier to find: a variable called name or NAME_FOR_DEFAULT_USER? Of course, the second option. It is necessary to avoid frequently occurring words (letters) in the names, as this will only increase the number of files found during the search, which is not good. We would like to remind you that programmers spend more time reading code than writing it, so be mindful of the naming of the elements of your application. But what if you didn’t manage to name it successfully? What if the name of a method does not describe its functionality well? This is where it comes into play, our next item is comments.

Comments

Rules for writing code: the power of correct naming, good and bad comments - 5There's nothing like a relevant comment, but nothing clutters up a module like meaningless, outdated, or misleading comments. It's a double-edged sword, isn't it? Still, you shouldn’t treat comments as an unambiguous good: rather, as a lesser evil. After all, a comment, in its essence, is compensation for an unsuccessfully expressed thought in the code. For example, we use them to somehow convey the essence of the method if it turns out to be too confusing. In such a situation, it is better to correctly refactor the code rather than write descriptive notes. The older the comment, the worse, because the code tends to grow and evolve, but the comment may remain the same, and the further it goes, the more dubious these notes become. Inaccurate comments are much worse than no comments, because they confuse and deceive, giving false expectations. And even if we have a very tricky code, it’s still worth not commenting on it, but rewriting it.

Types of comments

  • legal comments are comments left at the beginning of each source code file for legal reasons, such as:

    
    * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

  • informative comments - comments that provide an explanation of the code (providing additional information or intent of a given section of code.

    As an example:

    
    /*
    * Объединяет пользователя из бд и пришедшего для обновления
    * Когда в requestUser поле пустое, оно заполняется старыми данными из foundUser
    */
    private User mergeUser(User requestUser, User foundUser) {
           return new User(
           foundUser.getId(),
           requestUser.getFirstName() == null ? requestUser.getFirstName() : foundUser.getFirstName(),
           requestUser.getMiddleName() == null ? requestUser.getMiddleName() : foundUser.getMiddleName(),
           requestUser.getLastName() == null ? requestUser.getLastName() : foundUser.getLastName(),
           requestUser.getAge() == null ? requestUser.getAge() : foundUser.getAge()
           );
           }

    In this case, you can do without comments, since the name of the method and its arguments, coupled with the very transparent functionality, describe themselves quite well.

  • warning comment - a comment whose purpose is to warn other developers about the undesirable consequences of some action (for example, why the test was marked as @Ignore):

    
    // Слишком долго отрабатывает
    // Не запускайте, если не располагаете избытком времени
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
  • TODO - comments that are notes for the future that will need to be done, but for some reason cannot be done now. This is a good practice, but they still need to be reviewed regularly to remove irrelevant ones to avoid clutter.

    Примером послужит:

    
    //TODO: Add a check for the current user ID (when will be created security context)
    
    @Override
    public Resource downloadFile(File file) {
           return fileManager.download(file);
           }

    Тут мы помечаем, что нужно добавить проверку юзера, который скачивает (id которого мы вытащим из security контекста) с тем, кто сохранил.

  • усorвающий комментарий — комментарий, подчеркивающий важность Howого-то обстоятельства, что на первый взгляд может показаться несущественным.

    Как пример, кусочек метода, заполняющий тестовую БД, некими скриптами:

    
    Stream.of(IOUtils.resourceToString("/fill-scripts/" + x, StandardCharsets.UTF_8)
           .trim()
           .split(";"))
           .forEach(jdbcTemplate::update);
    // Вызов trim() очень важен, убирает возможные пробелы в конце скрипта
    // чтобы при считке и разбивке на отдельные requestы не было пустых

  • javaDoc — комментарии, которые описывают API определенного функционала для общего пользования. Наверное, самые полезные комментарии, так How с documentированным API в разы легче работать, но они также могут устаревать, How и любые другие. Поэтому не забываем, что главный вклад в documentацию вносится не комментариями, а хорошим codeом.

    Пример вполне обычного метода обновления пользователя:

    
    /**
    * Обновляет передаваемые поля для пользователя по id.
    *
    * @param id  id обновляемого пользователя
    * @param user пользователь с заполненными полями для обновления
    * @return обновленный пользователь
    */
           User update(Long id, User user);

Плохие сценарии комментариев

Rules for writing code: the power of correct naming, good and bad comments - 7
  • бормочущий комментарий — комментарии, которые обычно пишут на скорую руку, смысл которых понятен только разработчику, писавшего их, так How только он видит ту ситуацию с теми нюансами, на которые он и ссылается.

    Рассмотрим данный пример:

    
    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           }  catch (FileNotFoundException e) {
           //В случае отсутствия конфигурационного file, загружается конфигурация по умолчанию 
          }
    }

    Кто загружает эти настройки? Были ли они загружены ранее? Метод предназначен для перехвата исключений и вызова дефолтных настроек? Слишком много вопросов возникает, ответы на которые можно получить лишь углубившись в изучение других частей системы.

  • избыточный комментарий — комментарий, который не несёт смысловой нагрузки, так How и так понятно что происходит в заданном участке codeа (он читается не проще, чем code).

    Смотрим пример:

    
    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * Журнальный компонент, связанный с текущим классом
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Создаёт и возвращает connection с помощью входящих параметров
        */
       public static Connection buildConnection(String url, String login, String password, String driver) throws Exception {
           Class.forName(driver);
           connection = DriverManager.getConnection(url, login, password);
           log.info("Created connection with db");
           return connection;
       }

    Какой смысл таких комментариев, если мы и так всё прекрасно видим

  • недостоверные комментарии — комментарии, не соответствующие истине и лишь вгоняющие в заблуждение (дезинформирующие). Как например:

    
    /**
    * Вспомогательный метод, закрывает соединение со сканером, если isNotUsing истинно
    */
    private void scanClose(Scanner scan, boolean isNotUsing) throws Exception {
       if (!isNotUsing) {
           throw new Exception("The scanner is still in use");
       } scan.close();
    }

    What в этом комменте не так? А то, что он немножко врёт нам, ведь соединение закрывается, если isNotUsing = false, но ниHow не наоборот, How нам вещает пометка.

  • обязательные комментарии — комментарии, которые считают обязательными (Javadoc), но кои по факту иногда бывают излишне нагромождающими, недостоверными и ненужными (нужно задуматься, а нужны ли здесь такие комментарии).

    Пример:

    
    /**
    *  Creation пользователя по переданным параметрам
    * @param firstName Name созданного пользователя
    * @param middleName среднее Name созданного пользователя
    * @param lastName фамorя созданного пользователя
    * @param age возраст созданного пользователя
    * @param address addressс созданного пользователя
    * @return пользователь который был создан
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);

    Смогли бы вы понять, что делает метод без этих комментариев? Скорее всего да, поэтому комментарии в этом случае стают бессмысленными.

  • журнальные комментарии — комментарии, которые иногда добавляют в начало модуля, при каждом его редактировании (что-то вроде журнала вносимых изменений).

    
    /**
    *  Записи ведутся с 09 января 2020;
    **********************************************************************
    *  09.01.2020  : Обеспечение соединения с БД с помощью Jdbc Connection;
    *  15.01.2020  : Добавление интерфейсов уровня дао для работы с БД;
    *  23.01.2020  : Добавление интеграционных тестов для БД;
    *  28.01.2020  : Имплементация интерфейсов уровня дао;
    *  01.02.2020  : Разработка интерфейсов для сервисов,
    *  согласно требованиям прописанным в user stories;
    *  16.02.2020  : Имплементация интерфейсов сервисов
    *  (реализация бизнес логики связанной с работой БД);
    *  25.02.2020  : Добавление тестов для сервисов;
    *  08.03.2020  : Празднование восьмого марта(Миша опять в хлам);
    *  21.03.2020  : Рефакторинг сервис слоя;
    */
    

    Когда-то этот проход был оправдан, но с появлением систем управления исходным codeом (например — Git), это стало лишним нагромождением и усложнением codeа.

  • комментарии ссылки на авторов — комментарии, преднаmeaningм которых является, указание человека, писавшего code, чтобы можно было связаться и обсудить, How что и зачем:

    
    * @author  Bender Benderovich

    Опять же, системы контроля версий прекрасно запоминают, кто и когда добавил данный code, и подобный подход излишен.

  • commented code is code that has been commented out for one reason or another. One of the worst habits, because you commented it out and forgot, and other developers simply don’t have the courage to delete it (what if it’s something valuable).

    
    //    public void someMethod(SomeObject obj) {
    //    .....
    //    }

    As a result, it accumulates like trash. Under no circumstances should such code be left. If you really need it, don’t forget about the version control system.

  • non-obvious comments are comments that describe something in an unnecessarily complex manner.

    
    /*
        * Начать с массива, размер которого достаточен для хранения
        * всех byteов данных (плюс byteы фильтра) с запасом, плюс 300 byte
        * для данных заголовка
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];

    A comment should explain the code, not need an explanation itself. What's going on here? What are “filter bytes”? What does +1 have to do with this? Why exactly 300?

If you decide to write comments, here are a couple of tips for using them:
  1. Use styles that are easy to maintain: maintaining styles that are too fancy and exotic can be annoying and time consuming.
  2. Do not use comments at the end of lines that refer to single lines: this creates a large pile of comments, and it is difficult to come up with an expressive comment for each line.
  3. When creating a comment, try to answer the question “why” rather than “how.”
  4. Avoid shortcuts. As I said above, we do not need an explanation for the comment: the comment is the explanation.
  5. You can use comments to mark the units of measurement and the range of acceptable values.
  6. Place comments close to the code they describe.
As a result, I would still like to remind you: the best comments are the absence of a comment, and instead of it, proper naming in the application. As a rule, most of the time we will already be working with ready-made code, maintaining and expanding it. It is much more convenient when this code is easy to read and understand, because bad code gets in the way, puts a spoke in the wheels, and haste is its faithful companion. And the more bad code we have, the more performance drops, so we need to refactor from time to time. But if from the very beginning you try to write code for which subsequent developers will not want to find you and kill you, then you will need to refactor it less often. But it will still be necessary, since the conditions and requirements for the product are constantly changing, supplemented by adding additional connections, and there is no escape from this. Finally, I’ll leave a couple of interesting links for you to get acquainted with this topic here , here and here I guess that’s all for me today, thanks to everyone who read)) Rules for writing code: the power of correct naming, good and bad comments - 8
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION