CodeGym /Java Blog /ランダム /コーディング ルール: 正しい名前、良いコメントと悪いコメントの力
John Squirrels
レベル 41
San Francisco

コーディング ルール: 正しい名前、良いコメントと悪いコメントの力

ランダム グループに公開済み
コーディング ルール: 正しい名前、良いコメントと悪いコメントの力 - 1他人のコードを調べなければならなかったことがどれくらいありますか? 何が起こっているのかを理解するために、2 時間ではなく 2 日を費やすこともできます。面白いのは、コードを書いた人にとっては、すべてが明確で完全に透明であるということです。これは驚くべきことではありません。結局のところ、完璧なコードは非常に曖昧な概念です。なぜなら、各開発者は世界やコードについても独自のビジョンを持っているからです。私は、同僚と同じコードを見て、その正確さやクリーンさについて意見が異なるという状況に何度か遭遇しました。コーディング規則: 正しい名前、良いコメントと悪いコメントの力 - 2おなじみですね。それでも、遵守すべき実証済みの原則がいくつかあります。最終的には、コードはあなたにとって有利になります。なぜなら、あなた自身がコードを受け取りたい状態にコードを残しておけば、世界はもう少し幸せできれいになるからです。前回の記事では(というか小さなガイド) コーディング ルールについて、システム全体とその構成要素 (オブジェクト、インターフェイス、クラス、メソッド、変数など) を記述するための推奨事項を少し理解しました。同じ記事の中で、私は特定の要素の正しい名前についてさりげなく言及しました。正しい名前を付けるとコードが何倍も読みやすくなるため、今日はこれについて話したいと思います。正しいコードに関するトピックの締めくくりとして、いくつかの考察、コード内のコメントの小さな例、およびこれが良いかどうかについての考察を示します。さて、始めましょう。

正しい名前

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

テレビシリーズ「シャーロック」(2010-2017)より

インターフェースの命名

通常、インターフェイスの名前は大文字で始まり、キャメルケースで書かれます。インターフェイスを作成するときは、接頭辞「I」を追加してインターフェイス (IUserService など) として指定することが良い方法と考えられていましたが、これは非常に見苦しく、気が散ってしまいます。このような場合は、接頭辞 (UserService) を省略し、その実装の名前に接尾辞として「Impl」を追加することをお勧めします (例: UserServiceImpl)。あるいは、最後の手段として、実装の名前に「C」接頭辞を追加することもできます (CUserService など)。

クラス名

インターフェイスと同様に、クラス名は大文字でキャメルケースを使用します。私たちがゾンビの黙示録に直面しているかどうかは問題ではありません。終わりが近づいているかどうかも問題ではありません。クラスの名前を動詞にしてはいけません。クラス名とオブジェクト名は、名詞または複合名詞 (UserController、UserDetails、UserAccount など) である必要があります。各クラスの名前の末尾にアプリケーションの略語を付け加えないでください。不必要に複雑になるだけです。たとえば、ユーザー データ移行アプリケーションがある場合、各クラス (UDMUserDetails、UDMUserAccount、UDMUserController) に「UDM」を追加しないでください。

メソッド名

通常、メソッド名は小文字で始まりますが、キャメルケース スタイル (camelCase) も使用されます。上で、クラス名は動詞であってはいけないと述べました。ここでは、状況はまったく逆です。メソッドの名前は、動詞または動詞句である必要があります (findUserById、findAllUsers、createUser など)。メソッド (変数やクラスも同様) を作成するときは、混乱を避けるために一貫した命名規則を使用してください。たとえば、ユーザーを検索するには、メソッドに getUserById または findUserById という名前を付けることができます。そしてもう 1 つ、他の人にはジョークが理解できない可能性があるため、メソッドの名前にユーモアを使用しないでください。その結果、そのメソッドが何をするのかを理解できない可能性があります。

変数名

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

短い変数名

x や n などの変数がある場合、コードを書いた人の意図はすぐにはわかりません。n が何をするのかは明らかではありません。それを理解するには、より慎重に熟考する必要があります (これは、何度も何度も時間をかけて考えることを意味します)。たとえば、担当ユーザーの ID を表すフィールドがあるとします。x や単に id などの変数名の代わりに、この変数に「responsibleUserId」という名前を付けます。これにより、可読性と情報コンテンツが即座に向上します。とはいえ、n のような短い名前は、小さなメソッドのローカル変数として使用できます。この変数に関係するコード ブロックはわずか数行であり、メソッド名はそこで何が起こるかを完全に説明しています。このような変数を見ると、開発者は、それが二次的に重要であり、範囲が非常に限定されていることが理解されます。その結果、スコープは変数名の長さに一定の依存性を持ちます。名前が長いほど、変数はよりグローバルになり、その逆も同様です。例として、最後に保存したユーザーを日付で検索する方法を次に示します。

