JavaRush /Java Blog /Random-JA /コードのルール: 適切な名前付けの力、良いコメントと悪いコメント
Константин
レベル 36

コードのルール: 適切な名前付けの力、良いコメントと悪いコメント

Random-JA グループに公開済み
コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 1 他人のコードを理解する必要があったことがどれくらいありますか? 何が起こっているのかを理解するために、数時間ではなく数日を費やす場合。面白いのは、このコードを書いた人にとって、すべてが明確で非常に透明であるということです。これは驚くべきことではありません。結局のところ、各開発者は世界とコードについてそれぞれ独自のビジョンを持っているため、完璧なコードや理想的なコードは非常に曖昧な概念です。同僚と私が同じコードを見て、その正確さやクリーンさについて意見が異なるという状況に何度も遭遇しました。 コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 2懐かしい感じですね。ただし、遵守すべき長年の実績のあるポイントがいくつかあり、最終的にはそれが私たちの手に影響を与えることになります。なぜなら、あなた自身がコードを受け取りたいと思う状態にコードを残しておくと、世界は少し混乱してしまうからです。より幸せに、よりクリーンに。 コードの書き方のルール (というより小さなガイド) に関する前回の記事コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 3では、システム全体とその要素 (オブジェクト、そのインターフェイス、クラス、メソッド、変数など) を記述するための推奨事項について少し触れました。そこで、特定の要素の正しい名前について簡単に説明しました。正しい名前を付けるとコードが読みやすくなるため、今日はまさにこれについて話したいと思います。コード内のコメントの小さな例と、これが良いかどうかについての考察と小さな例を参考にして、正しいコードに関するトピックを終了します。それでは始めましょう。

正しい命名

名前がその機能を大まかに説明しているとメソッドの使用がはるかに簡単になるため、名前が正しいとコードの可読性が向上し、それに応じて慣れるまでの時間を節約できます。コード内のすべては名前 (変数、メソッド、クラス、ファイル オブジェクトなど) で構成されているため、この点は正しくクリーンなコードを作成する場合に非常に重要になります。上記に基づいて、名前は、たとえば、変数が存在する理由、その機能、使用方法などの意味を伝える必要があります。変数を説明するための最良のコメントは、その正しい名前であることを何度も指摘します。 コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 4

インターフェースの名前付け

通常、インターフェイスでは大文字で始まり、キャメルケース (CamelCase) で書かれた名前が使用されます。インターフェイスを記述するときは、インターフェイス (IUserService など) として指定するために接頭辞 I を付けることが良い習慣でしたが、これは非常に醜く、気が散ります。このような場合は、それを付けずに(UserService)を記述し、その実装に -Impl(UserServiceImpl)を追加すると良いでしょう。まあ、または最後の手段として、その実装に接頭辞 C (CUserService) を追加します。

クラス名

インターフェイスと同様に、名前は大文字で、キャメル スタイル (キャメルケース) を使用します。どのような黙示録が起こっていても、締め切りがどれほど早くても、クラス名は動詞であってはいけないということを決して忘れないでください。クラス名とオブジェクト名は、名詞とその組み合わせ (UserController、UserDetails、UserAccount など) である必要があります。このアプリケーションの略語を各クラスの名前に指定しないでください。不必要に複雑になるだけです (たとえば、User Data Migration アプリケーションがあり、各クラスに UDM (UDMUserDeatils、UDMUserAccount、UDMUserController) を追加します) )。

メソッド名

通常、メソッド名は小文字で始まりますが、キャメル スタイル (キャメルケース) も使用されます。上で、クラス名は動詞であってはいけないという事実について説明しました。ここでは状況は正反対です。メソッドの名前は動詞、または動詞との組み合わせである必要があります (findUserById、findAllUsers、createUser など)。メソッド (変数やクラスも同様) を作成するときは、混乱を避けるために、1 つの命名方法を使用してください。たとえば、ユーザーを検索するには、メソッドを getUserById または findUserById として記述できます。そしてもう 1 つ: メソッドの名前にユーモアを使用しないでください。そのジョークも、このメソッドが何をするのかも理解できない可能性があるからです。

