保守性をどのように有意義に測定しますか?


23

コンテキスト:私は、すべてがMSショップのエンタープライズ開発者です。

コードやアプリケーションの保守性を客観的に測定するための良い方法を誰かがお勧めできますか?

なぜ保守性があるのか:バグとコードカバレッジの数のみを対象とするグループの "品質"メトリックにうんざりしています。特に保守性を測定していない場合は、どちらのメトリックも簡単にゲームできます。近視眼と締め切りは、実際に対処されない膨大な量の技術的負債をもたらします。

なぜ客観的に測定できるのか:私は大企業グループで働いています。客観的に測定できない場合は、人々に説明責任を負わせたり、それを改善することはできません。主観的な測定は、発生しないか、一貫して発生しません。

私はVS2010コードメトリックスを見ていますが、誰か他の推奨事項があるかどうか疑問に思っています。


@アノン-私は同意しますが、少なくとも開始する場所を与えてくれるでしょう。今のところ何もありません。ゲームをする必要さえありません。
-nlawalker

1
ピアコードレビューなしでこれを行う方法は、実際にはわかりません。誰かが実際にシステム全体の設計を理解する必要があります(そして、存在する必要があります)。コードの単位を見て、これは改善された設計によって改善される可能性があります。 ...同様の注意で、「グリッドビューにインデックスをハードコードし、itemtemplatesを使用し、代わりに名前で列を選択することはお勧めできません」などの包括的なガイドラインを維持できます。結局のところ、開発者はうまくチームを組まなければなりません。ダ・ヴィンチは素晴らしさを教えることはできません。
P.Brian.Mackey

8
既に良いコードを書いているのではなく、開発者がゲームのメトリックスを持っている場合、メトリックスを追加すると、それらのメトリックスもゲーム化されますが、問題は解決しません。解決策は、メトリックを完全に廃止し、コードの品質を確保するために他の手段(たとえば、公開コードレビュー)を使用することです。
アノン。

3
「カウントできるものはすべてカウントする必要はありません。カウントするものすべてをカウントできるとは限りません。」
ジェイソンベイカー

@nlawalker回答者がすでに提起した問題に加えて、あなたの質問には疑わしい仮定が積まれています。低い保守性は、ソフトウェア自体の外部にあるさまざまな要因の結果です。プログラムが解決しようとする問題の難易度、明確な定義、スタッフの経験、離職率、市場投入までの時間、スコープの変更など。これを期待して、問題は善意の問題です。
アーサー・ハヴリチェク

回答:


7

保守性を測定する際の注意点は、将来を予測しようとしているということです。コードカバレッジ、バグカウント、LOC、循環的複雑度はすべて現在を扱います。

現実は、コードがそのまま維持できないという具体的な証拠がない限りです。つまり、バグを修正すると、維持できないコードのためにN時間の不要な時間が発生します。脚を立てることは本質的に困難です。この例では、もっと単純なもので十分な場合に過度に複雑な方法論が使用されたという事実によって引き起こされた可能性があります。方法論、パラダイム、およびベストプラクティスを測定しようとする領域に踏み込むことは、長期的な利益をほとんどまたはまったくもたらさずにますます困難になります。

残念ながら、この道を下るのはどこにも行かない道です。実質的なメリットがあり、コードベース全体の命名規則の欠如などの問題に対する個人的な感情に結び付けられていない根本的な問題の発見に焦点を当て、その根本的な問題に関する成功と失敗を測定する方法を見つけます。これにより、一連のビルディングブロックの組み立てを開始し、そこからソリューションの定式化を開始できます。


7

まあ、私が使用する、または私が使用すると思うのが好きな尺度はこれです:

独立した、単一の、1行の、テイクイットまたはリーブイットの機能要件ごとに、実装前にコードベースのスナップショットを作成します。次に、プロセスで導入されたバグを見つけて修正するなど、実装します。次に、diff前後のコードベース間でを実行します。diffあなたの変更を実施し、すべての挿入、削除、および変更の一覧が表示されます。(コードの連続した10行を挿入するのと同じように、1つの変更が行われます。)変更はいくつありましたか?通常、その数値が小さいほど、コードの保守性が高くなります。

これは、エラー修正コードの冗長性に似ているため、ソースコードの冗長性と呼びます。情報は1つのチャンクに含まれていましたが、Nチャンクとしてエンコードされ、一貫性を保つためにすべて一緒に行う必要があります。

これはDRYの背後にある考え方だと思いますが、もう少し一般的です。その数が少ないのが良い理由は、典型的な要件を実装するためにN個の変更が必要であり、誤りやすいプログラマーとして最初にそれらのN-1またはN-2しか正しく行われない場合、あなたは1つまたは2つのバグ。O(N)プログラミングの努力に加えて、これらのバグを発見、特定、および修復する必要があります。それが、小さなNが良い理由です。

