本「 リファクタリング 」のリファクタリング手法の続き。 既存のコードの改善Martin Fowler
構文はC#で記述されますが、主なことはアイデアを理解することであり、他のプログラミング言語でも使用できます。
メソッドのコンパイル。
- メソッドを強調表示する ( コードの一部を名前が意味を説明するメソッドに変換する )。
longメソッドを論理サブメソッドに分割します。
から
void PrintUserInfo(decimal amount) { PrintParentInfo(); Console.WriteLine(string.Format(": {0}", name); Console.WriteLine(string.Format(": {0}", age); Console.WriteLine(string.Format("-: {0}", amount); }
に
void PrintUserInfo(decimal amount) { PrintParentInfo(); PrintUserDetails(decimal amount); } void PrintUserDetails(decimal amount) { Console.WriteLine(string.Format(": {0}", name); Console.WriteLine(string.Format(": {0}", age); Console.WriteLine(string.Format("-: {0}", amount); }
- メソッドの埋め込み ( メソッドを呼び出すコードにメソッドの本体を入れて、メソッドを削除します )。
過度の間接化(メソッドへの分解)は、クラスを複雑にする可能性があります。
から
int GetPoints() { return HasMaxSum() ? decimal.One : decimal.Zero; } bool HasMaxSum() { return summ >= maxSumm; }
に
int GetPoints() { return summ >= maxSumm ? decimal.One : decimal.Zero; }
- 一時変数の埋め込み ( この変数へのすべての参照をこの式に置き換えます )。
追加の中間コード。
から
decimal cost = order.GetCost(); return cost > 1000;
に
return order.GetCost() > 1000;
- 一時変数をメソッド呼び出しに置き換えます ( 式をメソッドに変換します )。
このような場所が多数ある場合、メソッドはクラス内のどこからでも呼び出すことができます。
から
decimal MethodA() { decimal summ = amount * cost; if(summ > 1000) { //do something return summ * 10; } return 0; } decimal MethodB() { //do something decimal summ = amount * cost; return summ != 0 ? summ * 100 : 1; }
に
decimal MethodA() { decimal summ = GetSumm(); if(summ > 1000) { //do something return summ * 10; } return 0; } decimal MethodB() { //do something return GetSumm() != 0 ? GetSumm() * 100 : 1; } decimal GetSumm() { return amount * cost; }
- 説明変数の導入 ( 式の結果またはその一部を一時変数に入れる )。
コードの読み取りと理解が簡素化されます。
から
if(VisualItems.ColumnCount == FocusedCell.X && (key == Keys.Alt | Keys.Shift) && WasInitialized() && (resize > 0)) { // do something }
に
bool isLastFocusedColumn = VisualItems.ColumnCount == FocusedCell.X; bool altShiftPressed = (key == Keys.Alt | Keys.Shift); bool wasResized = resize > 0; if(isLastFocusedColumn && altShiftPressed && WasInitialized() && wasResized) { // do something }
- 説明変数を分割します ( 割り当てごとに個別の一時変数を作成します )。
コードの読み取りと理解が簡素化されます。
から
decimal temp = 2 * (height + width); Console.WriteLine(temp); temp = height * width; Console.WriteLine(temp);
に
decimal perimetr = 2 * (height + width); Console.WriteLine(perimetr); decimal area = height * width; Console.WriteLine(area);
- パラメーターへの割り当てを削除します ( 一時変数を使用することをお勧めします )。
メソッドは、明示的に指定されていない限り、入力パラメーターの値を変更しないでください(out、ref in C#など)。
から
int Discount(int amount, bool useDefaultDiscount, DateTime date) { if(amount == 0 && useDefaultDiscount) { amount = 10; } return amount; }
に
int Discount(int amount, bool useDefaultDiscount, DateTime date) { int result = amount; if(amount == 0 && useDefaultDiscount) { result = 10; } return result; }
- メソッドをメソッドオブジェクトに置き換える ( メソッドを別のオブジェクトに変換する )。
コードの柔軟性のためのクラス分解。
から
class MessageSender { public Send(string title, string body) { // do something // long calculation of some condition if(condition) { // sending message } } }
に
class MessageSender { public Send(string title, string body, decimal percent, int quantity) { // do something Condition condition = new Condition (percent, quantity, dateTime); if(condition.Calculate()) { // sending message } } } class Condition { public Condition(decimal percent, int quantity, DateTime dt) { } public bool Calculate() { // long calculation of some condition } }
- アルゴリズムの置換 ( アルゴリズムをより理解しやすいものに置き換えます )。
読みやすさやパフォーマンスを向上させるためのコードの最適化。
から
string FoundPerson(List<string> people) { foreach(var person in people) { if(person == "Max") { return "Max"; } else if(person == "Bill") { return "Bill"; } else if(person == "John") { return "John"; } return ""; } }
に
string FoundPerson(List<string> people) { var candidates = new List<string>{ "Max", "Bill", "John"}; foreach(var person in people) { if(candidates.Contains(person)) { return person; } } return ""; }
少し現実とコードレビュー手順。
リファクタリングする前に、または行われた変更を確認するために、コードレビュー手順が使用されます。
この場合、レビュアーの「コメント」(基準)に焦点を当てます。
- 修正する必要があります。
原則として、これらは明らかなものにつながる可能性があります:例外(たとえば、nullのチェックがない)、パフォーマンスの低下、およびプログラムのロジックの変更。
これには、建築的なタッチも含まれます。 たとえば、プロジェクト全体がMVC / MVPで記述されており、新しい同僚がすべてを1つのファイル/クラスにまとめてフォームを追加した場合です。 前例を設定せず、ルールに従わないために、もちろん、共通のアーキテクチャ用にこのスパゲッティコードをやり直すことをお勧めします。 - コメント、質問。
何かを理解していない場合は、遠慮なく質問してください。そのような解決策、なぜそのようなアルゴリズムが選ばれたのか、なぜそのような付加機能を備えているのか。 質問は一般的な開発に役立ちます。有用な機能を学習したり、現在のコードをよりよく学習したりできます。 したがって、同僚が意識的にソリューションを選択したことを理解することです。 - コメントの提案。
コードを改善するための提案がありますが、コードコミッターがそれらを無視する場合、私は主張しません。
コードコミッターとして何かが提供された場合、私はそれをしようとすることがよくあります。 ここで、レビュアーはコードをチェックする教師であり、文が不合理な点に達していない場合、彼は正しいという考えから進みます。
何かを提供すると、明確にするためにコードでこれを議論することができます。
現実には、これらの基準間の線はプログラマーごとに異なる場合がありますが、これは許容範囲です-通常です。 レビュアーに3番目の基準がない場合、つまり、 彼は常に正しい、そしてもし彼が正しくないなら、それを彼に証明する(しかし、すべてが決定的ではなく、まだ数学ではない)。 反対に、すでにコードコミッターになっているため、3番目の基準のみが適用されます。
そして、そのような2人が衝突するとき、それは炎であり、悲鳴を上げます(私は母親と一緒に見ました:))。
衝突を解決するには、3つの力が必要です。原則として、別のプログラマー(できれば経験が豊富)が意見を述べる必要があります。
利益相反とその解決策については、次の記事で説明します。