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

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

Published in the Random EN group
members
Code writing rules: the power of proper 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 of 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 purity. Code writing rules: the power of proper naming, good and bad comments - 2A familiar feeling, isn't it? However, there are some time-tested points that should be followed, which in the end will play into our hands, because if you leave your code in the state in which you yourself would like to receive it, the world would become a little happier and cleaner. Code writing rules: the power of proper naming, good and bad comments - 3In my last articleabout the rules for writing code (or rather, a small guide), we felt a little about the recommendations for writing the system as a whole and its elements such as objects, their interfaces, classes, methods and variables. In the same place, I casually mentioned the correct naming of certain elements. Today I would like to talk about this, because the correct names make the code much easier to read. We will close the topic of correct code with the help of reflections and small examples of comments in the code - this is good or still not very good. So let's get started.

Correct naming

Proper names improve the readability of the code, respectively, saving time for familiarization, because it is much easier to use a method when the name roughly describes its functionality. Since everything in the 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, the variable exists, what it does, and how it is used. I will note again and again that the best comment to describe a variable is its correct name. Code writing rules: the power of proper naming, good and bad comments - 4

Interface Naming

Interfaces tend to use names that begin with a capital letter and are written in camel case. It used to be good practice to prefix an interface with I to designate it as an interface (for example, IUserService), but that looks very ugly and distracting. In such cases, it is better to write without it (UserService), and add -Impl (UserServiceImpl) to its implementation. Well, or in extreme cases, add the prefix C (СUserService) to its implementation.

Class names

Just like interfaces, names are capitalized and use camel case (CamelCase). Whatever the apocalypse, no matter how the deadlines burn, but never, remember - never the name of the class should 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 an abbreviation of this application, as this will only add unnecessary complexity (for example, we have a User Data Migration application, and we will add UDM to each class - UDMUserDeatils, UDMUserAccount, UDMUserController).

Method names

