JavaRush /Java Blog /Random-JA /コーヒーブレイク#64。きれいなコードを書く方法。低遅延システムでは Java が C++ よりも優れている理由

コーヒーブレイク#64。きれいなコードを書く方法。低遅延システムでは Java が C++ よりも優れている理由

Random-JA グループに公開済み

きれいなコードを書く方法

出典: Dev.to きれいなコードを書くことは、詩を書くことに似ています。これは詩であり、簡潔で、理解しやすく、変化しやすいものでなければなりません。クリーンなコードは、スケーラブルな組織を意味します。これは、変更を加えても混乱が生じないことを意味します。このようなコードを作成できることは、経験豊富な開発者の重要な資質の 1 つです。何人かの人に『クリーン コード』という本を読むように勧められて、ついに勇気を出して読んでみました。この本は、表紙が周囲の誇大宣伝に完全に応えている本の 1 つであることがわかりました。この本の推奨事項は明確かつ具体的で実践的であり、ユーモアも交えて提示されています。今日はこの本から得た主な要点を皆さんと共有したいと思います。コーヒーブレイク#64。 きれいなコードを書く方法。 低遅延システムでは Java が C++ よりも優れている理由 - 1

1. コードは機能するだけでなく、読みやすくなければなりません

ソフトウェアのコストのほとんどは長期サポートに関連しています。したがって、作成するコードは意図を明確に表現する必要があります。チームに新しく参加する開発者が、コード内で正確に何が起こっているのか、そしてその理由を簡単に理解できるようにする必要があります。作成者が作成したコードが理解しやすいほど、他の開発者がコードを理解するのにかかる時間が短縮されます。これにより、欠陥とメンテナンスコストが削減されます。 これを達成するにはどうすればよいでしょうか? 適切なネーミング + 単一責任を持つクラスと関数 + テストの作成。

2. 後では決してないという意味

正直に言うと、私たちは皆、後で戻ってコードをクリーンアップしようと時々自分自身に約束しますが、結局それを忘れてしまいます。 不要になった無駄なコードを残さないでください。これらは他の開発者を混乱させるだけであり、何の価値もありません。したがって、機能に変更を加える場合は、必ず古いコードを削除してください。どこかで何かが壊れても、テストではすぐにそれが表示されます。 これを達成するにはどうすればよいでしょうか? コードの削除は、特に大規模なアーキテクチャでは恐ろしい場合があります。したがって、ここではテストが重要です。これにより、自信を持ってコードを削除できます。

3. 特徴は小さくする必要があります

関数を記述する際の最初のルールは、関数を 20 行程度まで小さくすることです。関数が小さくなり、1 つのタスクに集中するほど、適切な名前を見つけるのが容易になります。関数の引数の理想的な数は 0 で、次は 1、2 ですが、引数の数は 3 つまでにする必要があります 関数は、単一責任とオープン/クローズの原則に従って作成する必要があります。

4. コードの重複は悪質です

重複は、よく組織されたシステムの敵です。それは余分な作業、余分なリスク、そして余分な不必要な複雑さです。 それについてどうすればよいでしょうか?コードが DRY 原則に従って分離され、モジュール化されて書かれていることを確認してください。

5. 唯一の良いコメントは、書かない方法を見つけたコメントです。

「適切な場所に適切なコメントがあることほど役に立つものはありません。しかし、コメントは、たとえ最良のシナリオであっても、必要悪です。」 コメントは、コードで考えを表現できないことを補うことを目的としています。つまり、これは最初は敗北を認めたことになります。はい、コードで意図を常に明確にできるとは限らないため、これらを使用する必要がありますが、それを祝う理由はありません。問題は、コメントには嘘が多いということです。常にではありませんし、意図的ではありませんが、あまりにも頻繁です。コメントが古く、記述されているコードから離れているほど、コメントが間違っている可能性が高くなります。その理由は単純です。プログラマーはコードとすべてのコメントの両方を適切に保守できないからです。したがって、非常に多くの場合、コメントは参照先のコードから分離され、最小限の精度で孤立した注釈になります。 それについてどうすればよいでしょうか?わかりやすい命名方法を使用する必要があります。変数の名前を読むと、それが何であるかをすぐに理解できるはずです。他の開発者がどの機能が最も重要かを理解するためにもテストが必要です。

