自分が関わったSI案件のコードメンテナンスとその価値
2024-04-23T11:30:37+0900
僕がSI案件に関わりはじめてから早5年目に突入しました。SI案件に関わるようになった経緯については、2021-2022年のお仕事近況報告に詳しく書きましたが、あれからも継続してプロジェクトに関わり続けています。
それなりに長くプロジェクトに関わってきたので、保守や改修という業務も発生してきたわけですが、今日は僕が主導するプロジェクトでどのようにコードのメンテナンスを行いながら長期的にプロジェクトをやっているかを書いておきたいと思います。
コードメンテンナンスの機会が作りにくいSI案件 #
もちろんプロジェクトによって様々な状況があるので一概には言えませんが、僕が関わっているSI案件のプロダクトだと、コードメンテナンスを実施する機会がほとんどないと感じました(正確にはリリースするタイミングがない)。
その理由は、リリース後に不具合が多発したプロジェクトの場合はその対応に追われ、逆に不具合がほとんど発生しないプロジェクトの場合はリリースする機会がなくそのまま放置されるためです。また、リリース管理が厳格で承認等に手間がかかると、不具合改修も機能追加もないケースで、ライブラリのパッチバージョンを上げただけでリリースするのが精神的に億劫となってしまいます。
SI案件に関わる前は、基本的にCI/CDのパイプラインを整えて、コードレビューさえ通れば、いつでも誰でも好きなときに本番環境へコードをデプロイできるようにしていたのですが、そうではない環境で、コードをメンテナンスしていくのは初めての経験だったので、その違いをあらためて認識しました。
リリース頻度が下がることによる問題点 #
一般的にリリース頻度が下がり、リリース間隔があけばあくほど、ライブラリうやランタイムのバージョンが上がるため、改修しなければならないコードも増えて、リリース時の不具合が増加する可能性が高くなります。そうなってくると、今度は改修するときにできるだけ目的以外のコードを触らないようにして、穏便に済ませよう(いわゆる技術的負債の返済はしない)という考えに流されがちです。
こうして色々なものを放置していくと、あっという間に塩漬されたコードが増えて、いつかはメンテナンスできない化石となったコードとなる未来が手にとるように予想できます。もしかすると、そうなったときに「古くなってきたので作り直しましょう」と提案するのが、SI案件としての正しい姿なのかもしれませんが、自分としては、そうなる未来は望ましくないため、自分なりに解決するため試行錯誤していました。
大型の改修前にメンテナンスする #
では、いつメンテナンスするのかというと、僕の場合は大型の改修前にやるでした。これは理想的ではありませんが、結局のところ消去法としてこれしか方法が残らなかったという理由が大です。
大型の改修となると、ある程度の不具合が発生する前提として計画が進められているため、リリース前の受け入れテストなどもかなり厳密に行われるので、いっそのこと、コードのためになることであれば、ここで何でもやってやれと考えたわけです。
あとは、開発時のモチベーションとして、何世代も前のライブラリやランタイムに依存したコードを書くのはたいてい苦痛でしかなく、どこかで重大なセキュリティインシデントを抱えるくらいなら、改修前にリポジトリをできるかぎり綺麗にして実装に入ったほうが健全な状態(例えば、ライブラリなどは過去ではなく最新のドキュメントを見ればいい)で開発を開始できます。
メンテナンス予算の確保 #
フロント界隈はツールの入れ替わりが激しいと言われていていますが、確かに1、2年経つとそれになりの大きな変更が複数発生します。
それらを放置して開発を続けることも可能ですが、個人的経験として放置すればするほど、将来的に開発が困難になっていくため、よほど強い理由がないかぎりは、利用しているライブラリ等については最新のものに上げたほうが良いでしょう。また、僕個人としてもできるだけ新しめの技術を触ってみたいという欲求が高く、プロダクションに投入できるかどうかを見極めつつ、新しいものを導入していくことがひとつのモチベーションとなっています。
こういったメンテナンスについて、よくある話としては予算が確保できないから放置する、という意見がありますが、それは営業、ないしは予算を決める決済者の怠慢であり、開発案件を受けるのであれば、そういったメンテナンスに関する部分も予算に盛り込むべきです。今回の僕が扱ったケースでは、開発予算とは別に保守予算があるため、新規開発中は保守予算をメンテナンスにあてるという対応を行うことで、自分達が損しないように予算を確保していました。
具体的にやったこと #
それでは具体的にどんなことをやったのか、実例を交えて紹介したいと思います。
中〜大規模プロジェクトA #
これまでもっとも長く関わったプロジェクトAは、初期開発(以下、フェーズ1)が2021年の4月〜2022年11月で、そのあと大規模改修(以下、フェーズ2)として2023年4月〜2023年10月まで開発が行われました。
フェーズ2の開発を開始するにあたって、フェーズ1のリリース時から以下のメンテナンスを行いました。
- Node16からNode20へのアップデート
- MSWの導入
- Yarn v1からPNPMへ移行
- Turborepoの導入
- SWR v1からv2へのアップデート
- React v17からv18へのアップデート
- TypeScript v4からv5へのアップデート
- その他、もろもろのライブラリのアップデート
- 思いつくかぎりのコードリファクタリング
これらのメンテナンスは他の作業と平行しながら約2ヶ月ほどで完了して、その後本格的な改修の開発が開始されましたが、結果的にCIの実行時間の大幅な短縮に成功するなど、開発体験としてもかなりの効果を上げることができました。
小規模プロジェクトB #
直近で改修を行ったプロジェクトBは、フェーズ1が2022年12月〜2023年5月で、そのあとフェーズ2として2024年1月〜2024年4月まで開発が行われました。
フェーズ2の開発を開始するにあたって、フェーズ1のリリース時から以下のメンテナンスを行いました。
- Node18からNode20へのアップデート
- Mantine v6からv7へのアップデート
- Remix v1からv2へのアップデート
- MSW v1からv2へのアップデート
- Storybook v7からv8へのアップデート
- PrettierからBiomeへの移行
- ESLint v8からBiomeへの移行
- その他、もろもろのライブラリのアップデート
- 思いつくかぎりのコードリファクタリング
プロジェクトBはプロジェクトAよりも規模が小さいため、メンテナンス自体は1ヶ月で完了して、機能改修の開発に入ることができました。
Biome移行については、ESLint v8からv9への移行が面倒くさくなったため、カッとなって移行することにしたのですが、PrettierとESLintのどちらと比べてもむちゃくちゃ実行速度が早くて、SubversionからGitに移行したときの感動がよみがえりました。
メンテナンスで技術的成長を得るサイクル #
予算があるとはいえ、開発スケジュールがある中で、上記のようなそこそこの規模のメンテナンスを行うのはそれなりの苦労があります。ですが、いま対面しているプロジェクトで新しい技術を試すということは、メンバーの成長につながりますし、他のプロジェクトでもそこで得た知見を活用できるという大きなメリットがあります。
新しい技術を趣味で試してみることも可能ではありますが、プロダクション環境での開発・運用経験は個人的にまったくの別物で、プロダクションに導入してこそ得られる経験がのちのちの判断に大きなプラスとなります。
つまり、新規開発のときは、メインとしてはある程度知見が貯まった技術を使って機能開発に注力して、メンテナンスの中で新しい技術を導入して、知見を貯めていくというサイクルです。
SI案件では、新しい技術を学びにくいという話を聞いたことがありましたが、今回自分が数年やってみた感じだと、上記の流れができれば、常に最新の技術を試しながら学ぶことができるため、SI案件でも十分な成長が可能だと感じました。
まとめ #
メンテナンスはコストととらえる人も多いかもしれませんが、メンテナンスを通じて新しい技術を習得できればそれはコストではなく投資になります。
継続的に投資を行っていれば、新しいプロジェクトが始まったときでも、十分なプロダクションの知見を持った上で開発をはじめられるようになるため、調査コスト等が軽減され、結果的にはコスト削減につながります。
自分が携われるプロジェクトはかぎりがあるため、メンテナンスという機会を通じて積極的なインプットを行えるようになると、メンテナンスの価値観も変わるかもしれません。
なお、仕事の依頼については、面識のある方からの直接の依頼、あるいは紹介経由でしか受けておりませんので、もし何か依頼がある場合はそのようにお願いします。