したがって、次の状況を想像してください。 たまたま、非常に大きなコード、つまりサブシステム全体をリファクタリングする必要がありました。 ライン、コマーシャル、200K。 さらに、リファクタリングは明らかに非常に大きく見え、サブシステムが構築される基本概念に影響を与えます。 実際、ビジネスロジックを維持しながら、アーキテクチャ全体を書き直す必要があります。 これは、たとえば、1つのプロジェクトを作成していて、新しいプロジェクトを先に持っていて、そのプロジェクトの過去のすべての間違いを修正したい場合に発生します。 最初の推定によると、リファクタリングには約2か月かかります。 リファクタリングのプロセスでは、他のプログラマーが新しい機能を追加したりサブシステムのバグを修正したりすることを防ぐことは不可能を含め、すべてが機能するはずです。 多くの場合、このようなリファクタリングは非常に複雑であるため、古いコードを新しいものに変更することは完全に不可能であり、結果を部分的にロールアウトすることも不可能です。 実際、飛行機のエンジンをその場で交換する必要があります。
私と同僚の両方の実践例:
- Hibernate上の純粋なJDBCからすべてのデータベース作業をやり直します。
- サービスのアーキテクチャをリモートプロシージャコール(RPC)とのメッセージの送受信からやり直します。
- XMLファイルをランタイムオブジェクトに変換するためのサブシステムを完全に書き換えます。
どうする 問題に取り組む側 以下は、この問題に対処するのに役立つ一連のヒントとプラクティスです。 最初に、より一般的な言葉、次に特定のテクニック。 一般的に、超自然的なことは何もありませんが、誰かを助けることができます。
リファクタリングの準備
- 可能であれば、リファクタリングを部品に分割します。 可能であれば、問題ありません。 失敗した場合の対処方法に関するその他のすべてのヒント。
- サブシステムに新しい機能を追加するアクティビティが最小限になる期間を選択してください。 たとえば、バックエンドをやり直すと便利ですが、すべてのチームの努力はフロントエンドに集中します。
- コードをよく読んでください。なぜそれが必要なのでしょうか。 サブシステムの基盤となるアーキテクチャ、そこで使用された標準的なアプローチは何か。 新しい概念が何であり、何を変更したいのかを明確に定義してください。 測定可能な最終目標がなければなりません。
- リファクタリングがキャプチャするコードの領域を定義します。 可能であれば、別のモジュール/別のディレクトリに分離します。 これは将来非常に役立つでしょう。
- テストなしのリファクタリングは非常に危険です。 テストが必要です。 私は彼らなしで生きる方法を知りません。
- カバレッジの計算を使用してテストを実行します。これにより、多くの情報が得られます。
- 目的のサブシステムに関連する壊れたテストを修復します。
- メソッドに関するカバレッジ情報を分析することにより、未使用のコードを見つけて削除できます。 奇妙なことに、これは多くの場合10〜15%まで発生します。 削除できるコードが多いほど、リファクタリングは少なくなります。 利益!
- カバレッジによって、コードのどの部分がカバーされていないかを判断します。 不足しているテストを追加する必要があります。 単体テストが長くて面倒な場合は、少なくとも高レベルのsmkeテストを作成してください。
- 意味のあるコードの80〜90%をカバーするようにしてください。 すべてをカバーしようとしないでください。 ほとんど利益なしで多くの時間を殺します。 少なくともメインの実行パスをカバーします。
リファクタリング
- サブシステムをインターフェースでラップします。 このインターフェイスを使用するには、すべての外部コードを翻訳します。 これにより、アプリケーションに適切なプログラミング手法を強制するだけでなく、リファクタリングを簡素化します。
- テストでは、実装ではなくインターフェイスをテストしてください。
- 起動時に、このインターフェイスのどの実装を使用するかを指定できるようにします。 この機会は、テストと本番の両方でサポートされる必要があります。
- 新しい実装の作成が開始されたバージョン管理システムのリビジョンを記録します。 これからは、古いサブシステムへのコミットはすべて敵です。
- サブシステムのインターフェースの新しい実装を作成します。 ゼロから始めることもあれば、お気に入りの方法(コピー&ペースト)を使用することもできます。 別のモジュールで作成する必要があります。 新しい実装で定期的にテストを実行します。 あなたの目標は、すべてのテストが新旧の実装で正常に合格することを確認することです。
- すべてを完全に書くのを待つ必要はありません。 古い実装を含めたまま、できるだけ頻繁にリポジトリにコードを注ぎます。 長い間zagashnikにコードを保持しておけば、他の人が使用するモジュールをリファクタリングする問題に対処できます。 メソッドの名前を変更すると、多くの問題が発生する可能性があります。
- 新しい実装に固有のテストがある場合は、それを書くことを忘れないでください。
- すべてを書いた後、古いコードのあるフォルダー内のSVN履歴を見て、リファクタリング中にそこに何が変更されたかを見つけます。 これらの変更を新しいコードに転送する必要があります。 理論的には、何かを転送するのを忘れた場合、テストはそれをキャッチする必要があります。
- その後、すべてのテストが古いサブシステムと新しいサブシステムの両方に合格する必要があります。
- モジュールの新しいバージョンの安定性を確信した直後に、テストと生産を切り替えます。 古いサブシステムへのコミットをブロックします。 どうしても、2つのサブシステムのライフタイムを最小限に抑えるようにしてください。
- 1、2週間待って、すべてのラッパを集めて、考えて、古いサブシステムを大胆に削除します。
追加のヒント
- リファクタリングと並行して作成されたすべての新機能は、テスト100%でカバーされる必要があります。 これは、新しい実装に切り替えるときにテストが失敗し、新しい実装に古い実装からの十分なコードがないことを知らせるために必要です。
- バグ修正は原則に従って行う必要があります。まず、問題を再現してクラッシュするテストを作成してから、修復します。 理由は同じです。
- TeamCityのようにシステムを使用する場合は、リファクタリング時に別のビルドを作成します。ここでは、新しいサブシステムでのすべてのテストが追跡されます。 自動ビルドにより、まだ使用されていない新しいコードが「公式」になります。 すべての同じポリシーとルールが、他のすべてに関して彼に適用され始めます。
- 新しいアーキテクチャの古いコードで必要なものをすべて修正したかどうかわからないことがよくあります。 たとえば、コードがHibernateの代わりにどこかで直接JDBC接続を使用しているかどうかはわかりません。 または、突然RPCコールではなく、メッセージがどこかにスリップしました。 そのような場所を見つけるには、古い方法を無効にする方法を考え出す必要があります。 つまり テストでそれを破る。 たとえば、メッセージ配信システムを壊したり、破損したJDBCドライバーをシステムにスリップさせたりします。 練習により、この方法で、忘れられた場所や訂正されていない場所が少なくとも5つは通常見つかることがわかります。
- 他のプログラマーに相談して、進捗状況を知らせてください。 残りの1週間を知っている場合は、サブシステムの新しいバージョンがリリースされるまでタスクを移動できる場合があります。 変更をマージする必要はありません。
経験上、恐ろしくて大きなサブシステムでさえ、比較的少ない血液でリファクタリングできることが示唆されています。 主なアシスタントはテストと体系的です。