6. オブジェクトは動作を明らかにしますが、データは明らかにしません。

モジュールは、操作するオブジェクトの内部について知る必要はありません。オブジェクトはデータを隠し、その操作を明らかにします。これは、オブジェクトがアクセサー メソッドを通じて内部構造を公開すべきではないことを意味します。誰もがあなたの裸を見る必要はありません。 それについてどうすればよいでしょうか?必要以上に公開しないように、変数のスコープは可能な限りローカルにする必要があります。

7. テスト

テストコードは、本番環境に導入されるものと同じくらい重要です。したがって、プロジェクトの発展に応じて変化し、成長する必要があります。 テストにより、コードの柔軟性、保守性、再利用性が維持されます。これらがないと、変更を行うとバグが発生する可能性があります。テストを使用すると、何かが壊れるのを恐れることなく、コードをクリーンアップできます。したがって、テストの純度を維持することが非常に重要です。テストがクリーンであることにより、テストの可読性が保証されます。テストは、コード作成者の意図を他の開発者に簡単な言葉で説明する機会です。したがって、各テスト関数で 1 つの概念のみをテストします。これにより、テストが記述的になって読みやすくなり、失敗した場合でもその理由を追跡しやすくなります。 これを達成するにはどうすればよいでしょうか? クリーンなFIRSTテストの原則に従わなければなりません。テストは次のようにする必要があります。
  • 速い。テストは迅速に実行する必要があります。テストの実行までに長時間待つ必要がある場合、テストをより頻繁に実行する可能性は低くなります。
  • 独立・孤立(独立)。テストは可能な限り分離され、互いに独立している必要があります。
  • 再現可能。テストは、開発、ステージング、実稼働など、どの環境でも再現可能である必要があります。
  • 自己検証。テストの結果はブール値である必要があります。テストは成功するか失敗するかのいずれかでなければなりません。
  • 徹底的に。すべてのエッジ ケース、すべてのセキュリティ問題、すべてのユース ケース (使用例)、およびハッピー パス (コードにとって最も好ましいシナリオ) をテストでカバーするよう努める必要があります。

8. エラーと例外の処理

スローする各例外は、エラーのソースと場所を特定するのに十分なコンテキストを提供する必要があります。通常、例外のスタック トレースはありますが、スタック トレースからは失敗した操作の目的はわかりません。可能であれば、コード内で null を渡すことは避けてください。メソッドから null を返したくなる場合は、代わりに例外をスローすることを検討してください。エラー処理をメイン ロジックから独立して表示できる別個のタスクにします。 これを達成するにはどうすればよいでしょうか? 有益なエラー メッセージを作成し、例外とともに渡します。失敗した操作とエラーの種類を指定します。

9. 授業

クラスは少人数である必要があります。しかし、カウントする必要があるのはコードの行数ではなく、責任です。クラス名は、そのクラスが何を担当するかを説明する鍵となります。私たちのシステムは、いくつかの巨大なクラスではなく、多数の小さなクラスで構成されている必要があります。このような小さなクラスはそれぞれ、単一の責任をカプセル化する必要があります。各クラスが存在する特定の理由は 1 つだけである必要があり、システムの望ましい動作を達成するには、各クラスが他のいくつかのクラスと「協力」する必要があります。パブリック変数を作成する正当な理由はほとんどありません。カプセル化を弱めることは常に最後の手段です。さらに、インスタンス変数はほとんどないはずです。優れたソフトウェア設計により、大規模な投資や再作業を行わずに変更を加えることができます。変数の範囲を狭めると、この作業が容易になります。 これを達成するにはどうすればよいでしょうか? 関心の分離は、最も古く、最も重要な設計手法の 1 つです。クラスは拡張にはオープンですが、変更にはクローズされる必要があります。理想的なシステムでは、既存のコードを変更するのではなく、システムを拡張することで新しい機能を有効にします。

10. フォーマット

