レガシーコードベースを改善するための推奨ルート: スケーラブルで保守可能なシステムのための 11 のレッスン

何かを始める前に、何が起こってもデータが失われないように、関連する可能性のあるものをすべてバックアップする必要があります。毎日何が変更されるかを覚えておくのは困難です。特に構成データはこの種の問題の影響を受けやすく、構成は通常バージョン管理されていないため、定期的にバックアップを作成できれば、多くの問題を回避できます。読み取り専用モードでない限り決して触れない、非常に安全な場所にすべてをコピーします。

すべてのプログラマー、プロジェクト マネージャー、またはチーム リーダーの人生で少なくとも 1 回は起こることです。100 万行を超えるコードを含むシステムを継承します。元のプログラマーはずっと前に辞めて、おそらく晴れた場所で休暇中です。ドキュメント (存在する場合) は、既存のシステムと同期していない可能性が高くなります。

レガシー コード ベースを改善するための推奨ルート: スケーラブルで保守可能なシステムのための 11 のレッスン レガシー コード ベースを改善するための推奨ルート: スケーラブルで保守可能なシステムのための 11 のレッスン

そしてあなたの仕事は、この混乱からチームを導くことです。

逃げるという本能的な反応を経験した後、あなたはプロジェクトを理解し始め、会社の上層部はプロジェクトの失敗を容認しなくなります。ただし、手持ちのものでは、失敗する可能性が高くなります。では、どうやって対処すればいいのでしょうか?

私は幸運にも (または不運にも) 同様の経験をいくつか経験しており、少数の友人グループとこのジャンク コードを健全で保守可能なプロジェクトに変えることが実際に非常に価値があることに気づきました。ここでは、レガシー コード ベースを改善するために私たちがまとめたいくつかの経験 (または軍事規則) を紹介します。

1. データのバックアップ

何かを始める前に、何が起こってもデータが失われないように、関連する可能性のあるものをすべてバックアップする必要があります。毎日何が変更されるかを覚えておくのは困難です。特に構成データはこの種の問題の影響を受けやすく、構成は通常バージョン管理されていないため、定期的にバックアップを作成できれば、多くの問題を回避できます。読み取り専用モードでない限り決して触れない、非常に安全な場所にすべてをコピーします。

2. 実際のシミュレーション環境を構築するための重要な前提条件

この環境がすでに存在していると仮定して、前回の投稿でこのステップを見逃していましたが、多くの HN 関係者がこれを指摘しており、彼らは完全に正しかったです。

最初のステップは、実稼働環境で現在何が実行されているかを確認することです。つまり、実際の環境と一致するバージョンのソフトウェア、つまりバイナリ バージョンと同じソフトウェア環境を構築できる必要があります。 。

これを行う方法が見つからない場合、コードを運用環境にコミットすると、思わぬ事態に遭遇する可能性があります。新しいコードを本番環境で実行するのに十分な自信を得る前に、適切な環境で可能な限りテストするようにしてください。オンラインにするときは、いつでも古いコードに戻せるように準備し、関連する重要なコンテンツがログに記録されるようにして、後のトラブルシューティングに役立つようにしてください。

3. DB変更の凍結

データベース構造の変更を検討する前に、改善の第 1 段階が完了するまで、チームがコード ベースを完全に理解し、レガシー コードが放棄されるまで、データベースの変更を可能な限り凍結します。それより前にデータベースを変更すると、厄介な問題が発生する可能性があり、古いシステムと新しいコードベースを並行して実行できなくなります。DB を完全に変更せずに、新しいビジネス ロジック コードを古いビジネス ロジック コードと比較できます。これがすべて期待どおりに機能する場合、違いはまったくないはずです。

4. テストを書く

変更を加える前に、できるだけ多くのエンドツーエンド テストと統合テストを作成して、これらのテストが正しい出力を生成し、すべての潜在的なケースをカバーしていることを確認します。

これらのテストには 2 つの重要な機能があります。1 つは早い段階で誤解を解くことです。もう 1 つは、古いコードを置き換えるために新しいコードを書き始めると、これらのテストはシステムをより適切に保護します。

すべてのテストを自動化し、すでに CI の経験がある場合はできるだけ早くテストを使用し、各コミット後にテスト スイート全体を実行できるほど高速にテストが実行されることを確認します。

