ユユユユユ

webエンジニアです

「決断をしない」という決断をすること

アーキテクトの目的は、方針とは無関係に詳細を決めながら、方針をシステムの最も重要な要素と認識するシステムの形状を作ることである。こうすることで、詳細の決定を延期や留保することができる。1

 メールマガジンの配信システムを実装している。

 配信基盤には外部システムを利用している。外部システムの API を自社システムにつなぎこむだけだし、ひとまずは実験的に送信してみたいというクライアント要望から、急なスケジュールで実装を進めることになった。

 配信 API の呼び出しを抽象化するクラスを設計し、リクエスト/レスポンスのデータ構造も外部システムの仕様書通りにモデリングできた。つまり、要望通りにひとまず「実験的な送信」を行える環境はそろったわけである。

 実現したい振る舞いは十分実装できているから、あとはクラスを呼び出してレスポンスを検査する10行ばかりの簡単なスクリプトを作るだけ、というところで、追加要件があがってきた。いわく、クライアントが事前に用意した配信リストに沿って配信するのではなく、一定の条件でユーザーを抽出して動的に配信リストを作成し、あとでそのリストを提出してほしいのだという。

 初回配信日はすでに決まってしまっており、あわてて配信履歴の記録を実装しなければ、と焦ったメンバーが、急ごしらえでテーブルを設計した。みると配列として定義されたカラムがあり、そこにメールアドレスの配列を愚直に格納する構造となっている。

 Postgres の Array 型を使った設計で、確かに使い所によっては便利なデータ構造かもしれないが、少なくともこのユースケースでは不適格だという直感があった。たしかに現状求められる数百、数千の配列を適当に保存するだけなら耐えられるかもしれないが、まんがいち将来数十万、数百万と配信対象が拡大するとどうなってしまうかわからない。おそらく保存するだけなら耐えられるだろうが、「この数百万の配列対象の中に任意のメールアドレスが含まれているか調べてほしい」など検索系のユースケースが生じてしまうと、おそらく立ち行かなくなる。かと言って、実際に配信システムが本採用されて、やがて数百万単位の配信が実行されるようになるまで成長するかどうかはまだわからないし、検索要件まで含まれるようになるかどうかもわからない。まだわからない要件のために最適化を追求するのは、文字通りのオーバーエンジニアリングに陥ってしまうだろう。

 言ってみればこういう二律背反が生じてしまったとみなすこともできるだろう。

  • スケーラビリティをはなから捨てた設計を本番投入してしまうか
  • 設計をクリーンにするために求められるスケジュールは満たせないと謝罪するか

 とはいえ、この命題は誤っている。しかし(しばしば起こりうることだが)この誤った命題に基づいて議論してしまうと、きっと「技術の理解できないビジネスサイド」と「頭でっかちで顧客要望に対応できないエンジニア」が、互いに偏見をなすりつけあって、醜い闘争に至ってしまうだろう。

 僕のたどり着いた答えはこうである。

  • スケジュール上、入念な設計を検討する余裕はないが、かといって不十分な設計を本番投入する必要もない
  • メールアドレスのリストを保存したいだけなら、一時ファイルに保存して適当なストレージにしまっておくだけでよい

 これでひとまず顧客要望は実現できるし、不十分な設計を本番投入するリスクもなくなる。将来的にやはりテーブル設計が必要なら、それを検討する時間稼ぎもできる。ファイルに出力してストレージにアップロードするだけのコードなら簡単に書いて簡単に捨てられるわけで、負債化したスキーマを管理したり、本番DBでデータ移行しなければならないようなことも避けられる。まさに三方よしの打開案であって、我ながらよいアイデアを出せたと満足することができている。

 あとから振り返ると、この判断はまさに『クリーン・アーキテクチャ』に書いてあるような発想であるし、そう考えると、アーキテクトとしても正しい判断だったのだろうとあらためて満足を深めている。

ソフトウェアをソフトに保つには、できるだけ長い期間、できるだけ多く選択肢を残すことである。では、「残すべき選択肢」とは何だろうか? それは、重要ではない詳細である。2

メールマガジンを配信する」という大目標がすでに実現できているとき、「誰に配信したか記録する」というのは、重要とはいっても副次的な要件である。それは決して雑に管理すべきではないが、厳密な設計が求められる場面というわけでもない。大事なのは、そこにスケーラビリティが求められるのかどうか、誰もまだ知らないということである。

 しかし単に「配信対象者を出力すること」が求められているだけだと考えると、出力装置としてデータベースを使わなければならない、というのは、これは思い込みである。単に出力先を選択するのであれば、テーブルを作るのにも ORM につなぎこむのにも工数がかかり、そしてやがて変更したり廃棄するときにもまたコストがかかる RDBMS に出力するよりも、単にファイルに書き込むだけの方が遥かに安上がりだろう。

 適切なテーブル設計は、それが必要とされたときに考えればよいし、ひとまずは時間稼ぎさえできていれば、やがてより時間が詳細な要件を明らかにしてくれるはずである。アンクル・ボブはこういっている。

決定を遅延できれば、その分だけ適切に作るための情報が数多く手に入る。3

 手前味噌にほかならないが、不確実な未来を織り込んで判断をくだせた自分に満足できた経験には違いないので、記念としてブログに書き残しておく。「判断をくだした」といっても「いまは判断すべきでないという判断をした」というわけで、先延ばしにしたことを体よくいっているだけではあるが、アーキテクトの態度としてはそれで間違っていないらしい。

 エンジニアとして判断や意思決定が求められる場面は大小さまざまある。今回は自分なりに達成感が残せたためこうして振り返っているが、より精度を高め、より複雑な問題に対処するためには、結局のところより多くの判断に立ち合い、このようにそれを振り返る機会を持てるよう努めるべきなのだろう。

 少なくともこの一件で、考え方としてはおよそ間違っていない方針を持てているらしいことがわかり、いくらか自信も深められたので、今後は試行数を増やして経験を積んでいきたいなと感じている。「アーキテクト」という職能についてあまり深く考えたことはないものの、結局のところ「いま決めるべきこと」と「いま決めなくてもいいこと」の境界を正しく認識できていれば、おのずと正しい道筋は見えてくるのかもしれない。そのあたりの感覚もこのさき研ぎ澄ませていければ幸福だと思う。


  1. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ) Kindle版. Loc. 2270

  2. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ) Kindle版. Loc. 2263

  3. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ) Kindle版. Loc. 2285