それぞれの空行は、新しい別のコンセプトが始まったことを識別するのに役立つ視覚的な合図です。 ローカル変数は関数の先頭に記述する必要があります。 インスタンス変数はクラスの先頭で宣言する必要があります。 長い線よりも短い線の方が優れています。通常、制限は 100 ~ 120 文字です。これ以上長くしないでください。 これを達成するにはどうすればよいでしょうか? ほとんどのパラメーターは、CI またはテキスト エディターのリンターに渡すことができます。これらのツールを使用して、コードをできるだけクリーンにします。

プログラム開発原則

次のテクニックを使用すると、コードは常にクリーンになります: 変数に名前を付ける。適切な名前 (適切な命名) を選択することは、コードを読みやすく、したがって保守しやすくするために重要です。 「変数の名前は、自分の初子に付けるのと同じように責任を持って付けるべきです。」 開発者にとって、適切な名前を選択するのはしばしば課題です。これには、優れた説明スキルと共有された文化的背景が必要です。クリーン コードとは、まったく異なる開発者によって読み取られて改良されたコードです。変数、関数、またはクラスの名前は、このエンティティがなぜ存在するのか、何がどのように使用されるのかなど、基本的な質問のすべてに答える必要があります。名前にコメントが必要な場合、それは、その名前が説明する内容の本質を十分に明らかにしていないことを意味します。短い名前よりも長い名前の方が重要であり、定数よりも検索可能な名前の方が優れています。1 文字の名前は、短いメソッド内でローカル変数としてのみ使用できます。名前の長さはスコープと一致する必要があります。メソッド名は動詞または動詞句である必要があります。クラス名は動詞であってはなりません。 依存関係は最小限に抑える必要があります。自分がコントロールできないものに依存するよりも、自分がコントロールできるものに依存する方が良いのです。そうしないと、これらのものがあなたを支配することになります。 正確さ。コードのすべての部分は、読者が見つけられると期待される場所に配置する必要があります。コードベース内のナビゲーションは直感的である必要があり、開発者の意図が明確である必要があります。 クリーニング。コードベースに無駄なコードを残さないでください (古くて使用されなくなったり、「念のため」作成されたりするものではありません)。重複を減らし、早い段階でシンプルな抽象化を作成します。 標準化。コードを記述するときは、リポジトリ用に確立されたスタイルと慣例に従う必要があります。 自制心。使用されているテクノロジが開発され、新しいテクノロジが登場するにつれて、開発者は既存のコードの何かを変更および改善したいと願うことがよくあります。誇大宣伝にすぐに屈しないでください。新しいスタックを徹底的に研究し、特定の目的のためにのみ使用してください。コードベースをクリーンに保つことは、現在および将来の同僚に対して礼儀正しくするだけではありません。これはプログラムが長期的に存続するために不可欠です。コードがきれいであればあるほど、開発者は満足し、製品はより良くなり、より長く使用できるようになります。

低遅延システムでは Java が C++ よりも優れている理由

出典: StackOverflow 開発者としては、物事を行うには 2 つの方法があることを誰もが知っています。1 つは手動でゆっくりと煩わしく行う方法、もう 1 つは自動で困難かつ迅速に行う方法です。人工知能を使ってこの記事を書くこともできるでしょう。これにより、多くの時間を節約できる可能性があります。AI は 1 秒あたり数千の記事を生成できますが、最初の記事を生成するのに 2 年かかると知ったら、編集者はおそらく満足しないでしょう。コーヒーブレイク#64。 きれいなコードを書く方法。 低遅延システムでは Java が C++ よりも優れている理由 - 2待ち時間が短いソフトウェア システムを開発する場合にも、同様の状況が発生します。一般的な通念では、C++ 以外のものを使用するのはおかしい、というのが定説です。他のものはすべて遅延が長すぎるためです。しかし、私がここで皆さんに説得したいのは、逆の、直観に反した、ほとんど異端的な概念です。つまり、ソフトウェア システムで低遅延を実現するという点では、Java の方が優れているということです。この記事では、低遅延を重視するソフトウェア、つまり取引システムの具体例を取り上げたいと思います。ただし、ここで説明した議論は、低遅延が必要または望ましいほぼすべての状況に適用できます。私が経験した開発分野に関連して議論する方が簡単です。そして真実は、レイテンシーを測定するのが難しいということです。すべては、低遅延とは何を意味するかということになります。さあ、これを理解しましょう。