public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("No user exists"));
}
ここでは、短い名前の変数 x と y を使用してストリームを並べ替えますが、その後はそれらのことを忘れます。

最適な長さ

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

小さな違い

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

意味

たとえば、UserData と UserInfo は実際には同じ意味を持つため、名前を意味のあるものにする必要がありますが、同義語によって曖昧さを生じさせないようにする必要があります。この場合、必要な特定のオブジェクトを理解するには、コードをさらに深く掘り下げる必要があります。有益な情報を伝えない言葉は避けてください。たとえば、firstNameString では、なぜ String という単語が必要なのでしょうか? これは本当に Date オブジェクトでしょうか? もちろん違います。したがって、単純に firstName を使用します。ブール変数についても触れておきたいと思います。例として、flagDeleted という名前のブール値を取り上げます。フラグという言葉には意味がありません。isDeleted と呼ぶ方が合理的です。

偽情報

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

検索

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

コメント

コーディング規則: 正しい名前、良いコメントと悪いコメントの力 - 4適切なコメントに勝るものはありませんが、空虚なコメント、時代遅れのコメント、または誤ったコメントほどモジュールを乱雑にするものはありません。それらは両刃の剣になる可能性がありますね。それでも、コメントを明確に良いものとして扱うのではなく、むしろそれほど悪ではないものとして扱うべきです。結局のところ、コメントは基本的に、コード内で明確に表現されていない考え方を補う方法です。たとえば、メソッド自体がわかりにくい場合に、メソッドの本質を何とか伝えるためにこれらを使用します。この状況では、説明的なメモを書くよりも、コードを正しくリファクタリングする方が良いでしょう。コードは成長し進化する傾向がありますが、コメントは同じままである可​​能性があるため、コメントが古ければ古いほど、コメントは悪化します。コメントが作成されてから時間が経過すればするほど、そのコメントの疑わしい可能性が高くなります。不正確なコメントは、混乱を招き、欺瞞的で誤った期待を与えるため、まったくコメントしないよりもはるかに悪いです。また、非常にトリッキーなコードがある場合でも、コメントするのではなく書き直す必要があります。

コメントの種類

  • 法的コメント— 法的理由による各ソース ファイルの先頭のコメント。次に例を示します。

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

  • 有益なコメント— コードの説明を表すコメント (追加情報の提供、またはコードの特定のセクションの意図の説明)。

    例えば:

    
    /*
    * Combines the user from the database with the one passed for updating
    * When a field in requestUser is empty, it is filled with old data from 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 としてマークされた理由について警告する)。

    
    // Takes too long to run
    // Don't run if you don't have a lot of time
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
    

  • TODO — 将来実行する必要があるが、何らかの理由で今は実行できないことについてのメモであるコメント。これは良い習慣ですが、無関係なコメントを削除して混乱を避けるために、このようなコメントは定期的に確認する必要があります。

    例は次のとおりです。

    
    // TODO: Add a check for the current user ID (when the security context is created)
    
    @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);
    // The trim() call is very important. It removes possible spaces at the end of the script
    // so that when we read and split into separate requests, we don't end up with empty ones
    

  • Javadoc コメント— 特定の機能の API を説明するコメント。文書化された API の方がはるかに使いやすいため、おそらく最も役立つコメントが含まれます。とはいえ、他の種類のコメントと同様に、古いコメントになる可能性もあります。したがって、ドキュメントへの主な貢献はコメントではなく、優れたコードによってもたらされるということを決して忘れないでください。

    ユーザーを更新するための非常に一般的な方法の例を次に示します。

    
    /**
    * Updates the passed fields for a user based on its id.
         *
    * @param id id of the user to be updated
    * @param user user with populated fields for updating
    * @return updated user
    */
           User update(Long id, User user);
    

