web-dev-qa-db-ja.com

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

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

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

メンテナンス性の理由:私のグループでは、バグとコードカバレッジのみを中心に展開する「品質」メトリックにうんざりしています。特にメンテナンス性を測定しない場合は、どちらの指標も簡単に理解できます。近視眼と締め切りは、実際には対処されない膨大な技術的負債をもたらします。

客観的に測定できる理由:私は大企業グループで働いています。それを客観的に測定できないと、人々に説明責任を負わせたり、上手にさせたりすることができません。主観的な測定は行われないか、一貫して行われません。

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

23
nlawalker

保守性の測定に関する警告は、将来を予測しようとしていることです。コードカバレッジ、バグカウント、LOC、循環的複雑度すべて現在に対処

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

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

7
Aaron McIver

まあ、私が使用している、または私が使用していると思いたい尺度はこれです:

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

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

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

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

Nが十分に削減された場合(最適は1)、ソースコードはドメイン固有言語(DSL)のように読みます。プログラムは、問題を「述べる」ほど問題を「解決」するわけではありません。理想的には、各要件は単一のコードとして再表現されるためです。

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

7
Mike Dunlavey

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

与えられたコードのために、完璧設計のアイデアを思い付きます。

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

例:

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

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

5
user8685

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

さて、これは実際に機能するのは、妥当な数のバグを修正して「平均」(それが何であれ)の時間を取得した後だけです。追跡がどれほど難しいかは、コードの「保守性」に依存するだけではないため、特定のバグにこの図を使用することはできません。

もちろん、より多くのバグを修正すると、コードはより改善され(少なくともそうでなければならない)、コードに慣れるにつれて、コードを保守しやすくなります。これに対抗することは、バグがより曖昧になり、追跡がさらに困難になる傾向があるという事実です。

これはまた、人々がラッシュバグ修正を行ってスコアを低くする傾向がある場合、新しいバグが発生するか、既存のバグが適切に修正されず、さらに作業が増え、場合によってはさらに悪いコードになるという問題も抱えています。

4
ChrisF

Visual Studioコードメトリックスは、迅速な「保守性」メトリックスを提供するのにかなりまともです。 5つの主要なメトリックがキャプチャされます。

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

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

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

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

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

2
Marcie

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

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

私は安っぽいコードを書いて、それを生産に投入します。

あなたはそれを保守できないことを正しく観察します。

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

「技術的負債」は、法的変更によりすべて廃止され、解消されます。

「保守性」の測定基準は、外部の考慮事項により「悪い」から「無関係」になりました。

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

1
S.Lott

意味のある2つは 循環的複雑度 とクラス結合です。複雑さを排除することはできません。できることは、それを管理可能な部分に分割することだけです。これらの2つの方法により、保守が難しいコードを配置できる場所、または少なくとも最も難しい場所を特定できます。

循環的複雑度は、コード内にあるパスの数の尺度です。各パスをテストする必要があります(ただし、テストされていない可能性があります)。約20を超える複雑なものは、小さなモジュールに分割する必要があります。サイコマティック複雑度が20のモジュール(これを20個の連続するif then elseブロックで重複させることができます)には、テストする2 ^ 20パスの上限があります。

クラス結合は、クラスがどれだけ強くバインドされているかの尺度です。以前の雇用主で使用したいくつかの不良コードの例には、コンストラクターに約30項目の「データレイヤー」コンポーネントが含まれています。そのコンポーネントの主な担当者は、本当に大きな泥の玉になるまで、コンストラクター/オープンコールにビジネスおよびUIレイヤーパラメーターを追加し続けました。メモリが適切に機能している場合、約15の異なる新規/オープンコール(一部はもう使用されなくなった)があり、すべてわずかに異なるパラメーターセットを使用していました。私たちは、彼がこのようなことをするのを止めることを唯一の目的としてコードレビューを制定しました-そして私たちが彼を単一化しているように見えるのを避けるために、私たちはチームの全員のコードをレビューしたので、4-6のために約半日を無駄にしました私たちは一人の馬鹿の感情を傷つけたくなかったので、毎日、人々。

1
Tangurena

一番下の行で、保守性は実際にはafterではなくbeforeではなく測定のみ可能です。つまり、コードを保守する必要がある場合にのみ、コードの一部が保守可能かどうかを判断できます。

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

あなたができる唯一のことは、一連の具体的な規則(SOLID原則など))に基づいてチームに同意することです。
原則が適切に選択されている場合(SOLIDから始めるのが良い選択だと思います)、それらが違反されていることを非常に明確に示し、著者に責任を負わせることができますそのため。
あなたは非常に苦労し、メンテナンス性のための絶対的な手段を推進しようとする一方で、現実的な現実の確立された原則の継ぎ目のセットに固執するようにチームを徐々に説得します。

1
back2dos

ピアコードレビューの次善の策は、ユニットまたは製品をコーディングする前に、実行可能なアーキテクチャを作成することです。 Red-green-refactor は、それを実行するためのかなりきちんとした方法です。シニアの人に実行可能なインターフェースを一緒に投げてもらい、仕事を分割してもらいます。誰もが自分のパズルのピースを取り、勝利への道を赤緑化することができます。この後、ピアコードのレビューとリファクタリングが必要になります。これは、私が取り組んだ過去の主要な製品ではかなりうまくいきました。

0
P.Brian.Mackey

私はしばしば、「最短の同等」の解が最も保守しやすい傾向があることに気づきます。

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

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

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

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

したがって、コードの繰り返しを見つけることができるツールがあるはずですが、問題は最適な圧縮を見つけることに似ていると思います。これは、決定不可能なコルモゴロフの複雑さの問題です。しかし、もう一方の端では、未使用および使用頻度の低い抽象化は、参照の数に基づいて簡単に見つけることができます。そのチェックは自動化できます。

0
Calmarius

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

保守性を(再)定義しただけですが、それでも主観的なものです。一方、それはそれほど重要ではないかもしれません。お客様を満足させて楽しむだけでいいのです。

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

0
Martin Maat

アンケート

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

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

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

保守性を検討する2つの方法を考えることができます(他の人が良い定義を考え出せることを望んでいます。

理解せずに修正。

システム全体のしくみを理解していなくても、バグ修正担当者がコードにアクセスして問題を修正できますか。

これは、包括的な単体テスト(回帰テスト)を提供することで実現できます。システムに何らかの変更を加えても、特定の適切な入力に対するシステムの動作が変更されないことを確認できるはずです。

この状況では、バグ修正担当者はシステムの最小限の知識のみで(簡単な)バグを修正することができます。修正が機能する場合、回帰テストはどれも失敗しないはずです。回帰テストが失敗した場合は、ステージ2に進む必要があります。

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

理解した変更。

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

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

だから、多分私たちはこれのいくつかの尺度を考え出すことができます:

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