最近、同僚とコードスタイルについて話し合いました。彼は、APIの使用法と使用している一般的なパターンは、コードの外観(ブレースの配置、大文字の使用など)と同じように、コードベース全体ではなくても、可能な限り周囲のコードと同様である必要があると主張しました。たとえば、C#でDAOクラスにメソッドを追加する場合、そのクラスの他のメソッドがそれを使用していなくても、コードをクリーンで保守しやすいように適切な場所でLINQを使用しようとします。しかし、私の同僚は、そのクラスの既存のスタイルに反するため理解しにくいため、その場合は使用しないでくださいと主張します。
最初は彼の立場はかなり極端だと思いましたが、しばらく考えた後、彼の要点が見えてきました。架空のLINQの例では、同僚がLINQに慣れていないため、このクラスには含まれていない可能性がありますか?もしそうなら、私がそれを使用しなかった場合、私のコードは私の仲間の開発者にとってより保守しやすいのではないでしょうか?一方、そのような手法を使用するとコードがよりクリーンになると本当に確信している場合は、周囲のコードと大幅に異なっていても使用しないでください。
私の同僚の議論の核心は、私たち全員が異なる方法でコードベースに同様の機能を実装しようとし、私たちそれぞれが私たちの方法が「最良」であると思う場合、結局のところ、コード全体がただ難しくなるということだと思います理解する。ただし、現時点では、既存のコードを盲目的にフォローしすぎると、時間の経過とともに品質が徐々に低下すると考えています。
では、パターンはどの程度コードスタイルの一部であり、一貫性の維持と改善の間に線を引く必要があるのでしょうか。
より一般的な答えを与えるには:
このような場合、互いに反対のプログラミングの「ベストプラクティス」が2つあります。コードの一貫性は重要ですが、タスクを達成するための最良の方法を選択することも重要です。このジレンマに対する正解は1つではありません。それはいくつかの要因に依存します:
「正しい」方法はどのくらい有益ですか?
不整合が発生すると、どれほど大きな問題が発生しますか?
これらの問題のバランスに基づいて、どのルートを取るべきかについて正しい選択をしなければなりません。個人的には、一貫性のために一貫性にほとんど価値がないと考えています。そうするためにかなりのコストがない限り、最新の最良の方法を使用することを好みます。
もちろん、3番目のオプションがあります。既存のコードを書き換えて、最適なメソッドとを使用するように一貫性を持たせます。これが必要な場合もありますが、コストがかかります。
一貫性を保つことは私の観点ではほとんど価値がありません。継続的な改善が必要です。
あなたの同僚の立場はイノベーションを本当に妨げています。一貫性の引数により、たとえば、LINQを使用するようにallコードを移行した場合にのみLINQを使用できる状況になります。そして、これには時間がないのですよね?
一部のコードがArrayListsに対してforeach
を実行しており、他の部分がIEnumerable<T>
でLINQを使用しているため、時間の終わりまで最も古い方法に固執するのではなく、一貫性がないと思います。
関連性を保ち、新しいやり方を学ぶことは同僚の責任です。
APIの一貫性は、パブリックAPIと内部APIの両方にとって非常に重要です。
コードのフォーマットの一貫性は重要であり、理想的には、すべてのユーザーに対して同じフォーマットルールを使用して自動フォーマットツールによって実施する必要があります。共有されたバージョン管理されたコードベースを使いやすくします。
命名規則は、ローカル変数などについても一貫している必要があります。
静的分析ツールを使用して、他の特定の慣例や優れた慣行を実施する必要があります(ただし、そのようなツールのデフォルトを盲目的に実行しないでください。デフォルトが時々狂ってしまう可能性があります)。正当化できる場合は、一時的に(通常はコメント内のディレクティブを使用して)チェックします。
関数/メソッド内で何が起こるかは、上記にリストされているものを除いて、それが一貫している必要はありません。それ自体は良いコードです。わかりやすく、理解しやすい wellコメント付きコード は非常に重要ですが、その後、コンパイラと静的分析ツールが一貫したコードであると考えれば、十分に一貫しています。
LINQなどの新しい言語機能(まあ、それはまったく新しいというわけではありません)について考慮する必要があるのは、言語/ライブラリの十分に新しいバージョンが使用されるどこでもコードはどこで使用されますか?疑問がある場合は、互換性があることがわかっている機能を使用してください。もちろん、これによってシステム全体にバージョンアップグレードをプッシュすることが妨げられることはないため、新しいNiceの使用を開始できます。
そして、コードを扱うすべての開発者は最新の状態に保つ必要があるため、.NET開発者はLINQを知っておく必要があります。知らない場合は、自分の利益のために学習を強いられる必要があります(いつ新しいものを探すかわかりません)。何らかの理由でこのビジネスでの仕事)。
これに対する答えは簡単です。
一貫性が最も重要です。
ただし、注意が必要です...
あなたとあなたの同僚はおそらく間違った種類の一貫性に取りつかれている
実装は使い捨てです。テストスイートの品質と包括性に応じて、簡単にさまざまな方法で完全にオーバーホールすることができます。 「これはプロパティである必要がありますか?」、「コードを低レベルの構造の代わりにLINQを使用しないでください」などのことを心配します。疑わしい値です。測定値を実装レベルの一貫性の値に結び付けるのは困難です。このレベルで尋ねるはるかに良い質問は、「このコードは宣伝どおりに機能するか?」です。 TL; DR実装の一貫性は、「リトルマインド」がホブゴブリンを獲得する場所です。
ここで一貫性がそれほど重要ではないのはなぜですか?通常、実装にはごく少数の貢献者がいます。ほとんどのメソッドは記述されており、二度と変更されることはありません。残りのコードのうち、2つのコントリビューターを持つメソッドの数はほぼ確実に過半数です。このパターンは続きますad infinitum。この文脈では、一貫性はそれほど重要ではありません。コードの保存期間がかなり短い(数年)場合、積極的な一貫性からの利益はおそらく要因ではありません。
これは、実装に夢中になるべきだと言っているのではありません。むしろ、ナイスでクリーンでシンプルな設計は、方法ごとの愚かなボイラープレートの一貫性よりも、仮想の将来のメンテナーにとって桁違いに価値があると言うべきです。これは私たちを本当の意味で連れて行きます...
APIは使い捨てではありません。
これはすべてのAPIコードレベル、Webサービス、SDKなどです。これらは一貫している必要があります。このさまざまな一貫性による生産性の向上は、多くの理由で非常に大きくなります。
統合テスト:
APIの一貫性を保つ場合は、統合テストのスイートを作成できます。これにより、開発者は実装の詳細を自由に入れ替えて、すぐに検証を行うことができます。共同作業のがらくたをLINQに交換しますか?統合テストは実行されますか?また、本番環境への移行準備の際の検証も提供します。コンピューターは高速であるため、1台のラップトップで日常的なタスクを実行する1000人のテスターの作業を実行できます。組織の人員を大幅に増やすことと同じです。
生産性
APIが一貫している場合、APIの他の部分の使用について学んだことをたどることによって、APIの使用方法を推測できます。これは、APIが自然で一貫した「ルックアンドフィール」を提供するためです。これは、クライアントがドキュメントをふるいにかける時間を短縮することを意味します。オンボーディングはより簡単で安価です。 APIを開発した人々に尋ねられる質問は少なくなります。一貫性は誰もが勝者になる
このシナリオで一貫性が重要なのはなぜですか? APIには実装の正反対の問題があるからです。それらを使用する人の数は、通常、その実装に貢献する人の数よりもはるかに多くなります。わずかな一貫性から得られる小さな利益が増大し、その一貫性を維持するためのコストが償却されます。
結論
一貫性は高価です。一見すると生産性が低下します。開発者を制約し、開発者の生活を困難にします。彼らは問題を解決する方法に制限を課し、時には非最適な方法でそれを解決することを強います。これは、多くの場合、彼らが理解していない、誤解されている、または彼らが特権を持たない理由(契約、大規模な組織または組織間のポリシー)のためです。
レイモンドヘッティンガーは、pythonプログラマーのチームのためのPEP8スタイルガイドの使用に関する彼のPycon 2015の講演でいくつかの優れた点を作りました。深刻なロジックとデザインの欠陥。彼の仮説はとして要約できます。スタイルの矛盾を見つけるのは簡単です。コードの実際の品質を判断するのは難しいです
ここでのポイントは重要です。一貫性が重要な場所を特定し、積極的に保護します。重要ではない場所で時間を無駄にしないでください。一貫性の値を測定する客観的な方法を提供できない場合(上記の場合、「効果的な人数」、生産性の関数としてのコスト)、収益が大きいことを実証できない場合は、あなたの組織。
LINQに不慣れですか?もしそうなら、私がそれを使用しなかった場合、私のコードは私の仲間の開発者にとってより保守しやすいのではないでしょうか?
C#言語はまだ進化しています。 C#1からの変更を学ばなければ、次のことを逃してしまいます。
これは、Wikipediaの記事にある一般的な機能のほんの一部です。私が指摘しているのは、開発者が学ばなければ、コードベースは空白のままであるということです。開発者が継続的に改善し、コードベースが進化し、完全なテストスイートによってサポートされることを願っています。プロパティを手動で実装することが.NET 1でどれほど悪かったか覚えていますか。
Linqは生活を楽にします。できる限り使用してください。あなたのチームメンバーをやる気にさせるかもしれません。
では、パターンはどの程度コードスタイルの一部であり、一貫性の維持と改善の間に線を引く必要があるのでしょうか。
改善は段階的です。私にとって、可読性が低く、メンテナンス性が低い可能性がある古いスタイルのコードを保持することは意味がありません。チームメンバーは、たとえ書けなくても、少なくとも何が起こっているのかを理解できる必要があります。
一貫している必要がありますが、必ずしも古いコードと一致している必要はありません。つまり、チームは何かを行うための正しい方法に同意し、新しいコードが記述されたとき、または大幅な変更が加えられたときは常にその方法を使用する必要があります。
こうすることで、一貫性のほとんどのメリットを享受できます(特に、コードをだれが書いてもかまいません)が、チームが別の方法で明確なメリットを享受できれば、さらに改善できます。
理想的な世界では、すべての古いコードを新しい正しい方法に準拠するように書き換えます。これは経済的に実行可能ではありませんが、技術的に理にかなっているはずです(または、新しい方法はより良い方法ではありません)。長期的な計画は、アップグレードすることです。それが価値がない場合は、新しい方法を気にしないでください。別の言い方をすると、正しい方法であると宣言することを検討する新しい方法には明らかな利点があるはずです。
プロジェクトでコードstyleに従うことが重要だと思います。命名規則、インデントなど.
同僚がそれらを理解していない、または以前にプロジェクトで使用されたことがないという理由だけで、新しい言語構造またはデザインパターンの使用を制限する必要があることに同意しません。
もちろん、これらのものはそれらを使用するための十分な理由があるはずです。必要に応じて、パフォーマンスまたは簡潔さ。
現在の設計パターンを盲目的にフォローすることは非常に慎重になります。もちろん、明らかな欠点がない場合は、コードベース全体で常に同様のパターンに従うようにしてください。
ただし、大多数の開発者が既存の悪いパターンに従うのが「ベストプラクティス」であるかのように感じて、優れた開発者が保守性のない悪いコードを書いている状況に至るのは、あまりにも簡単です。
一方、一貫性は重要です。膨大なコードベースを扱う場合、開発者がコードベースの隅々まで読まなくても、何が期待できるかを理解できるように、同様のパターンに従うことを試みることは非常に役立ちます。
したがって、可能であれば、開発者が従うべきパターンについてのガイドラインを確立して更新するのが最善であると思います。このようにして、新しいコードは他の新しいコードと一貫しています。