ここまでコードリファクタリングについて4本の記事を挙げてきたが、なぜ私がコードリファクタリングについて考えているのかを記載する。
私が入社した会社のプログラムは、言ってしまえば「企業で使用するためのロジックを学生が頑張って書いたような」プログラムであった。
どのような問題があったのかを記録し、戒めとする。
1. 1つのクラスのコード量が莫大
C#でプログラムを作成していると、MVVM(Model-View-ViewModel)の設計思想に触れることがある。
MVVMとは、Modelがビジネスロジックを担い、Viewが表示を担当することで、ViewとModel間の結合度を下げるための設計思想である。そして、ViewModelがModelとViewの橋渡しを行う。
しかし、この思想を遵守しようとした結果、ViewModelにロジックが集中し、クラスの肥大化が発生していた。ひどいものでは1クラス1万行を超えていた。
クラスに1万行以上あると、ソースコードのどこに何があるのかを把握することが困難になり、変数の変更がどこで行われているのかの影響範囲を調査するのに膨大な時間がかかっていた。
❌ 悪い例
public class HugeViewModel
{
public void ProcessData()
{
// 何百行もの処理がここに存在...
}
public void ValidateInput()
{
// さらに膨大なロジック...
}
}
✅ 良い例
public class DataProcessor
{
public void Process() { /* データ処理 */ }
}
public class InputValidator
{
public void Validate() { /* 入力検証 */ }
}
2. publicで書き換え可能な変数が多く存在する
public
なクラス内において、public
で宣言された変数が存在することは、すなわちどこからでも読み書き可能な変数、つまりグローバル変数を公開しているのと同義である。
グローバル変数となった値は、クラス内の影響範囲にとどまらず、引数で渡された先のクラスや、このクラスを作成したクラスにも影響を与える。そのため、コード全体において影響の確認が必要となり、管理が非常に困難になっていた。
❌ 悪い例
public class UserData
{
public string Name; // どこからでも書き換え可能
}
✅ 良い例
public class UserData
{
public string Name { get; private set; }
public UserData(string name) { Name = name; }
}
3. int, string等で扱われる変数の恐ろしさ
外部との接続があるプログラムであったため、最初からクラスとして扱うのが難しい場合があった。
そのため、利便性を優先し、int
やstring
などの基本型で扱っている変数が多数存在していた。しかし、これには大きな問題がある。int
やstring
といった基本型では値の検証が難しく、不正な値が入力されてもコンパイルが通ってしまう。
特に深刻だったのは、ある変数をint
で保存していた結果、2つの異なるEnum
が比較されたり、代入されたりすることでバグが発生していたことである。
❌ 悪い例
public class Order
{
public int Status; // 数値で状態を管理
}
✅ 良い例
public enum OrderStatus { Pending, Shipped, Delivered }
public class Order
{
public OrderStatus Status { get; private set; }
public Order(OrderStatus status) { Status = status; }
}
4. コメントの陳腐化
プログラム内で表現が難しい部分に関して、コメントで補足することは重要である。
しかし、過剰にコメントを記述すると、コードの修正に伴いコメントの修正が漏れ、ソースコードの内容とコメントの内容が乖離してしまうことがある。その結果、コードとコメントのどちらが正しいのかを判断する手間が増えてしまう。
また、TODOコメントがリリースプログラムに残っていたり、「これは〜なっていると思う」といった曖昧なコメントが記載されていたりすることで、コメントの信頼性が低下し、結果として陳腐化していた。
❌ 悪い例
public class Calculator
{
// たぶんこのメソッドは掛け算をする
public int Multiply(int a, int b) { return a * b; }
}
✅ 良い例
public class Calculator
{
/// <summary>
/// 2つの整数を掛け算する
/// </summary>
public int Multiply(int a, int b) { return a * b; }
}
まとめ
これらの問題から、コードの可読性や保守性を向上させるためにリファクタリングの必要性を強く感じた。特に、クラスの適切な分割、変数のスコープの適正化、型の厳格な管理、コメントの適正な運用が重要である。
リファクタリングは単なるコードの整理ではなく、プログラムの品質を向上させ、長期的な開発・保守を容易にするための重要なプロセスである。今後もこれらの課題を念頭に置きながら、より良いコードを書くことを心がけたい。