未知のコードベースを探索および学習するためにどのツールとテクニックを使用しますか?
grep
、ctags
、単体テスト、機能テスト、クラス図ジェネレータ、コールグラフ、sloccount
などのコードメトリックなどのツールを考えています。私はあなたの経験、あなたが自分で使用または作成したヘルパー、および作業に使用したコードベースのサイズに興味があります。
コードベースに精通することは、時間の経過とともに発生するプロセスであり、親しみやすさは「コードを要約できる」から「リファクタリングしてサイズの30%に縮小できる」まで、あらゆることを意味します。しかし、どうやって始めるのですか?
私がいつもやっていることは次のとおりです:
エディター(Visual Studio/Eclipse/Whatever)の複数のコピーを開き、デバッグしてコードをステップごとに改行します。コードのフローを調べ、スタックトレースを実行して、重要なポイントがどこにあるかを確認し、そこから進みます。
メソッドごとにメソッドを見ることができますが、何かをクリックして、コードのどこで実行されているかを確認し、追跡できるのは素晴らしいことです。開発者がどのように機能するかを感じてみましょう。
どのように象を食べますか?
一度に一口:)
真剣に、私は最初にコードの作者と話そうとします。
仕事が完了するまでハックする必要がありますか
大部分は、はい(申し訳ありません)。
考えられるアプローチ:
コードを明確にするために私がすることのいくつかは次のとおりです。
...そして、あなたが行うことができる他のどんな簡単な改善も。
徐々に、すべての背後にある意味が明らかになるはずです。
始める場所は?あなたが知っていることから始めましょう。入力と出力を提案します。多くの場合、これらが何であるか、何に使用されているかを把握できます。アプリケーションを介してデータを追跡し、データの場所と変更方法を確認します。
これらすべてに関して私が抱えている問題の1つは動機です-それは本当のスローガンになる可能性があります。それは私がビジネス全体をパズルとして考えるのを助けて、どんなに小さいにせよ、私がしている進歩を祝うのを助けます。
あなたの状況は実際には一般的です。処理する既存のコードがある新しい仕事に足を踏み入れる必要がある人はだれでも、そのいくつかの要素を処理します。システムが本当に厄介なレガシーシステムである場合、それはあなたが説明したものと非常に似ています。もちろん、現在のドキュメントはありません。
まず、多くの人がMichael Feathersによる レガシーコードで効果的に作業する を推奨しています。これは確かに良い本であり、「このクラスをテストハーネスに入れることができない」または「アプリケーションに構造がない」などの便利な章が含まれていますが、フェザーは解決策よりも同情を提供できる場合があります。特に、本とその例は、中括弧言語に主に向けられています。節のあるSQLプロシージャを使用している場合は、それほど役に立ちません。 「このコードを変更するのに十分理解していない」という章はあなたの問題について語っていると思います。フェザーは、メモを取る、リストをマークアップするなどの明らかなことをここで言及しますが、ソース管理がある場合は、未使用のコードを削除できることも重要です。多くの人がコメント付きのコードのセクションをそのまま残しますが、それは多くの場合役に立ちません。
次に、あなたの提案するアプローチは確かに良いステップだと思います。まず、コードの目的が何であるかを大まかに理解する必要があります。
質問に回答してもらう必要がある場合は、メンターまたはチームの誰かと確実に協力してください。
また、欠陥が明らかになった場合は、コードをサポートする機会を得てください(場合によっては、これを志願する必要がないこともあります...欠陥によって見つけられます!)。ユーザーは、ソフトウェアの使用目的と、欠陥がユーザーに与える影響について説明できます。これは、ソフトウェアの意味を理解しようとするときに、非常に役立つ知識になることがよくあります。さらに、意図的に攻撃対象を指定してコードにアクセスすると、「獣」に直面したときに集中できる場合があります。
非常に大きなソースファイルがある場合は、次のようにします。
通常のエディターに戻ると、コードがどれほど奇妙に見慣れているかに驚かれるでしょう。
特に、慣れていないテクノロジー/言語/フレームワークを使用している場合は、レガシーコードベースを理解しようとする際に慌てないでください。時間がかかるのは避けられない学習曲線です。
1つのアプローチは、コードと関連テクノロジのチュートリアルを行き来することです。チュートリアルを読み、それからコードを見て、前任者がどのように行ったかを確認し、類似点と相違点に注意し、メモを取り、既存の開発者に質問します。
「なぜこの部分をこのようにしたのですか」
「オンラインでほとんどの人がこの方法でやっているのに気づきましたが、皆さんもそれを別の方法で行っていました。なぜこれが原因ですか?」
「テクノロジーYよりもテクノロジーXを選んだ理由は何ですか?」
これらの質問に対する回答は、プロジェクトの履歴と、設計および実装の決定の背後にある理由を理解するのに役立ちます。
最終的には、物事を追加/修正し始めることができるように、十分に親しみを感じるでしょう。すべてが混乱しているように見えたり、「魔法」が多すぎるように見える場合は、十分な時間をかけて、それを調べ、要約し、図を作成していません。図(シーケンス図、プロセスフロー図など)を作成することは、複雑なプロセスを理解するための優れた方法であり、さらに「次の人」を支援します。
cscopeは、Cに対してctagsが実行できることをすべて実行できます。さらに、現在のすべての関数が呼び出される場所をリストすることもできます。さらに、それは非常に高速です。数百万のLOCに簡単に拡張できます。 emacsとvimにきれいに統合されます。
CおよびC++コードカウンター-ccccは、HTML形式でコードメトリックを生成できます。 LOCの取得にもwcを使用しました。
doxygenは、HTMLで構文を強調表示して相互参照するコードを生成できます。大きなコードベースを閲覧するのに役立ちます。
Drupalで推奨する方法ですが、実際にはDrupal固有ではありません。問題トラッカーから始めてください。古い、閉じられていないバグレポートが確実にあります。それらを再現しますか?はいの場合、チケットを更新して確認します。いいえの場合、それを閉じます。この方法でソフトウェアを使用する多くの方法が見つかり、クラッシュしたコードベースをのぞき始めることができます。または、ステップを開始することもできます。このようにして、コードベースを理解し始めるだけでなく、大量のカルマを蓄積し、質問がコミュニティによって温かく歓迎されます。
すべき重要なことの1つは、ツールを使用してコードアーキテクチャをトップダウンで調査するために 依存関係グラフを生成 することです。最初に.NETアセンブリまたはjar間のグラフを視覚化します。これにより、機能とレイヤーがどのように編成されているかがわかります。次に、名前空間の依存関係(1つまたはいくつかの関連する.NETアセンブリまたはjar内)を調べて、コードの詳細を把握します。最後に、クラスの依存関係を見て、一連のクラスがどのように連携して機能を実装するかを理解できます。 NDepend for .NET など、依存関係グラフを生成するためのツールがいくつかあり、以下のグラフが生成されます。
私はかつてかなり素晴らしいソフトウェアエンジニアに、コード分析とメンテナンスの最も高価な形式はコードを1行ずつ実行することだと教えてくれました。もちろん、私たちはプログラマーであり、それは仕事にほとんど付随しています。幸いな方法は、(この順序で)と思います。1。ノートブックを入手して、コードがどのように機能するかを理解するためのメモを作成し、時間の経過とともにそれに追加します。2。コードに関するドキュメントを参照してください3。コードベースをサポートしている作者や他の人と話してください。彼らに「ブレインダンプ」を依頼してください。4.詳細レベルのクラスの関係のいくつかを理解できるようになったら、コードのステップスルーデバッグを行って、コードの動作と、コードが実際にどのように機能するか。
まず、それが何をするつもりなのかを理解してください。ユーザーに話しかけ、マニュアルを読んでください。
次に、実行を押して、主要な機能のように見えるコードを調べ始めます。
分割統治。私は各機能と関連するコードを見て、それらをステップ実行して次へ進み、全体の画像をゆっくりと作成します。
プロジェクトに単体テストがある場合、私もそれらを実行するのが好きです。それらは常に非常に明快で啓発的です。
Michael Feathersのレガシーコードを効果的に使用するを参照してください
これが私の短いリストです:
可能であれば、コードの概要を誰かに説明してもらいます。どのパターンが考慮されたか、どのような種類の規則が見られるかなどなど。これにはいくつかのラウンドがあるかもしれません。最初は、コードに慣れてくると新しい質問があるかもしれないという話が1つあります。既存のプロジェクトのタマネギを使って作業しているときに質問します。
コードを実行して、システムがどのように見えるかを確認します。いくつかのバグがあるかもしれませんが、これは何をしているのかを理解するのに役立ちます。これはコードを変更することではなく、これがどのように実行されるかを確認することです。さまざまな部分がどのように組み合わさってシステム全体になるのでしょうか?
コードの内部メンタルモデルの構築に役立つ可能性のある基本的なドキュメントのテストやその他の指標を探します。もちろん、ドキュメントやテストが極端に少ない場合を除いて、少なくとも数日はここで提案するでしょう。
このプロジェクトで使用されている言語とフレームワークをどの程度知っていますか?ここで重要なのは、いくつかのことを見て、「はい、何十回も前に見て、それをかなりよく知っている」と「これは世界中で何が試みられているのか、これは良いアイデアだと誰が思ったのか」という違いです。私はそれらを大声で言うことはしませんが、特に私が非常に壊れやすいかもしれないレガシーコードを見ていて、それを書いた人が利用できないか、単に理由を覚えていない場合は、そのような質問をします物事は彼らがいた方法で行われました。新しい領域では、構造とは何か、このコードでどのパターンを見つけることができるかを知るために、追加の時間を費やすことは価値があるかもしれません。
最後に重要なこととして、以下のいくつかの予想されるアイデアを考慮して、各時点で何をすることになっているのかについて、プロジェクトを実行している人々の期待を理解してください。
私はドキュメンテーションなどから始めようと思いますが、私の経験では、ドキュメンテーションの深さとローカルな知識は、多くの場合、システムの古さ、サイズ、複雑さに反比例します。
そうは言っても、私は通常、いくつかの機能的なスレッドを特定しようとします。機能的とは、ログイン、顧客のリストのプルダウンなどのことを意味します。パターンがまったく同じである場合、1つのスレッドがシステムの断面図を提供します。パターンが一貫しているかどうかを判断する最良の方法は、少数のスレッドを分析することです。
これは言うまでもありませんが、私の意見では、技術的な観点からではなく、機能的な観点からシステムを理解することをお勧めします。私は通常、使用されているツール(ORM、ロギングライブラリなど)についてあまり心配せず、使用されているパターン(MVPなど)に重点を置きます。私の経験では、ツールは一般に、パターン化するより流動的です。
ソースコードを印刷して、読み始めます。特に大きい場合は、その一部を印刷して理解を深め、必要な数のメモやコメントを作成してください。
プログラムの実行の最初からトレースします。コードベースの特定の部分に割り当てられている場合は、その部分内の実行をトレースし、どのデータ構造が使用されているかを把握します。
オブジェクト指向言語を使用している場合は、一般的なクラス図を作成してみてください。これにより、概要がわかりやすくなります。
残念ながら、最終的には、できるだけ多くのコードを読む必要があります。運が良ければ、以前のプログラマーは何が起こっているのかを理解するのに役立つように、できるだけ多くのドキュメントを書いています。
すべてのプログラムには1つ(メインメソッド、メインクラス、initなど)があるので、私は常にプログラムへのエントリポイントから始めてみます。これにより、何が始まるのか、場合によってはどのようにリンクされるのかがわかります。
その後、ドリルダウンします。データベースとDAOはどこかで構成されているので、物事がどのように格納されているかがわかります。おそらく、ある種のグローバルインスタンスクラスも開始され、そこに何が格納されているのかがわかります。そして、優れた屈折ツールを使用して、誰が何を呼び出すかを見つけることができます。
次に、情報の次のエントリポイントであるため、インターフェイスがどこで構成および処理されているかを調べます。屈折解析、検索、およびデバッグツールは、私の検索に役立ちます。次に、情報の処理がどこから始まり、どこで終わるかを把握し、すべてのクラスファイルを調べます。
次に、フローを紙に書き留めて、最初に頭を覆います。送信ボタンは汎用検証に渡され、DAOまたはデータベースに渡されて、データベースに格納されます。これはほとんどのアプリの大幅な単純化ですが、その一般的な考え方です。ここではペンと紙が非常に役立ちます。すべてをすばやく書き留めることができ、役立つはずのプログラムでのフォーマットについて心配する必要がないためです。
私がするいくつかのこと...
1) Source Monitor のようなソース分析ツールを使用して、さまざまなモジュールサイズ、複雑さのメトリックなどを決定し、プロジェクトの感触を得て、重要でない領域を特定するのに役立ちます。
2) Eclipse でコードを上から下にドリルスルーします(参照などを参照できるエディターがあると便利です)。コードベースの何がどこで何が行われているのかがわかります。
3)時折、アーキテクチャをよりよく理解するために Visio で図を描画します。これは、プロジェクトの他のユーザーにも役立ちます。
新しいコードベースを学ぶときに最初に行う必要があるのは、それが何をすることになっているのか、どのように使用されているのか、そしてどのように使用するのかを学ぶことです。次に、アーキテクチャのドキュメントを調べて、コードがどのようにレイアウトされているかを確認します。また、この時点でのデータベースの方法も確認します。同時に、アーキテクチャを学習しているので、プロセスフローやユースケースドキュメントを確認する良い機会です。全体像を理解した後、コードに飛び込んで読み始めますが、このコードで実行している可能性のあるすべての作業に関連するコードだけで、すべてのコードを読み取ろうとしないでください。 Xがどのように行われるかよりも、コードがXをどこで行うかを知ることの方が重要です。コードは常にあり、Xを見つけることができるかどうかを教えます。
コードを習得する以外の目的がなくても、コードにジャンプして読み込もうとするだけでは一般的に非生産的であり、小さな変更を自分で行うか、他の誰かの変更のコードを確認することは、時間をはるかに生産的に使用することがわかります。
コードベースが大きい場合は、現在作業中の部分に注意を向けてください。さもなければ、圧倒され、おそらく頭が爆発するかもしれません。高レベルの概要は役立つと思いますが(利用可能な場合)、デバッガーでプログラムフローを追跡するために多くの時間を費やす可能性があります。アプリケーションの概要を確認し、それが使用されていることを確認することをお勧めします。これにより、コードがどのように/何のために/なぜ使用されているのかを理解できます。
私は通常、コードに対してある種のコード複雑度ツールを実行して、問題のある領域がどこにあるかを教えてくれます。高得点のエリアを更新することはおそらく非常に困難です。たとえば、私は循環的スケールで450点をとる関数に出くわしました。案の定、数百のIF。それを維持または変更することは非常に困難です。最悪の事態に備えてください。
また、既存の開発者、特にシステムで作業している場合は、恐れずに質問してください。自分の内面の考えを自分に保ち、問題の解決に集中してください。他の開発者を怒らせるコメントは避けてください。結局、それはあなたの赤ん坊であるかもしれません、そして、誰も彼の赤ん坊が醜いと言われるのを好きではありません。
小さな一歩を踏み出してください。小さなコード変更でも大きな影響を与える可能性があります。
プログラムのコードフローを考え出すことが役立つので、変更を加える場合は、依存関係検索を実行して、どのメソッド/関数が何を呼び出すかを確認できます。メソッドCを変更するとします。
1つのメソッド/関数だけがCを呼び出す場合、それはかなり安全な変更です。数百のメソッド/関数がCを呼び出す場合、その影響は大きくなります。
うまくいけば、あなたのコードベースはうまく設計され、書かれ、そして維持されています。もしそうなら、それを理解するにはしばらく時間がかかりますが、最終的には潮流は変わります。
それが泥の大きなボールである場合、その内部の仕組みを理解することはできません(または理解したくありません)。
たくさんやりました...
これが「何かが機能している」状況での私の現在のアプローチであり、「何か他の方法で機能する」ようにする必要があります。
各ステップの間に必要になる可能性があるもう1つのオプションのタスク:「これらの変更はすでに昨日行われているはずです」と言うマネージャー(プロジェクトオーナー)からの通知。いくつかのプロジェクトの後、彼は事前に仕様とドキュメントを入手するのを手伝い始めるかもしれません。
しかし、通常(特にスクリプトの場合)は、ビジネススコープでは不可能です(コストが高すぎ、値が低くなります)。 1つのオプションは、クリティカルマスに到達し、システムが本番稼働から停止するまで(たとえば、新しいシステムが登場するまで)、またはこれらすべてを実行する価値があると経営陣が決定するまで、変更を行わないことです。
PS:設定が異なる5つのクライアントに使用された1つのコードを覚えています。そして、変更(新機能)ごとに、「何が使用されているか」、「何がクライアントに設定されているか」を考え、何もブレーキをかけたり、コードをコピーペーストしたりしないようにする必要がありました。それらの設定をプロジェクトCVに適用し、仕様を作成すると、この思考時間はほぼ0に短縮されます。
ドキュメントがないか、不十分なドキュメントがあるか、古くなっています。存在するすべてのドキュメントを見つけます。チームリポジトリにある場合は、コピーを作成しないでください。そうでない場合は、そこに置いて、おそらくいくつかの監督の下で、それを整理する許可をマネージャーに求めてください。
すべてをチームのリポジトリに入れ、用語集を追加します。すべての基地には専門用語があります。用語集に記録します。ツール、製品、顧客固有などのセクションを作成します。
ソフトウェア環境作成ドキュメントを作成/更新します。すべてのツール、癖、インストールの選択肢などはここにあります。
次に、「ProductName」ドキュメントなどをアップロードします。ただ心の流れであり、時間とともに自己組織化してください。次に、古くなったドキュメントを調べて、最新の状態に戻します。他の開発者はそれを高く評価し、コードを学びながら独自の方法で貢献することになります。特に、あなたを困らせたり、間違った名前を付けたり、直感に反するものをすべて文書化してください。
学習曲線が終了したら、ドキュメントの更新について心配する必要はありません。次の新しい人にそれをさせましょう。彼が到着したら、彼をあなたの仕事に向けさせます。彼が常にあなたに答えを求めてバグを出しているとき、彼に答えないでください。むしろ、質問をドキュメントに追加してから、URLを渡してください。釣り竿。
副作用の1つは、何ヶ月も忘れて自分で参照できるツールを作成したことです。
そして、それはドキュメントではありませんが、関連する問題は、チームメイトが行う、少し風変わりで手作業が多い手順です。バッチ、SQLスクリプトなどでそれらを自動化し、それらも共有します。結局のところ、手続きに関する知識は、新しい環境で生産的になるという点で、おそらく宣言的な知識と同じくらい大きいのです。それが何であれ、それをしないでください。むしろ、それをスクリプト化し、スクリプトを実行します。釣り竿がまたたく。
これはよく起こります。オープンソースプラットフォームの開発に取り掛かるまでは、コードに「癖」があったことを認めずに仕事を始めなかったと思います。
あなたはステップデバッガと多くの粘り強さで長い道のりを得ることができます。残念ながら、泥の特定の大きなボールを学ぶには、多くの場合時間がかかり、経験が必要です。それでも、何年経っても、だれも知識を持たないサブシステムが発生する可能性があります。
最も重要なことの1つは、単純な機能を採用し、考えられる最も単純な機能を選択して実装することです。維持されているウィッシュリストがある場合は、それを使用するか、コードベースに詳しい人に話しかけて、機能を提案してもらいます。通常、これは5〜20 LOCの変化であると予想します。重要な点は、非常に凝った機能を追加しているのではなく、コードベースを操作して(または、:)作業していて、ワークフロー全体を実行していることです。あなたはする必要があります
リストは続きますが、要点は、このようなミニプロジェクトは、システムに精通するためのチェックリストのすべての項目を順番に実行し、生産的な変更が行われることにもなります。
追加したかった小さなこと:
私が最近この種の問題に使用し始めたツールの1つに、マインドマッピングがあります。頭の中で何かがどのように実装されているかについての詳細を詰め込むのではなく、私が経験しているシステムがどのように機能するかを説明するマインドマップを作成します。何が起こっているのか、そして私がまだ理解する必要があることをより深く理解するのに本当に役立ちます。また、変更する必要があるものを非常に正確なスケールで追跡するのにも役立ちます。
マインドマッピングの選択肢が豊富な中で、 自由平面 を使用することをお勧めします。
私はこのトピックについてかなり長い記事を書きました。ここに抜粋があります
私はしばらくの間この問題について考えました。私は自分の個人的な解決策を一般的なプロセスとして書くことにしました。私が文書化した手順は次のとおりです。
このプロセスは、大きなデスクトップアプリケーションのコンテキストで記述されていますが、一般的な手法は、Webアプリケーションや小さなモジュールにも適用できます。
取得元: 新しいコードベースを学習するプロセス
共有できる小さなヒントがいくつかあります。
既存の製品については、集中的にテストを開始します。タスクを選択/取得する場合、特定の機能にさらに焦点を当てます。
次のステップは、侵入して探索を開始できるコードを見つけることです。途中で、依存するモジュール、ライブラリ、フレームワークなどを見つけます。
次のステップは、その責任を持つ(CRCカードのように)単純なクラス図を作成することです。
小さな変更を加えるか、小さなバグを取り込んで修正してコミットします。プロジェクトのワークフローを学ぶことができます。コードだけではありません。多くの場合、大規模な製品には、承認と監査のために何らかの種類の簿記があります(たとえば、ヘルスケアプロジェクト)。
すでにプロジェクトに取り組んでいる人々と話してください。あなたのアイデア、考えを表現し、その見返りに、このプロジェクトで長い間働いたときの彼らの経験と見解を得てください。これはチームとうまくやり取りするのにも役立つので、これは非常に重要です。
泥の玉の中の何かを変更する前に、単体テストを書くことをお勧めします。そしてonlyテストに合格するためにその時点で十分なコードを変更します。リファクタリングするときは、事前にユニットテストを追加して、リファクタリングによってビジネス機能が破壊されていないことを確認してください。
ペアプログラミングはオプションですか?別の人にアイデアを跳ね返らせることは、その量の厄介なことに対処するための素晴らしいアイデアです。
これは、重複を排除するために使用する手順です。
[dupe]
を使用します。[dupe][procedure_arbitrary_name]
を追加します。[dupe][procedure_arbitrary_name][n]
);grep
幸せです!自分で大規模なコードベースに飛び込む必要があったので、久しぶりです。しかし、ここ2、3年の間、私は新しい開発者を既存のかなり大規模なコードベースが存在するチームに参加させるために何度も試みました。
そして、私たちがうまく使用してきた方法、そして私が疑いなく私見なしで最も効果的な方法はペアプログラミングです。
過去12か月の間に、チームには4人の新しいメンバーがおり、新しいメンバーは毎回、コードベースに精通している別のメンバーとペアを組んでいました。最初は、古いチームメンバーがキーボードを持っていました。約30分後、キーボードを新しいメンバーに渡し、新しいメンバーは古いチームメンバーの指導の下で作業します。
このプロセスは非常に成功していることが証明されています。
大規模なコードプロジェクトを研究する私の方法は次のとおりです。
プログラムのメインフローとコアシステムの実装を理解したら、プログラムの他のモジュールを探索できます。
これで、大規模なコードプロジェクトを理解できました。お楽しみください!