レガシーシステムにどう立ち向かうかの検討
はじめに
今回は古いシステムやリファクタリングなどに関して色々と思うことがあり、調べたりもしたので、ここにまとめを記します。有用なテクニックなどを紹介することはあまり無いと思いますので、この記事は感想文に近いと思います。
タイトルでは書いたレガシーシステムというのはこの記事では「誰かが昔につくったまま放置された謎システム」という意味で書いてます。
注意書き
- 技術的な話は無いです(というより書いてたら何万文字の記事になるんだ)
- 私見のため偏った見方をしている可能性があります
- 社内エンジニアなのでB2B/B2Cよりエンジニアだと少しイメージが湧きづらいかもしれません
- 社内情報を書かないように一部表現をボカしてます
- 指摘・感想は歓迎です
TL;DR
- テストやリファクタリングが評価に繋がりにくい
- リファクタリングでミスして減点でなく貢献度による加点式のほうが良さそう(したい)
- リファクタリングは書籍などから学びつつレベルにあったものから始める
これはなんとかしないとダメだなっと思った経緯
社内システムの開発チームの管理職に配属されてから、各メンバーの働き方、特に開発の進め方に疑問を持ちました。気になったのは主に次の3つです。
- 設計に関する資料が無い
- テストが無いもしくは少ない
- リファクタリングしない
それぞれについて説明します。
まず設計に関する資料がありません。関連部署や課長や部長など上の人から口頭で要望が伝えられて、至急そのまま実装に移るためです。当然、既知のことですが、この開発の進め方は初期開発では問題ないかもしれません。しかし、機能追加や不具合修正の場合にはこれが問題になる可能性があります。なぜなら、
- 何のための作ったのか
- どのシステムと連携するのか
- 修正した場合はどこまでが影響範囲になるのか
など多くの情報が失われてるからです。これらの情報が無い場合、1から情報を探索したり、ソースコードを注意深く読む必要があり、余計な工数が取られるため、あまり良い状態とは言えないと思います。
次にテストがありません。社員に貸与するパソコンやモバイル端末など様々な機種を一元管理するシステムを運用・開発してますが、これが20年以上稼働するとても古いシステムです。聞いた話では、昔はメモ帳でコーティングしてFFFTPでコードをアップロードしたりしてたっということなので、かなり年季が入ってます。最近では追加機能や修正の場合はテストコードを書くようになりつつありますが、またまだテストしていないコードが多く残されてます。
三つ目が今回の記事の主題の1つですが、私のチームではリファクタリングをやりません。これについては長くなりそうなので次の章で説明します。
そもそもなぜリファクタリングしないのか?
今時、リファクタリングをやらない開発というのも珍しい気もしますが、やらないのには私のチームに限らずそれぞれ理由があると思います。今回あえて挙げるなら、私のチームがやらない理由の1つが評価制度だと考えています。
なぜ評価制度がリファクタリングと関係するのでしょうか?それでは実例に基づいて説明します。私の会社では社員の評価は5点満点評価で行われ、1点が最低で5点が最高評価です。そして3.5点を超えると昇給対象となります。ここで開発者AさんとBさん、評価者である上司Cさんの評価時期のやり取りを見てみます。
Aさん「機種ごとの貸出数を見える化した機能開発しました!」
Cさん「業務の可視化は素晴らしい!4点で昇給です!」
Bさん「Aさんの開発した機能に不具合があったので調査して修正しました。あとテストコードが無かったので足しました。」
Cさん「不具合修正とかありがとう!3点です。来期もよろしくお願いします!」
これは評価時期に行われるやり取りのほんの一部ですが、なんとなく背景が分かってくるのではないでしょうか?成果主義に基づく評価のためBさんが評価されにくくなっています。さらにタチが悪いのは、実際に不具合が発生した際にケツモチをするのはBさんです。何故なら「不具合を修正してテストもしたというのに、これは一体どういうことなのだ?」っと偉い方々はBさんに問い詰めるためです。一方Aさんは次々に新機能やシステムを開発して行き評判を上げていきます。果たしてこんな評価で誰がテストやリファクタリングをやろうと思うのか?っと考えたら少なくとも私はやりません。
さらに酷い事例は、この悪循環を利用して、評価点を稼いで昇給を狙う人間がいることです。先の例は、発想を逆転すると、機能追加や見える化など業務に貢献してそうな開発をすれば昇給しやすいということです。「貢献してそう」というのがミソですが、実際に業務に貢献しない機能でも問題ないわけです。なぜなら評価時にアピールできれば十分だからです。そのため社内にはなぜ動いているかよく分からないシステムや何故止めてはいけないのか理由が分からないシステムなどが数多く存在します。そしてこのレガシーシステム達は年々増えていくので、近年ではレガシーシステムの不具合修正やCVE脆弱性対応などに工数がほとんど取られ、新規のことがほとんど進められない状況に陥っています。※このように作るだけ作ってどこかに異動してしまうエンジニアを私はやり逃げエンジニアと呼んでいます。
少し長くなりましたが、このような状況に陥っているのはさすがに不味いでしょっと思ったので古いシステムのクローズやリファクタリングなどについて調査して対応の検討を最近行っています。古いシステムのクローズに関してはシステム連携先の担当者と連絡して1つ1つ利用状況を聞いて回れば良いですが、利用している場合はどう対応していけば良いのか?という疑問にあたりました。
- どうすれば古いシステムの利用を停止できるのか?
- どうずればコードの修正を安全かつ楽にすることができるのか?
この2点について色々と考えた結果を次の章でまとめていきます。
どうすれば古いシステムの利用を停止できるのか?
まず最初に思いついた(というより思い出した)のは式年遷宮です。式年遷宮の説明を以下に引用します。
神宮には内宮にも外宮にもそれぞれ東と西に同じ広さの敷地があり、式年遷宮は20年に一度宮処を改め、古例のままに社殿や御装束神宝をはじめ全てを新しくして、大御神に新宮へお遷りいただく神宮最大のお祭りです。
つまり、この考えをシステムやインフラに適用して、一定年数ごとにシステムを一新すると同時に技術継承や若手育成もやろうということです。さらに開発完了後に次にいつ一新されるのかあらかじめ知ることができるので「急にシステム停止と言われても対応できないよ」などと言われることを防ぐことができるのもこの手法のメリットだと思います。いくつか事例もあるので下記に記載します。
この手法はとても良さそうですが、現実問題を考慮するとある懸念があります。それは約束を反故されるという点です。例えば5年おきにシステムリプレイスを計画しても、5年目になって急に「工数がないのでシステムリプレイスは延期してくれ」っと言われる可能性があります。これは式年遷宮なら遵守しなければならないルールですが、如何せん社内システムの場合はお客様向けのパッケージ開発やユーザ向けのウェブサイトと比較して、うるさく品質や期日を求められることがありません。そのため期日を伸ばしたり、土壇場で仕様を変えてくることは、日常的なので式年遷宮は効果がいまいちな可能性もあります。
別の案はシステム間で連携する時は、腐敗防止層(ACL)や公開ホストサービス(OHS)を適用することです。※ ACLとOHSについてはDDD難民に捧げる Domain-Driven Designのエッセンス 第3回 大規模なプロジェクトへの適用かエリック・エヴァンスのドメイン駆動設計を参照して頂けると助かります。
社内のレガシーシステムではSELECT文で読み込んだデータをそのままXMLやJSONに変換して連携するものも多くはあります。そのためテーブル構造の変更は即ちそのままシステム間連携に影響を与えることになります。そうではなく、先のACL/OHSを適用して、システム連携のためのインタフェースを定義してシステム内のデータ構造を外に公開しないようにする、という考えです。
他にもデータベースに直接アクセスするような連携やCSVファイルを転送するような連携もありますが、当然ですがすべての連携にACL/OHSは適用できないと思います。なので、できるだけACL/OHSを適用できるようにシステムを改修したり他部署の担当者とネゴることが重要なのでは思います。もちろん境界づけられたコンテキストの見極めと場合によっては再定義なども必要になってくると思うので、実践する場合は優れてたアーキテクトの意見が必要になると思います。
どうずればコードの修正を安全かつ楽にすることができるのか?
実際に複雑な怪奇なソースコードをどうリファクタリングをしていくかについても考える必要があります。1つ確かなのは「仕様をそのままに1からコードを綺麗に書き直そう」は失敗するということです。なぜなら、これは私が配属される前に既に今のチームは2回ほど経験済みだからです。
1回目は開発範囲があまりに広すぎて把握しきれず、設計ができずに断念したパターンです。この失敗は先に述べた膨大な数のレガシーシステムが原因です。ゴミ屋敷でゴミを出さずに家をどう整理しようとしたようなもので、上手くいかなかったのは納得です。
2回目はどういう理由なのかClean Architectureで実装しようとして、結局実装できなかったパターンです。これはエンジニアの技術的好奇心が先行して現実の課題を認識してなかったのが問題で、エンジニアが起こしがちなトラブルな気がします。
一気にコードを修正しようとするのは問題領域が大きすぎて普通の人間の認知能力では対応しきれないのが原因な気がします。やはりコードを修正していくには地道にリファクタリングを行うのが良いのかもしれません。
じゃあ、どうリファクタリングをしていくかを考えると「まずはリファクタリングについて勉強するしかないじゃない」というのが答えです。身も蓋もない。もちろん私一人で勉強して解決する話でも無いのでメンバーにも勉強してもらう必要があります。私がリファクタリングの勉強に役立ちそうと感じた本をいくつか列挙します。私が読んでいいなーっと思ったものなので他にあればぜひ教えて頂きたいです。
それぞれの本の感想は長くなってしまうので割愛しますが、どれも読みやすく実戦向きの内容でエンジニア向きだと思っています。特に現場で役立つシステム設計の原則では「自己文書化」というコードの変数名や関数名、行間などを国語的な視点で捉えるという考え方を学べたので個人的なオススメです。
あとはリファクタリングについて勉強しつつ、最初は下記のような簡単なステップから始めていくしかないかなという気がしてます。リファクタリングという行為自体が文化として形成されるまでは地道な努力しかないかもれしれませんね。
- コメントアウトされてるコードを削除
- 未使用メソッド・関数を削除
- 実装と全然違うコメントの修正
- formatterとかで書き方を統一する
- 不要なimport/require削除
リファクタリング以外にやるべきこと
まず最初にやろうと思うのが、目標設定と評価方法の是正です。
リファクタリングという地道ながらも着実かつ確実にコードを改善する行為があまりに低評価なのがそもそも納得が行きません。確かにリファクタリングをしなかったことによる損失を定量的に評価することはできません。しかしコードの行数が減ったり読みやすくなることが結果として工数削減や不要なシステムのクローズに繋がるということをしっかりアピールする必要があります。なのでここは継続的に偉い方々を説得して徐々に「リファクタリングをやって当然でしょ!」っと思えるように洗脳する必要がありそうです。
また目標も新機能開発だけを評価対象とせず、リファクタリングの貢献度でも評価するように評価軸を正す必要がありそうです。こうすることで「あ、リファクタリングでも昇給できるじゃん!」ということになれば自発的にリファクタリングをやろうと思える人も増えてくるかもしれません。やってみないと分かりませんがやる価値はありそうです。
まとめ
結局この記事は何を言いたかったのかというと、書いてるうちに少しわからなくなりました。自分の今置かれている環境をどうにか改善したくリファクタリング等についての考えを文書化したかったというのが目的な気もします。また同じような状況に置かれてる人が居たら情報共有になればっとも思っています。ただ、これはZennに書くことなのか少し疑問。リファクタリングについて語ってるのにコードブロックが1つも無いのは如何なものだろうか。。
Discussion