読者です 読者をやめる 読者になる 読者になる

無限のメモリ空間と絶対に落ちないプロセスを仮定して「ビジネスロジック」をあぶり出す

先日、前職の上司から「そろそろプロフィールに"詩人"を追加するべきだ」と言われました a-suenami です。今日も今日とて詩人業を行なっていきますよ!

ビジネスロジック」とは何か

最近、業務で、比較的中長期的なアーキテクチャの見直しだったり、新機能の設計だったりをさせてもらう機会が増えた。

コンポーネントをどういう風に分割するかとか、それぞれのコンポーネントを主にどのチームでメンテナンスしていくかとか、そういうのを考えるのは楽しい反面、かなり熟慮に熟慮を重ねないといけないものでもあるのでかなり責任を感じるというのもある。

まあ、そんなこんなでいろいろうーんうーんって悩んでいると昔(たぶん DDD コミュニティだと思うけど)誰かに言われた「無限のメモリ空間と絶対に落ちないプロセスがあったとして、それでもそのコードを書かないといけないのならそれがあなたのドメインだ」という言葉だ。

モデリングをしているとドメインロジックとかビジネスロジックとかって言葉はよく出てくるんだけど、これは結構なかなか人によって解釈が違っていたり、明確な定義がなくて難しい。エリックエヴァンスの DDD 本ではユビキタス言語というパターンがあって、それがちゃんと構築できてる前提であればドメインか非ドメインかわかりやすいんだけど、あれをちゃんと実践するのはすごく大変だ。僕も何年か前にあの本を読んで以来、チーム内でいろいろ試みてみたけどいまだに手応えのある成功体験はないし、プロダクトオーナーを含むチーム全体を巻き込んでいかないとかなり厳しい。

で、もうちょっと簡単にそれがビジネスロジックなのか or not を判別したいことがあって、それをもとにその振る舞いをどこに実装していくべきかって考える感じのことがある。まあイメージとしては軽量 DDD というか、少なくともエンジニア同士では認識が揃っていて、何かを実装しないといけないときにそれをどこに定義すればいいかを迷わなくてもいい仕組みくらいだと思ってもらえるとよいと思う。もしそれを修正しないといけないことになったとしたときに、それがビジネス都合なのか、アーキテクチャ都合なのかをちゃんと区別して、決してそれが混じらないということが実現されるだけでもかなりシステムのメンテナンスは楽になる。逆に、どっち側の変化によっても同じオブジェクトやメソッドが修正されるという状態は明らかにオブジェクト指向設計の単一責務原則に反しているし、障害が発生したときの問題切り分けが著しく難しくもなるので基本的に避けたい。

もちろんそうやって分割されたオブジェクトやメソッドのうち、ビジネス都合で定義される側のクラスやメソッドがユビキタス言語になってるほうがなおよいけど、まあそこは一旦エンジニア同士で伝わればいいよねっていう妥協もアリだと最近は思い始めた。*1

そして、その判別方法が「無限のメモリ空間」と「絶対に落ちないプロセス」を仮定することによる思考実験である。たぶん厳密には「断線・遅延しないネットワーク」も必要なのかもしれないけど、まあ要するに永続化やキャッシングから解放されたときにそれでもそのコードは必要なのかっていうことで、これはなかなか結構おもしろい思考実験である。

僕たちがどれだけ永続化に関するコードを書いているか

これ、実際にやってみるとわかるんだけど、実際に考えてみるとほとんどのコードは必要なくなるってことに気づく。僕らが一体どれだけ永続化とキャッシュに振り回されてるのかってことだ。

逆に言うと、そのレイヤーの心配ごとが軽減すれば僕たちはもっと自分たちのビジネスに集中できるし、ちゃんとしかるべきクラスだかオブジェクトだかに隠蔽してあげてビジネスロジック層からは意識しなくて済むようにしてあげるべきなんだよ。設計ってそういうことだと思うんだ。僕が ActiveRecord を Dis るのは(おっと誰か来たようだ

システムは何故バグるのか

これは完全に僕の経験則だけど、システム障害において、ビジネスロジックにバグが混入していたというケースは実はそんなに多くない。エンタープライジーな開発現場を経験してないので、そもそもこのレイヤーのロジックが薄いプロジェクトしか知らないというのはあるのかもしれないけど、それにしたって永続化やキャッシュに関するバグ、ミドルウェアや連携システムの冗長化不備がほとんどである。

その中でも本当に多いのは

  • キャッシュに関する何か
    • リフレッシュされてなくて古いキャッシュを参照する、等
  • 失敗可能性(要するに NULL 参照)の考慮漏れ
  • 永続化したデータの取得遅延
    • まあ、平たく言うとスロークエリ

で、僕は勝手にこれを三大バグ発生要因と呼んでいる。(あくまで勝手に)

永続化もキャッシュもなくてよくて、NULL もない、そんな理想郷がもしあるならその世界で実装されるシステムの障害は激減するはずだ。

ビジネスロジックは意外と薄い(かもしれない)からこその創造性

これは仮説だし、僕自身まったく検証できてないんだけど、それを念頭に読んで欲しい。

思考実験として仮定した無限のメモリと落ちないプロセスは実際には実現不可能だけど、コンポーネント分割を工夫して永続化に関する関心事をあるレイヤーで隠蔽することはできるし、そうするべきでもある。それによって、少なくともビジネスロジック層から見れば永続化を意識しなくてよくなるので、先に述べた理想郷が仮想的には実現できる。

で、このときに気づくんだけど、実際にはビジネスロジックなんて予想外に少ない。もちろんドメインによると思うけど、Web アプリケーションにおける参照系の機能(つまり Web ページの閲覧)なんてだいたい DB に入ってるデータをそのまま画面に表示するだけだったりするし、あるとしたら表示整形くらいでそれはビジネスロジックというよりはプレゼンテーションのロジックだ。僕は今メディアの会社にいるのでなおさらだけど、ビジネス = プレゼンテーションみたいなもんである。

そういう状況にエンジニアが放り込まれたらどうなる?

エンジニアは本質的にコードを書きたい人種が多いんじゃないかと僕は思っている。そんな人たちが永続化の関心事が隠蔽されていて「コードを書く必要がない」環境に置かれたら、どうやったら自分たちはもっとコードが書けるか、こういう機能が実現できたらいいんじゃないかっていう創造性が発揮されるんじゃないかなと。これは予想というよりも自分と一緒に仕事をしてくれる人たちにそれを期待したいっていう意味も込もってるんだけど。

もちろん一定数のエンジニアには低レイヤーへの憧れみたいなものもあると思うし、僕も若い頃には Linux コマンドを使いこなして、呪文のようなバイナリを見たり、まるで MySQL と会話しているかのような先輩エンジニアに尊敬の念をよく抱いたものである。ビジネスロジックが意外と薄いということは、逆に言えばシステムの根幹をなすのは永続化部分のコードだとも言えるのでそこに興味を持つのは自然なことだし、その場合は隠蔽された先の、永続化に関するコンポーネントの実装に携わればよい。

重要なのは、今自分が何のコードを書いているのかちゃんと意識すること。

ビジネスを加速していくために新しい機能を実装するか、その人たちを支えるために適切に永続化を隠蔽するか、趣味・嗜好も得手・不得手あるだろうし、会社やチームの都合でどっちがより重要なフェーズかってのもあると思うけど、少なくともそこが適切に分離されていて、どちらかをやっているときはもう一方を意識しなくていい状況は最低限実現していきたよねと思った週末なのであった。(いい感じにまとまった。たぶん。)

*1:DDD界隈の方々、すいません。マサカリは甘んじて受ける覚悟です。