獲得した知恵

C++ はハードウェアに非常に近いため、ほとんどの開発者は、この言語でコーディングすると速度が向上すると言うでしょう。高速取引などの低遅延の状況では、ミリ秒がソフトウェアの実行可能性と従来のディスク領域の浪費との違いを生む可能性があり、C++ がゴールド スタンダードとみなされます。少なくとも以前はそうでした。しかし現実には、現在、多くの大手銀行や証券会社が Java で書かれたシステムを使用しています。つまり、Java でネイティブに記述されているという意味ですが、Java で記述されてから C++ で解釈されてレイテンシが短縮されるのではありません。これらのシステムは(おそらく)遅いという事実にもかかわらず、ティア 1 投資銀行でも標準になりつつあります。どうしたの?確かに、C++ はコードの実行に関しては「低レイテンシ」かもしれませんが、新機能のデプロイや、それを作成できる開発者の検索に関しては、決して低レイテンシではありません。

Java と C++ の (実際の) 違い

実際のシステムにおける Java と C++ の違いに関して言えば、開発時間の問題は始まりに過ぎません。この文脈における各言語の真の価値を理解するために、もう少し深く掘り下げてみましょう。まず、ほとんどの状況で C++ が Java よりも高速である本当の理由を覚えておくことが重要です。C++ ポインタはメモリ内の変数のアドレスです。これは、ソフトウェアが個々の変数に直接アクセスでき、変数を検索するために計算負荷の高いテーブルをクロールする必要がないことを意味します。または、C++ ではオブジェクトの有効期間と所有権を明示的に管理する必要があることが多いため、少なくともオブジェクトの場所を指定することで対処できます。その結果、コードを書くのが本当に得意でない限り (このスキルを習得するには数十年かかる場合があります)、C++ のデバッグには数時間 (または数週間) かかります。モンテカルロ エンジンや PDE テスト ツールをデバッグしようとした人なら誰でもわかるように、基本的なレベルでメモリ アクセスをデバッグしようとすると、非常に時間がかかることがあります。1 つのポインタに欠陥があるだけで、システム全体が簡単にダウンしてしまう可能性があるため、C++ で書かれた新しいバージョンをリリースするのは本当に恐ろしいことです。もちろんそれだけではありません。C++ でのプログラミングを楽しんでいる人は、Java のガベージ コレクターが非線形の遅延スパイクに悩まされていることを指摘するでしょう。これは、レガシー システムを使用する場合に特に当てはまります。そのため、クライアント システムを中断せずに Java コードに更新を送信すると、Java コードが非常に遅くなり、使用できなくなる可能性があります。これに応えて、Java GC によって生じるレイテンシを削減するために、過去 10 年間に多くの作業が行われてきたことを指摘したいと思います。LMAX ディスラプターたとえば、Java で書かれた低レイテンシーの取引プラットフォームであり、実行されるハードウェアと「機械的相互作用」を持ち、ロックを必要としないフレームワークとしても構築されています。継続的インテグレーションおよびデリバリー (CI/CD) プロセスを使用するシステムを構築すると、問題はさらに軽減されます。CI/CD では、テストされたコード変更の自動デプロイが可能になるためです。これは、CI/CD がガベージ コレクションのレイテンシを短縮するための反復的なアプローチを提供するためです。これにより、出荷前にさまざまなハードウェア仕様に合わせてコードを準備するというリソースを大量に消費するプロセスを必要とせずに、Java が段階的に改善され、特定のハードウェア環境に適応できるようになります。IDE の Java サポートは C++ よりもはるかに幅広いため、ほとんどのフレームワーク (Eclipse、IntelliJ IDEA) で Java をリファクタリングできます。これは、IDE が低レイテンシーのパフォーマンスを実現するためにコードを最適化できることを意味しますが、C++ を使用する場合にはこの機能はまだ制限されています。Java コードの速度が C++ に完全に一致しない場合でも、ほとんどの開発者は、C++ よりも Java の方が許容できるパフォーマンスを達成するのが簡単であると考えています。

「より速い」とは何を意味するのでしょうか?

