Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Builders Box イベントレポート 〜クリーンアーキテクチャ〜 (後編)

はじめに

DSOC サービス開発部の正木です。普段はアプリケーションエンジニアとして、Sansan や Eight のサービス基盤となるシステムを Rails をメインに開発・運用を行っています。

今回は Builders Box - ON AIR #3 Clean Architecture レポートの後編として、講演の後半の質疑応答パートについてレポートします。


※レポートの前半(講演パート)はこちら
buildersbox.corp-sansan.com

今回の講演の様子

今回の講演は、アメリカにいらっしゃる Martin 氏とオンラインでつないで行われました。アメリカとは時差があるので、日本時間の 22:00 スタート、アメリカの現地時間は朝7:00でした。
日本時間の遅い時間のスタートとなりましたが、当日は大勢の参加があり、 Twitter でも多くのポストがありました。

また、私は家族に小さい子供がいるため 19:00 ごろは手が離せず、ここ数年は平日の夜に開催される IT 系の勉強会にはほとんど参加できていないのですが、今回は 22:00 からのスタートということで、子供を寝かしつけてから参加することができました。

質疑応答

まず始めに、頭出しもかねて進行のCTO 藤倉から、以下の質問がありました。

質問1:

アーキテクチャの歴史を振り返ると、アーキテクチャの抽象度が上がったり、下がる時がある(webに特化したアーキテクチャ、DBに特化したアーキテクチャなど)。
抽象度が高いアーキテクチャには賛成だが、それを全てのエンジニアが理解するのは難しい。それ故、シンプルなもの、迅速にソフトウェアが作れるアーキテクチャが登場するのではと考えているが、Bob さんはどう考えているか?

回答:

アプリケーションにはシンプルで、高度なアーキテクチャが必要ないもの、寿命が短いものがある。
そのようなアプリケーションには高度なアーキテクチャが必要ないだろう。
ただしよくあることとして、これから作ろうとしているアプリケーションがシンプルであまり長持ちしないと思っていたが、とても長続きし、どんどん複雑になるかも知れない。
ソフトウェア開発者としては、注意しておく必要がある。

  • アプリケーションがどれくらいの寿命になるか? どれくらい複雑になるか?
  • あまりにもシンプルにしてしまうと、後が大変。メンテナンスが大変になり、チームの生産性が下がってしまう。

これは避けたいので、慎重にアーキテクチャを考えないといけない。アーキテクチャが抽象度をうまく考えて長期的に変更が加えられるように、また生産性をキープできるように考えないといけない。

質疑応答(参加者の方から)

ここからは Zoom のQ&Aで参加者の方から質問を受け付け、それをピックアップして Bob さんに質問するという形で行われました。

質問2:

よいアーキテクチャは重要な決定を延期させてくれるもの、という点についてはなるほど、と思った。
では、延期をした決定はいつすればいいのか? 意志決定の適切なタイミングはいつなのか?

回答:

可能な限り先送りする。
もちろんなにも入力が無かったり画面表示がないシステムはありえないので、いつかは決めないといけないが、初期にやる必要がないものもある。
たとえば画面表示の美しいフォーマットやアニメーションは、初期にやる必要は無い。
初期はシンプルに骨子のものやビジネスルールが確認できればよい。

ここでいう延期とは無視ではない。初期の投資を抑えること。

データベースがいい例。
最初に高価な製品を使う必要は無い。初期の段階は無償のデータベースを暫定的に使うことができる。
その後何らかの段階が来て、当初やりたいことが実現できるとわかったり、いよいよお金を掛けてスループットやスケーラビリティを確保しなければいけないとわかるときが来る。

ここで延期しているのは、高価なものへの投資、本質から目を背けてしまうような決定。これをギリギリまで先延ばしにする。
いよいよ決定しなければいけない地点に到達したとき、最初に何か決めようとしたこととだいぶかけ離れているはず。

十分に材料が揃い賢明に意志決定できるタイミングまで、意志決定を先延ばしにする。

思ったこと:

仕事ではなるべく決まっていないことを先送りしないようにしがちですが、極力先延ばしにすることで、後になったらそのことが本質ではなくなったり、そのままでも問題なかったということはあります。
また先送りにできるような設計が、必然的に付け替え可能にできる設計につながっていくのでは、と思いました。

質問3:

Railsを使って Clean Architecture をうまく取り入れて行くにはどうしたらいいか?

回答:

Rails には ActiveRecord というとても便利な仕組みがある。ビジネスオブジェクトとデータベースとのやりとりを、うまく組み合わせて扱うことができる。
コメントとしては、ビジネスオブジェクトが ActiveRecord の派生クラスにするのはやめた方が良い。
Business オブジェクトは、ActiveRecord から分離しておき、(Railsが構築する)アーキテクチャとの分離が必要。
Business オブジェクトから ActiveRecord へ delegate するといったようにする。

今回の出席者には Rails プログラマ以外の方もいると思うので、これ以上のコメントは今回はここまでにする。

思ったこと:

私の所属するチームでもビジネスオブジェクトを ActiveRecord と切り離す取り組みは行っていますが、オブジェクトの属性がデータベースのテーブルとほぼ変わらなければ、 ActiveRecordのサブクラスのままにしていることも多いです。
Rails を選択している時点で「Rails のレールに乗る」ために、Railsのアーキテクチャから分離することに注力していませんでしたが、ビジネスオブジェクトとテーブルは本来同じものではないので、きちんとモデル設計して分離するものは分離すべき、と思いました。

質問4:


Bob さんが「Clean Architecture がうまくいった」と感じた後にご自身が感じた、魅力を持っている他のアーキテクチャ、パラダイムは何かあるか?

回答:

以下があげられる。

  • ポート&アダプターアーキテクチャ
  • ヘキサゴナルアーキテクチャ
  • DCIアーキテクチャ

この15年ぐらいのスパンで使われているアーキテクチャは、非常に類似性が高い。

類似性が高く、同じような問題を似たような手法で解決しようとしている。
これは我々の業界で何が起きているのだろうか?

90年代後半から2000年にかけてドットコムバブルが崩壊したが、10年ぐらい経って徐々にIT業界は復活し、90年代に議論されてきた問題が再び取り上げられるようになった。
この15年でそういった問題への認識が高まってきたのだと思われる。

質問5:

会社の中でクリーンアーキテクチャの勉強会をやっていて、社内に浸透してきた。
しかし、以前の開発手法に比べ実装に時間がかかってしまっているという感覚がある。
これは習熟すると速度は上がってくるものなのか?
また、納期が短いプロジェクトには Clean Architecture は向かないといったことはあるか?

回答:

これは見方による。
データを画面に出力するのに、アーキテクチャのことを考えずに実装すればすぐにできるだろう。するとより早く実装できているように感じる。

でもそれを10の機能について、同じように早くするはできない。
早く進めて、その後スローダウンしていくのか、継続的なスピードで何年も続けていくのか? 継続的なスピードで続けていきたいのであれば、アーキテクチャについて考えていかないといけない。

質問6:

Clean Architectureを厳密に実践するときに、静的型付け言語で実装するのは難しいと思った。
静的型付け言語で実装するには強固なライブラリを実装する必要がある考えている。

私は Java や Scala でやるときに専用のライブラリを実装しなければできなかった。
Bob さんからみて、うまくClean Architecture を実現するにはどんな言語やフレームワークを使うとよいか?

回答:

おっしゃるとおりだと思う。
静的型付け言語は Clean Architecture を複雑にする。
大きな理由がある。 type safety が、high level policy と low level detail をロックインしてしまう。
どこかの段階で type safety を放棄しなければいけない。

全てを放棄する必要は無く、1つか2つの戦略的な地点で type safety を放棄しなければいけない。
多くのデベロッパは type safety をなんとかして維持せねばという思いがある。
すると Clean Architecture を type safety な言語でやるのは難しいと感じてしまう。

しかし以下のようにやればうまくいく。
type safety を慎重に放棄する。static type safety を dynamic type safety に置き換える。
つまり boundary のところで dynamic に置き換える。