コードがどのように機能するかを学んでいないプログラマーにとって、Maintainableは必ずしも読みやすいという意味ではありません。Nを最適化するには、プログラマーの学習曲線を作成するいくつかのことを行う必要があります。 以下に例を示します。 役立つことの1つは、プログラマーが将来の変更を予測しようとして、プログラムの解説にハウツーの指示を残す場合です。

Nが十分に減少すると(最適値は1)、ソースコードはドメイン固有言語(DSL)のようになります。プログラムは、問題を「述べる」ほど問題を「解決」することはありません。理想的には、各要件は単一のコードとして言い換えられるだけです。

残念ながら、これを行う方法を学んでいる人はあまりいません。むしろ、彼らは精神的な名詞はクラスになり、動詞はメソッドになり、彼らがやらなければならないことはクランクを回すだけだと考えているようです。私の経験では、その結果、Nが30以上のコードになります。


これは、すべての機能要件がほぼ同じサイズであるという非常に壮大な仮定を立てていませんか?そして、この測定基準は責任の分離を妨げませんか?水平機能を実装する必要があります。したがって、最も「維持可能な」コードは、1つのモノリシックメソッドに完全に含まれるプログラムのほぼ完全な書き換えです。
アーロンノート

@Aaronaught:それがどれほど壮大なのかはわかりませんが、私たちのグループでは、要件/機能のリストを作成しています。それぞれに比較的短い説明があります。大幅な書き直しが必要な場合、私はそれらを見て/行ったことを確認しますが、コードを整理するより良い方法がおそらくあると私に言います。これは私の標準的な例です。簡単に習得できるとは言いませんが、一度習得すれば、測定可能な労力を大幅に節約でき、エラーなしで迅速に変更を加えることができます。
マイクダンラベイ

5

保守性は実際にはそれほど測定できません。それは、個人の経験と好みに基づいた個人の主観的な見方です。

あるコードのために、完璧なデザインのアイデアを思いつきます。

次に、その完全なコードから実際のコードが逸脱した場合、100の値をある数だけ減らします。選択した非完全アプローチの結果に正確に依存するもの。

例:

コードの一部はいくつかのデータ形式を読み取ってインポートし、何か問題がある場合はエラーメッセージを表示する場合があります。

完璧なソリューション(100)では、エラーメッセージが1つの共通の場所に保持されます。ソリューションでコード内に文字列定数として直接ハードコーディングされている場合は、たとえば15をオフにします。したがって、保守性インデックスは85になります。


4

保守が困難なコードの結果の1つは、バグを修正するのに(「平均」で)より長くかかることです。そのため、一見すると、1つのメトリックは、バグが割り当てられたとき(つまり、修正が開始されたとき)から「テストの準備ができた」ときまでバグを修正するのにかかったように見えます。

さて、これは「平均的な」(それが意味する)時間を得るために妥当な数のバグを修正した後にのみ実際に機能します。特定のバグにこの数字を使用することはできません。追跡するのがどれだけ難しいかは、コードの「維持可能性」だけに依存しているわけではないからです。

もちろん、より多くのバグを修正するにつれて、コードはより良くなっている(または、少なくともそうあるべきです)ため、保守が「簡単」になり、コードに慣れてきています。それに対抗するという事実は、バグがより不明瞭になる傾向があるため、追跡がさらに困難になることです。

これは、人々がバグ修正を急いでより低いスコアを取得する傾向があるため、新しいバグを引き起こしたり、既存のバグを適切に修正しなかったりして、さらに多くの作業とおそらくさらに悪いコードをもたらすという問題もあります。


2

Visual Studio Code Metricsは、迅速な "保守性"メトリックを提供するのに非常に適切であると思います。5つの主要なメトリックがキャプチャされます。

  • 循環的な複雑さ
  • 継承の深さ
  • クラスクーリング
  • コードの行(メソッドごと、クラスごと、プロジェクトごとなど、ロールアップのレベルに応じて)

保守性指数は私が便利だと思うものです。以下に基づいた複合インデックスです。

  1. 合計サイズ(コード行)
  2. クラスまたはファイルの数
  3. メソッドの数
  4. 20を超える循環的複雑度(または10-構成可能、10が私の好み)
  5. 複製

ときどき、保守性指数が低い(低=この方法では悪い)メソッドを調べます。ほぼ間違いなく、私のプロジェクトの保守性指数が最も低いメソッドは、書き換えが最も必要で、読み取り(または保守)が最も難しいメソッドです。

