家永さんの発言
リファクタリングの話のときに、publishedインタフェース、publicインタフェースというキーワードが出てきましたが、その点についてもう一度整理してください。
publishedインタフェース、publicインタフェースという言葉が出てきました。
まず、publicというのはJavaのpublicだと思ってかまいません。プログラムのどこからでもアクセスできる可視性を持っているインタフェースをpublicインタフェースといいます。Javaで言えばインタフェースは全部publicですね。
それに対してpublishedインタフェースというのは、そういったpublicインタフェースの中のさらに一部分のことを指します。publishedというのは「公布済み」とか、「公開済み」と訳されることがよくあります[1]。たとえば他のチームや他の組織に使ってもらうためのインタフェースや、Web APIのように公開APIのような形で公布しているプログラミングインタフェースのことです。
日々開発している現場では、たとえばpublicなクラスやインタフェースも当然リファクタリングの対象になり得ます。たとえば、このクラスの名前がもう現状とマッチしてないなとか、このメソッド名よくないと思ったりとか、この責務はここじゃなくて、もっと別の場所にあるべきだ、などと考えるときに、publicインタフェースやpublicなクラスに対して、リファクタリングによってクラス名を変えたり、メソッド名を変えたりしていくことはよくあります。
しかし、publicインタフェースのリファクタリングには自分たちで好きなだけそれらのインタフェースをいじっていける領域と、もう他のチームにこれをこう使ってくださいと公表してしまっているので、好きにはいじれないというような領域の二種類があります。
正確には、二種類というよりは、publicインタフェースの中の一部分は、公布され、他の人に公開されているものなので、リファクタリングで好きにいじるわけにはいかない、ということです。それが公布済みインタフェース(publishedインタフェース)です。他の人も使っているがゆえに、それらpublishedインタフェースに対するリファクタリングは、一定の縛りが生じるわけです。
変更のアナウンス
公布済みインタフェースに変更を加える場合には、次のリリースでこう変えます、今はまだ古い状態でも使えるようにしていますが、次のリリースからは使えなくなるので、代わりにこのメソッドを使ってください、代わりにこのクラスを使ってください、というようなちょっと段階を踏んだアナウンスをしていかなければならない状況もあります。
たとえばJavaでは、「deprecated」というJavadocタグがあります。これは「このクラス/メソッドは近々無効になります」というマークです。公布済みインタフェースのリファクタリングや変更のために存在するといってもいい、Javadocの機能ですね。
たとえば、新しく機能が追加されていって、パッケージを分けたくなったとします。パッケージ名が変わったら、もうメカニズムとしてはインタフェースは別物扱いになってしまいます。このため、パッケージを分けたいので、このクラスは次の次のリリースにはもう使えなくなります、代わりにサブパッケージのこのクラスを使ってくださいというようなコメントを書いて、まず現状としては、使える状態でリリースしていくというような運用の仕方を行います。
新旧インタフェースのコードの重複
公布済みインタフェースのリファクタリングにおいて、新旧のコードは完全重複でいいのかというと、そうではありません。
新インタフェースと旧インタフェースとがあったときに、旧インタフェースが呼ばれたら、新インタフェースにそのまま呼び出しを行うようにし、旧インタフェースの中身自体は新しいインタフェースの中身のほうにどんどん移してしまって、古いメソッド呼び出し自体は新しいしくみのほうに委譲するだけ、という構造にすることが多いです。
ここまで説明してきたように、publishedインタフェース、公開されたインタフェースのリファクタリングというのは、publicな可視性に対するリファクタリングの中でも特に縛りがきついです。
縛りがきついというのを意識したうえで、それでも変更していかなければよりよいものにはならないというのがわかっている場合には、段階を踏んで、アナウンスと新旧のインタフェースを、まず二つとも使える状態にしたうえで、段々に新しいしくみのほうへと移行を促していくような運用が必要になってきます。
アジャイル開発のジレンマ
公布済みインタフェースについては、もう少しだけ話しておくことがあります。アジャイル開発のジレンマの話です。
アジャイル開発のような、小さい開発期間を単位とした繰り返しをどんどん行うような開発スタイルでは、公布済みインタフェースは比較的早い段階でできてしまいます。そして早い段階でできた公布済みインタフェースをどんどん変えていくときに、複数のチームで繰り返し型開発を行っていると、すり合わせを積極的に行わなくてはいけないというのが、一つジレンマとしてあります[2]。
このようなジレンマはありますが、私は、リファクタリングしていけばもっとより良いものができるというのが、基本的に共通理解として得られる場合には、どんどんアナウンスして新旧インタフェースをいじって、だんだんに新インタフェースに移行していく運用も含めて、複数のチームでやっていくことができると考えています。
トップダウンとボトムアップ、ハイブリッド
家永さんの発言
今ちょっと移行の話が出てきたんですけど、publishedをなるべく安定させたい、チーム間で共通のインタフェースを導きたいという視点と、TDDとかモデリングの視点の間に、なんていうかミスマッチがっていうか……。
わかります。基本的にTDDはボトムアップでの変更をどんどんやってよしとするようなやり方ですが、たとえばこのpublished API、publishedインタフェースが全然別の組織や、ややもするとどうやら世界中で使われている、というようなときに、頻繁に変更してていいのかというジレンマ、なんかモヤモヤした感じというのは出てくると思うんですね。
実際にやはり、publishedインタフェース自体は、やり方によってはある程度トップダウンで決めるところもあるとは思います。もしくはpublishedインタフェース自体が、一番最初に開発されるということも多いと思うんですね。たとえばWeb APIを開発するときに、こうアクセスされるべしというのを先に決め、後から開発を行うときには、基本的にあんまり変更しないというような進め方も、どうしても出てきてしまうと思います。
そういうときに、「トップダウンのやり方、設計は初回一発勝負のやり方、最初によく考えるというやり方」と、ボトムアップな設計手法を混ぜるハイブリッドな進め方というのは、ありかなと思います。その辺で苦しんだ経験が、おありですか?
チーム開発
家永さんの発言
いや、実際にあるかというと、あれなんですけど。
1回モヤモヤした…(笑)。だからずっと感じているところではあります。
複数のチームで開発したり、複数の人から使われるものに対して、どうやってすり合わせをやっていくかっていうのは結構重要な問題だと思っています。
たとえばクライアントとサーバは別のチームが開発します、もしくは別の組織が開発しますというときに、まず最初にクライアントとサーバの取り決めのところから先に決めて、そこからあとそれぞれのチームが、それぞれの担当分野を開発していくという進め方が取られることがあります。大きいプロジェクトになるほどこの傾向は強いのではないでしょうか。
そのような場合ですと、TDDで自由に開発できる空間というのは、publishedインタフェースの中だけとなりますね。インタフェースは縛りとして固定されたままで、その中の実装をより良くしていくために、TDDやリファクタリングを行っていくことしかできないというような状況も、実際には十分にあり得ると思います。