Usually method names start with a small letter, but they also use camel case (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 should just be verbs or their combinations with verbs: findUserById, findAllUsers, createUser, and so on. When creating a method (as well as variables and classes), in order not to get confused, use one naming approach. For example, to find a user, the method could 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 start with a small letter and also use Camelcase, except when 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, for convenience, you can use meaningful context. 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 that points to the object of which this variable is a 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 intent of the person who wrote the code. It is not obvious what method n does: it requires more thoughtful reflection (and this is time time, time). For example, we have a field - the id of the responsible user, and instead of some type name - x or just id, we will call this variable responsibleUserId, which immediately increases our readability and meaningfulness. However, short names like n have a place as local changes to small methods, where the block of code with this change is just a couple of lines of code, and the method name perfectly describes what happens there. The developer, seeing such a variable, understands its secondary importance and a very limited scope. As a result, there is a certain dependence on the length of the variable name: the longer it is, especially a global variable 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 the short names x and y to specify the sorting of the stream, and forget about them.

Optimal length

Let's continue the theme of the length of names. The optimal name length is somewhere between maximumNumberOfUsersInTheCurrentGroup and n. That is, too short ones suffer from a lack of meaning, and too long stretch the program without adding readability, and they are simply too lazy to write every time. Not considering the above case, for variables with a short name like n, you need to stick to a length of about 8 -16 characters. This is not a strict rule, but rather as a guideline.

small differences

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

semantic part

You need to put the semantic part in the names, but not overplay with synonyms, since, for example, UserData and UserInfo actually have the same meaning, and you will have to dig a little deeper in the code to understand which specific object we need. Avoid uninformative words like firstNameString: why do we need the word string? Can a name be an object of date type? Of course not: so just - firstName. Also, as an example, I would like to mention boolean variables, for example, flagDelete. The word flag does not carry any semantic load. It was more reasonable to call - isDelete.

Disinformation

I would also like to say a few words about incorrect naming. Suppose we have a userActivityList naming, and at the same time, the object named so is not of the List type, but some other container or custom object for storage. This can lead an ordinary programmer into a stupor: it's better to name 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 which will be easier to find: a variable named 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. As a reminder, programmers spend more time reading code than writing it, so think carefully about naming your application elements. But what if it didn't work out well? If the name of the method does not describe its functionality well? This is where it comes into play, our next item is comments.

Comments

Code writing rules: the power of proper naming, good and bad comments - 5There is nothing better than a pertinent comment, but nothing clutters up a module like empty, outdated, or false comments. A double-edged sword, isn't it? Still, you should not treat comments as an unequivocal good: rather, as a lesser evil. After all, a comment, in its essence, is a compensation for an unsuccessfully expressed thought in the code. For example, we use them to somehow convey the essence of the method, if it turned out to be too confusing. In such a situation, it is better to correctly refactor the code than to write descriptive notes. The older the comment, the worse, because the code tends to grow and evolve, and the comment can remain the same, and the further, the more doubtful these notes are. Inaccurate comments are much worse than none, because they are confusing and deceiving, giving false expectations. Code writing rules: the power of proper naming, good and bad comments - 6

Varieties of comments

  • legal comments - 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 to the code (providing additional information or intentions of this 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 a 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 a note for the future, what needs to be done, but for some reason cannot be done now. This is a good practice, but still they should be reviewed regularly to remove irrelevant ones to avoid clutter.

    An example would be:

    //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);
           }

    Here we mark that we need to add a check of the user who downloads (whose id we will pull out from the security context) with the one who saved it.

  • reinforcing comment - a comment that emphasizes the importance of some circumstance, which at first glance may seem insignificant.

    As an example, a piece of the method that fills the test database with some scripts:

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

  • javaDoc - comments that describe the API of certain functionality for general use. Probably the most helpful comments, since the documented API is much easier to work with, but it can also become outdated like any other. Therefore, do not forget that the main contribution to the documentation is made not by comments, but by good code.

    An example of a quite common user update method:

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

Bad Comment Scripts

Code writing rules: the power of proper naming, good and bad comments - 7
  • mumbling comment - comments that are usually written in haste, the meaning of which is clear only to the developer who wrote them, since only he sees the situation with the nuances to which he refers.

    Consider this example:

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

    Who downloads these settings? Have they been uploaded before? Is the method intended to catch exceptions and call default settings? Too many questions arise, the answers to which can only be obtained by delving into the study of other parts of the system.

  • redundant comment - a comment that does not carry a semantic load, since it is already clear what is happening in a given section of the code (it is no easier to read than the code).

    Let's see an example:

    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;
       }

    What is the point of such comments, if we already see everything perfectly

  • inaccurate comments - comments that do not correspond to the truth and only mislead (misinforming). Such as:

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

    What is wrong with this comment? And the fact that he is lying to us a little, because the connection is closed if isNotUsing = false, but not vice versa, as the mark tells us.

  • mandatory comments - comments that are considered mandatory (Javadoc), but which in fact are sometimes unnecessarily heaping, unreliable and unnecessary (you need to think about whether such comments are needed here).

    Example:

    /**
    *  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);

    Could you understand what the method does without these comments? Most likely yes, so comments in this case become meaningless.

  • log comments - comments that are sometimes added to the beginning of the module, each time it is edited (something like a log of changes made).

    /**
    *  Записи ведутся с 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  : Рефакторинг сервис слоя;
    */

    Once this passage was justified, but with the advent of source code management systems (for example, Git), this has become an unnecessary heap and complication of the code.

  • author link comments - comments whose purpose is to indicate the person who wrote the code so that you can contact and discuss how what and why:

    * @author  Bender Benderovich

    Again, version control systems are great at remembering who added a given code and when, and this approach is overkill.

  • commented code - 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 remove it (in case it’s something of value).

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

    As a result, it accumulates like trash. In no case should you leave such a code. If you really need it, do not forget again about the version control system.

  • non-obvious comments - comments that are unnecessarily difficult to describe something.

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

    The comment should explain the code, not need explanation itself. What is there? What are "filter bytes"? Why +1 here? Why exactly 300?

If you already decide to write comments, here are a couple of tips for using them:
  1. Use styles that will be easy to maintain: Maintaining styles that are too quirky and exotic can be annoying and time consuming.
  2. Don't use comments at the end of single-line lines: you get a lot of comments, and it's hard to come up with a meaningful comment for each line.
  3. When coming up with a comment, try to answer the question “why”, not “how”.
  4. Avoid abbreviations. As mentioned above, we do not need an explanation for a comment: a comment is an explanation.
  5. You can use comments to mark the units of measurement and the range of valid values.
  6. Position comments close to the code they describe.
As a result, I still want to remind you: the best comment is the absence of a comment, and instead of it, competent naming in the application. As a rule, most of the time we will already work with ready-made code, with its maintenance and expansion. It is much more convenient when this code is conveniently readable and understandable, because bad code gets in the way, puts those other spokes in the wheels and haste is his faithful friend. 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 the next developers will not want to find and kill you, then you will need to refactor it less often. But still, it will be necessary, since the conditions, requirements for the product are constantly changing, supplemented by hanging additional connections, and you can’t run away from this.here , here and here Perhaps that's all for me today, thanks to everyone who read it)) Code writing rules: the power of proper naming, good and bad comments - 8
Comments
  • Popular
  • New
  • Old
You must be signed in to leave a comment
This page doesn't have any comments yet