計算の詳細については、ホワイトペーパーを参照してください。


1

意味のある2つは、循環的複雑さとクラス結合です。複雑さを排除することはできません。できることは、それを管理可能な部分に分割することだけです。これらの2つの手段により、保守が困難なコードがどこにあるか、または少なくともどこが一番難しいかを知ることができます。

循環的複雑度は、コード内に存在するパスの数の尺度です。各パスをテストする必要があります(ただし、おそらくそうではありません)。複雑度が20を超えるものは、小さなモジュールに分割する必要があります。cycomaticの複雑度が20のモジュール(これを20個の連続したif then elseブロックで複製できます)には、テストする2 ^ 20パスの上限があります。

クラスカップリングは、クラスがどの程度緊密にバインドされているかの尺度です。以前の雇用主で働いていたいくつかの悪いコードの例には、コンストラクターに約30の項目を持つ「データ層」コンポーネントが含まれています。そのコンポーネントの大部分は「責任者」であり、本当に大きな泥の塊になるまで、ビジネスおよびUIレイヤーパラメーターをコンストラクター/オープンコールに追加し続けました。メモリが適切に機能する場合、約15種類の新規/オープンコール(一部はもう使用されていません)があり、すべてがわずかに異なるパラメータのセットでした。私たちは彼がこのようなことをするのを止めることだけを目的としてコードレビューを実施しました-そして、私たちが彼を孤立させているように見せないために、チームの全員のコードをレビューしたので、4-6のために約半日を無駄にしました私たちがしなかったので、毎日人々


2
正直なところ、全員にコードレビューを行うことは悪いことではありません。あなたは時間を無駄にしているように感じるかもしれませんが、誰もがそれを怠けるための口実として使用していない限り、あなた彼らから貴重な洞察を得ているはずです。
アノン。

1

要するに、保守性は実際必要なのは測定後であり、測定ではありません。つまり、メンテナンスが必要な場合にのみ、コードの一部がメンテナンス可能かどうかを判断できます。

変化する要件にコードを適合させることがどれほど簡単かを測定することは比較的明らかです。要件の変化にどのように対応するかを事前に測定することはほぼ不可能です。つまり、要件の変化を予測する必要があります。そして、それができるなら、ノーベル価格を手に入れるべきです;)

唯一できることは、一般的な保守性が向上すると考えられる具体的なルール(SOLID原則など)に基づいてチームに同意することです。
原則が適切に選択されている場合(最初はSOLIDを選択するのが良い選択だと思います)、違反していることを明確に示し、著者にその責任を負わせることができます。
保守性の絶対的な尺度を推進しつつ、チームに、確立された原則の現実的な継ぎ目の合意セットに固執するように徐々に説得しようとするのは非常に困難です。


1

本当に対処されない膨大な量の技術的負債

「イベントによって追い越された」技術的負債についてはどうですか?

私は安っぽいコードを書き、本番に突入します。

あなたは、それが保守可能ではないことを正しく認識しています。

ただし、このコードは、法的コンテキストが変更され、製品ラインに将来がないため、廃止される製品ラインの機能の最後のラウンドです。

「技術的負債」は、それをすべて時代遅れにする立法改正によって排除されます。

「保守性」メトリックは、外部の考慮事項により「悪い」から「無関係」になりました。

それはどのように測定できますか?


「100年後、私たちは皆死んでしまいますが、どれも重要ではありません。物事を遠近感のあるものにしています。」無関係なものがある場合、質問への回答ではないのはこの応答です。
マーティンマート

0

ピアコードレビューの次善策は、ユニットまたは製品をコーディングする前に実行可能なアーキテクチャを作成することです。 Red-Green-Refactorは、これを実行するための非常に適切な方法です。上級者に実行可能なインターフェースを一緒に投げてもらい、作業を片付けましょう。誰もがパズルのピースを取り、勝利への道を赤緑することができます。その後、ピアコードのレビューとリファクタリングが適切に行われます。これは、私が取り組んだ過去の主要製品ではかなりうまく機能しました。


0

アンケート

月に1回程度記入するために、開発者向けの匿名アンケートを作成するのはどうですか?質問は次のようになります。

  • プロジェクトXに先月費やした時間(大体)[0%... 100%]
  • 保守性の観点からコードベースの状態をどのように評価しますか(本当に悪い、悪い、中立、いい、良い、本当に良い)。
  • プロジェクトの複雑さに比べて、コードベースをどの程度複雑に評価しますか[非常に複雑で、ちょうどいい、単純すぎます]。
  • コードベースが過度に複雑であるため、タスクを解決する上で妨げになったと感じる頻度はどれくらいですか?[まったくない、たまに、しばしば、常に]。

