作成したコードが簡単に読みやすく、理解しやすく、保守可能であるかどうかをどのようにして知るのでしょうか?もちろん、作成者の観点から見ると、コードは読みやすく、保守可能です。ただし、私たちの職業がコードを測定できる客観的で定量化可能な標準が必要です。
これらの目標は、コードなしで元の作成者の専門家のアドバイスを使用して次のことを実行できるときに満たされます。
コードを読んで、基本的なレベルでロジックの流れを理解することができます。
入力、出力、アルゴリズムを含めるためにコードが何をしているかをより深いレベルで理解することができます。
他の開発者は、バグ修正やリファクタリングなど、元のコードに意味のある変更を加えることができます。
元のコードを活用するクラスやモジュールなどの新しいコードを書くことができます。
コードの品質を数値化または測定して、コードが読みやすく、理解可能で、保守可能であることを確認するにはどうすればよいですか
ピアを確認すると、コードを確認した後
作者として、あなたはコードがそれ自体で言うよりも多くを知っているので、これを自分で決定することはできません。コンピュータは、絵画が芸術であるかどうかを区別できないのと同じ理由で、あなたを区別することができません。したがって、あなたが書いたものを見て彼または彼女の意見を述べるには、ソフトウェアを保守できる別の人間が必要です。このプロセスの正式な名前はpeer reviewです。
場合によっては、6か月前に作成したコードに戻って、そのコードが何をするために作成されたかを理解することが最善の方法です。
あなたはそれをすぐに理解すれば-それは読みやすいです。
それは:
1.の実際のテストは、(Alex in Parisおよびquant_devと言うように)数か月後に何か他のことをした後でそれをピックアップできることです。
2.と3.のテストは、他の誰かがそれを拾い上げて、設計の細かい部分に従ってコードを拡張または修正する方法を理解できることです。彼らがデザインを理解できない場合、それが問題空間とどのように関連するか、またはコードがどのように使用されるか意図されているかは、ハッキングされます代わりに穀物全体のソリューション。
経験則、原則(つまり、誰かが上手に書いて名前を付けた経験則)と、正しい方向に導く、または一般的な落とし穴から遠ざかる可能性のあるあらゆる種類の提案があります。ただし、それらのいずれも、あなたが求めている品質を保証するものではありません。
コードが [〜#〜] solid [〜#〜] および [〜#〜] dry [〜#〜] の原則に従っており、それの周りのユニットテスト、それはおそらくメンテナンス可能です。
読みやすいですか?それを読んで。メソッドと変数の名前は意味がありますか?問題なくプログラムロジックを追跡できますか?答えが「はい」の場合、コードは読み取り可能です。
リーディング メンテナンス不可能なコードの書き方-人生の仕事を確実にする Roedy Green、笑い、そして学び。
...維持するのが非常に困難で、あなたの後に来る人々が最も単純な変更でさえ何年もかかるようなコードの書き方。さらに、これらのルールをすべて忠実に守っていれば、コードの保守を希望する人はいないので、一生の雇用を保証することにもなります...
エッセイは、面白いコードをたくさん使って、悪いコードを書く方法の多くの例をあなたに与えます。 Creative Miss-spelling、Reuse of Names、グローバル名のプライベートとしての再利用の高く評価されている手法。
ユーモラスな方法で、このエッセイは、読み取り不能で保守不可能なコードの例をすべて回避する方法を教えてくれます。
実際、本文中の例に似たコードを誰もが書くとは信じ難いことに気づきました。それは私が学校を卒業した時でした。しかし、数年間働いた後、私は毎日テキストのコードを目にしています…
それがどのように見えるかにかかわらず、あなたが検討できるいくつかのかなり客観的な対策があります。 C++ Coding Standards 、 Refactoring 、および Clean Code のような本には、意味のある名前などを見て、コードを判断するための基準の長いリストがあります。関数のサイズ、結合や結束のような原則、オブジェクトの設計、単体テスト、逐次的な改良など.
リストが大きすぎてチェックリストを理解できませんが、その本を読んで作業に必要ないくつかの重要なものを選び、数か月後にもう一度読んでさらに改善します。
証拠はプリンにあります。適度に有能な人にそれを引き渡した後に何が起こるかを見てください。コードの難しさに関して多くの質問をする必要がない場合は、問題はありません。
これは私のキャリアの初期のレッスンでした。メンターは、「すべてを文書化して、後でプログラムから逃れることができるようにします。答えが頭の中で新鮮なときに質問を予想しない場合は、そうでないときにそれらを理解する必要があります。」
私はすべての回答を読みましたが、コードの複雑さに言及している人はいませんでした。
コードの複雑さと可読性/保守性の間には密接な相関関係があります。多数のコード複雑性スコアリングアルゴリズムがありますが、ここではMcCabe複雑性スコアリングのしくみについて説明します。
基本的に、McCabeスコアリングはコードを読み取り、そこを通る固有の「パス」の数を計算します。分子としてMcCabeを使用し、分母としてコード行を使用すると、「読みやすさ」のかなり良い近似値も得られます。
10行のコードがあり、そのコードを通る300のパスがある場合、それはかなり保守不可能なコード(安全かつ簡単に変更するのが難しい)であり、おそらくあまり読みにくいでしょう。逆に、300行のコードがあり、それを通るパスが1つしかない場合(条件がない場合)は、読み取り可能であり、簡単に保守できます。
McCabeが落ちるのは、後者の例です。条件なしで300行のコードがある場合、「コピー/貼り付けの再利用」を行った可能性は非常に高く、明らかにそれも良いことではありません。したがって、McCabeに加えて適用するシステム全体のメトリックがあります-重複またはほぼ重複したコード検出など。
彼が作成したコードが簡単に保守可能で読みやすいかどうかは、どうしたらわかるでしょうか。
次のプロパティを探すことで、メンテナンスが簡単で読みやすいコードを見つけることができます。
非常に面倒で保守不可能なコードを記述したかどうかは、どうすればわかりますか?乱雑なソフトウェアを開発したかどうかを知るための構造やガイドラインはありますか?
1つの単語で、経験。
最初に、基本的な作業を行う必要があるため、プログラマーが Refactoring などの本を読むのに時間をかけて、より重要なツールのいくつかを提供することを強くお勧めすることはできませんコードを維持する能力を向上させるプログラマーの武器、および クリーンコード は、この分野で最も高い評価を得ている才能のある人によって書かれ、理解する必要があるほぼすべてを説明しています。コードがクリーンで読みやすいことを確認します。
読書の量は、しかし、苦労して稼いだ経験に代わるものではありません。コードの品質への注意がもたらす違いを十分に理解するためには、しばらくの間コードを操作する必要が本当にあります。クリーンで適切に因数分解されたコードで作業する喜び、およびコードスパゲッティで作業する苦痛を経験することにより、これらの本の著者が実際にあなたに教えようとしていたことをよりよく理解することができますが、より広い文脈でそうします実際の運用プロダクションコードの場合、実行する作業の品質が重要であり、日常的にコードを簡単に操作する能力に影響を与えます。
また、優れたメンター、または経験を積んだ仲間が、高水準のコードを書くことに力を注いでいることを確認するのにも役立ちます。これは、コードレビューが非常に役立つ理由の1つにすぎません。コードチェックツールと書式設定ツールを使用することも、物事をきれいに保つために非常に役立ちます。ただし、何年にもわたってソフトウェアを作成してきた経験に匹敵するものはありません。たとえば、メンテナンスを簡単にするために、簡潔で読みやすく、構造化されたコードを自動的に作成していること、そしてすべてにベストプラクティスを適用する習慣を付けているためです。長いです。
私が共有する1つのポイントは、コードが「モジュール」に組み込まれている場合であり、モジュール内の1つのものを変更して簡単に全体で機能させることができるということです。それは無関係なものの間の影響を排除します。また:
The Pragmatic Programmerを読むことを強くお勧めします。
いくつかのテスト/インジケーター:
IDEをオフにします。まだ自分のコードを読むことができますか?バグがある場合、手作業でかなり簡単に追跡でき、どのクラスにブレークポイントが必要かを把握して、問題の原因を特定できますか?または、IDEを使用する場合は、煩わしさを感じず、最初からステップ実行するだけですか?
デバッグは、多くの場合、1つのバグを修正するとさらに2つ以上のバグが発生する奇妙なゲームになります。
トリガーのプルから実際に役立つ何かに至るまで、メソッド呼び出しはいくつかかりますか?正確に同じ、またはほとんど同じパラメータを別のメソッド呼び出しに渡すメソッドはいくつありますか?
単純な新しいメソッドをクラスに追加するために、いくつのファイルを開く必要がありますか?
あなたが採用したパターンと実践を考えてください。彼らが完璧に理にかなっているか、誰かが「それがそれを行う唯一の方法だ」とあなたに確信させたので、あなたはそれをしましたか?またはあなたがあなたの履歴書にそれを望んでいたから、あるいはロックスターの開発者がそう言ったからです。
純粋主義的ではなく、機能的なスタイルを好む。最近のほとんどの言語(.NET、Ruby、Python、Javascriptなど)は、それをサポートおよび宣伝しています(たとえば、LINQ、underscorejs)。
非常に読みやすいです。
var recentTopCustomers = OrderList
.Where(o => o.Date >= DateTime.Now.AddDays(-5))
.Where(o => o.Amount > 1000)
.OrderBy(o => -o.Amount)
.Take(10)
.Select(o => o.Customer);
目的を明確にするために、各ノードに単一の集中インテントを貸すように強制します。また、個々のタスクは分離されているため、ポップアウト、プラグイン、ノード(操作)の異なる目的への再配置は簡単です。これにより、メンテナンスが容易になります。
読み取り可能で保守可能なコード:プログラマーが一目見ただけで、プログラマーが簡単に理解できる理解できるコード:
これは、「明快さ」に要約されます。つまり、予期しない副作用を引き起こすことなく現在のタスクを達成するために「十分にうまく機能していることを理解する」と確信する前に、プログラマーはコードの特定のセグメントについて尋ねる必要がある質問の数。
著書「Code Complete、by Steve McConnell」では、これについて詳しく説明しています。
彼は、コードが良質であるかどうかを判断するために使用できるさまざまなメトリックを調べます。
こちらの例をご覧ください: http://books.google.co.uk/books?id=3JfE7TGUwvgC&lpg=PT376&pg=PT389#v=onepage&q&f=false
副作用を最小限に抑える(理想的には副作用がない)
自身のスコープ外の状態に3つの変化を引き起こす関数は、単に何かを入力し、何かを出力するだけのものよりも、推論および維持するのがはるかに困難です。関数が何をするかを知るだけでなく、関数が何をしたのか、それが他のすべての関連する関数にどのように影響するかを覚えておく必要があります。
OOPの場合、副作用を最小限に抑えることは、メンバーの数が少なく、特にクラスの状態を変更できるメンバーの数が少ないことを意味します。これは、メンバー関数が自身の状態を超えて状態を変更し、副作用があるためです(それらはクラスの内部など。これは、独自のデータメンバーが少ないクラスも意味するため、これらのメソッドが改ざんする状態が少なくなり、それらが引き起こす可能性のある副作用が少なくなります。
簡単な例として、sorted
状態を維持できるファンシーデータ構造を設計して、バイナリ検索と線形検索のどちらを実行するかを決定することを想像してみてください。このような場合、デザインを2つのクラスに分けると便利です。ソートされていないクラスでsorted
を呼び出すと、別のクラスのデータ構造が返され、そのコンテンツは常にソートされたままになります。これで、副作用が少なくなり(したがってエラーが発生しにくくなり、コードを理解しやすくなります)、より広く適用可能なコードが得られます(前の設計は、ソートする必要のない小さな配列の処理と人間の知的効率の両方で無駄になります)。
余分な外部依存関係を回避する
13の異なるライブラリを使用して比較的単純なタスクを実行することにより、コードを最大限に再利用して、考えられる最も簡潔なコードを実装できる場合があります。ただし、その場合、少なくとも13の異なるライブラリの一部を理解させる必要があるため、読者に知的オーバーヘッドが転送されます。この固有の複雑さは、機能するために他の数十のライブラリーを取り込んで構築する必要のあるサードパーティーのライブラリーを構築して理解しようとした人ならすぐに理解できるはずです。
これはおそらく非常に物議を醸すビューですが、最終結果が十分にテストされている場合は、反対の極端よりも少しコードを複製することをお勧めします(何回も複製されるテストされていない障害のあるコードよりも悪いことはありません)。ベクトルのクロス積を計算するための3行の重複したコードの選択か、3行のコードを削り取るために壮大な数学ライブラリーを取り込む場合は、チーム全体がこの数学ライブラリーに参加していない限り、前者を推奨しますその時点で、分離の利点と引き換えに十分な場合は、1行ではなく3行のコードを記述することを検討することもできます。
コードの再利用はバランスをとる行為です。再利用しすぎると、1対多の方法で知的複雑さを転送します。上記で保存した3行の単純なコードでは、リーダーとメンテナーに3行のコードよりもはるかに多くの情報を理解する必要があるという犠牲が伴います。 。また、数学ライブラリが変更されるとコードも変更される可能性があるため、コードの安定性が低下します。再利用が少なすぎると、知的オーバーヘッドが倍増し、コードは中心的な改善の恩恵を受けなくなります。そのため、それはバランスをとる行為ですが、バランスをとる行為であるという考えは、あらゆる小さな形の控えめな複製を打ち消そうとすることは、反対の極端と同じかそれ以上ではないと維持するのが難しい結果に。
クラップをテストする
これは当たり前のことですが、コードがすべての入力ケースを処理せず、一部のEdgeケースを逃した場合、他の人があなたの書いたコードを維持して、目と手に移る前に正しく理解できなかったとどうしたらよいでしょうか?そもそも完全に正しくなかったコードはもちろんのこと、完全に機能するコードに変更を加えることは十分に困難です。
その上、徹底的なテストに合格したコードは、通常、変更する理由が少なくなります。これは安定性に関連しており、変更する必要のない安定したコードには保守コストがかからないため、保守性よりも達成するのは至高の目標です。
インターフェイスドキュメント
両方を文書化するために同じ時間を費やすことができない場合は、「物事が行う方法」よりも「物事が行うこと」を優先します。考えられるすべての入力ケースで何を行うか(少なくとも、何を行うかについて)の意図が明らかな明確なインターフェースにより、独自の実装にコンテキストが明確になり、方法だけでなく、コードを使用するだけでなく、それがどのように機能するか。
一方、人々がそれが何をすべきかさえ知らないこれらの品質を欠くコードは、SOL実装の詳細がどれほどよく文書化されているかに関係なく。ソースコードがどのようにあるかに関する20ページのマニュアル実装することは、そもそもそれがどのように使用されることになっているか、考えられるすべてのシナリオで何をすべきかさえ正確に理解できない人々にとっては価値がありません。
実装面では、他の誰とも違う方法で文書化することを優先してください。例として、インテルにはレイトレーシングカーネル用の境界ボリューム階層があります。私はこの分野で働いているので、ドキュメントを調べなくても、彼らのコードが行っていることの大部分を一目で認識できます。ただし、これらはBVHをトラバースし、rayパケットを使用して並列に交差を実行するという考え方で、独自の処理を行います。コードのこれらの部分はエキゾチックであり、ほとんどの歴史的なBVH実装からは珍しいので、ドキュメントの優先順位を付けたいのはここです。
読みやすさ
この部分は非常に主観的です。私は人間の思考プロセスに近い種類の読みやすさについてはあまり気にしません。筆者が奇妙で複雑な思考プロセスを使用して問題を解決した場合、最も高いレベルで物事を説明する最も詳細に文書化されたコードを追跡することは依然として困難です。一方、2つまたは3つの文字の名前を使用した簡潔なコードは、ロジックが非常に単純であるかどうかを理解しやすい場合があります。他の人が何を好むかをピアレビューして見ることができると思います。
私は主に保守性、そしてさらに重要なことに安定性に関心があります。変更する理由がないコードは、メンテナンスコストがゼロのコードです。
ここに私が使用したいテクニックがあります:
同僚のプログラマーの1人にコードを見せ、彼らにそれが何をしているか説明してもらいます。これらのことに注意してください。
1)コードのブロックの目的を簡単に説明できない場合、それをリファクタリングします。
2)現在のセクションを理解するためにコードの別のセクションにジャンプする必要がある場合は、リファクタリングします。
4)プロセス中に発言したいときはいつでも、コードのそのセクションにリファクタリングが必要です。 (コードはそれ自体のために話していません)。
新しいチームメンバーがコードを取得して理解し、修正して欠陥を修正するか、比較的簡単に新しい要件を満たすことができるかどうかを確認する方法の1つだと思います。
最も保守しやすいコードは、そこにないコードです。したがって、LOCカウントに追加するのではなく、LOCカウントを「削減」する新しいコード(単独で表示すると保守性が少し低くても)は、サイズを小さくするだけで、コードベース全体の保守性を高めることができます。したがって、保守可能なコードの主なルールは次のとおりです。
第二に、隠された依存関係よりも保守性に悪いことは何もありません。ルール番号2の場合:
第3に、すべてのプログラマーが、特定のより高度な技法の言語機能またはイディオムを使用して保守または作成するのに等しく熟練しているわけではありません。コードベース全体を調整すると、サイズが大きいため維持が難しい大きなコードベースが得られます。コード全体で高度なテクニックの機能とイディオムを許可すると、すべてのコードを上級開発者しか保守できなくなります。保守性の鍵は、スキルレベルベースのレイヤリングです。次に例を示します。
クロスプロジェクトライブラリ:上級開発者、裏技の完全なコード/イディオム/テクニックプロジェクト固有のライブラリとシステムバックエンド:中規模の開発者は、最も高度で説明が難しいものを避けます。高齢者はDRY改善の機会を探すためにこのコードを利用します。
フロントエンド:ジュニア開発者。厳格なスタイルガイドと一連のテクニックを使用して、回避する言語の構成要素とイディオムを設定します。中程度の開発者は、このコードを使用してDRY機会と隠されたビジネスロジックを探します。
ルール番号3の場合:
私