規模感の違う脱レガシーで必要なこと

「レガシー」を保守したり、刷新したりするにあたり得られた知見・ノウハウ・苦労話 by Works Human Intelligence Advent Calendar 2022 の 15日目の記事です。

qiita.com


筆者は過去に、中〜小規模のWebアプリケーションでレガシーフロントエンドの改善作業を業務でやっていた。その経験を元に技術同人誌を作成し、それがきっかけで「レガシーフロントエンド安全改善ガイド」という書籍を出した。

初版から数年経ってしまい、詳細な利用技術などの説明は少し古くなってしまっているのだが、ベースとなる考え方の部分は今でも変わっていないと思う。

一方で自分自身は、その経験が他の環境でも通用するのかを試してみたくなり、転職して一年強ほど大規模なフロントエンド刷新に関わっていた。

あまりにも規模が大きいため完遂を見届けたわけでもないが、現段階でも学びや得られたものは多くあったように思う。それらを踏まえて

  • 規模感関係なく必要だったこと
  • 大規模刷新で新たに必要になること

について、自分なりに考えてみた内容を整理してみる。

話の内容的に、中〜小規模と大規模の両方で得られた知見をベースに書いているため、多くの人に何かしらの部分でマッチする内容になっているはず(と信じたい)

なお、客観的な数値などに基づく事実ではなく、個人の感覚としての部分も多く書いている。そのため、あえて個人ブログに書く形とした。環境によっては大きく違う意見になる可能性もあるが、あくまでも個人の所感として見て頂ければと。

目次

前提

この記事内で説明する「規模感」については、筆者が経験した次のような規模を想定している

  • 中〜小規模
    • 改善対象のコード分量が10万行未満程度
    • ある程度の時間をかければ、個人で全体を把握できる
  • 大規模
    • 改善対象のコード分量が50万行を超える
    • 全体を把握するためにはかなりの時間と労力を要する

規模感関係なく必要だったこと

過去に経験した中〜小規模のレガシーフロントエンド刷新の経験で得た学びで、大規模になったとしても基本的には同じ考えが必要だと感じた部分。少し違う部分もあったりするが、知っておいて良かった・この考えは変わらず持っておいた方がいいな、と思ったようなもの。

改善自体のリスクを把握する

あらかじめ改善作業のリスクを把握することが重要になる。レガシー=悪ではなくて、誰も求めてない改善であればやらないほうがいいかもしれないし、やるなら納得のできる理由がいる。メリット・デメリットを天秤にかけて着手したほうがよい。

これは規模感に関係なく同じで、むしろ規模が大きいほうがユーザーを含めた影響範囲も大きくなるため、むしろ重要度は上がるかもしれない。

把握しておいたほうがよいリスクをいくつか紹介する。

改善のリスク: 挙動の破壊

当たり前ではあるけど、バグを埋めたり既存の動作をぶっ壊してしまう可能性はある。もちろんこれによってユーザー影響が出るのは怖い事態だが、さらに「リスクを取るぐらいなら改善作業はやめておこう…」みたいな空気感になる恐れがある。そういった心理的な障壁は組織に染み付いたらなかなか払拭できるものではないと思われる。

現在筆者が経験している環境ではE2Eテストや非常に優秀なQAチームの皆さんの存在があるので、そもそもの振る舞いを根底から破壊するリスクはかなり軽減されている。逆に言えば「これが無かったら…」と考えるとわりとゾッとする。(無かったとしたら、まずはE2Eを書こう!と強く言っていた気がする)

やはり、まずは安全のために何ができるかを考えてから進めるのは規模感問わず大事。

改善のリスク: 中途半端な状態での頓挫

改善は長く続く可能性があり、さまざまな事情により途中で頓挫してしまう可能性がある。

その場合、改善前後のコードが入り混じった状態になる。これはメンテナンス対象が増えるだけで、かえって複雑化した結果になってしまう恐れがあり、これは規模感に関係なく存在するリスクだと思う。

