わかりましたので、多くのコードレビューはかなり日常的です。ただし、既存の複雑で壊れやすいコードに広く影響を与える変更がある場合があります。この状況では、変更の安全性の検証、回帰の欠如などにかかる時間が非常に長くなります。おそらく、開発自体を行うのにかかった時間を超えることさえあります。
この状況で何をすべきか?マージして、何も抜けないことを願っていますか? (それを擁護しないでください!)最善の方法は、明らかな欠陥を見つけることだけを試みてください(おそらくこれは、コードレビューが狙うべき最も多くのコードレビューです)。
これは、コードレビューの一部としてテストを行うべきかどうかという問題ではありません。これは、特に差し迫った期限があり、包括的なユニットテストスイートが利用できないか、変更された断片化されたコードで実行できないユニットテストがない場合に、説明されている状況で最良のオプションは何かを尋ねる質問です。
編集:私はこれまでにいくつかの回答/コメントが「広範囲に影響を与える」というフレーズを拾い上げたという印象を受け、おそらくそれは変更が多数のコード行を含んでいたことを意味すると解釈しました。私はこれが解釈であることを理解できますが、それは本当に私の意図ではありませんでした。 「広範囲に影響する」とは、たとえば、コードベースの相互関係、またはノックオン効果の範囲のために、回帰自体の可能性が高いことを意味しますが、必ずしも変更自体が大きなものであるとは限りません。たとえば、開発者は、多くの低レベルルーチンへの呼び出しをカスケードする既存の高レベルルーチンを呼び出すことにより、1行でバグを修正する方法を見つける場合があります。バグ修正が機能したことをテストして確認するのは簡単です。すべてのノックオン効果の影響を手動で(コードレビューを介して)検証することは、はるかに困難です。
質問の前提は、率直に言って、驚異的です。脆弱で複雑なコードに大幅な変更が加えられており、それを適切に確認するだけの時間がないと仮定します。これは、レビューに費やす時間が少ない時間の最後のコードです!この質問は、コード自体だけでなく、変更管理の方法論にも構造的な問題があることを示しています。
では、この状況にどう対処するのでしょうか?そもそもそこに入らないことから始めましょう。
複雑さの原因を特定し、注意深く、徹底的にレビューされた正しいリファクタリングを適用して、抽象化のレベルを上げます。このコードは、あなたのビジネスドメインについて何か知っている、大学を卒業したばかりの新入社員が理解できるものでなければなりません。
脆弱性の原因を特定します。これは、コード自体のレビュー、コードのバグ修正の履歴の調査などによって可能です。壊れやすいサブシステムを特定し、それらをより堅牢にします。デバッグロジックを追加します。アサーションを追加します。同じアルゴリズムの遅いが明らかに正しい実装を作成し、デバッグビルドで両方を実行して、それらが一致することを確認します。デバッグビルドで、まれな状況がより頻繁に発生するようにします。 (たとえば、常に再割り当て時にブロックを移動するか、常にページの終わりなどにブロックを割り当てるメモリアロケータを作成します。)変更に直面してもコードを堅牢にするこれで、壊れやすいコードはもうありません。これで、バグを引き起こすのではなく、バグを見つけるコードができました。
自動テストのスイートを作成します。明らかに。
大きな変更を加えないでください。一連の小さな対象を絞った変更を行います。それぞれの変更が正しいことがわかります。
しかし、基本的に、あなたのシナリオは「技術的な借金の穴に自分自身を掘り起こし、レビューされていない複雑な変更ごとに深く掘り下げます。どうすればよいですか?」です。あなたがその穴に自分を見つけたとき、あなたは何をしますか? 掘るのをやめる。借金が多すぎてお互いのコードを確認するなどの基本的なタスクを実行できない場合は、借金を増やすのをやめて、返済に時間を費やす必要があります。
コードレビューの主な目的の1つは、 品質を向上させ、堅牢なコードを提供する です。通常、4つの目は2つよりも多くの問題に気付くため、堅牢です。追加のコードを記述していないレビュー担当者は、仮定に異議を唱える可能性が高くなります。
ピアレビューを回避すると、コードの脆弱性が高まるだけです。もちろん、確実で再現可能なテストスイートでテストを強化することで、品質を確実に向上させることができます。しかし、それはピアレビューを補完するものでなければなりません 代替ではありません 。
複雑さを理解し、習得する必要があると思います 完全なピアレビューは知識を共有する機会です そしてこれを達成します。脆弱なコードの長所と短所をより多くの人々に理解してもらうために投資することは、時間の経過とともにコードを改善するのに役立ちます。
結論の引用:
「速く行きたいなら一人で行きなさい。遠くに行きたいなら一緒に行きなさい」
レガシーソフトウェア開発の世界へようこそ。
数十万、数百万、数千万のコード行があります。
これらのコード行は価値のあるものであり、収益の流れを生み出し、それらを置き換えることは不可能です。
ビジネスモデルは、そのコードベースの活用に基づいています。したがって、チームは小さく、コードベースは大きくなります。に機能を追加することは、人々に新しいバージョンのコードを購入してもらうため、または既存の顧客を満足させるために必要です。
完璧な世界では、巨大なコードベースはwazooでユニットテストされています。あなたは完璧な世界に住んでいません。
完璧ではない世界では、技術的な負債を修正する予算があります。コードを単体テスト可能な部分に分解し、高額な統合テストを行って、繰り返します。
しかし、これは新しい機能を生み出すことなく借金を返済しています。これは、「アップグレードのインセンティブを生成するためにコードを修正しながら、既存のコードから利益を得る」というビジネスケースと一致しません。
あなたはコードの巨大な塊を取り、より近代的な技術を使用してそれを書き直すことができます。しかし、既存のコードとやり取りするすべての場所で、ブレークポイントの可能性が明らかになります。あなたが取り除いたシステムのハックは、書き換えなかったサブシステムの癖を実際に補償しました。常に。
あなたがすることcanすることは注意深く行動することです。実際に理解し、システムの残りの部分との動作や相互作用がよく理解されているコードの一部を見つけることができます。ユニットテストを追加してその動作をさらに明確にすることで、それを最新化できます。
次に、アプリの残りの部分のうち、主にそれと相互作用する部分を見つけ、一度に1つずつ攻撃します。
そうすることで、サブシステムを改善し、顧客が喜んで支払う機能を追加できます。
要するに、これは可能な技術であり、ビジネスケースを提供するものを壊すことなく変更を加えることです。
しかし、これはあなたの質問ではありません。あなたの質問は、「私は巨大で何かを壊す可能性が高いことをしています。どうすればベストプラクティスに従うことができますか?」です。
巨大なことを行う場合、確実にそれを実行したい場合、それを書くよりも、バグの追跡と修正に多くの労力を費やすことになります。これがソフトウェア開発の一般的なルールです。ものを書くのは簡単で、完璧に機能させるのは難しいです。
おそらく、この大規模な変更が行われることを関係者に約束したビジネスケースが頭に浮かんでいます。それは「完了」しているため、「いいえ、これは完了していません。いいね"。
あなたが力と予算を持っているなら、実際に変更が機能するという自信を生み出す努力をするか、単に変更を拒否します。これは親切ではなく程度の問題になるでしょう。
それほど多くの能力はないが、それでも能力がある場合は、新しいシステムが単体テスト可能であることを主張してください。一部のサブシステムを書き換える場合は、新しいサブシステムが適切に指定された動作とその周りの単体テストを備えた小さなパーツで構成されることを要求します。
次に、最悪のケースがあります。あなたは借金に深く入ります。機能を実現するために壊れやすいコードやバグを増やしてnowを作成し、その結果を非難することで、プログラムの将来に逆らって借ります。スイープベースのQAを実行して最悪の問題を見つけ、残りは無視します。これは、現在最も安いので、実際にはビジネスの観点からは正しい答えになる場合があります。特に、破産による債務の清算(コードの放棄)が検討されている場合、利益を生み出すために借金をすることは有効なビジネス戦略です。
大きな問題は、会社のオーナーのインセンティブが意思決定者やプログラマーと一致することはめったにないということです。 「提供する」には多くのプレッシャーがかかる傾向があり、技術的な負債は(上司には)目に見えないように生成することで実現します素晴らしい短期および中期戦略あなたの上司/利害関係者がnotによって最善のサービスを提供されるとしても、そのすべての借金を作成します。
コードの確認を難しくしている大きな問題を解決します。
これまでに見つけたもの:
コードレビューを送り返して、開発者にそれをより小さく、より増分的なチェンジセットに分割し、より小さなコードレビューを送信するように指示できます。
コードの詳細をすべて確認することなく、コードのにおい、パターンとアンチパターン、コードのフォーマット基準、SOLIDの原則など)を確認できます。
変更セット全体の全体的な意図を必ずしも理解していなくても、詳細なレベルで適切な入力検証、ロック/スレッド管理、未処理の例外の可能性などの戦術的なコード検査を実行できます。
コードの影響を受ける可能性があることがわかっている全体的なリスク領域の評価を提供し、開発者にこれらのリスク領域が単体テストされていることを確認するよう依頼する(または自動化された単体テストを作成し、レビューのために提出するよう依頼する) )。
この状況では、変更の安全性の検証、回帰の欠如などにかかる時間が非常に長くなります。
コードレビューは、主に正当性を目的とすべきではありません。これらは、コードの可読性、保守性、およびチーム標準への準拠を向上させるためにここにあります。
コードレビュー中に正しさのバグを見つけることは、それらを行うことのいい副産物ですが、開発者はコードは完全に機能します(非回帰を含む)レビューのために提出する前にを確認する必要があります。
最初から正確性を組み込む必要があります。 1人の開発者がそれを達成できない場合は、プログラム全体をペアにするか、チーム全体で計画を立てるようにしますが、後から追加できるものとして扱わないでください。
コードレビューが難しいと思う場合、コードを壊すことなく変更することはほぼ不可能である脆弱なコードを変更したため、問題が発生します。しかし、問題はコードレビューではありません。脆弱なコードはユニットテストできないため、問題はユニットテストにもありません。もしあなたのコードがユニットテスト可能であれば、それは小さな独立したユニットに分割され、それぞれがテストされ、それらはうまく機能し、それはまさにあなたが持っていないものです!
つまり、ごみコードの山(別名「技術的負債」)があります。あなたができる最悪のことは、そのごみコードのヒープを修正し始めることですそして仕事を終えないその方法であなたはさらに大きなごみコードのヒープを得るでしょう。ですから、まず最初にあなたの経営陣にそれを修正してもらうよう依頼することですand仕事を終えます。またはあなたはしません。その場合は触れないでください。
それを修正するときは、コードから1つのユニットを抽出し、明確に定義され、十分に文書化された動作を持つものにして、そのユニットのユニットテストを記述し、コードをレビューして、何も壊れないように祈ります。そして、あなたは次のユニットについても同じことを繰り返します。
バグに遭遇すると、注意が必要です。物事は非常に壊れやすく複雑なので、ネズミのコードネストは、場合によっては間違った動作をします。ユニットを抽出すると、残りのコードがより明確になります。 (リファクタリングの後で、関数が「if(condition1 && condition2 && condition3)crash();」で始まるケースがありました。これは、リファクタリング前の動作とまったく同じですが、より明確になりました。その後、その行を削除しました:-)あなたがそれを修正できるように、奇妙な、望ましくない動作が明確に。一方、ここでmust既存のコードの動作を変更するため、慎重に行う必要があります)。
残念ながら、コードレビューの時点でこれについてできることは、コーヒーを1杯飲む以外にあまりありません。この問題の実際の解決策は、蓄積した技術的な負債に対処することです:壊れやすい設計、テストの欠如。うまくいけば、少なくともある種の機能的なQAがあることでしょう。あなたがそれを持っていない場合は、常にいくつかの鶏の骨の上で祈っています。
バギー/機能しないソフトウェアを同梱して後で修正することに満足していない場合は、V&Vの取り組み[〜#〜]すべき[〜#〜]開発の取り組みよりも長くなります!
既存のコードが壊れやすい場合、最初の質問は「変更する必要があるか」です。管理者は、このコードの再設計と再実装のコスト/リスクが、がらくたのがらくたの山を修正するコスト/リスクより大きいかどうかを尋ねる必要があります。 1回限りの場合は、パッチを適用するだけの方が簡単な場合があります。今後さらに多くの変更が必要になる可能性がある場合は、今すぐ打って将来の痛みを回避することをお勧めします。 あなたあなたの経営者と共にこれを上げる必要があります。マネージャーに良い情報を与えることはあなたの仕事の一部だからです。 彼らそれはあなたの責任レベルを超える戦略的決定であるため、その決定を行う必要があります。
まだ言及されていない理由はわかりませんが、これらの2つは最も重要な部分です。
*例:ライブラリAをライブラリBに置き換えます。1つのチェンジリストがライブラリBを導入し、さまざまな異なるチェンジリストがAの使用を1つずつBに置き換えます(たとえば、モジュールごとに1つのチェンジリスト)。最後のチェンジリストはライブラリAを削除します。
最善の方法は、明らかな欠陥を見つけることだけです(おそらく、これはとにかくコードレビューで目指すべき最も多くのコードレビューです)。
コードレビューの潜在的な価値を過小評価しないでください。それらはバグの検出に優れている場合があります。
他の理由でも役立ちます:
この状況で何をすべきか?
最良/理想的なケースでは、コードインスペクションに合格することは、「明らかなバグがない」ことを意味するだけではありません。
コードインスペクションで新しいコードベースを検証できない場合は、より広範な「ブラックボックス」テストが必要になります。検査に合格した後にコードを本番環境に置く開発サイクルに慣れているかもしれませんが、「検査に合格」できない場合は「本番環境に置く」ことができず、より長いサイクルが必要になります。統合テスト、システムテスト、アルファテスト、受け入れテスト、ベータテストなど.
ユニットテストの包括的なスイートが利用できない、または変更された断片化されたコードに対して実行できないユニットテスト
統合テスト、システムテスト、受け入れテストについてはどうですか?
とにかく、おそらくプロジェクトマネージャーと製品マネージャーに、コードにはバグがあり、バグの数は不明であることを伝える必要があります。そして、彼らは単に「期待するもの」を得るのではなく「彼らが検査するものを手に入れる」-つまり、コードの品質は彼らのテストよりも優れていない(コードの品質はされておらず、コード検査によって保証されないため) 。
彼らはおそらくそのメッセージを顧客またはユーザーに中継する必要があるため、ベータテストを実施するか(早期導入を希望する場合)、または新しいバージョンのベータ版がリリースされるまで(そうでない場合)、古いバージョンを使用します。
私の経験から、問題のシステムに変更を加える前に、ユニットと統合の両方のかなりの量のテストでコードをカバーすることを強くお勧めします。今日、その目的のために非常に多くのツールが存在することを覚えておくことは重要です。開発に使用している言語は問題ではありません。
また、統合テストを作成するためのすべてのツールのTHEツールがあります。はい、私はコンテナーについて、特に Docker および Docker Compose について話しています。インフラストラクチャ(データベース、mongodb、キューサーバーなど)とアプリケーションを使用して、複雑なアプリケーション環境をすばやくセットアップする方法を美しく提供します。
ツールが利用可能です、それらを使用してください! :)
より多くの回答が、あなたがこの時点に到達した方法を扱っています。それらの多くは状況を改善するためのいくつかの提案をしますが、私は短い答えを与えるために私の答えを投入したいと思います。
あなたの開発者は素晴らしかったです!猫はみんなのために戻ってきました!
(または、米国のテレビで " The Simpsons "を見て成長しなかった人:テストに合格した場合は、違いを確認するのをスキップして、開発者にツアーの案内をしてもらいます変更)
テストがパスするまで、リファクタリングを続け、テストカバレッジを追加します。
@EricLippertが彼の優れた答えで指摘しているように、この種の変更にはmore注意が必要ですlessではありません。自分が取り組んでいる変更がそのような変更になることに気付いた場合、役立ついくつかの戦略があります。
十分なコードレビューなしで、多くのコードが作成され、マージされます。それは働くことができます。 「壊れたコード」ではなくコードsmellと呼ばれるのには理由があります。コードレビューの欠如は警告の兆候であり、Doomの前兆ではありません。
この問題の解決策は、StackExchangeスタイルの回答にまとめることができるすべてのケースに当てはまる解決策がないことです。コードレビューが重要な「ベストプラクティス」であるというのは、ソフトウェア開発コミュニティの強いコンセンサスであり、この場合はスキップされています。あなたの開発は、もはや「すべてのベストプラクティスに従う」というその狭いチャネルにありません。あなた自身の方法を見つける必要があります。
とにかく「ベストプラクティス」とは何ですか。あなたがそれに完全に行き着くとき、それは一般に人々がコードをより良くすると考える一連の実践です。 コードは正しく作成されていますか?わかりません!インターネットは、「ベストプラクティス」を実践し、それに巻き込まれた企業の話でいっぱいです。 おそらく「ベストプラクティス」のより良い視点は、それらがソフトウェアの世界の「ファイアアンドフォーゲット」ソリューションであるということです。私はあなたの会社、プロジェクト、チームについて何も知ることができず、あなたを助けるものとして「ベストプラクティス」をやめる。それらは一般的な「害を及ぼさない」アドバイスです。
あなたは明らかにこの計画から逸脱しています。幸い、あなたはそれを認識しています。よくやった!彼らは知識は戦いの半分であると言います。もしそうなら、意識はその半分以上です!今、解決策が必要です。あなたの説明から、あなたがいるビジネス環境は、「コードレビューを行ってください、それはベストプラクティスです」という退屈なアドバイスがそれをカットしないところまで進化したことは明らかです。このため、ソフトウェアのベストプラクティスに関して私が使用する主要なルールをお勧めします。
ソフトウェア開発のベストプラクティスがビジネスニーズに勝るものはありません。
率直に言って、彼らは給料を支払っており、ビジネスの存続は通常、ソフトウェアの品質よりもはるかに重要です。私たちはそれを認めたくありませんが、完全に書かれたソフトウェアを維持しようとするその努力によって死んで会社の体に閉じ込められてしまうと、完全に書かれたソフトウェアは役に立たなくなります。
どこに行くの?力の軌跡をたどります。なんらかの理由で、あるタスクのコードレビューを受けるのは不合理であると指摘しました。私の経験では、その理由は常に一時的なものです。それは常に「十分な時間がない」または「時間を費やしている間給与を維持するのに十分なお金がない」のいずれかです。これはビジネスです。いいんだよ。それが簡単だったら、誰もがそうするでしょう。力の証跡を上向きに追跡し、コードレビューが選択肢ではない理由を理解するのに役立つ管理者を見つけます。言語は難しいです、そして、多くの場合、法令は上層部から滴り落ち、歪められます。あなたの問題の解決策はその歪みに隠されているかもしれません。
これに対する答えは、必然的に、特定のケースのシナリオです。コイントスが表か裏かを予測しようとするのと同じです。ベストプラクティスでは100回フリップするように言われており、予想はおおよそ50のヘッドと50のテールになりますが、1回フリップする時間はありません。ここで、状況の詳細が重要になります。コインは通常、約51%の時間から投げられたのと同じ向きで着地することを知っていますか?時間をかけてコインを投げる前のコインの様子を観察しましたか?それは違いを生む可能性があります。
利用可能な一般的な解決策の1つは、コードレビュープロセスを引き出す方法を見つけて、それを非常に低コストの努力にすることです。コードレビュープロセスのコストの多くは、コードレビューの実施中、全員がコードレビューに100%専念していることです。コードレビューが完了すると、コードは祝福されるため、これは事実である必要があります。おそらく、コードを別のブランチに配置し、メイントランクでの開発と並行してコードレビューを行うことができます。または、ソフトウェアがテストを実行するように設定することもできます。多分あなたはあなたの顧客が古いものと並行して「新しい」コードを実行し、彼らに結果を比較させることができるビジネス環境にいるでしょう。これにより、お客様は一連のユースケース作成デバイスに変わります。
これらの実行中の「たぶん」のすべての鍵は、コードを簡単に分割できるように努力する必要があることです。ミッションクリティカルでないプロジェクトで使用することにより、正式なコードレビューに依存せずにコードの一部を「証明」できる可能性があります。変更が小さければ、それらの合計がピアレビューには大きすぎても、これを行う方が簡単です。
一般に、プロジェクト、会社、チームに固有のソリューションを探します。一般的な目的の答えは「ベストプラクティス」でした。あなたはそれらを使用していないので、今度はこの問題に対するよりカスタム化されたソリューションを探す必要があります。これはビジネスです。すべてが常に期待どおりに進んだとしたら、IPOは値を割り当てるのがずっと簡単になるでしょう。
コードレビューの置き換えが困難な場合は、コードレビューで機能することが証明されたコードが1つもなかったことに注意してください。*コードレビューのすべてのことは、コードに自信を与え、修正する機会を与えることです。問題になる前に。コードレビューのこれらの価値ある製品の両方は、他の方法で取得できます。コードレビューは、特にそれが得意であるという認識された価値を持っています。
*まあ、ほとんど:L4マイクロカーネルは、コードが自動校正システムによってしばらく前にレビューされました。これは、コードが適合C++コンパイラーによってコンパイルされた場合、ドキュメントの内容を正確に実行することを証明します。