変数名

ほとんどの場合、変数名は小文字で始まり、変数がグローバル定数である場合を除き、キャメルケースも使用されます。このような場合、名前の文字はすべて大文字で書かれ、単語はアンダースコア「_」で区切られます。変数に名前を付けるときは、便宜上、意味のあるコンテキストを使用できます。つまり、firstName、lastName、status など、より大きなものの一部として変数がある場合、この変数が一部であるオブジェクトを示すプレフィックスを追加できます。例: userFirstName、userLastName、userStatus。また、変数の意味がまったく異なる場合、変数に類似した名前を付けることも避ける必要があります。変数の一般的な反意語:
  • 始まり/終わり
  • 最初の最後
  • ロック/ロック解除
  • 最小/最大
  • 次へ/前へ
  • 古い/新しい
  • 開いた/閉じた
  • 見える/見えない
  • ソース・ターゲット
  • 送信元/宛先
  • 上下

短い変数名

x や n などの変数がある場合、コードを書いた人の意図はすぐにはわかりません。メソッド n が何を行うかは明らかではありません。より思慮深い思考が必要です (そして、それには時間、時間、時間がかかります)。たとえば、担当ユーザーの ID というフィールドがあり、x や単なる ID のような名前の代わりに、この変数を責任ユーザー ID と呼びます。これにより、読みやすさと意味がすぐに向上します。ただし、n のような短い名前は、小さなメソッドのローカルな変更として適切な位置を占めており、その変更を含むコード ブロックはわずか数行のコードであり、メソッド名はそこで何が起こっているかを完全に説明しています。開発者は、このような変数を見て、その重要性は二次的であり、範囲が非常に限られていることを理解します。その結果、変数名の長さにある程度の依存性が生じます。変数名が長ければ長いほど、変数はよりグローバルになり、その逆も同様です。例として、最後に保存されたユーザーを日付で検索する方法は次のとおりです。
public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
ここでは、短い名前 x と y を使用してストリームの並べ替えを設定し、それらの名前は忘れます。

最適な長さ

名前の長さの話題を続けましょう。最適な名前の長さは、maximumNumberOfUsersInTheCurrentGroup の名前の長さと n の間のどこかになります。つまり、短すぎるものは意味が欠如し、長すぎるものは可読性を高めることなくプログラムを拡張し、毎回書くのが面倒なだけです。上記の場合を考慮しないと、n のような短い名前の変数の場合、長さを約 8 ~ 16 文字に抑える必要があります。これは厳密なルールではなく、ガイドラインのようなものです。

小さな違い

名前の微妙な違いを無視することはできません。これは単に混乱したり、名前の小さな違いに気づくために多くの余分な時間を費やす可能性があるため、これも悪い習慣だからです。たとえば、InvalidDataAccessApiUsageException と InvalidDataAccessResourceUsageException の違いは、一見しただけではわかりにくいです。また、小さな L と O を使用すると、誤った情報が生じることがよくあります。これは、これらの文字が 1 や 0 と混同されやすいためです。フォントによっては、違いがより明らかなものもあれば、そうでないものもあります。

意味部分

たとえば、UserData と UserInfo は実際には同じ意味を持ち、必要な特定のオブジェクトを理解するにはコードをもう少し深く掘り下げる必要があるため、意味的な部分を名前に含める必要がありますが、同義語を使いすぎないようにする必要があります。 。たとえば、firstNameString: なぜ単語文字列が必要なのでしょうか?など、有益でない単語は避けてください。名前を日付型オブジェクトにすることはできますか? もちろんそうではありません。したがって、単純に - firstName です。例として、flagDelete などのブール変数について説明します。flag という単語には意味的な意味はありません。isDelete と呼ぶ方が合理的です。

偽情報

間違った命名についても少し述べておきたいと思います。userActivityList という名前があり、その名前が付けられたオブジェクトが List タイプではなく、ストレージ用の他のコンテナまたはカスタム オブジェクトであるとします。これは平均的なプログラマを混乱させる可能性があります。userActivityGroup や userActivities などと呼ぶ方がよいでしょう。

検索

短くて単純な名前の欠点の 1 つは、大量のコード内で名前を見つけるのが難しいことです。name という変数と NAME_FOR_DEFAULT_USER のどちらが見つけやすいでしょうか。もちろん、2番目のオプションです。頻繁に出現する単語 (文字) を名前に含めることは避ける必要があります。これは、検索中に見つかるファイルの数が増えるだけであり、良くありません。プログラマはコードを書くよりもコードを読むことに多くの時間を費やすので、アプリケーションの要素の名前に注意してください。しかし、うまく名前を付けることができなかった場合はどうすればよいでしょうか? メソッドの名前がその機能をうまく説明していない場合はどうすればよいでしょうか? ここで重要になります。次の項目はコメントです。

コメント

コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 5関連性のあるコメントほど重要なものはありませんが、意味のない、時代遅れの、または誤解を招くコメントほどモジュールを乱雑にするものはありません。それは両刃の剣ですよね。それでも、コメントを明確な善として扱うべきではなく、むしろ、より小さな悪として扱うべきです。結局のところ、コメントは本質的に、コード内で表現できなかった考えを補うものです。たとえば、メソッドがわかりにくい場合に、そのメソッドの本質を何とか伝えるために使用します。このような状況では、説明的なメモを書くよりもコードを正しくリファクタリングする方が良いでしょう。コードは成長し進化する傾向があるため、コメントが古ければ古いほど問題になりますが、コメントは同じままである可​​能性があり、コメントが進めば進むほど、これらのメモはより疑わしいものになります。不正確なコメントは、混乱と欺瞞をもたらし、誤った期待を与えるため、コメントがないことよりもはるかに悪いです。たとえ非常にトリッキーなコードを持っていたとしても、それについてコメントするのではなく、書き直す価値があります。

