不要なものは消す
まず、そもそもの大前提からです。不要なものは消そうって話です。
アプリケーションに1個、複雑な部分がある。その複雑さがそのままのうちは、まだなんとかなるかもしれない。でも、例えば機能の拡張、あるいはそれのスケーリング、あとは開発環境を用意しましょうというときに、その複雑さをさらになんとかしようと思うと、もっともっと複雑になっていく。
その複雑さの理由にはいろいろあると思うんですけど、少しでも、1ミリでもシンプルで複雑じゃないほうがいい。
できる方法としては、まず、いらないファイルやクラスやライブラリは消そう。もしかすると、あってもなくてもいいかという理由で残ってるのかもしれませんが、僕は経験上、そういうものは絶対にないほうがいいと思います。まずはそれを消そう、ということが最初にできる取り組みかなと。
たまに、消すなんてもったいないって気持ちも出てきます。でも、おおよそGitを使ってると思うので、GitHubでいつでも取り戻せます。そうでない方ももしかしたらいるかもしれないですが、そのときいらないようであれば、どんどん消したほうがいいと思います。
隠蔽しない
シンプルにしていく1つ目「隠蔽しない」。これも最近あった話なんですが、CircleCIって、並列実行の仕組みがありますよね。parallelismだったかな? インスタンスを分けて実行できるという。(それで)PHPUnitを並列実行したいなと思った。
テストファイルを分割するコマンドはCircleCIで用意されている。ただこれ、分割されたファイルのリストを出してくれるんですけど、phpunitのコマンドにはそのまま渡せない。phpunit.xmlとか、設定ファイルでこのテストを実行してくださいって指定する必要がある。
つまり並列実行に必要なこととして、まずcircleciのコマンドでテストファイルを得る。そこからそれ用の、例えばXMLを生成して、そのXMLをphpunitコマンドのconfigurationというオプションで渡してやって実行する、みたいな手順が必要になってくる。
これをやろうとしたとき、最初、一連のやらなきゃいけないことを一発でやってくれるスクリプトでも書こうかなと思ったんです。すごく簡単ですよね。
でもよくよく考えると、けっこう大変なことが出てくる。phpunitにはいろんなオプションがあります。カバレッジを出すかどうかとか。状況によって違ったりします。
あと、circleciのコマンドを含めてしまうと、ローカルで検証しにくい。CircleCIをローカルで動かすライブラリも提供されているんですが、完全に再現できるわけではないみたいなので、あまり良い方法ではないと思います。
またRich Hickeyのプレゼンテーションの引用ですが「抽象化とは隠蔽することではありません。ただ隠すだけでは、なんの役にも立ちません」とはっきり言っています。
じゃあどうしようかと思って、僕らは、PHPUnit用の、XMLを作るだけのスクリプトを書きました。
ほかの部分はそれぞれでちゃんと書いて、使い方としてCircleCIのテストのファイルを分割します。それを使ってXMLを作り、そのXMLを使ってPHPUnitを実行します。これはCircleCIに書いてあるものです。
何がいいかというと、(実際の)書く量は増えているんですけど、例えばリポジトリに全部のテストを実行するphpunit.xmlがあって、それをもとに生成するので、ほかの項目の環境変数とか、あとグローバル変数をどうするかなどを変更しても、差分が発生しないんです。
circleciのコマンドやphpunitのコマンドには、自由にオプションを渡せる。かつ、一番いいところは、ローカルでちゃんと検証ができる。このへんはQiitaに書いたので、詳しいことは見てみてください。これがまず1つ目です。
まとめない
2つ目「まとめない」。
先ほど紹介した「北欧、暮らしの道具店」というECサイト、これはいくつかのアプリケーションから成り立っています。表側に2つと、裏側に管理用の画面のアプリケーションがあって、それらが組み合わさって動いているサービスです。
これらには共通する処理があるので、lumen-modulesという、共通の処理をまとめるライブラリを作っていました。この名前、スライドには歴史的経緯によるって書いたんですけど(笑)、正確にいえば、僕が入社する前からあったものなので由来はわからないです。なんとなくわかる気もしますけど。
これを1つ、独立したリポジトリに分けて、Composerでそれぞれのアプリケーションがそれに依存するというかたちで運用していました。確かに共通する処理がまとめられていれば、その部分に関する変更はlumen-modulesを変更するだけでよくなるので、楽というか、合理的な面もありました。
しかし、きれいに分割できてたらよかったんですが、共通化する部分だけを抽象化してきちんと分けられていたわけではなかった。
本当に共通する部分はあったとしても、共通していないところもlumen-modulesに入れなければいけない。クラスの依存関係とか、lumen-modules内でテストを実行しようとするときに必要になる部分が含まれている、という状態になっていたんですね。
こういうものを運用していくと、結局、(1つのアプリケーションで)ぜんぜん共通してないところだけど、このリポジトリを触らないといけない部分を変更する必要があるときに、各アプリケーションが依存しているせいで、最新版に保つために各アプリケーションでcomposer updateを実行するという手間があったり。
関係ないはずのアプリケーションのほうでなぜかテストが落ちることもあって、まあまあ開発の足を引っ張っている状況がありました。
『マイクロサービスアーキテクチャ』の本に「サービス間の結合が多すぎることによる害は、コードの重複が引き起こす問題よりもはるかに悪くなります」と書いてあって、あ、これのことや! ってすごく思いました。
結局どうしたかというと、分割することにしました。
さっきのlumen-modulesというモジュールに入っていたコードを、多少のコードの重複があったとしても、各アプリケーション内に含めるようにしました。
構成上どうしても共通にしておく必要があったmigrationsとseedsのところだけ残して。まあこれ自体もどうかなってところはあるんですけど、さっきよりはだいぶシンプルになりました。
かつ、さっきありました変更があるアプリケーションではうまくいくけど、ほかのアプリケーションではうまくいかないということを防ぐために、CircleCIでかなりがんばっているのですが、こいつに依存しているすべてのアプリケーションのコードを引っ張ってきて、それらのテストを実行して初めてマスターにマージできるみたいな仕組みにしました。
これが2つ目です。
作りすぎない
シンプルにしていこうという話の3つ目、「作りすぎない」。さっき紹介したように、僕らのアプリケーションは複数に分かれています。
厳密にはマイクロサービスではないですが。
何が問題かって、開発環境の構築がすっごく面倒くさい。会社に入ったとき、途方に暮れるくらいびっくりしました。そんな状況でhokuoukurashi-dev-envというものを作って、最初は自分用だったんですけど、今は開発のチームみんなで使うようにしています。
これは、すべてのアプリケーションの開発環境を一度に立ち上げられるというもので、ただのdocker-compose.ymlとか、必要なDockerfileとかが入ってるだけです。とくにスクリプトとかを書いているわけではありません。僕はそれでいいと思ってたんです。
そしたら同僚が「一緒に立ち上げられるのは便利だから、各アプリケーションのセットアップや、アセットのビルドとか、ほかの大変なやつも一発でできるように作ろう」って言ってきたんです。でも僕は、それにすごく抵抗があった。
例えば、Aというアプリケーションのセットアップ手順が変わったら、そのスクリプトも追従するのか? アセットのビルドにも、ホットモジュールリプレイスメントとか、いろんなパターンがありますよね。それもオプションで渡すの? というようなことを考えると、なんだかなと思った。
そのへんをどうやって伝えようかと思ったときに、コレコレがなにかを複雑にすることを「〇〇をコンプレクトする」という言葉で説明するといいんじゃないかなと。(Rich Hickeyの)プレゼンテーションにあったんですけど。「それコンプレクトするんじゃないの?」って、便利ですよね。
今日の話を踏まえると「それ、創味のつゆになってるんじゃないですか?」って言い方が使えるかな。
(会場笑)
結局、どうしたか。スクリプトを書くのだけはどうしても嫌だったので、スクリプトよりはメンテが容易なREADMEを書きました。
容易というか、動作確認とかはそれぞれのアプリケーションの手順を書くだけだし、その手順自体はそれぞれのアプリケーションで確かめられるというイメージです。
READMEをとにかく書く。いいところとしては、いろんな手順が隠蔽されない。さっきの「隠蔽しない」ですね。そして、これだけダーって書いたら、そんなに複雑なセットアップ手順がそもそも問題だということに気づくわけです。じゃあそこを直していこうという気持ちにもなれる、と思います。
まとめ
まとめです。
SimpleとEasyは違う。ちゃんと区別して考える。Easyを選ばなければいけないときはあるけれど、それはトレードオフであって、なにかを犠牲にしている。
そこをちゃんと認識したうえで、できればSimpleを選択したい。自動的にシンプルになるわけではないです。選びとっていきたい。できるところから、SimpleにしていけるところはSimpleにしていこう、というふうにやっていきたいと思っています。
僕らが作っている「北欧、暮らしの道具店」というサイトも、ECだと思っていたらいきなり短編ドラマを作り始めたり、どんどん変わっていくわけですね。
これに対して、僕らはどう対応していくか。
もちろん(新しいコンテンツは)楽しい話なので歓迎ではあるんですけど、システムを作る人間として、それに対応していかなければいけない。Simpleにしていくのも、なかなか終わらない道です。結局、Laravel MixはWebpackへ移行しようかなと考えています。
知ってる人、いますかね? 昔、日産MOCOというCMで「あなたはあなたが選んだものでできている」というコピーがありました。
言い替えるのであれば「あなたが作ったものは、あなたが選んだものでできている」。こういうふうにするかしないかはあなたの選択ですよ、ということを肝に銘じて、仕事していきたいと思います。
以上です。ご清聴ありがとうございました。
(会場拍手)