web-dev-qa-db-ja.com

大きなコードベースを理解しやすくする方法

比較的大きなプロジェクトを開発しているとしましょう。私はすべてのクラスと関数をDoxygenで既に文書化していますが、各ソースコードファイルに「プログラマーのメモ」を付けるというアイデアがありました。

この背後にある考えは、特定のクラスが機能するhow(そして、ほとんどのコメントがそうであるようにwhyだけではない)の言葉で説明することです。言い換えれば、クラスの仕組みについて他のプログラマーに別の見方をさせることです。

例えば:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

これは、大規模なプロジェクトを新しいプログラマー/寄稿者がそれがどのように機能するかを理解しやすくするための良い方法でしょうか?一貫したコーディングスタイルと「標準」のディレクトリ構成を維持すること以外に、これらの場合に「標準」または推奨事項はありますか?

105
Alex Spataru

これは素晴らしいです。これを行うためにもっと多くのソフトウェア開発者が時間と労力を費やしたいと思います。それ:

  • クラスが何をするかを分かりやすい英語で述べます(つまり、それは責任です)。
  • コードがすでに言っていることを逐語的に繰り返すことなく、コードに関する有用な補足情報を提供します、
  • 設計上の決定のいくつかと、それらが行われた理由の概要、および
  • あなたのコードを読んでいる次の人に降りかかるかもしれない落とし穴のいくつかをハイライトします。

悲しいかな、多くのプログラマーは「コードが適切に書かれていれば、文書化する必要はない」という陣営に陥ります。違います。コード自体を読み取るだけでは明らかではない、コードクラス、メソッド、モジュール、その他のアーティファクトの間には、多くの暗黙の関係があります。

経験豊富なコーダーは、ドキュメントがなくても明らかである、明確で簡単に理解できるアーキテクチャを備えた設計を慎重に作成できます。しかし、そのようなプログラムをいくつ実際に見ましたか?

141
Robert Harvey

大きなコードベースで作業するための鍵は、変更を行うためにコードベース全体を読み取る必要がないことです。プログラマーが探しているコードをすばやく見つけられるようにするには、コードを整理し、整理する必要があります。つまり、実行可能ファイル、ライブラリ、名前空間から個々のクラスに至るまで、コード内の各論理ユニットには明確な責任があるはずです。したがって、ソースファイルだけでなく、それらが存在するディレクトリも文書化します。

プログラマーのメモは、設計決定の背景にもなります。これは貴重な情報になる可能性がありますが、責任の表明とは別に(読者がクラスの責任またはその設計根拠について読みたいかどうかを読者が選択できるようにするため)、それを説明するソースの近くに移動します可能な限り、コードが更新されたときにドキュメントが更新される可能性を最大化します(ドキュメントは、その正確性を信頼できる場合にのみ役立ちます。古いドキュメントはどれも劣ることはありません!)。

とは言っても、ドキュメントはDRYのままにする必要があります。つまり、コードで表現されている可能性がある情報や、すでに別の場所で説明されている情報は繰り返さないでください(「ドキュメントの状態」のようなフレーズは警告サインです)。特に、将来のメンテナは英語なので、プロジェクトのプログラミング言語に習熟しているだけです。コメントで実装を言い換えても(人々がドキュメントを誇りに思っている場合によく見られます)、特にドキュメントが記述されているコードの近くにない場合は、実装から逸脱する可能性があります。

最後に、ドキュメントの構造をプロジェクト全体で標準化して、誰でも見つけられるようにする必要があります(バグトラッカーのPeterドキュメント、wikiのSue、ReadmeのAlan、およびソースコードのJohnの王室の混乱です...) 。

36
meriton

これが非常に良いアプローチであることに私は同意しません、主に

  1. プロジェクトをリファクタリングし、メソッドを移動すると、ドキュメントが壊れます。

  2. ドキュメントが適切に更新されていないと、コードの理解に役立つよりも混乱が生じます。

各メソッドのユニットテスト/各モジュールの統合テストがある場合、それはコードコメントに比べて保守しやすく、理解しやすい自己文書になります。