悪いコメント

  • つぶやきコメント— 通常、急いで書かれ、そのコメントが指す微妙な状況を認識できるのは開発者だけであるため、その意味を理解できるのは開発者だけです。

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

    
    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           } catch (FileNotFoundException e) {
           // If there is no configuration file, the default configuration is loaded 
          }
    }
    

    これらの設定をロードするのは誰ですか? すでにロードされていますか? このメソッドは例外をキャッチしてデフォルト設定をロードすることになっていますか? システムの他の部分を詳しく調査することによってのみ答えられる疑問が多すぎます。

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

    例を見てみましょう:

    
    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * The logger associated with the current class
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Creates and returns a connection using the input parameters
        */
       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;
       }
    

    そのようなコメントには何の意味があるのでしょうか?彼らが説明することはすべてすでに完全に明らかです。

  • 信頼できないコメント— 真実ではなく、誤解を招くだけのコメント (偽情報)。たとえば、これがその 1 つです。

    
    /**
    * Helper method. Closes the connection with the scanner if isNotUsing is true
    */
    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 コメントなど) ですが、実際には過剰に蓄積されることがあり、信頼性が低く、不要なコメントです (これらのコメントが実際に必要かどうかを考える必要があります)。

  • 例:

    
    /**
    * Create a user based on the parameters
    * @param firstName first name of the created user
    * @param middleName middle name of the created user
    * @param lastName last name of the created user
    * @param age age of the created user
    * @param address address of the created user
    * @return user that was created
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);
    

    これらのコメントがなくても、このメソッドが何をするのか理解できますか? ほとんどの場合、そうです。したがって、ここではコメントは無意味になります。

  • ログ コメント— モジュールが編集されるたびにモジュールの先頭に追加されることがあるコメント (変更ログのようなもの)。

    
    /**
    * Records kept since January 9, 2020;
    **********************************************************************
    * 9 Jan 2020: Providing a database connection using JDBC Connection;
    * 15 Jan 2020: Adding DAO-level interfaces for working with the database;
    * 23 Jan 2020: Adding integration tests for the database;
    * 28 Jan 2020: Implementation of DAO-level interfaces;
    * 1 Feb 2020: Development of interfaces for services,
    * in accordance with the requirements specified in user stories;
    * 16 Feb 2020: Implementation of service interfaces
    * (implementation of business logic related to the work of the database);
    * 25 Feb 2020: Adding tests for services;
    * 8 Mar 2020: Celebration of International Women's Day (Terry is drunk again);
    * 21 Mar 2020: Refactoring the service layer;
    */
    

    このアプローチはかつては正当化されていましたが、バージョン管理システム (Git など) の出現により、コードが不必要に乱雑になり、複雑になりました。

  • 作者コメント— コードを書いた人を示すことを目的としたコメントで、その人に連絡して、どのように、何を、なぜについて話し合うことができます。例:

    
    * @author Bender Bending
    

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

  • コメントアウトされたコード— 何らかの理由でコメントアウトされたコード。これは最悪の習慣の 1 つです。なぜなら、あなたが何かをコメントアウトして忘れてしまうと、他の開発者にはそれを削除する勇気がないということが起こるからです (結局、それが価値のあるものだったらどうするでしょうか?)。

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

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

  • 自明ではないコメント— 過度に複雑な方法で何かを説明するコメント。

    
    /*
        * Start with an array large enough to store
        * all the data bytes (plus filter bytes) with a cushion, plus 300 bytes
        * for header data
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];
    

    コメントでコードを説明する必要があります。それ自体は説明の必要はないでしょう。それで、ここで何が間違っているのでしょうか?「フィルターバイト」とは何ですか? その「+1」とは一体何なのでしょうか?なぜちょうど 300 なのでしょうか?

すでにコメントを書くことに決めている場合は、次のいくつかのヒントを参照してください。
  1. 維持しやすいスタイルを使用します。あまりにも派手でエキゾチックなスタイルを維持するのは面倒で時間がかかります。
  2. 単一行を参照する行末コメントは使用しないでください。結果として大量のコメントが山積みになります。さらに、各行に意味のあるコメントを考えるのは困難です。
  3. コメントを作成するときは、「どのように」ではなく「なぜ」という質問に答えるようにしてください。
  4. 要約された情報は避けてください。上で述べたように、コメントに説明は必要ありません。コメント自体が説明です。
  5. コメントを使用して、単位と値の範囲をメモすることができます。
  6. コメントは、説明するコードの近くに配置します。
最後に、最良のコメントはコメントなしであり、アプリケーション全体で巧みな名前付けを使用することであることを思い出していただきたいと思います。原則として、ほとんどの場合、既存のコードを使用して作業し、それを維持および拡張します。悪いコードは邪魔になるため、このコードが読みやすく理解しやすいと非常に便利です。それは作業中にレンチを投げ込むようなもので、速攻はその忠実な仲間です。そして、悪いコードが増えれば増えるほど、パフォーマンスはさらに低下します。これは、時々リファクタリングする必要があることを意味します。しかし、最初から、次の開発者があなたを見つけて殺そうとしないようなコードを書こうとすれば、それほど頻繁にリファクタリングする必要はありません。しかし、製品の条件や要件は新しい依存関係や接続の追加によって常に変化するため、これは依然として必要です。さて、今日はこれで終わりだと思います。ここまで読んでくれた皆さん、ありがとう:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION