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


104

私が比較的大規模なプロジェクトを開発しているとします。すでにすべてのクラスと関数をDoxygenで文書化しましたが、各ソースコードファイルに「プログラマーのメモ」を置くことを考えていました。

これの背後にある考え方は、特定のクラスがどのように機能するを素人の用語で説明することです(ほとんどのコメントがそうする理由だけでなく)。言い換えれば、仲間のプログラマーにクラスがどのように機能するかについての別の見方を提供することです。

例えば:

/*
 * 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.
 */

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


32
地獄 コードが読めない場合、ドキュメントは役に立ちません。
テラスティン

35
@jeffo-問題は、これを行うのに時間がかかることが1回しか発生しないことです。コードを読みやすくする時間は、時間の経過とともに発生します。私はこの種のドキュメンテーションがある場所にいました。プロジェクトが若かったとき、または完璧主義者のジョーがまだチームにいたときです。その後、それは放棄され、コメントは残り、正確ではなくなりました。
テラスティン

25
少なくともより高いレベルでは、プロジェクトが何をするのか、どのように機能するのか、アーキテクチャでどのようなトレードオフが行われているのかについてのコード外の散文の記述は非常に貴重です。この種のドキュメントは、新参者がコードツアーに参加するに読む必要のあるものです。私の方法論は、あまりにも過激なドキュメントのためのでたらめがネットの周りにたくさんあり、初期のアーチ文書と進化しているアーチ文書が整合しないこと事実ですが、散文の説明が必要です誰にとっても、大規模で重要なコードベースをすばやく把握できます。(貧しい)例です:zxq9.com/erlmud/html/001-002_architecture.html
zxq9

11
@Telastyn:これは、コードが読み取り可能かどうかとは関係ありません(そして、そうであることを願っています)。設計原理を文書化することは絶対に重要です。
軌道上の明るさのレース

7
@Telastyn:ええ、多分。個人的には、スタンドアロンのドキュメントに記述します。ただし、ソースファイルの先頭にあるコメントブロックはそれほど悪くはありません。
軌道上の明るさのレース

回答:


139

これはすごい。より多くのソフトウェア開発者がこれを行うために時間と労力を費やしたことを望みます。それ:

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

残念ながら、多くのプログラマーは「コードが適切に記述されていれば、文書化する必要はない」という立場に陥ります。違います。コードクラス、メソッド、モジュール、その他の成果物の間には、コード自体を読むだけでは明らかでない多くの暗黙の関係があります。

経験豊富なコーダーは、明確でわかりやすいアーキテクチャを備えた設計を慎重に作成できます。しかし、実際にそのようなプログラムをいくつ見ましたか?


15
そして、なぜ「Mythical Man Month」が自己実現的な予言になるのか、それが彼らの心に新鮮で、プロジェクトが遅れなかったとき、誰も新しい開発者のためにこれをすべて書くのに時間をかけませんでした。
ジェフ

3
ここでのすべての点に同意します。私はOPが彼の投稿で使った用語が好きではありませんhow a class works。これは時間とメンテナンスによって変わります。私のチームはソースに上記を入れていませんが。決定を含むWikiを維持し、設計決定に関するスラックチャンネルディスカッションをドキュメントにそのままコピーします(決定の要約と結論から生のメモへのリンクを提供するため、古い決定を再ハッシュする必要はありません)。すべてがgithubできちんと行われます(したがって、すべて1か所で行われます)。
マーティンヨーク

1
私の唯一の問題は、これをグローバルに適用することです。このクラスは十分に複雑であり、特定の落とし穴が利用可能であり、明らかにそれは本当に便利です(ただし、まだコメントロートを処理することになります)。クラスがより明白な場合、コメントは少し不必要になります。
-deworde

1
「経験豊富なコーダーは、ドキュメントがなくても明確でわかりやすいアーキテクチャを備えた設計を慎重に作成できます。しかし、そのようなプログラムを実際にいくつ見ましたか」コード。適切に設計されたコードには、無意味なドキュメントが含まれている場合があります。設計が不十分なコードには、「増分x 1」などのコメントがあります
-deworde

3
私はこの答えに完全に同意し、コードでOPの例のようなものを見つけたら、私はとても幸せです。たった1つの追加:コメントの日付を追加することを検討してください。最終的な読者に説明の新鮮さに関するヒントを与え、テキストを更新するたびに更新します。
Svalorzen

36

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

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

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

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


あなたの最初の文はまさに私がこれを見る方法です。大規模なコードベースは、新しいプログラマが他のコンポーネントを危険にさらすことなく確実に変更できる多数の小さなコンポーネントとして構成する必要があります。
ジョンチェスターフィールド

1
コードがのときにドキュメントが更新される可能性を最大化するために、記述されているソースのできるだけ近くに移動します。これは貴重な経験です。
laike9m

ドキュメントのガイドラインとしてのDRYは非常に良い点です!それは自動的にフォーカスを正しく設定し、有名な不快な「// increment x by 1」コメントを禁止します。
ハンス・ピーターStörr15年

13

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

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

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

各メソッドの単体テスト/各モジュールの統合テストがある場合、コードのコメントと比較して、メンテナンスが容易で理解しやすい自己ドキュメントになります。

はい、適切なディレクトリ構造を持っていることが間違いなく役立ちます。


コードベースを理解する最良の方法であるテスト用に+1。単体テスト、統合テスト、受け入れテストはすべて、アプリケーションの動作方法と使用方法についてのストーリーを伝えます。
BZink

7

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

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


16
20年前、私のコードはすべて1つの巨大なファイルに収められていました。現在では、数千の小さなファイルとテストファイルになっています。これには正当な理由があり、ソフトウェア開発の20年を反映しています(私の知識ではなく、一般的なエコシステム)。しかし、コメントするには長すぎます。
マイケルデュラント

4
ああ、コーディングを開始する前に、単一の、すべてを包括する不変の真実を記述する古いウォーターフォール方式は、その真実から実装を逸脱することを不可能にします。
15

2
@jwenting:そこまで取る必要はありません。しかし、何を構築しているのかをある程度理解しておくのはまだ良いことです。
ロバートハーベイ

1
確かにこれを適切に分解する方法と規則を破る場所の警告なしで、あなたは非常に迅速に古くなっているか石臼のいずれかであるドキュメントを持っているでしょう。「新しいクラスを追加する必要があります。時間を食べるベヒーモスであるドキュマントに!」
-deworde

2
@deworde:私はそれを「ドキュメントを維持するのが面倒」と読みました。
ロバートハーベイ

6

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

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

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

これに続いて、クラスのドキュメント、および関数/メソッドを適切に完成させる必要があります。特にパブリックAPI。以下のすべてがそれぞれの場合に何であるかを明確にする必要があります。

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

+1各クラスを説明するよりも優れています。これは、全体的な設計よりも古くなってしまうためです。
ロード

4

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

新しい開発者が作業中のシステムを完全に理解する必要がある場合、就職の機会がすべて失われます。プログラマーのメモは素晴らしい出発点だと思いますが、さらに先に進みます。新たにアプローチした場合、開発者が実行前に学習することを要求するのではなく、実行中に何をしているのかを開発者が把握できるコードを記述してください。決して発生しないことがわかっているケースのアサートなど、ささいなことは、アサートが有効である理由を説明するコメントとともに、大いに役立ちます。したがって、何か間違ったことをすると、セグメンテーション違反ではなく、正常に失敗するコードを書くこともできます。


私のルールはコメントであるべきであるということですWHYではなく、どのように。コードはHOWについて説明しています。
user11393

3

ドキュメントを含む大きなクラスを見てきましたが、ドキュメントを読んだ後、このクラスが何に役立つのか、誰がそれを使用するのか、手がかりがありません!同時に、いくつかの機能が必要であり、それを処理するためのクラスが必要であり、どこにも見つからないことを確信していました-必要なものからクラスに導くドキュメントがなかったからですしている。

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


0

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

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


-1

複雑なシステムの場合、各ファイルを文書化するだけでなく、それらの相互作用と階層、プログラムの構造と理由を文書化する価値があります。

たとえば、ゲームエンジンは通常非常に複雑であり、100層の抽象化の後、何が何を呼ぶかを決定するのは困難です。「Architecture.txt」のようなファイルを作成して、コードがこのように構成されている方法と理由、およびそこに無意味な抽象レイヤーがある理由を説明する価値があります。


-7

これは、一人一人のプログラマーがプロジェクトの一部のみを理解しているため、一人のプログラマーがそれを書くのが難しいために、部分的に可能性があります。

プロジェクトマネージャーのメモからこの情報を取得できる場合もありますが、この形式でメモを書き換えることはめったにないので、それで十分です。


7
githubを見ると、README.mdファイルにこの種のメモがあるプロジェクトがたくさんあります。これは一般的なgitの文化の一部になりつつあり、特にほとんどの人にとってjavascriptプロジェクトは、この種の高レベルのドキュメントを持たないライブラリを使用しません。jQueryやsocket.ioのようなものを見て、そのようなことを書いているプログラマーを見つけるだけでよいので、「プログラマーがそれを書かない」というのは間違っています。また、正確ではないREADMEファイルがバグレポートを生成する文化にもなっています。
スリーブマン

1
これは、提案された文書スタイルが機能するかどうかの理由、および文書標準の理由を探していた質問に答えていないようです。
user52889

5
製品で作業しているプログラマーのチームがあり、各プログラマーが作業した特定のコードのみを理解している場合、チームは不条理なバスファクターで信じられないほど機能不全になっているだけでなく、コードの品質に疑問を投げかけています。同じシステム内の残りのコードを理解せずに、どのようにコードを製品に統合しますか??!?
軌道上の明るさのレース
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.