もちろん、単体テストを boundary のところでしっかりやらないといけない。
型がきちんとチェックされているか、コンパイル時ではなく実行時チェックをしないといけない。

また、言語はなにがいいか? オブジェクト指向型の特性を持っていればどの言語でもいいと思う。
Scala、F#、Java でも C#、 C++ でも大丈夫だと思う。C だとちょっと原始的かも知れない。 Ruby でも Python でも大丈夫。
私が最近使っているのは Clojure 。

とてもいい言語で、dynamic で、 非常に美しく、シンプル。

思ったこと:

Clean Architecture をシステムで徹底するには、むしろ「固く」することができる静的型付け言語のほうがよいのではと思っていました。
しかし静的型付け言語を用いるのは難しいというのは、以下のような理由によるのではと思いました。

  • 何らかのエンティティオブジェクトなどに変更が発生した場合、とたんにシステム全体のビルドが通らなくなってしまう。
  • Clean Architecture が掲げるシステムの層の切り替え可能を実現するには、 boundary で動的に結びつけるか、コンテキストによって実装クラスを変えるといった取り組みが必要なのでは、と思いました。

質問7:

Clean Architecture は、マイクロサービスアーキテクチャを実践できないようなプロダクトのために考えられた手法のように思った。
最初からマイクロサービスアーキテクチャを実践できるのであれば、Clean Architecture は、少し過剰な設計にも思える。
Clean Architecture はどのような場面で適用すべきか?

回答:

マイクロサービスはアーキテクチャではない。デプロイのメカニズムである。
マイクロサービスとは、1つのサービスが別のサービスを呼び出すこと。1つの function が別の function を呼び出すことであり、別の function は呼び出されたということを理解しないといけない。これはただの function call である。

このことから、それぞれのソフトウェアを同じアドレススペースに配置すれば、マイクロサービス(の考え方)を排除しモノリスにできる。
モノリスであれば、function が呼び出されたということを検知しなくてよい。単に関数が呼び出されただけ。

これが、まさにマイクロサービスがアーキテクチャではないことの証明であり、デプロイのための戦略である。
なのでマイクロサービスを慎重に扱わないといけない。

多くの場で、マイクロサービスがアーキテクチャであり、マイクロサービスがそれだけでとても優れていると書かれているが、そうではない。
マイクロサービスの目的はアーキテクチャではなく、スケーラビリティやセキュリティであり、そういった理由のためだけにマイクロサービスを使うべき。

つまり、マイクロサービスはサービスのデカップリング(分離)のために使うのではない。
モノリスでもサービスの分離はできるし、マイクロサービスをデカップリングのために使わないでほしい。

なぜかというと、様々な意味でコストが高い。

  • runtime のコストが高い。function call が socket 呼び出しになることで、ナノ秒であった呼び出しがミリ秒になってしまう。
  • それぞれのソフトウェアをコンパイルし、別々のところにデプロイし、メンテしなければならない。これもコストになる。
  • それぞれのサービスを、ある順番でスタート/停止しなければいけない。

ということでサービスのオーバーヘッドがとても高い。これが必要なければコストが高すぎる。
現在、マイクロサービスへの熱意が高すぎて、それにより非常に複雑すぎるシステムが作られていると思っている。
マイクロサービスは慎重に扱ってほしい。

おわりに

講演の中で取り上げられた質問は時間の関係で上記の7件でしたが、夜遅くにもかかわらず多くの参加者から質問があり、かつどの質問も高度なもので驚きました。
みなさんの Clean Architecture への関心が高いことの表れだと思います。

また Martin 氏の回答も実践的なもので、今後 Clean Architecture を採用するかどうかに役立てられるお話を聞くことができたと思います。
特に「可能な限り決定を先送りする」の所は、多くの方から頷きの声がありました。

なお今日から1週間の期間限定でアーカイブ動画をBuilders Boxの会員サイト上で閲覧できます。こちらのWebサイトから会員登録の上、ぜひ貴重な講演をご覧ください。

© Sansan, Inc.