担当からの発言
みなさんが、リファクタリングをどこまでするかとか、やめどきとかについて聞かせてください。
「重複は悪」「DRY(Don't repeat yourself)」
リファクタリングをどこまでするかというのは、実はすごく難しい質問なんですけども、端的に一言で「いつまで」と言うならば、「重複がなくなるまで」ということが一つの指標としてありますね。重複というのは、コードの重複です。まったく同じコードが二箇所以上に存在している状態です。
「重複は悪」もしくは「DRY(Don't repeat yourself)」という言葉があります。たとえばあるコードが書かれています。そのコードをコピーして、もう一つ機能を作りましたというときには、ほぼ同じコードが二ヵ所に書かれていることになります。
あるときコードにバグが見付かった、もしくは機能を変更しなければならなくなったときに、まったく同じようなコードが二ヵ所あると、二ヵ所メンテナンスしなければならなくなってきます。そのようなことの積み重ねが、徐々に開発のスピードを遅れさせていってしまいます。
ですから、コードの重複を見つけたらすぐにリファクタリングをして、たとえばコードの共通部分をメソッドに括り出したりクラスとして抽出したりするような「リファクタリング」を行って、開発のスピードを一定に保っていきます。「開発のスピードを一定に保つ」、これがリファクタリングの目標の一つですね。
不安や感情
いつまでリファクタリングをするか、リファクタリングのやめどきのもう一つの指標は、簡単に言うと「感情」です。
また不安とか感情の話になりますが、リファクタリングをする理由の一つに、自分自身のモヤモヤですとか、納得していない感というのがあると思うんですね。
たとえば「この名前、このメソッド名はあまりよくないな」「機能をいろいろ変えていった結果、このクラスの名前はもうそのクラスの役割と合わないものになってしまったな」などのモヤモヤです。
プログラムの実態と責務と名前とが、うまく整合性が取れていないと思うときに、名前を変えたり、責務を移動したり、メソッドを移動したりというリファクタリングを行うことがあります。そういうリファクタリングを行っているときの「やめどき」はどういうときかというと、一つはもう自分が納得した、満足したときですよね。
このリファクタリングを行ったことによって、いま自分が思っている不整合は解消されたという感情を得たときに、リファクタリングをやめるという、一つのきっかけになると思います。
深追いはしない
ただ、リファクタリングをそういう自分の感情や美的感覚みたいなものを前提に進めていくと、やめどきがなくなってしまうことがあります。
際限なく、ここをこうしてみたいという感情、欲望が出て来てしまうときには、「ある程度モヤモヤが解消され、不安が解消され、ある程度重複が解消されたら、プロジェクトとして、そこまででひとまずやめておく」というのが、リファクタリングのやめどきのもう一つの考え方です。プロジェクトとしてもっと他にやることがある場合には、リファクタリングに対して深追いしないというのが、一つの良識かなと思っています。
なぜかというと、リファクタリングという行為自体は、たとえばお客さんに対して、新しい機能を提供しないからです。提供している機能が変わらないままで、内部の構造をよりよくしていくのがリファクタリングですので、お客さまに提供する価値の量自体は、リファクタリングの前後では変わらないんですね。際限なくリファクタリングに興じていたら、実はその間お客さんに対しては何も「見える仕事」をしていないということになってしまいがちです。
そこはお客さまに説明をしなければならないところです。私自身も「リファクタリングをすることによって、内部の構造がキレイになります。するとこれから先に機能を追加していくスピードが落ちません」もしくは「リファクタリングをすることによって、バグフィックス、バグ対応が今までより速くなります」というお話をして、お客様同意の上でリファクタリングを行っていくための交渉などをよく行いました。
リファクタリングがお客様に提供するのは、直接的な価値(新機能)ではなく、間接的な価値(お客様に価値を提供するスピードの安定)なんです。この点を履き違えてはいけません。
タイムボックス化
私がお客様に説明するときには、たとえばプロジェクトのイテレーションの長さが2週間だったとしたら、2週間のうちの80%の時間は機能追加、機能提供のために使って、20%の時間は開発者の権利としてコード内部のリファクタリングのために使わせていただきますというような取り決めをしたり、その20%の中でできる範囲までをリファクタリングのターゲットとして、その20%でできなかったことは、次のイテレーションや次の時期に繰り越すというような感じのプロジェクトの進め方をしていました(注)。
家永さんの発言
時間をタイムボックス化っていうか、つまり、どこかで制限をして、それ以上はっていう……。
そうですね。今「タイムボックス」という話が出たんですけど、タイムボックスとはまあ簡単に言えば締め切りベースですね。区切りの時期までにできることを選び、きちんと時間を区切り、「延長戦」をしない、という考え方が「タイムボックス」です。
要するに2週間で何かやらなければなけない場合に、リファクタリングをその期限が過ぎたあとまでずっと続けるのではなくて、その区切られた時間内でできるものだけを、まずやりますと。その次の機能提供の時期が来たら、リファクタリングはいったん一区切りとして、次の機能提供のために動いていきます、というような進め方があります。
そして、次のイテレーション、次の開発期間が始まったときに、前回繰り越したリファクタリングの続きを行ったほうが、結果的にその期間の中で開発速度が速くなることが予想できる場合には、ちゃんとお客さまに話をします。
お客さまに「まずリファクタリングの続きをやったほうが、結果的に今の機能提供ももっと素早くできます、もっといいものができます」ということを説明して、リファクタリングの続きをやる、そういったことは当然プロジェクトの進め方として考えていくことができると思います。
お客さんに黙ってリファクタリング
MIZOさんの発言
今の話に絡むんですけど、機能提供に絡めてリファクタリングをすることはありますか?要は、お客さんに言わずにやることはありますか?
「あります」「ありません」の話だと、あります。
リファクタリングをいつまでやるのかというお話を先ほどまでしていましたが、リファクタリングをしてはいけないときの話をしていませんでしたね。
リファクタリングをやってはいけないときというのは、テストが通っていないときです。ということは、リファクタリングを行おうとしているときはテストがグリーンであるということですね。
テストがグリーンであるときには、リファクタリングを機能追加の後にするのか、それとも機能追加の前にするのかという選択肢があります。
たとえば、これまでよく似た機能を二つすでに作っていて、三つ目の機能を作らないといけないというときに、二つの機能ですでにある程度の重複が判明したときに、すでにある二つをベースに三つ目の機能のコードを書くと、重複が三ヵ所になってしまいますね。重複が三ヵ所になってしまうと、重複を排除するリファクタリングのコスト自体もそれだけまた高くなってしまいます。
このようなときの開発の進め方として、ではまず機能Aと機能Bの共通部分をリファクタリングした形で機能Dという共通部分を作って、これから作る機能Cは共通部分Dを前提に開発を行ったほうが、結果的に早く開発ができますし、いいものもできるということが、開発者としてはある程度見えている状態だと思うんですね。
そういうときに、お客様に相談することなく、開発者の判断として、先に重複を共通部分に括り出すリファクタリングを行って、そのリファクタリングの結果をもとに、あとから新規機能追加をすばやく作るという選択は十分ありえる、と私は考えます。