- 本エントリーは、年月を経たシステムにどんな闇が宿るかをイメージしていただくため、DDD2
アドベントカレンダー向け『ドメイン駆動設計の手法を導入して、くたびれたモノリスな実システムの改修(IoT対応改修)を試みるシリーズ』の一部(闇ネタ)の先行公開です。
闇の元ネタ。面白い。
https://qiita.com/advent-calendar/2018/yami
闇に対する防衛術の一つ、ドメイン駆動設計(DDD)に関しては以下を参考のこと。
https://qiita.com/advent-calendar/2018/ddd
https://qiita.com/advent-calendar/2018/ddd-2
また、《モノリス》の出典を知りたい方ははこのあたりを。
https://blog.goo.ne.jp/gooasagao/e/ac53b78020332bebb1d0cdf36ce03e0e
(前書き) モノリスなシステムがくたびれちまった経緯。
コピペしまくりの結果、今ではコード量が100万行を超えてしまった、モノリスでくたびれた、とある自社システムがある。本システムは、もともとは物販コールセンター向けに作られたシステムであったが、web物販システムとしての大改修を経て、今に至る。このシステムのこれまでの貢献は大きく、今では、システムによる年商は100億円を超えてくれている。
だが、ビジネスが急成長しシステムにやっつけの改修が入るたびに、次々とシステムには技術的負債は蓄積されていった。エンタープライズ・システムではよくあることなのかもしれないが、お客様の登録ワークフローを変更する(例 カード支払いに加え各社のQRコード払いにも対応)、商品の提示方法を変更する(例 賃貸不動産の紹介ページに、最寄り駅からの距離を近い順に自動で上位3件まで追加する)、商品の販促キャンペーンを個別設定する管理者画面の追加、はたまた、コールセンター側の連携システム構成が変化したり、などなど。
そうした中、度重なる改修に疲れ果てた、メインの実装担当者が退職してしまった。
あなたは、このシステムの保守を一人で任された、とする。引継ぎの文書は少なく、改修時の仕様書などは存在しない。やっつけでこのシステムへの改修を加えることになったあなたは、さまざまな闇を見ることになった。
そんなある日、部長が、あなたに「ちみちみ、これからはうちの商品もIoT対応するよ。Amazon Alexaなんかに話しかけると、商品の状況をぱぱっとレポートしてくれる感じにね。いや~、頑張って予算取っといたから、よろしくね。」と嬉しそうに言った...
とある学園都市の話として、ラノベ風に。
以上は、実話を戯画化したものであり、今日も、実際にシステムは稼働している。
が、もともとはPHP4ベースの実装から始まった実システムを中途半端に戯画化すると生々しいので、私が15年ものの本システムに垣間見た、過度に実装が具体的になっていまっている闇たちを、以下では、とある未来の学園都市の話として、ラノベ風に記しておこう。
なお、以下には、Hub-of-All-Things(HAT)なる、実在するマイクロサービス(AGPL3ライセンス)が登場するが、HATの実際のアーキテクチャ等については、別の回で取り上げることとする。
ラノベ風ポエム 「とある《矢印》のベクトル変換」
[1] 兵庫県のとある学園都市の生徒たちの放課後の学びの多様化を支援・管理する《システムⅠ》
平成が終わりを遂げた、2019年のゴールデンウィークの11連休明け、ギークを気取る若きあなたは、兵庫県のとある都市にある学園都市(以下、<学園都市Ⅰ>)に配属された。配属先であなたは、少子高齢化が進む我が国において、学園都市という名に恥じず、国内外の10万人を超える学生たちの学びの多様化を支援するシステムのメインの開発者である。あなたの上司にあたる、最高技術責任者(CTO、ボス)は、うれしいことに、アーキテクチャの選定から自由になるスクラッチ開発を許してくれた。
イングランドから来たボスは、クイーンズ・イングリッシュ交じりの英語を話す。DeepLearningの研究で博士号を取っており、もともとは貴族階級の出だという。経済学部出身ながら、つぶしの効く仕事としてプログラマになったあなたは、実装についての経験はボスより上だ、と自負しているものの、情報工学の知識の深さなど、ボスには尊敬すべき面もあると思っている。
ボスは、システムのコンセプトを「ユーザー(学生)が学びの楽しさを自ら見つけていくことを支援するハブとなること」とあなたに伝える。そして、参考になる事例として、大学時代の知人がイギリスで立ち上げたプロジェクト『THE HUB OF ALL THINGS』をintroduceしてくれた。
cf. https://www.hubofallthings.com/main/what-is-the-hat/
本プロジェクトのソースコードは、githubで公開されている。
https://github.com/Hub-of-all-Things/HAT2.0
ざざっとコードを見たあなたはつぶやく
実装はscalaベースで、外部とのインターフェースではPlayFrameworkが用いられており、データベース周りはslickライブラリ経由でPostgres決め打ちだが、両者の境界にはアダプターがakkaを用いられたreactiveな作りになっていて、それぞれを切り離すことは可能だ。
Haskellerなあなたは、アカデミアな雰囲気の<学園都市Ⅰ>にふさわしく、haskellベースでシステムを書いていきたかったが、ボスの顔を立てて、GPLなHAT2.0をfolkして、scalaで書いていくこととした。scalaならエンジニアも探しやすいしな、たぶん、と思いつつ。haskellに未練があったので、フロントエンドはelmを使っていくことにした。
どっかのおっさんがPlayFramework+elmでお試しを書ているようだし、play周りの設定で困ることはあまりなさそうだ。開発コード名は、HATとelmをつなげて、『はてるむ(hat-elm)』としておこう。たぶん、検索機能は必要になるから、elastic4sライブラリあたりを使って、検索エンジン対策を進めるか,うんぬん...
あなたは、開発コード名「はてるむ」の《システムⅠ》の設計に取り掛かる。まずは、システムのステークホルダーにヒアリングを行い、システムの主なユースケースを以下のように整理した。
- 「はてるむ」では、ユーザー登録時に、今関心があることをユーザーに書いてもらう。
- 「はてるむ」を訪問したユーザーには、それぞれの関心事に応じ、いくつかの学習コースが提示される。
- 「はてるむ」の学習コースは、リアルな教室の公開講座と、web上のeラーニング講座とからなる。
- 「はてるむ」の学習コースには、受講状況やアンケートの結果から、関心分野別にランキングが用意される。
- 「はてるむ」では、マイナーな講座を見つけやすいよう、検索機能が用意される
- 「はてるむ」では...(以下、略)
あなたは、とあるステークホルダーから、「はてるむ」では、当面の間、ユーザーの属性はさほど変更されない一方で、学習コースの講座の方は、IoTを用いる、新いた体験学習講座が企画されていることを知った。この新講座では、ビデオ録画と四肢に装着したセンサー情報を組み合わせ、講師と生徒の動きの一致度を計測し、生徒の学びに役立てることができるようになるという。生徒たちに人気のダンスレッスンに新講座が用意されると、受講者が殺到しそうだ。
あなたは、設計段階から、新たな方式の学習講座の追加を念頭にシステムのインターフェース設計を行っていった。あなたは、システム改修時に、haskellベースの新興フレームワーク『となとな』をこっそりと導入したりと、<学園都市Ⅰ>でのエンジニア生活を満喫していった...
##[2] 15年後の分散マイクロサービス群《システムⅢ》
2035年、あなたは、東京都下にある学園都市<学園都市Ⅲ>に転属となっていた。かつて<学園都市Ⅰ>で生み出された、《システムⅠ》は、<学園都市Ⅲ>に住まう200万人以上の生徒たちの日常生活を広く管理・監視するハブシステム、字義通りに《The-Hub-of-All-Things》という役割を果たす《システムⅢ》へと発展していった。「はてるむ」の実装を開始してから、はや15年。システムには数多くのシステム改修が行われていった。中でも改修量が大きかったのが、VR型のMMORPG(Massively Multiplayer Online Role-Playing Game;大規模多人数同時参加型オンラインRPG)への対応を伴う、《システムⅠ》から《システムⅡ》へのアップデートであった。
VRMMORPGでは、生徒たちは空中浮遊などリアルワールドで不可能な動作を学ぶことができる。そんな現実世界に存在しない動きを学んで何に役に立つのだろうかと、当初思っていたあなたは、突如、埼玉県の自衛軍の飛行場の近くにある<学園都市Ⅱ>へと転属される。どうやら、急速に発展を遂げるVRMMORPGを、これからの機動隊や自衛軍レンジャー部隊の候補生たちの学びの場とする構想があるらしい。VRMMORPGによって、ゲーム感覚で、剣技や銃器の取り扱いの基礎を学べるようになっているのは事実だ。
<学園都市Ⅱ>は、近隣の脳科学研究を行う厚労省系の独立行政法人と提携関係にある。あなたのミッションは、CTOとして、VRMMORPGシステムのログと、VRMMORPGプレイヤーたちの脳波を図る独立行政法人側のシステムとを統合解析できる機能を実現する《システムⅡ》の構築を統括すること。あなたの指導の下、投入されたエンジニアたちの尽力の結果、比較的モノリシックな《システムⅠ》は、いくつかの言語で記述されたマイクロサービスベースの《システムⅡ》へと発展していった。
<学園都市Ⅱ>の生徒は数の上では数千人にすぎないが、2年近くの間、VRMMORPGシステムにログインしたままであったという特殊な子たちで、中には...(以下、略)。
ともあれ、今の問題は、転属先の<学園都市Ⅲ>の《システムⅢ》だ。すっかり中年のおっさんとなったあなたは、《システムⅢ》の技術顧問。15年前に自らコードを書き始めたシステムとはいえ、当初は想定していなかった改修を加えていったことで、システムのコードの多くは、あなたが知らないAI支援型ドメイン特化言語Helmesで記述されるようになっていた。《システムⅢ》から《システムⅢ》への改修は、実装パラダイムの変更を伴った。かつて、scalaやelmなどのコードはIDEやエディタで手打ちされていたのに対し、AI支援型DSLでは、プログラマが脳内に浮かんだコードをAIが対話的に補完していきリポジトリへとコミットしていく。これによりプログラマは職業病である腰痛や腱鞘炎にかかるおそれは軽減されたものの、プログラミングの生産性は必ずしも向上したわけではなかった。一説では、AI支援型DSLの導入は、コードをAIを通じ集中管理することで、《システムⅢ》内の機密情報を<学園都市Ⅲ>を外に漏らすことかないようにする狙いがあるとされていた。
正直、あなたにとって、AI支援型DSLのHelmesは性に合わない。確かに、元になったelmの特徴は残っているものの、DOMの操作言語から脳波情報の汎用記述言語へと記述目的が変わったことは大きい。
こうなったのも、<学園都市Ⅱ>のオーナーである自衛軍が、<学園都市Ⅲ>のオーナーである統括理事会の下にある「暗部」に敗北したことが大きい。オーナーシップの変更に伴い、《システムⅡ》と《システムⅢ》は目指すところが全く異なっている。恐るべきことに、《システムⅢ》では、《システムⅡ》が蓄積してきた脳波情報を〇〇〇することで、200万人を超える生徒たちを「能力者」へと変えていくことを目的とするらしい。システムの目的の変更も大きい。加えて、CTOを外さられたあなたには、システムの機能〇〇〇や△△△などが開示されなくなっていた。《システムⅢ》の技術顧問という肩書きは、実のところは、レガシーなscala/akka周りのコードを時折保守するおじさんという意味合いしかなかった。
そんなあなたのところに、とある統括理事から「暗部」の一組織を通じた依頼が入る。それは、《システムⅢ》上の統括理事会向けフロントエンドからの検索から漏れている、「液状被覆超電磁砲」に関する情報をシステムのレガシーなデータベースから抜き出すことと、こうした検索漏れを起こさないようにすること、だ。あなたは「液状被覆超電磁砲」がいかなるものかは知らないが、<学園都市Ⅲ>中に分散配置されている《システムⅢ》のサブシステムから、「液状被覆超電磁砲」に関する情報を抽出するべく調査を開始する。
[3] リファクタリングは、《矢印》のベクトル変換で。
あなたの主な担当範囲は、バックエンド・システムのうちscalaとhaskellで記述された部分だ。かつて、あなたが書いたコードも含まれるが、現在のコード量ははるかに大きい。非開示の部分もあるため全体はわからないが、あなたが、CTOを務めていた《システムⅡ》の頃に、すでにコード量は1億行を超えていた。かつての<学園都市Ⅱ>では豊富な国防予算がつぎこまれて、大規模な開発チームが構成されたが、<学園都市Ⅲ>での開発体制はそれを上回る。どうやら、その間、あるサブシステムでは、アカデミア系あるあるで、謎のこだわりをもっていたり、時々の流行に流されやすい老若男女のコーダーたちに、時として「暗部」の人間までが加わって、イマドキのHelmesや、古のhaskellやscalazの形式で、黒魔術コードを埋め込んでいた。また、AI支援型DSLが生み出す白魔術コードの中には、人間が読めたものではないものもあった。他方で、《システムⅡ》の頃にオフショア開発に出され、納期を遅延するうちに納品先が、<学園都市Ⅲ> へと変更された別のサブシステムでは、目を覆いたくなるようなコードのコピペが乱発されていた。
結果、検索漏れ問題の特定は長期に及んだ。
疲れ果てたあなただったが、コピペ乱発のとあるサブシステムで、ついに原因を突き止める。
それはかつてどこかで見たようなクソコードだった。とりあえず、いったん落ち着かせるために、テストコード代わりにコメントに置かれていたコードをREPLで走らせてみる。
scala> val 現在の学園都市レベル5たち = "一方通行、垣根帝督、御坂美琴、麦野沈利、食蜂操祈、(未判明)、削板軍覇".split("、")
現在の学園都市レベル5たち: Array[String] = Array(一方通行, 垣根帝督, 御坂美琴, 麦野沈利, 食蜂操祈, (未判明), 削板軍覇)
scala> val register5 = new CreateLevel5Users
register5: CreateLevel5Users = CreateLevel5Users@1435103b
scala> for (name <- 現在の学園都市レベル5たち) register5.addToRepository(name)
scala> register5.showAll
User(現在第1位 : 一方通行)
User(現在第2位 : 垣根帝督)
User(現在第3位 : 御坂美琴)
User(現在第4位 : 麦野沈利)
User(現在第5位 : 食蜂操祈)
User(現在第6位 : (未判明))
User(現在第7位 : 削板軍覇)
あなたは、学園都市のレベル5という変数やCreateLevel5Usersなるクラスに見覚えはなかった。だが、継承元のCreateUserを書いたのは、15年前のあなただった。
あなたはわなわなと震える。
class CreateLevel5Users extends CreateUser{
private val myUserRepository = new UserRepository
private var order = 0
def addToRepository(name:String) = {
order += 1
val registname = name match {
case "一方通行"=> name+("(より強力な黒い翼,白い翼もあり")
case "御坂美琴"=> name+("(より強力な食蜂操祈の合体技の液状被覆超電磁砲もあり。黒子とも合体するか。)")
case _ => name
}
myUserRepository.add(s"現在第${order}位 : ${name}") // sは,補間 (string interpolation) を意味
}
def showAll = {
val users = myUserRepository.getAll
users.foreach {u => println(u)}
}
}
なんの理由でこんなの書いたの。だめじゃん、この作りだと、能力者レベル5の持つ能力の応用に関する排他的検索のところから落ちちゃうじゃん。だが、あなたの怒りの真の向き先は、クリーンアーキテクチャにならって書いていた《システムⅠ》のコードのビジネスロジックが、CreateUserの実装に依存してしまっていることだった。このままでは、特定の検索条件では、液状被覆超電磁砲は御坂美琴にも食蜂操祈にも帰属しないという結果を返してしまう。そして、もうひとつ怖いのが、一方通行の黒い翼,白い翼やらが、能力者以外の属性を持つ者との関係で不具合を起こしていないかということだった。
技術顧問であるあなたの数少ない部下のひとりに影響範囲を調べてもらったところ、潜在的な影響範囲は懸念した通り大きいことが分かった。あなたと年老いてくたびれはてた部下たちとの、とっちらかった実装のクラス間の依存関係の《矢印》を本来あるべき一方通行に戻すべく、ベクトル変換に勤しむ日々の始まりであった。
昔々読んだ、クリーンアーキテクチャ本のという《矢印》を思い出し、「悪いな、ここから先は一方通行なんだよ。」、あなたは小さな声で呟くと、レガシーなエディタを使い、またひとつ循環参照を起こしているコードを直すのであった。しこしこと、しこしこと。
(後書き)
ちなみに、実システムの方では、都道府県に関する情報はデータベースに入っていたのに対し、政令指定都市の一部に関する情報がハードコーディングされていた。これにより、某県に、同じ名前を持つ政令指定都市が誕生した後のシステム改修でバグが発生した(型付けが弱いまま暗黙の変換があるらしいPHPでの癖のある書き方に起因するバグ)。だが、そんななんか笑えてすぐに治せる不具合がある一方で、よりシャレにならないユーザー様にご迷惑をおかけするときがあるのに不具合を起こしている箇所が特定しきれないものもあるのだった。恐るべし、循環参照とハードコーディングのコンボ技(それ以外にも問題は多いのだけれども)。
15年間って、長いんだな(遠い目)。
そういえば、SAOシリーズや、とあるシリーズも15年ものだね。