5. インストルメンテーションとログ

古いプラットフォームでもまだインストルメンテーションをインクリメントできる場合は、新しいデータベース テーブルでそれを行い、考えられるすべてのイベントに単純なカウンターを追加し、これを行う単一の関数を追加して、イベントの名前に基づいてこれらのカウンターをインクリメントします。 。

そうすれば、数行のコードを追加するだけでタイムスタンプ付きのイベント ログを実装でき、1 種類のイベントにつながるイベントの数がわかります。例: ユーザーがアプリを開き、ユーザーがアプリを閉じます。2 つのイベントによってバックエンド リクエストが発生する場合、これら 2 つのカウンターは長期にわたって一定のままである必要がありますが、その違いは現在開いているアプリケーションの数です。終了するアプリよりも開いているアプリの方が多い場合は、アプリを終了する別の方法 (クラッシュなど) があるはずであることがわかります。

この単純なトリックは、すべてのバックエンド アプリケーションを一種の簿記システムに変えます。実際の簿記システムと同様に、すべての数値が一致し、どこで使用されても問題がないことを確認する必要があります。

時間が経つにつれて、このシステムは健全性の側面を監視するのに非常に価値のあるものとなり、ソース管理システムの変更ログの優れた相棒となるでしょう。これにより、各バグが導入された時点を特定し、さまざまな影響のカウントに変更を加えることができます。状況。

通常、これらのカウンタは 5 分の解像度 (つまり、1 時間あたり 12 ログ) で保持されますが、システムのイベントが少ない場合や多い場合は、この間隔を変更する必要がある場合があります。すべてのカウンターは同じデータベース テーブルを使用するため、各カウンターはそのテーブル内の単なる列にすぎません。

6. 一度に 1 つのポイントのみを変更します

新しい機能を追加したりバグを修正したりするときに、コードの改善とコードが実行されるプラットフォームの変更を同時に行うという罠に陥らないようにしてください。これにより、多くの頭痛が引き起こされる可能性があります。

7. プラットフォームの変更

アプリケーションを別のプラットフォームに移行する場合は、最初に移行しますが、すべてがまったく同じように機能するようにしてください。さらにドキュメントやテストを追加できますが、この時点を超えてはならず、すべてのビジネス ロジックと相互依存関係は現状のままにする必要があります。

8. アーキテクチャの変更

次に取り組むべきことは、(必要に応じて) アプリケーションのアーキテクチャを変更することです。この時点で、通常はモジュール間の水平リンクの数を減らすことにより、コードの上位レベルの構造を自由に変更できます。これにより、エンド ユーザーとの対話におけるコード アクティビティの範囲が縮小されます。古いコードが本質的にモノリシックだった場合は、変数名とデータ構造を保持しながら、大きな関数を小さな関数に分割して、コードをよりモジュール化するのに良い時期です。

HN ネチズン mannykannot は、アーキテクチャの変更は必ずしも実現可能ではなく、特に運が悪い場合は、アーキテクチャの変更を行うためにコードを非常に深く理解する必要があるかもしれないと指摘しました。私もそれに同意するので、少し追加します。高レベルの変更と低レベルの変更の両方を行う場合、変更を制限するには、少なくとも 1 つのファイル、最悪の場合は 1 つのサブシステムに制限する必要があります。可能な範囲で。そうしないと、行った変更をデバッグするのが困難になる可能性があります。

9. 低レベルのリファクタリング

ここまでで、各モジュールの機能を十分に理解し、コードをリファクタリングして保守性を向上させ、新しい機能を拡張できるようにするという実際の作業の準備ができているはずです。これはプロジェクトで最も時間がかかる部分である可能性が高く、ドキュメントもそれに付随する必要があります。ドキュメントの導入部分を完全に作成し、モジュールを完全に理解するまでは、モジュールを変更しないでください。

この段階では、コードの明瞭さと一貫性を向上させるために、変数と関数の名前を変更したり、データ構造を変更したりすることもできます。関連するテスト コードを忘れずに追加してください (必要に応じて単体テストを実行できます)。

10. バグを修正する

