web-dev-qa-db-ja.com

大きなファイルのリファクタリングを処理する最良の方法は何ですか?

私は現在、残念ながらソフトウェアの品質に関するガイドラインに従っていないファイルがいくつかある大きなプロジェクトに取り組んでいます。これには、複数の異なる機能が明確に含まれている大きなファイル(2000〜4000行を読み取る)が含まれます。

次に、これらの大きなファイルを複数の小さなファイルにリファクタリングしたいと思います。問題は、それらが非常に大きいため、異なるブランチの複数の人(私も含む)がこれらのファイルで作業していることです。これらのリファクタリングを他の人々の変更とマージすることが難しくなるので、私は実際に開発とリファクタリングから分岐することはできません。

もちろん、全員をマージしてファイルを開発し、「フリーズ」して(つまり、誰も編集できないように)、リファクタリングしてから「フリーズ解除」することもできます。ただし、リファクタリングが完了するまで、基本的に全員がこれらのファイルに対する作業を停止する必要があるため、これも実際には適切ではありません。

それで、リファクタリングする方法はありますか?他の誰かに(長い間)動作を停止したり、機能ブランチをマージして開発したりする必要はありませんか?

42
Hoff

これは技術的な問題ではなく、社会的な問題であることを正しく理解しています。過度のマージの競合を回避したい場合、チームはこれらの競合を回避する方法でコラボレーションする必要があります。

これはGitの大きな問題の一部であり、分岐は非常に簡単ですが、マージには依然として多くの労力が必要です。開発チームは多くのブランチを立ち上げる傾向があり、ブランチをマージすることが難しいことに驚いています。おそらく、そのコンテキストを理解せずにGit Flowをエミュレートしようとしているためです。

高速で簡単なマージの一般的なルールは、大きな違いが蓄積するのを防ぐことです。特に、機能ブランチの存続期間は非常に短くなければなりません(数時間ではなく数時間または数日)。変更を迅速に統合できる開発チームでは、マージの競合が少なくなります。一部のコードがまだ本番環境に対応していない場合は、コードを統合することは可能ですが、機能フラグを使用して非アクティブにすることができます。コードがマスターブランチに統合されるとすぐに、実行しようとしている種類のリファクタリングにアクセスできるようになります。

それはあなたの当面の問題には多すぎるかもしれません。ただし、リファクタリングを実行できるように、同僚にこのファイルに影響を与える変更を週の終わりまでマージするよう依頼することは現実的かもしれません。もし彼らがもっと長く待つなら、彼らはマージの衝突を彼ら自身で扱わなければならないでしょう。それは不可能ではありません、それはただ回避可能な仕事です。

また、依存するコードの大きな帯を壊さないようにして、API互換の変更のみを行うこともできます。たとえば、いくつかの機能を別のモジュールに抽出する場合は、次のようにします。

  1. 機能を別のモジュールに抽出します。
  2. 古い関数を変更して、呼び出しを新しいAPIに転送します。
  3. 今後、依存コードを新しいAPIに移植します。
  4. 最後に、古い関数を削除できます。
  5. (次の一連の機能について繰り返します)

このマルチステッププロセスにより、多くのマージ競合を回避できます。特に、他の誰かが抽出した機能を変更している場合にのみ競合が発生します。このアプローチのコストは、すべてを一度に変更するよりもはるかに遅く、2つのAPIが一時的に重複していることです。これは、緊急の事態がこのリファクタリングを中断し、複製が忘れられるか、優先順位が下がり、最終的に大量の技術負債が発生するまで、それほど悪くはありません。

しかし結局のところ、どのようなソリューションでも、チームと調整する必要があります。

42
amon

小さなステップでリファクタリングを行います。大きなファイルの名前がFooであるとしましょう:

  1. 新しい空のファイルBarを追加し、「トランク」にコミットします。

  2. Fooに移動できるBarのコードのごく一部を見つけます。移動を適用し、トランクから更新し、コードをビルドしてテストし、「トランク」にコミットします。

  3. FooBarが同じサイズ(または任意のサイズ)になるまで手順2を繰り返します

そうすれば、次にチームメイトがトランクからブランチを更新するときに、変更を「小さな部分」で取得して1つずつマージできるため、1つのステップで完全なスプリットをマージするよりもはるかに簡単です。手順2で他の誰かが中間でトランクを更新したためにマージの競合が発生した場合も同様です。

これにより、マージの競合やそれらを手動で解決する必要がなくなるわけではありませんが、各競合がコードの小さな領域に制限されるため、管理が容易になります。

そしてもちろん-チームのリファクタリングを伝えます。特定のファイルに対してマージの競合を予期する必要がある理由を相手が知っているように、相手に通知します。

30
Doc Brown

ファイルをアトミック操作として分割することを考えていますが、中間的な変更が可能です。ファイルは時間の経過とともに徐々に大きくなり、時間の経過とともに徐々に小さくなります。

