Completness of Large Refactoring and Structure Evolution

大きなリファクタリングとプログラムの構造進化との関係は?


リファクタリング」によれば、個々の小さなリファクタリングは数分から数時間で終わるのに対して、大きなリファクタリングは数ヶ月から数年かかる。

また、大きなリファクタリングの場合、どこでやめるのかを決めることができる。たとえば、意図的に途中でやめる場合もあれば、さらにリファクタリングできることに気付かずに途中でやめてしまうこともある。


いずれにせよ、大きなリファクタリングの過程は、モジュール(クラス)間の構造の進化(あるいは構造の成長)の過程に影響を与える。


たとえば、大きなリファクタリングの途中で、あるクラスのフィールドにアクセスするために get メソッドを追加することが必要になるかもしれない。そして、結果として get メソッドを追加するとする。この後、構造の進化を追跡しようとする場合、現在進行中の大きなリファクタリングを終わらせるかどうかによって、少なくとも二つの可能性が生まれる。

  • (1) 終わらせない場合:終わらせることなくリファクタリングを続けた結果、先ほど追加した get メソッドは一時的に必要だったのであり、さらにリファクタリングを続けることで、追加した get メソッドは削除される。
  • (2) 終わらせる場合:この場合、get メソッドは追加されたままとなる。


1 の場合、あるクラスの構造は、リファクタリング前と後では、get メソッドが存在するかどうかの視点では、変更されていない。

2 の場合、クラスに get メソッドが追加されたままそのクラスは成長を続ける。その後、機能追加の要求などにより、そのクラスは、さきほどの get メソッドが追加されただけでなく、さまざまな可能性(たとえば、あるクラスを継承するようになったり、ある interface を実装するようになったり)で成長する。その後、先ほどの大きなリファクタリングが再開されるかもしれない。そして、その結果として、get メソッドの必要性がないことに気付き、そのメソッドは削除されることになるかもしれない。この場合、クラスの構造の進化の視点から見ると、メソッドがなくなったという点で、構造進化と言えるかもしれない。


より形式的に考えるとこうなる。まず、大きなリファクタリングは、二つの(大きな)リファクタリングに分割できるものとする(リファクタリングAとB)。また、その後の進化的な要求としてある機能を追加しなければならないとする(機能Aの実装)。

1の場合は、「リファクタリングA、リファクタリングB、機能Aの実装」という流れであり、2の場合は「リファクタリングA、機能Aの実装、リファクタリングB」となる。


1と2いずれの道を通ったとしても、プログラムの振る舞いは同じである。しかし、構造進化の視点では、微妙な違いを観察できる。先ほど述べたように、あるクラスの進化(成長)過程において get メソッドがいかに追加され削除されるかといった違いである。


この違いがどんな意味を持っているのかについては、今後の課題である。ただし、少なくとも、構造進化を観察することを目的としている場合には、リファクタリング時における構造進化と、機能追加時における構造進化を意識する必要がある(かもしれない)ということである。