エンドユーザーに見える変更を加える準備ができたので、最初に行うことは、長年にわたってキューに蓄積されたバグを修正することです。いつものように、最初にバグがまだ存在していることを確認し、次にテストを作成してバグを修正します。継続的インテグレーションとエンドツーエンドのテストは、理解不足や間違いによるバグや周辺の問題を回避するのに役立ちます。

11. データベースのアップグレード

上記の作業が完了すると、信頼性が高く保守しやすいコード ベースが再び得られ、データベース スキーマを変更したり、データベースを置き換えたりすることもできます。上記のすべての作業は、予期せぬ事態を心配することなく、負担のない方法で変更を加えるのに役立ちます。新しいコードを使用して新しいデータベースをテストし、すべてのテストを実行して、データベースに問題がないことを確認できます。移住。

ロードマップに沿って前進する

おめでとうございます。この時点でジャングルから抜け出し、新しい機能を実装する準備が整いました。

完全に書き直そうとしないでください

完全な書き直しは、ほぼ確実に失敗する種類のプロジェクトです。一方で、あなたは未知の領域からスタートしており、何をリファクタリングすればよいのかさえわかりません。また、他方では、すべての問題を最終日、つまり本番稼働の前日まで先送りしていることにもなります。新しいシステム。悲しいことに、それは失敗するときでもあります。ビジネス ロジックの想定は最終的には問題があることが判明します。その時点で、なぜ古いシステムが奇妙な方法で動作するのかが突然わかり、最終的には、古いシステムを機能させるために組み立てたすべての人々が愚かであるわけではないことに気づきます。本当に会社 (そして自分自身の評判) を泥沼に陥れたいのであれば、全面的な書き換えを行うべきですが、十分に賢い人であれば、通常、システムの完全な書き換えは議論の俎上に上る選択肢ではありません。

代替案: 反復的な改善

これらの結びつきを解く最も簡単な方法は、すでに理解しているコード (ペリフェラルの可能性もありますが、コア モジュールの可能性もあります) から始めて、古いコンテキストの範囲内で段階的に改善を試みることです。

古いビルド ツールが利用できなくなった場合は、いくつかのトリック (以下を参照) を使用する必要がありますが、少なくとも、変更を開始する間は可能な限り古いシステムを動作させ続けてください。通常、一般的なコミットには数行のコードしか含まれていません。

リリース!

変更されたコードがエンドユーザーに見えない場合でも、すべての変更は可能な限り実稼働環境にリリースされます。これは、システムについて十分な知識がない場合、新しい変更のどこに問題があるかを知ることができるのは実稼働環境だけであるためです。この問題が小さな変更後にのみ発生する場合は、いくつかの利点が得られます。

何が問題なのかを理解するのは簡単です

プロセスを改善するために良い状態になるでしょう

得られた新しい洞察を文書化するには、すぐにドキュメントを更新する必要があります。

プロキシサーバーを適切に使用する

Web システムをリファクタリングしている場合、エンド ユーザーとレガシー システムの間にプロキシ サーバーをデプロイできることに感謝します。各 URL のどのリクエストを従来のシステムに送信し、どのリクエストを新しいシステムにルーティングするかを正確に制御できるため、実行内容をより簡単かつ詳細に制御できるようになります。

プロキシが十分に強力であれば、URL のトラフィックの特定の割合を新しいシステムに送信することも制御できるため、新しいシステムの動作を監視できます。統合テストもこのプロキシに接続できれば便利です。

当然のことですが、すべてを行うには時間がかかりすぎます。

まあ、それは見方次第です。これらの手順に従うのは大変な作業ですが、うまくいきます。プロセスを最適化することで、システム全体をさらに深く理解できるようになります。私自身もこの点では非常に評判が良く、このような仕事に関してネガティブな問題が生じることは本当に望んでいません。

場合によっては、会社のシステムにすでに問題があり、それが顧客に影響を与える可能性がある場合、このプロセスに従うことで状況が改善される可能性がある場合、数日または数週間を節約する表面的な方法よりも、このプロセスを完全に制御して使用したいと考えます。あなたがカウボーイ的なやり方で、上司も同意するのであれば、それは許容できるリスクの高いアプローチかもしれませんが、ほとんどの企業はむしろ、もう少しゆっくりでより堅牢なリファクタリングの道を選択します。

 

おすすめ

転載: blog.csdn.net/yaxuan88521/article/details/132333870