はい、適切なディレクトリ構造があれば間違いなく役立ちます。

13

私は個人的に、デザインの概要とクラスとリソースのリストを提供する高レベルの設計ドキュメント(できればコードより前に記述)のファンです。トップダウン設計は物事を大幅に簡素化します-あなたは「ゲームエンジン->ハードウェア->コントローラ->ジョイスティック」かもしれません;したがって、新しいプログラマーは、「xyzコントローラーの「a」ボタンを修正する」と、少なくともどこから探し始めるかがわかるだろうと言いました。

現代の言語が多すぎると、コードが数百の小さなファイルに分割される傾向があるため、適切なファイルを見つけるだけでも、中程度のプロジェクトでは難しい場合があります。

7
DWalker

コードベースが大きい場合-私は設計を提供しようとしますその設計と実装の主要な要素をマップするドキュメント。ここでの目的は、使用されるクラスの詳細を示すことではなく、コードの鍵と設計に取り入れられた考えを提供することです。これは、システム、そのコンポーネント、およびアプリケーションに包括的なコンテキストを提供します。

設計ドキュメントに含めるものは次のとおりです。

  • アプリケーションのアーキテクチャ
  • 論理コード構造
  • データフロー
  • 使用される主要なパターンとその使用の動機
  • コードソースの構造
  • それを構築する方法(これは暗黙的な依存関係と物理的なコードソース構造への洞察を提供します)

これに続いて、クラスおよび関数/メソッドのドキュメントは必要に応じて記入する必要があります。特にパブリックAPI。いずれの場合も、次のすべてが何であるかを明確にする必要があります。

  • 前提条件
  • 効果
  • 不変
  • 例外条件(スロー)
6
Niall

新しい開発者がコードベースを理解しやすくするために私が見つけた最も重要なルールは完全な合意には費用がかかります。

新しい開発者が取り組んでいるシステムを完全に理解する必要がある場合、それは就職学習のすべての機会を妨げます。プログラマーのメモは素晴らしいスタートだと思いますが、私はさらに進んでいきます。新たにアプローチした場合、開発者が事前に学習することを要求するのではなく、開発者がその場で何をしているのかを理解できるようにするコードを記述してください。決して発生することがないことがわかっている場合のアサートのような小さなことと、アサートが有効である理由を説明するコメントは、長い道のりです。したがって、何か悪いことをすると、segfaultするのではなく、正常に失敗するコードを書くことになります。

4
Cort Ammon

私はドキュメンテーションを含む大きなクラスを見てきましたが、ドキュメンテーションを読んだ後、このクラスが何に適しているのか、そして誰がなぜそれを使用するのかわかりません。同時に、私はいくつかの機能が必要であり、それを処理するためのクラスが必要であることを確信していて、どこにもそれを見つけることができませんでした。している。

したがって、ドキュメントで最初に必要なのは、クラスが実行することのほんの数文と、なぜそれを使用したいかです。元の質問のコメントは、その点でかなりうまくいっています。これらのコメントを読んだ後、それが提供する値を解釈できないためにうまく機能しないジョイスティックがあった場合、チェックするコードがわかります。

3
gnasher729

@meritonが言ったように、コードを個別のコンポーネントに分割します。さらに良いのは、コードベースを個別のパッケージ(JAR、gem、卵など)に分割して、コンポーネントの分離方法をさらに明確にすることです。バグがある場合、開発者は、バグが存在するpackageを見つけて、(うまくいけば)バグを修正するだけで済みます。言うまでもなく、単体テストを行う方が簡単で、依存関係管理を利用できます。

別の解決策:コードベースを小さくする。コードが少ないほど、理解しやすくなります。未使用または重複したコードをリファクタリングします。 宣言型プログラミング手法 を使用します。もちろん、これには手間がかかり、多くの場合、不可能または実用的ではありません。しかし、それは価値のある目標です。 Jeff Atwoodが書いたように 最良のコードはまったくコードではない

0
Sam Jones