実際、C++ が Java よりも本当に「高速」であるか、あるいは「遅延が低い」かどうかを疑う十分な理由があります。私はかなり濁った状況に陥っていること、そして多くの開発者が私の正気を疑い始めることを認識しています。でも聞いてください。この状況を想像してみましょう。2 人の開発者がいます。1 人は C++ で、もう 1 人は Java で作成し、高速取引プラットフォームをゼロから作成するように依頼します。その結果、Java で書かれたシステムは、C++ で書かれたシステムよりも貿易取引を完了するのに時間がかかります。ただし、Java では、C++ よりも未定義の動作のインスタンスがはるかに少ないです。ほんの 1 つの例を挙げると、配列外のインデックス付けは Java と C++ の両方でバグです。C++ でこれを誤って実行すると、セグメンテーション違反が発生するか、 (多くの場合) 乱数が発生するだけになる可能性があります。Java では、範囲外になると常にArrayIndexOutOfBoundsExceptionエラーがスローされます。これは、通常、エラーがすぐに特定され、エラーの場所を追跡しやすいため、Java でのデバッグがはるかに簡単であることを意味します。さらに、少なくとも私の経験では、どのコードを実行する必要がなく、どのコードがソフトウェアの動作にとって重要であるかを認識するのが Java の方が優れています。もちろん、無関係なコードがまったく含まれないように C++ コードを調整するのに何日も費やすこともできますが、現実の世界では、どのソフトウェアにもある程度の肥大化が含まれており、それを自動的に認識するのは Java の方が優れています。これは、現実の世界では、標準的な遅延メトリックで見ても、Java は C++ よりも高速であることが多いことを意味します。また、そうでない場合でも、言語間のレイテンシーの差は、高速取引においてさえ問題にならないほど大きくない他の要因によって圧倒されることがよくあります。

低遅延システムにおける Java の利点

私の意見では、これらの要素はすべて、Java を使用して高速取引プラットフォーム (および一般に低遅延システム、これについては後ほど詳しく説明します) を作成するための非常に説得力のある議論になります。ただし、C++ 愛好家を少し興奮させるために、Java を使用する追加の理由をいくつか見てみましょう。
  • まず、Java がソフトウェアに導入する過剰な遅延は、インターネットの問題など、遅延に影響を与える他の要因よりもはるかに小さい可能性があります。これは、(よく書かれた)Java コードであれば、ほとんどの取引状況で C++ と同様に簡単に実行できることを意味します。

  • Java の開発時間が短いということは、現実世界では Java で書かれたソフトウェアが C++ よりも早くハードウェアの変更 (または新しい取引戦略) に適応できることも意味します。

  • これをさらに詳しく調べると、Java ソフトウェアの最適化でも、C++ での同様のタスクよりも (ソフトウェア全体で考慮した場合) 高速になることがわかります。

言い換えれば、Java コードを記述してレイテンシを短縮することが非常に可能です。開発のあらゆる段階でメモリ管理を念頭に置きながら、C++ として記述するだけで済みます。C++ で記述しないことの利点は、デバッグ、アジャイル開発、および複数の環境への適応が Java の方が簡単かつ迅速であることです。

結論

低レイテンシーの取引システムを開発している場合を除き、おそらく上記のいずれかが自分に当てはまるかどうか疑問に思うでしょう。ごく一部の例外を除いて、答えは「はい」です。低遅延を実現する方法に関する議論は、新しいものでも、金融の世界に特有のものでもありません。このため、他の状況でも貴重な教訓をそこから学ぶことができます。特に、Java のほうが柔軟性が高く、耐障害性が高く、最終的に開発と保守が高速であるため「優れている」という上記の議論は、ソフトウェア開発の多くの分野に適用できます。私が (個人的に) Java で低遅延システムを書くことを好む理由は、この言語が過去 25 年間にわたって大きな成功を収めてきたのと同じ理由です。Java は、記述、コンパイル、デバッグ、学習が簡単です。これは、コードの作成に費やす時間が減り、コードの最適化により多くの時間を費やすことができることを意味します。実際には、これにより、より信頼性が高く、より高速な取引システムが実現します。高速取引にとって重要なのはこれだけです。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION