これはklis Advent Calendar 2022 24日目の記事です。 こんにちは、klis19(3編)のnotch_manです。今日はクリスマスイブですね。皆さんはいかがお過ごしでしょうか。巷では熱々ムードが漂っていますが、私に関しては表題にあるように”レガシーコード”と相まみえています。そんな私がこの1年間で向き合ってきたレガシーコードに向き合った感想を綴ろうと思います。
結論
- レガシーコードは向き合い続ければ必ず克服できる
- ソースコードはメンヘラなので手を加え続けよう(手から離れたソースコードはその瞬間にレガシーコードになる)
- レガシーと戦いやすい実装を心がける
はじめに
私は現在で大学での短期雇用、2社の長期インターン、また業務委託でソフトウェア開発を行なっています。ほとんどの現場のコードベースは長い年月を経て作られたものです。 私のインターンでの主な業務は、いにしえのソースコードを解読し現世人が解読出来るものに復元することです。 今日はそのうち1社と大学での業務でレガシーコード改善を行なった感想を綴ろうと思います。
10年以上の歴史のあるシステムの根幹にメスを入れる
PRTIMESでは現在PHPを始め、各種コードベースのリファクタリングやバージョンアップを進めています。最初は細かいライブラリのリファクタリングを行なっていき、現在は大規模な修正範囲を伴う作業を進めています。 一般に、影響範囲の広いものほど放置される傾向にあります。しかし、その間にもサービスは成長を続けるので負債もさらに増加していく一方です。だから、誰かがいつかは手を付けなければいけません。私はこの1年で、そんなレガシーコードに向き合う精神と技術力を養うことが出来ました。
レガシーコードの改善は至ってシンプル
レガシーコード改善と名前は格好いいですが、技術的にやることは以下の2つだけでシンプルです。
- ライブラリのリプレイス・バージョンアップを行なう
- 以前と同じ挙動を担保する
ただし、実際に手を加えると以下の様なことを考えなければなりません。そして、これには途方もない労力が必要になります。
- メジャーアップデートで以前の互換が切られている可能性
- 将来のバージョンアップを見据えたライブラリ選定
- 本当に以前と同等の挙動をしているか確認する(これが一番難しい)
そして、技術以外に必要な物もシンプルです。最早、精神論ですが…(笑)
- くじけない心
- 粘り強く調査→修正のサイクルを繰り返す忍耐力
はい、最後は精神論です。
「レガシーコードの改善は技術力だけでなく,それよりもむしろ精神力が要求されます.チーム内でレガシーコード問題の深刻さを共有し,精力的に取り組みましょう」
技術で解決出来る事は技術で殴れば解決できます。しかし、レガシーコードリファクタリング緻密に調査を積み重ねる、泥臭く1つ1つを修正していくなど技術以外の能力が要求されます。だから鍛錬を積み重ねて、これらの作業を行なう精神力を養っていく必要があると考えています。
これらを兼ね備えてやるべきことをやっていけば必ずレガシーを克服することが出来ます。今年、様々な現場でレガシーを解消してきた私が言うので多分間違いないと思います(笑)
結論1:レガシーコードは向き合い続ければ必ず克服できる
結論、何が起きても勇敢に向き合う腕力、忍耐力、技術力があればいつかは必ず克服できます。そして、究極のテストである「以前と同じ動作を保証する」テストを終えるだけで実績がそのまま評価に繋げられます。皆さんも臆すること無くレガシーコードに向き合い続けましょう。その力はソフトウェア開発以外でも必ず活かせます。
たった数ヶ月で腐敗したコードベースを手直しする
続いての事例は融合知能デザイン研究室で開発中のシステム「NextCrowd4u」です(以下N4U)。N4Uは融合知能デザイン研究室でサービスを運営しているCrowd4u(以下C4U)の後継システムとして現在開発中のシステムです。こちらは前任者から引き継ぎ現在も開発を続けています。
事件は唐突に起きる
私は4月から開発業務に関わり始めましたが、早速トラブルが発生しました。
と言うわけで、復旧作業をしようと思ったのですがまず本番環境への接続方法を確認するのに手間取りました。
結局、過去のチャットログから接続方法を確認しログイン出来ました。これ以外にもトラブルが多発している状態で、当時の現場はとても混乱してました。コードベースも前任者からの引き継ぎが十分でなく、ゼロからコードリーディングをして何とかデバッグするという状況でした。
結論2:ソースコードはメンヘラなので手を加え続けよう
ソースコード、特にPythonのようなドラスティックな変化をする言語は手を加え続ける必要があります。数ヶ月コードベースに手を付けられなかったら、pip install -r requirements.txt
すら通らなくなるでしょう。まるでメンヘラですね、手がかかって本当に困ります。
エンジニアはメンヘラと付き合いがちという俗説をよく耳にします。確かに、プログラムがメンヘラみたいなものなのでそれに扱い慣れてたり類似性を感じるからでしょうかね。 個人的にはPythonとかすぐに壊れがちの言語をメインに扱っている人ほどメンヘラと付き合ってるのでは?と思ってしまいます。言語別で統計を取ったら面白そうですね(笑)
このように、開発陣でコントロール出来ないシステムを運用するのはリスクであり、早急に開発体制を立て直す必要がありました。
STEP1
まず、システムをコントロール下に置くために私がシステムやコードベースの全容の把握を行なう必要があります。しかし、稼働中のシステムの運用を止める訳にもいかないので、時間稼ぎのためオペレーション部分から立て直しを進めていきました。最初は私1人で作業を行ない、その手順を全て示すことで他の人も同じ作業が出来るように障害対応と全体のレベルアップ施策を当時に行なっていました。
深夜の復旧作業は中々辛かったですが、復旧後は1つ1つの手順を説明し着実にレベルアップを図っていきました。
STEP2
6月頃から本格的にコードベースの復旧に取りかかります。しかし、この時には4~5月のシステム障害対応の段階でシステム開発の手が止まってしまい担当者もいなくなったことで完全にレガシーシステムと化してしまいました。 この時の問題点は概ね以下の通りです。
- Python3.7で動いている
- ライブラリのメジャーアップデートなどで互換の維持が出来ない
- アーキテクチャの問題で耐障害性が低くシステムダウンが頻発
4月時点では右も左も分からない状態だった開発陣もシステム障害に向き合う中でコードベースへの理解が深まっていました。そこで私はマネジメントやコードレビューに徹し、さらにメンバーのスキルの底上げを図っていきました。 レガシー改善では以下のワークフローで開発を進めました。これにより、手を動かしながら私のノウハウも伝えることができメンバーの開発力を大幅に向上させることに成功しました。
- 設計に関してはDesignDocを作成
- DesignDocでソフトウェア設計に関してnotch_manの経験も踏まえつつアドバイス・改善
- GitHubでタスクチケット(Issue)を作り開発着手
- 一旦、自力で実装する
- コードレビューで設計面でnotch_manのノウハウを伝授
これらの手順に沿ってまずライブラリのアップデートや明らかなデッドコードの削除を進めていきました。そして、それが終わった後にソフトウェアアーキテクチャに問題になっていた箇所の大規模リファクタリングを実施しました。(これについては開発者ブログの記事をご覧下さい)。 最後は以下のPRによって一旦のレガシー改善は完了としました。4月にはてんやわんやしていたチームが見事大規模なレガシー改善を達成した瞬間です。
STEP3
これまではレガシーの改善に尽力しましたが、今後はサービスグロースを進めながらレガシーと戦う必要があります。 n4uのレガシー改善としては主に以下の項目が残っています。
- テストコードの実装
- CRUDロジックを新設計の実装にフルリプレイス
- 各種ライブラリの見直し
- テストを含めたCI/CDの構築
- ログ基盤の改善
今後、n4uの開発チームは新機能開発を積極的に行なっていき、これまで以上のリリース速度で研究室が目指すサービスの実現に向けて歩みを進めていきます。その一方で、過去の負債やこれから生まれる負債についても戦略的に向き合う体制を構築していきます。
結論3: レガシーと戦いやすい実装を心がける
これは今後のレガシーコードの向き合い方の話です。と言いつついきなり残念な話ですがですが、システムというのは誕生した瞬間に腐り始めるものです。つまり、作ったシステムはその瞬間にレガシーとなるのです。そのため、レガシーを生まないことはほぼ不可能です。だから、システムを開発するときにはコードベースが腐ることを前提として実装を行なう必要があります。 少し前に技術負債の話が話題になりましたが、私のこれまでの経験を踏まえると以下の点を気をつける必要があると思います。
- SOLID原則を守る
- 手に負えなくなった機能は置き換えやすいように実装を行なう
- テストコードを実装する(ユニットテストだけでなくE2Eテストも用意する)
- CI/CDを整えてテストやコード規約を強制的に機能させる仕組みを用意する。
まず、1つ目について触れます。ソフトウェアの開発原則には様々な物がありますが、Web開発ではSOLID原則を意識するだけでかなり改善すると考えています。特に単一責任の原則と依存性逆転の原則は非常に大事だと思っているので、この辺りの実装についてはコードレビューで品質を保つように努めていきます。
2つ目ですが、時の担当者がメンテナンスをしなければならない機能に手を付けられないとそれが放置されてしまい負債という形でレガシーが引き継がれてしまいます。だから、困ったときには捨てることが出来るシステム設計を心がける必要があります。関心の分離はソフトウェアの設計で大事ですが、特にメーラーなどの外部ライブラリを使う際の変更容易性には注意して開発を行ないます。
3つ目と4つ目は当たり前の話ですね?ただ、テストコードや静的解析をツールを頑張って導入しても使われなかったら意味が無いです。そのためCI/CDの中でそれらを強制的に動かす仕組みを整えていきます。こうすることで、テストや静的解析の効果を最大限発揮し将来に渡って一定のコード品質を保つことが出来ます。
このようにレガシーを生み出さない、あるいは改善するためには普段からどうすれば戦いやすいか?という視点に立つ必要があるなと痛感しました。今後、N4Uの開発の中でこうした知見が貯まっていったら積極的に紹介していきます。
雑にこの1年を振り返る
この1年で超ド級の謎物体やら小学生もビックリするような限界状態の中で前に進み続ける腕力、精神力や技術力を身に着けることが出来ました。来年は攻めの姿勢で構えながら、さらなる深淵へと歩みを進めていきたいと思います。
そして、今年はめっちゃ頑張った。その結果、レガシーコードリファクタリング業(みならい)は名乗れる程度に成長したのでは?と思ってます。研究室に眠るレガシーシステムの改善のご用命は融合知能デザイン研究室へ(笑)
最後に
キラキラ光る街並み、その裏側には多くのエンジニアの汗と涙が詰まっています。2人の愛の育みも大事ですが、そういった人達の光を浴びぬ物語を時々で良いから思い出してあげてください。皆様、素敵なクリスマスをお過ごしください。
(私のクリスマス?おっと、何処かで案件の燃えてる香ばしい匂いがするぞ…)