(コメントで保守性を測定するのに役立つと思われる質問を自由に追加してください。追加します。)


0

保守性を見るには2つの方法が考えられます(他の人が良い定義を思いつくことができればもっといいと思います。

理解せずに修正。

システム全体の動作を理解する必要なく、バグ修正プログラムをコードに入力して問題を修正できますか。

これは、包括的な単体テスト(回帰テスト)を提供することで実現できます。システムへの変更は、特定の適切な入力でのシステムの動作を変更しないことを確認できるはずです。

この状況では、バグ修正プログラムはシステムの最小限の知識のみで(単純な)バグを修正できるはずです。修正が機能する場合、回帰テストはいずれも失敗しません。回帰テストに失敗した場合は、ステージ2に移行する必要があります。

maintainabilty1 = K1 . (Code Coverage)/(Coupling of Code) * (Complexity of API)

理解のある修正。

バグ修正が自明ではなく、システムを理解する必要がある場合。次に、システムのドキュメントはどのようなものですか。外部APIのドキュメントについて話しているわけではありません(比較的役に立たない)。理解する必要があるのは、実装などで使用される巧妙な(読み取りハック)トリックでシステムがどのように機能するかです。

しかし、ドキュメントは十分ではなく、コードは明確で理解可能である必要があります。コードの理解度を測定するために、ちょっとしたトリックを使用できます。開発者がコーディングを終了した後、彼/彼女に何か他の作業をする月を与えます。次に、桟橋がシステムを理解できる程度に戻ってシステムを文書化するように依頼します。コードが比較的理解しやすい場合は、迅速に行う必要があります。それがひどく書かれている場合、彼らは彼らが構築したものを解決し、ドキュメントを書くのに長い時間がかかります。

そのため、これについて何らかの尺度を考え出すことができます。

maintainability2 = K2 . (Size of doc)/(Time to write doc)

0

「最短の同等の」ソリューションが最も保守性が高い傾向にあることがよくあります。

ここで、最短とは、操作が最も少ないことを意味します(行ではありません)。また、同等のことは、以前のソリューションよりも短いソリューションでも時間やスペースの複雑さが悪化しないことを意味します。

これは、すべての論理的に類似した繰り返しパターンを適切な抽象化に抽出する必要があることを意味します。類似したコードブロックですか。機能するように抽出します。一緒に発生するように見える変数?それらを構造体/クラスに抽出します。メンバーがタイプのみで異なるクラス?ジェネリックが必要です。あなたは多くの場所で同じことを再計算するようです?最初に計算し、値を変数に保存します。これらを行うと、コードが短くなります。それが基本的にDRYの原則です。

また、未使用の抽象化を削除する必要があることに同意することもできます。不要になったクラス、関数はデッドコードであるため、削除する必要があります。バージョン管理は、元に戻す必要があるかどうかを記憶します。

しばしば議論されるのは、一度だけ参照される抽象化です。一度だけ呼び出される理由もなく、一度だけ呼び出される非コールバック関数です。1つのタイプのみを使用してインスタンス化されるジェネリック。別のタイプでインスタンス化される理由はありません。一度だけ実装され、他のクラスなどによって実装されることになる本当の理由はありません。これらは不要であり、削除する必要があるという私の意見は、基本的にはYAGNIの原則です。

したがって、コードの繰り返しを見つけることができるツールが必要ですが、問題は最適な圧縮を見つけることに似ていると思います。しかし、もう一方の端では、未使用および未使用の抽象化は、参照の数に基づいて簡単に見つけることができます。そのチェックは自動化できます。


0

それはすべて主観的であり、コード自体に基づく測定は最終的には無関係です。最終的には、要求を満たす能力に帰着します。まだ要求されている機能を提供できますか、可能であれば、何かがまだ正しくないためにそれらの変更がどれくらい頻繁に戻ってくるか、それらの問題はどれほど深刻ですか?

保守性を(再)定義しただけですが、それはまだ主観的です。一方、それはそれほど重要ではないかもしれません。顧客を満足させ、それを楽しむ必要があるだけです。それが私たちが目指していることです。

どうやら、コードベースの状態を改善するために何かをする必要があることを上司や同僚に証明する必要があると感じているようです。私は、あなたが変更または追加しなければならないあらゆる些細なことに対して、回避することができた他の10の問題を修正または回避しなければならないという事実に不満を抱いていると言うのに十分であるべきだと主張します。次に、悪名高いエリアに名前を付けて、逆さまにするケースを作ります。それがあなたのチームのサポートをもたらさないなら、あなたはどこか別の方が良いかもしれません。あなたの周りの人々が気にしないなら、あなたのポイントを証明することは彼らの心をとにかく変えないでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.