頓挫する理由は、メインのメンバーが退職してしまったり、組織の変更によって改善作業の優先度が下がってしまったり、色々考えられる。ただ、大規模な刷新の場合は期間が長くなることもあるため、そういった「きっかけ」に遭遇する頻度も上がることになる。

改善のリスク: 改善後の状態が共有できていない(自己満足で終わる)

アーキテクチャをまるっと刷新した場合、刷新後のコードベースに触れる人は新しいアーキテクチャを理解する必要が出てくる。これには一定のコストが必要になる。

「技術が変わるなら学習するのはそりゃ必要だよね」という気持ちになるかもしれないが、ここで大事なのは “腹落ち感” で、なぜ変更するのか・何に変更するのか、といった点が納得できているかどうかで、だいぶモチベーションが変わると思う。

このあたりを雑にやると「改善したと思ったら開発コストめっちゃ上がりました」なんてことになりかねない。規模が大きいと人数も増えるため、このあたりの影響も大きくなる。

ちなみに、筆者が過去にやった場合は、事前にADRを書いて認識を確認したり、刷新後も勉強会を開いたりという対応をしていた。

現在筆者が関わっている大規模刷新の環境においては、刷新チームを立ち上げるタイミングで、旗振り役をしてくれている方がきっちりと思想の部分を文書として見える形にし、さらに丁寧にMTGを重ねて共有をしてくれた。また、数ヶ月に1度程度のタイミングで全メンバーが集まって意識を揃える場が設けられている。そのおかげで、個々の小さいチーム単位では目標が変わったりすることはあっても、刷新チーム全体でのベースの思想や目的みたいなところは安定している印象がある。このあたりはあまり関われてなかった部分なので、今は「すごいなぁ」と横で思いつつ、今後の糧にしていきたい。

まずレガシーコードをちゃんと理解する

いきなりコードに触るのではなく、ちゃんとレガシーコードを理解するところから始めたほうが良い。

特に歴史が長いサービスの場合はコードを読み解くのもかなり苦労する。だが、理解できないものは刷新することもできないので、ある程度時間をかけて把握していく必要がある。

また、規模が大きくなると、”レガシーコードの理解” の範疇に人やチームの概念が頻繁に登場してくる印象を持った。純粋にコードを読んで理解すれば良いだけではなく、変更において影響を受ける関係者が誰なのかを意識する必要が生じる。

アジャイル開発においてインセプションデッキを作ったことがあると、その中で「ご近所さんを探せ」という項目があるが、それに近い感覚。プロジェクトに関係するメンバーをきっちり洗い出しましょうね、という話なのだが、規模が大きくなるとさらに重要になってくる印象を持った。

レガシーコードを読み解いていくなかで「これはなぜこんなことに…」みたいな仕様が顔を出すこともあり、関係者が把握しきれていない場合、このあたりが迷宮入りしてしまう恐れがある。

ちなみに、筆者は書籍の中では「できれば理解した内容は資料化もするといいよ」と書いていたが、これもやはりそのまま同じ考えのほうが良いと思った。期間が長いと必然的にメンバーの入れ替わりも一定数発生するため、その際に資料が残っているメリットは大きい。また、新規メンバーに限らず、そもそも書いた本人も数ヶ月とか時間が経つと普通に内容を忘れるので、未来の自分のためにもなる。また、”ご近所さん” に確認してもらうタイミングでも資料はあったほうがよい。

改善で得たいものを明確にする

改善したいということは、何らかの得たいものがあるはずで、それをちゃんと明文化したほうがいい。これは色々あるはず

  • 開発速度を効率化したい
  • 魅力的な職場にしたい
  • ページのパフォーマンスを上げたい
  • などなど…

作業を進めていく中で、優先順位をつけて取捨選択する機会は頻繁に訪れる。その際に、自分達が何のためにこの改善作業をやっているかがわかっていれば、判断軸の一つになる。

また、段階的に改善が進んでいったときに、思い描く理想のゴールが見えていれば、それに対してどれだけ近づいたのかもわかるため、モチベーションにもつながってくる。

大規模な場合、チームが複数に分割されることも考えられるため、全体として目指すものが何かをきちんと明文化しておかないと、チームがそれぞれ的外れな方向に進んでしまうかもしれない。

小さく進める

規模感に関係なく、いろんなものを小さくしていくほうがよい。

コードの変更量を例にとっても、1回の変更が大きいほうがコンフリクトのリスクが上がっていく。大規模刷新の場合は複数チームが並行して同じコードベースを触っていることも多く、リスクはより高くなる。

ちなみに、筆者が思っていたより特に重要だったと気付かされたのは “リリースサイクルの短さ” だった。

リリースサイクルが短いことのメリットは多くの書籍などで語られており、もはや誰しもが知るところだと思われるため割愛するが、なによりもメンバーのモチベーションに直結している印象があった。

筆者は大前提として「改善作業はやらなくていいなら誰もやらない」という認識を持っているのだが、これは目に見える形でのユーザーへの価値提供を感じにくいから、というのもある。

ただでさえそういった性質の作業にも関わらず、対応した作業が長期間に渡ってリリースされないと「俺は一体これだけの期間なにを・・・(ここで記憶が途絶える)」みたいなことになる。

ただ、リリースサイクルはサービスの性質によっては簡単は変更できないケースも多い。もし調整できるなら短いサイクルでのリリースとしていくとよいが、厳しければ、自分たちで何らかのマイルストーンを設定し、きちんと進んでいる実感を得られるようにすることが大事なのかもしれない。実際筆者の環境はそんな感じでやっていて、「ここまでできれば実質リリースと同じ」みたいなラインをチームで設定することで、ある程度細かくかつ短いスパンで進められるようにしている。

一度に複数のことをやらない

改善をやってると、その中でいろんなことが目についてきて、複数の改善を並行してやりたくなってくるが、できれば避けたほうがいい。

先に挙げた “小さく進める” と相反してしまうことになり、1回1回の作業ボリュームが増えてしまう。「○○が終わった!」というまでの期間も長くなる。成果の得られない作業が続くのは結構ツラいと思う。

「どうせ改善をやるならついでに○○もやろう」みたいな気持ちで、小さな機能開発やデザインの変更なども一緒にやりたい気持ちになるかもしれないが、脱レガシー以外の作業を一緒にやるのはさらに強い気持ちで回避したほうが良い印象がある。

そもそも脱レガシーとそれ以外の作業では大きく文脈が異なり、関係者も違えば影響範囲も異なる。それを混ぜてしまうと、自分たちが何を目的として作業しているのかを見失ってしまう。また、トラブル発生時に、どちらに原因があったのかの追求も難しくなる。最終的なゴール達成までの工程や手順も同じではない可能性があり、作業プロセスの改善もしづらい。

もちろん作業環境などに応じて背景や事情はあるため、「そうはいってもな…」となるかもしれないが、できるだけひとつに集中して片付けてから次に行ったほうが懸命。

大規模刷新で新たに必要になること

ここからは、大規模ならではで必要になると感じた部分。

「規模が変わるとこういうケースもあるよ」と気をつけておいた方がいいと思ったもの。

チームや関係人数も「小さくする」

先に述べた通り、以前から筆者は「小さく進めましょう」というのを重要視している。一度に進めるものが大きいほどリスクが高まる。修正するコード量からPRのサイズ、作業サイクルやリリース間隔など、さまざまなことに対して言えると思う。

これが大規模なものだと、さらに「チームや関係者の数」という概念が出てくる。そもそも刷新作業に参加するメンバー数が多く、伴って外部関係者の数もかなり多くなる。

一つ一つの作業量を小さくしようと思っても、関係者が多すぎるとそれ自体が困難になる。手こぎボートなら1メートル単位で調節して船を進めることも容易だが、巨大客船ではなかなかそうはいかない。

このあたりは、現在のチームで輪読会などもやったチームトポロジーにおける「認知負荷」の考え方から得られたものも大きいように感じる。

大規模刷新で人数が多い場合、何らかの形で小さなチーム単位で分割し、それぞれがオーナシップを持って動けるようにするのが重要だった。どうしてもコード上での重複などは発生してくるが、体感的にコミュニケーションコストのほうが圧倒的に高い。適切に権限が委譲されていれば、それぞれのチームで責任を持って進めることができ、意思決定が速くなる。

全体を加速させる取り組み

小さい規模の場合、極端な話 “めっちゃ凄い数人がゴリ押しで刷新を終わらせる” みたいなパワープレイもできてしまう。全体像も見えやすいし、終わってみてから「結果的に○○ヶ月で終わりました!」で済むことも多い。

一方で規模が大きいと、24時間365日コードを笑顔で書くようなGODエンジニアでない限り、個人の力で直接的に影響させられる範囲には限界がある。

多くのメンバーが長い時間関わることを考えると、一人がパフォーマンスを出すだけではなく、周りが加速するための取り組みが求められてくる。いままではレベル高い人がパワーで殴れば敵を倒せていたものが、メンバーにバフをかける役割の重要度が上がってくる、みたいな感じ。

具体的なところでは

  • チーム間でのコミュニケーションを円滑化させる(ツール導入や会議体をうまく設定する)
  • そもそも普段の開発効率を上げる(CI高速化とか)

みたいな部分が該当してくると思う。

筆者がやってみた取り組みとしては、レガシーコードの解読を加速させるために、Chromeで使える DevTools を作ったりVSCode Extensions を作ったりしてた。

モチベーション維持がより重要になる

脱レガシー作業において最悪な事態は何かと考えると、それは「脱レガシーをやる人が誰もいなくなる」だと思う。人がいなければそこで終わりです。

大規模なものは期間も長いし、困難も多い。モチベーションが維持できないとそこから崩れていく可能性がある。「仕事なんだからモチベーションとか甘えたこと言わずにやれよ」と思う人もいるかもしれないが、筆者は「仕事なんだからモチベーションを保つ努力をしましょう」という意見です。

ちなみに、現在関わっている大規模刷新では、わりときっちりとしたスクラムを組んで進めており、それがモチベーション維持にも有効に働いている面があるような印象を受けている。複数チームが存在し、チーム単位でスクラムマスターがいる。

このあたりは、初期段階で社内でのスクラム神みたいな方が入って一通り整理してくれたのが大きかった。傍から見ていて手腕がすごかった。これが神かという感じ。

正直なところ、最初は「脱レガシーみたいな刷新作業とスクラムって相性良いのだろうか?」みたいな気持ちも少しあったのだが、実際やってみると、経験も多種多様なメンバーが長期間に渡って協力して進めていくなかで、チームが消化できるベロシティを測定して進めていくことは結構重要に感じた。ベロシティが数値として見えないと全然現実的な予測が立てられない。

きっちりとバックログとして見積もりを立てて消化していくと、チーム内で一定の目標やマイルストーンも上手く設定できるようになってくる。「こんだけ進んでるぞ!ウォー!!!」となるだけで、ある程度は楽しくやれる。

「戦略的撤退」が難しくなる

小さく進めていくことの一つの理由として「途中での戦略的撤退を可能にしておく」という点をメリットに感じていた。

脱レガシーは途中で立ち行かなくなる可能性があるため、その際に更なる負債を増やしてしまう可能性をできるだけ小さくする意味でも、「ここまでやったら一旦終わることができる」というチェックポイントを設けるのは一つの手だった。

これは改善が複数テーマにわたる場合には規模感関係なく有用だと思う。たとえば、Lintもテストも型もないようなコードベースを改善する場合、「ひとまずLintは入れた。組織体制が変わってしまったので一旦これで撤退」みたいな判断ができる。やっていることが単純なものであれば、ロールバックも可能かもしれない。

しかし、大規模の場合は、期間も修正量も大きいため “取り返しがつかない” といった凶悪な事態を引き起こす可能性が出てくる。単純な話として、年単位の時間をかけた大勢の手による変更を全部ロールバックできるか?と言われると現実的に厳しいものがある。

一人で隣町まで行っただけなら帰り道も辿れそうだが、みんなで宇宙に行ったら簡単には地球には帰ってこれない。ちゃんと次の惑星に辿り着かないといけない。撤退という選択肢がどこかのタイミングで難しくなってくる。

対応策は何だろうと考えてみたが、アプリケーションを機能単位などでうまいこと分割して境界を作り、影響範囲を境界内に閉じていくことかもしれない。やはり「小さくする」というのは重要になってきそう。あとはもう、具体的でもなんでもない話になっちゃうが、ある程度は「覚悟」みたいなものが必要になるのかもしれない。

「手伝う」には限界がある

これは自分が関わったチーム・組織固有の話の部分もあるが、最初は特定技術分野に特化した横断チームで脱レガシーを「支援」するという形を取っていた。規模が小さければ、支援チームだけで文字通り「手伝う」形でガッと改善対象をやり切ることも可能かもしれない。

ただ大規模になるとこのスタンスでは厳しいものがあることを学んだ。

冷静に考えると当然なのだが、多くの人々が長い期間かけて作り上げた巨大なコードベースに対して、支援チームが片手間でやれることには限界がある。何かやろうにも、どうしても ”チームのできる範囲でできることだけやる” というところで終わってしまう。

現在では完全に刷新チームが立ち上がり、それを手伝うというよりも完全に中に入って一緒に作業を進めていく形を取っている。より踏み込んだ話もできるし、改善作業におけるコードベース以外のプロセスなどの課題点も見えてくるのは大きい違いがあるように感じる。

総合して → 知見やノウハウは対象規模とセット

いろいろと書き綴ったが、総合してまとめるとこれに集約されそう。

脱レガシー作業というのは常に需要があり、流行りの言語やFWを使っていたとしても、時間が経てば結局レガシーになる。脱レガシーは世の中の至る所で実践されており、それらは発表資料やブログ、書籍などで多くの事例が出てくる。筆者が書いた本もその一部でしかない。

それらから知見やノウハウを得る場合、そもそもどういった規模感を対象にした情報なのか留意する必要がある。「3人の脱レガシーチームで、ツールを使うことで1ヶ月で全体を置き換えました。」みたいな情報があったとき、単純に「ツール使えば簡単にできるんや!!」と思ってやってみると、全然思った通りに進まずに事故るかもしれない。

知見やノウハウをそのまま鵜呑みにするのではなく、どういった前提が置かれているのかも注意が必要になる。具体的に幾つか例を挙げると次のようなものがありそう。

  • 全体のコード量やユーザー数はどの程度なのか
  • サービス性質として、軽微な不具合がどの程度許容されるのか
  • どの程度古いコードが対象だったのか
  • 脱レガシーで影響を受ける他のエンジニアはどの程度の人数いるのか
  • など

なお、これは “既存の情報が役に立たないことがある” という話をしたいわけではなく、”あなたがその知見やノウハウの対象ではない可能性がある” 点に気をつけた方がいいという話。これはまさに筆者自身が自分で書いた書籍と現実の内容とでギャップを感じた部分でもある。

ただ、前提とされている対象に近づくことができれば、知見やノウハウが実践可能になるケースもあることも同時に感じた。中〜小規模の経験に基づくものでも、チームを少人数規模に分割する・機能単位でコードをメンテナンスできる体制を整える、みたいなことができれば適用できる部分が出てくる。このあたりの前準備が必要になることも併せて意識しておくと良さそう。


というわけで、規模感の違いによる脱レガシーの話でした。

だいぶ個人の感想っぽいものを長々を書いてしまったが、誰かの役に立ったのなら嬉しいです。