コメントの種類

  • 法的コメントとは、次のような法的理由により各ソース コード ファイルの先頭に残されるコメントです。

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

  • 有益なコメントは、コードの説明を提供するコメントです (追加情報や特定のコード部分の意図を提供します)。

    例として:

    /*
    * Объединяет пользователя из бд и пришедшего для обновления
    * Когда в 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()
           );
           }

    この場合、メソッドとその引数の名前は、非常に透過的な機能と相まって、それ自体を非常によく説明しているため、コメントなしで行うことができます。

  • 警告コメント- 何らかのアクションの望ましくない結果について他の開発者に警告することを目的としたコメント (たとえば、テストが @Ignore としてマークされた理由)。

    // Слишком долго отрабатывает
    // Не запускайте, если не располагаете избытком времени
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
  • TODO - 実行する必要があるが、何らかの理由で今は実行できない将来のメモであるコメント。これは良い習慣ですが、乱雑を避けるために、定期的に見直して無関係なものを削除する必要があります。

    例は次のとおりです。

    //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 を取得します) と保存したユーザーのチェックを追加する必要があることに注意してください。

  • 補強コメント- 一見すると重要ではないように見える、ある状況の重要性を強調するコメント。

    例として、テスト データベースにいくつかのスクリプトを入力するメソッドの一部を示します。

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

  • javaDoc - 一般的に使用される特定の機能の API を説明するコメント。文書化された API は操作がはるかに簡単であるため、おそらく最も役立つコメントですが、他のコメントと同様に古くなってしまう可能性もあります。したがって、ドキュメントへの主な貢献はコメントではなく、優れたコードであることを忘れないでください。

    完全に通常のユーザー更新方法の例:

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

不適切なコメント スクリプト

コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 7
  • つぶやきコメント- 通常、急いで書かれるコメント。その意味は、それを書いた開発者のみに明らかです。なぜなら、彼が言及しているニュアンスで状況を理解できるのは開発者だけだからです。

    次の例を考えてみましょう。

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

    これらの設定をロードするのは誰ですか? 以前にダウンロードされたことがありますか? このメソッドは例外をインターセプトしてデフォルト設定を呼び出すことを目的としていますか? あまりにも多くの疑問が生じますが、その答えはシステムの他の部分を詳しく調査することによってのみ得られます。

  • 冗長コメントは、コードの特定のセクションで何が起こっているかがすでに明らかであるため、セマンティックな負荷をまったくかけないコメントです (コードほど読みやすいものはありません)。

    例を見てみましょう:

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

    このコメントの何が問題なのでしょうか? そして、マークが示すように、 isNotUsing = false の場合接続は閉じられますが、その逆は成り立たないため、彼は私たちに少し嘘をついています。

  • 必須コメント- 必須(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  : Рефакторинг сервис слоя;
    */

    かつてはこの一節が正当化されていましたが、ソース コード管理システム (Git など) の出現により、これはコードの不必要な乱雑さと複雑さになりました。

  • コメントは作成者へのリンクです - コードを書いた人を示すことを目的としたコメントです。これにより、どのように、何を、そしてなぜ、連絡して話し合うことができます。

    * @author  Bender Benderovich

    繰り返しになりますが、バージョン管理システムはこのコードを誰がいつ追加したかを完全に記憶しているため、このアプローチは不要です。

  • コメント化されたコードは、何らかの理由でコメントアウトされたコードです。これは最悪の習慣の 1 つです。コメントアウトして忘れていて、他の開発者にはそれを削除する勇気がないからです (もしそれが貴重なものだったらどうしよう)。

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

    その結果、ゴミのように溜まっていきます。いかなる場合でも、そのようなコードは残すべきではありません。本当に必要な場合は、バージョン管理システムを忘れないでください。

  • 非自明なコメントとは、不必要に複雑な方法で何かを説明するコメントです。

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

    コメントはコードを説明するものであり、説明自体は必要ありません。ここには何があるの?「フィルターバイト」とは何ですか? +1 はこれと何の関係があるのでしょうか? なぜちょうど 300 なのでしょうか?

コメントを書く場合は、コメントを使用するためのヒントをいくつか紹介します。
  1. 維持しやすいスタイルを使用します。あまりにも派手でエキゾチックなスタイルを維持すると、面倒で時間がかかる場合があります。
  2. 単一行を参照する行末にコメントを使用しないでください。これにより、大量のコメントの山が作成され、各行に対して表現力豊かなコメントを考え出すのが困難になります。
  3. コメントを作成するときは、「どのように」ではなく「なぜ」という質問に答えるようにしてください。
  4. 略語は避けてください。上で述べたように、コメントについての説明は必要ありません。コメントは説明です。
  5. コメントを使用して、測定単位と許容値の範囲をマークできます。
  6. コメントは、説明するコードの近くに配置します。
したがって、注意していただきたいのは、最良のコメントとは、コメントを省略し、その代わりにアプリケーション内で適切な名前を付けることです。原則として、ほとんどの場合、既製のコードを使用して作業し、それを維持および拡張します。このコードが読みやすく理解しやすいと、はるかに便利です。なぜなら、悪いコードは邪魔になり、混乱を招くため、性急なコードはその忠実な仲間だからです。そして、悪いコードが増えれば増えるほどパフォーマンスが低下するため、時々リファクタリングする必要があります。しかし、最初から、後続の開発者があなたを見つけて殺したくないようなコードを書こうとするのであれば、リファクタリングの必要性は少なくなります。しかし、製品の条件と要件は常に変化し、追加の接続を追加することで補われるため、これは依然として必要であり、これから逃れることはできません。最後に、このトピックについて知っていただくために、ここ、ここ、そしてここに興味深いリンクをいくつか残しておきます。 今日はこれで終わりだと思います。読んでくださった皆さんに感謝します)) コードを書くためのルール: 正しい名前付け、良いコメントと悪いコメントの力 - 8
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION