こんにちは!年初からクラウドワークス開発に新たにジョインした所と申します。
先日、クラウドワークスではテスト駆動開発とRESTFulアーキテクチャのエバンジェリストとして有名な和田卓人さんをお招きして社内勉強会を開催いたしました。
和田さんは、数多くの会社にてレガシーコード改善のコンサルティングの経験をお持ちで、書籍も多数執筆されており界隈でも有名な方です。 また、弊社CTO大場の旧知の友人でもあります。
クラウドワークスのサービスは立ち上げから現在に至るまでRuby on Railsで開発を行っており、サービス拡大に伴いアプリケーションの規模も大きくなっています。 比較的テストが書きやすいフレームワークではあるものの、ビジネスの急激な成長を支えるために速度を優先した機能開発が行われていた時期もあり、レガシーコードが残っている部分があります。 将来に向けて技術的負債の返済をしていくことは、言うまでもなく開発の質と速度を落とさないためにとても重要な事です。
クラウドワークスでは現在のサービスを更に力強く開発していくために、経験豊富な和田さんを講師として「レガシーコード改善の戦略と戦術」をテーマにご講演いただきました。
本記事では、この勉強会の様子をレポートします。
「レガシーコード改善の戦略と戦術」
講師:和田 卓人(@t_wada)
タワーズ・クエスト株式会社 取締役社長、プログラマ、テスト駆動開発者。
学生時代にソフトウェア工学を学び、オブジェクト指向分析/設計に傾倒。 その後様々な縁に導かれソフトウェアパターンやXP(eXtremeProgramming)を実践する人たちと出会い、後のテスト駆動開発の誕生を知る。 テスト駆動開発によって「完璧主義の呪い(完璧な設計を得るまではコードを書けないし良いシステムも出来ないという強迫観念)」から解かれてからは、文章や講演、ハンズオンイベント等を通じてテスト駆動開発の啓蒙に努めている。 今日もグリーンバンド(テスト駆動開発者の証)を左手に着け、テストと共にコードを書いている。 『プログラマが知るべき97のこと』『SQLアンチパターン』(オライリージャパン)監修。
戦略編
銀の弾丸は無い
レガシーコード改善に正解はありません。 手法や事例は溢れていますが、実際の現場ではコードの状態や開発者・組織の状況は千差万別です。 レガシーコード改善の重要な手法である「テスト自動化」も銀の弾丸^1ではありません。
他社の事例を見て羨ましく思ったり焦りを感じることもあるでしょうが、それが自分たちにも適している/やるべきであるとは限りません。
また、自分たちに適していない手法を導入しようとするあまり、いつの間にか「導入そのもの」が目的にすり替わってしまう事例も多々あります。
でも、なぜレガシーコード改善において自動テストが重要なのでしょうか?
構造的に繰り返される「ストレスとテストの関係」
この図は ”ストレス(ex.バグ,納期,複雑性)” と ”(手動)テスト実行” の関係を表しています。 図の○付き矢印は「矢印の根本の事象が増えると矢印の先の事象が減る」いう関係を表現しています。
この図では「”ストレスが増える"と"テストが減る"」という関係が表現されており、次の矢印の「"テストが減る"と"ストレスが増える"」ということにつながります。 さらにこの関係は構造的に繰り返されることを示しています。
「ストレスが増える」と「テストが減る」
↓
「テストが減る」と「ストレスが増える」
↓
「ストレスが増える」と「テストが減る」
... (繰り返し)
この悪循環をどう断ち切ればよいのでしょうか? 手動テストを自動テストに変えた場合、関係に変化が起こります。
先ほどの図と比較して、「ストレス」と「テスト」の位置が逆転しています。 この図は、先ほどとは違う関係を示しています。
「自動テストが増える」と「ストレスが減る」
↓
「ストレスが減る」と「自動テストが増える」
↓
「自動テストが増える」と「ストレスが減る」
... (繰り返し)
先程と同じように構造的に繰り返されますが、内容は真逆の正の循環が起きています。 これが自動テストがもたらす重要な効果です。
アジャイルコーチの James の言葉を借りれば、
「テストを書く時間がないのではなく、テストを書かないから時間がなくなるのです。」
by James Grenning - 組み込みアジャイルコーチ -
ではどうすれば、この正の循環に入ることができるのでしょうか? どうすれば、自動テストを書けるようになるのでしょうか?
文化を変える
自動テストが書かれるようになるためには、文化を変えないといけません。 しかし、これは一朝一夕でできるものではなく、年単位の時間が必要になることが多いです。(和田さんの経験では2年程かかることが多いそうです)
変化を阻むのは「動くコードに触れるな」という考え方です。 この考え方は少し前までは常識のように捉えられており、ある機能に拡張を施す際に現在稼働している既存のコードに手を加えずに新規にコード追加を行うことで、既存部分を壊してしまうリスクを回避できる、というものです。 しかしこれはコードの重複が増え、複雑性が増していくことを意味していました。
手を入れなければ事態は悪化していくだけです。"動くコードに触れなければ死あるのみ" です。
イマココから始める
人は自分の速度でしか成長できず、プロジェクトもプロジェクトの速度でしか成長できません。 高い山の頂上ばかり夢見ると、現実の自分が立っている場所との距離に辛くなります。
隣の芝は青く見えますが、気にしてはいけません。 「まわりはもうみんなやっていますよ」というキャッチは強力に作用しますが、気をつけないと焦るばかりでモチベーションが保てなくなります。
イマココ(AsIs)から、こうなりたい(ToBe)ではなくこうなりたくない(NotToBe)で考え、他社の事例とではなく過去の自分との対比で、成長を測っていきましょう。
人を知る
同じエンジニアでも、どこに価値/モチベーションを感じるのかは人それぞれです。
汚いコードを美しくするリファクタリングに快感を覚える人もいれば、テストカバレッジ率向上という数字(メトリクス)にモチベーションを感じる人もいます。 また、自分の書いたコードがビジネス/ユーザーに与える影響を追い求める人もいます。
人を知ることが、自分たちに適したやり方を知る近道になるでしょう。
変えることの難しさ
人はそれぞれの度合いで変化に対して身構えます。 「前例が無い」「事例が無い」という反応が出たりします。
また、リファクタリングは外からは価値が見えづらく機能が増えるわけではないので、経営層/ビジネスサイドからは拒否されがちです。
ですが必要なことはわかってるので、まず始めましょう。 現実には、許可を得るより始めてしまったほうが物事は進みやすいです。
"It is easier to ask forgiveness than it is to get permission."
- 事前に許可を得るより、あとで許してもらうほうが楽 -
by Grace Hopper アメリカ海軍准将・計算機科学者
全ては変化する
現実の事象を扱っているので、全ては常に変化しています。
仕様が固まることはありません。そして、開発が終わることもありません。 開発者の理解もスキルも深化し、技術も進化し続けます。
手を付けなければ、技術的負債は積み重なる一方です。
技術的負債の四象限(マーティン・ファウラー^2)
技術的負債(TechnicalDebt)は現実の負債と似た性質を持っており、元本を返済しないと利子が付き、将来に支払うべき総額コストが大きくなっていきます。
ただし、技術的負債は考えが足りないから生まれるだけではなく、考えた上での負債も存在します。
Reckless(無鉄砲な) / Prudent(用心深い)
×
Deliberate(意図的な) / Inadvertent(無意識な)
左上: reckless-deliberate 「設計する時間がないんだからしょうがない」
右上: prudent-deliberate 「今すぐリリースしないといけない。リスクは承知の上だ」
左下: reckless-inadvertent 「レイヤー化?なにそれ?」
右下: prudent-inadvertent 「よし、これでオッケー!」
技術的負債が生まれることを避けることは難しいです。 そして、元本を返済するためには、自動テストはとても重要です。
テストは品質を上げない
テストは測定に当たるものであり、品質が「わかる」ようになるだけです。 ですが、「わかる」ようになることはとても大事です。
でも、テストを書くだけでは品質は良くなりません。 「体重計に乗るだけでは痩せない」のです。
品質を上げるのは、「設計とプログラミング」です。 「再設計」と「リファクタリング」をテストで支えるのです。
"テストは「ゴール」ではなく「スタート」"
前篇(戦略)はここまでになります。 まとめると、
レガシーコード改善に正解はないが、自動テストはとても重要。自動テストによって構造的な「ストレスとテスト」の悪循環を断ち切り、「自動テストとストレス」の正の循環に入ることができる。 自動テストが書かかれるようになるために、文化を変える。
「動くコードに触れるな」と戦う
他社の事例に引っ張られずに自分たちの現状に合わせて、こうなりたい(ToBe)ではなくこうなりたくない(NotToBe)で考えてモチベーション低下を防ぐ
今のチームの人を知ることで、自分たちに適したやり方を知る
人は変化に対して身構える。変えることは簡単ではないが、まず始めよう
全ては変化し続けているので、技術的負債が生まれないようにするのは難しい。返済できるように、自動テストで守るべき。
テストは品質を上げない。自動テストを書くことで品質が「わかる」ようになり、品質を向上させる「再設計」と「リファクタリング」を自動テストで支える。
レガシーコード改善の戦略において自動テストが重要であり、どのように考えながら導入すべきなのかがよく分かりました。
では、具体的に自動テストをどのように書いていけばよいのでしょうか?後篇(戦術)に続きます。
※クラウドワークスではスキル向上のために多くの勉強会・セミナーが開かれています。 興味をもったエンジニアやデザイナーは、こちらでお待ちしています!