久しぶりに交換する必要のないパーツを選びましょう(git blameはこれに役立ちます)、そしてそれを最初に分割します。その変更を全員のブランチにマージしてから、次に分割する最も簡単な部分を選択します。たぶん、1つの部分を分割することも1つのステップとしては大きすぎるため、まず大きなファイル内でいくつかの再配置を行う必要があります。

人々が頻繁にマージして開発に戻らない場合は、それを奨励し、マージした後に、変更した部分を分割する機会を与える必要があります。または、プルリクエストレビューの一部として分割を行うように依頼します。

目標はゆっくりと目標に向かって移動することです。進行が遅いように感じますが、突然、コードがはるかに優れていることに気付くでしょう。定期船を回すには時間がかかります。

18
Karl Bielefeldt

この問題の通常の解決策とは異なる解決策を提案します。

これをチームコードイベントとして使用します。誰でもできるコードをチェックインし、ファイルを操作している他の人を助けます。関係者全員がコードをチェックインしたら、プロジェクターが設置された会議室を見つけ、協力して新しいファイルに移動します。

これに特定の時間を設定して、最終的に見えないまま1週間分の議論になることがないようにすることができます。代わりに、これは毎週1〜2時間のイベントであり、すべての人がそれがどのようにあるべきかを理解するまで続きます。たぶん、ファイルをリファクタリングするのに必要な時間は1〜2時間だけです。試すまでは分からないでしょう。

これには、リファクタリングを使用して全員が同じページにいる(しゃれた意図はない)利点がありますが、必要に応じて、ミスを回避したり、維持できるメソッドのグループ化について他のユーザーから入力を得たりするのにも役立ちます。

このようにすることは、そのようなことを行う場合、組み込みのコードレビューがあると見なすことができます。これにより、適切な数の開発者がコードをチェックインしてレビューの準備ができるとすぐにコードをサインオフできます。あなたはまだ彼らがあなたが逃した何かのためにコードをチェックすることを望むかもしれませんが、レビュープロセスがより短いことを確認するために長い道のりを行きます。

これは簡単に実行できるように作業が分散されていないため、すべての状況、チーム、または会社で機能するとは限りません。また、(誤って)開発時間の誤用と解釈されることもあります。このグループコードには、リファクタリング自体だけでなく、マネージャからの同意も必要です。

このアイデアを上司に売り込むために、コードレビューのビットと、最初からどこにいるかを知っている全員に言及してください。開発者が時間を無駄にして新しいファイルのホストを検索しないようにすることは、避ける価値があります。また、開発者が物事が終わった場所や「完全に見当たらない」場所についてPOedされるのを防ぐことは、通常は良いことです。 (メルトダウンが少なければ少ないほど、IMOは優れています。)

この方法で1つのファイルをリファクタリングすると、それが成功して有用であれば、より多くのリファクタリングの承認をより簡単に取得できる可能性があります。

しかし、あなたはあなたのリファクタリングをすることに決めました、幸運!

9
computercarguy

この問題を修正するには、共有リソース(コード自体)を変更しようとしているため、他のチームからの賛同が必要です。そうは言っても、人を混乱させることなく巨大なモノリシックファイルから「移行」する方法はあると思います。

また、個々のファイルのサイズに加えて巨大なファイルの数が制御不能に増加しない限り、すべての巨大なファイルを一度にターゲットにしないをお勧めします。

このような大きなファイルをリファクタリングすると、予期しない問題が頻繁に発生します。最初のステップは、大きなファイルが追加機能を蓄積しないようにすることです現在マスターまたは開発ブランチにあるものを超えて

これを行う最良の方法は、デフォルトで大きなファイルへの特定の追加をブロックするコミットフックを使用することですが、@bigfileokなどのコミットメッセージ内の魔法のコメントで却下できます。簡単で追跡可能な方法でポリシーを却下できることが重要です。理想的には、commitフックをローカルで実行でき、エラーメッセージ自体でこの特定のエラーをオーバーライドする方法が示されているはずです。また、これは私の好みですが、認識されない魔法のコメントまたは魔法のコメントによって、コミットメッセージの実際には発生しませんでしたがコミット時の警告またはエラーになるため、誤ってトレーニングしないでください。人々は、必要があるかどうかにかかわらず、フックを抑制する必要があります。

Commitフックは、新しいクラスをチェックしたり、他の静的分析(アドホックかどうか)を実行したりできます。現在のファイルよりも10%大きい行数または文字数を選択して、大きなファイルは新しい制限を超えて拡大できないと言うこともできます。行が多すぎる、文字が多すぎる、またはw/eで大きなファイルが大きくなる個々のコミットを拒否することもできます。

大きなファイルが新しい機能の蓄積を停止すると、一度に1つずつリファクタリングできます(また、コミットフックによって強制されるしきい値を減らして、ファイルが再び大きくなるのを防ぎます)。

最終的に、大きなファイルはコミットフックを完全に削除できるほど小さくなります。

4
Gregory Nisbet