Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

リモートワーク大時代に来るアーキテクチャ、それは疎結合

なんかタイトルでデカく出てしまったけど、リモートだと疎結合なアーキテクチャのがうまくいくね、という経験をしたという話。特にオチはないです。ソフトウェア設計が好きな皆様のおやつとして読んでください。

COVID-19でリモートワークが拡大した

特に言うまでもないけど、COVID-19の世界的な大流行によって人々は核戦争もかくやと言わんばかりの厳重な暮らしをするようになった。まぁ最近はその気配も薄れてそれなりに出歩くようになったが、それでもマスクを完全に手放す日は当分やってこないだろう。

自分が働いているはてなでも昨年からリモートワークへの比重をどんどん増やしていて、今はフルリモートで全国どこからでも勤務できる状況が構築された。

はてな、働き方制度をアップデート。働く時間や場所に捉われないフレキシブルワークを推進 - プレスリリース - 株式会社はてな

実際リモート勤務はかなり定着していて、自分も今はほぼリモートで勤務しているし、チームの過半数はリモートで家から勤務している*1。全体で見てもリモートの比率はかなり高いのではないかと思う。 家の回線がへぼくてDocker Imageを拾ってくる間にTwitterを見ることになるのを除けば、在宅勤務は快適だ。

最近やったプロジェクトで意図的に疎結合なアーキテクチャを採択した

そんな中、とあるプロジェクトで僕がアーキテクトをやる機会をもらった。極めておおざっぱに表現すると、あるデータを処理して別のデータに変換するというものだ。後述する通り、自分はそれを意図的に疎に設計し、Cloud Functionsなどを組み合わせる形式とした。

設計と実装はうまくいった。PoCもうまく動作したし、実装の進捗が良かったのでチームはアーキテクチャを高く評価してくれた。

もちろんアーキテクチャが全ての進捗を左右するというわけではない。進捗はチームメンバーの実装のおかげでもある。

しかし、アーキテクチャに関係する範囲では、間違いなく疎結合アーキテクチャが全体の進捗に好影響を及ぼしていた。この記事はその分析と考察である。 といってもたいして深い話はできてませんが・・・

疎結合の意図

ざっくりアーキテクチャを紹介すると、Google Workflowsを使って複数のCloud Functions(や、Cloud Runなど)を呼ぶような構成でデータを処理するといった感じで、それぞれのCloud Functionsは互いに独立している。

だいたいこんな感じ

Workflowsは別途用意したNext.jsフロントエンドからキックされるという感じで運用される。

このように疎結合にした意図はいくつかあった。

まず、利用する技術の都合(MLを使うのでPythonを使わなければならない)で言語を統一できないこと。

次に、ML技術を使うので一部のコンポーネントに限って極端なGPUワークロードが発生すること。

そしてチームのエンジニアは完全にフルリモートであること(1人だけ出社しているが、それは全員がフルリモートなのと同じである。)。

最後に、チームのエンジニアが3人と少人数なので各自が意思決定しやすい形にしたかったことである。

とはいえ全て勝手にやらせるとアーキテクトの意味がないので、おおまかなアーキテクチャとコンポーネント間の接続インターフェイスを自分が用意して、各コンポーネントはタスクとして配って各自にヨロシクするという形をとった。

ノーコンフリクトで快適だった。3人を超えるとどうなるかは不明

このような疎結合なアーキテクチャによって、リモートワークしているメンバー同士が常に別のコンポーネントをいじることになった。GitHub上でのコンフリクトがほぼ発生せずにスムーズに開発が進んだ。

ディレクトリ構成そのものはモノレポで、1つの大きなリポジトリにコンポーネントごとのディレクトリが切られており、そこで世界観が完結する(Prismaのスキーマを除いてほぼ共有しない)という形にした。本当はDBスキーマも隔離したかった(そういうの専門のAPIを立てるのが本筋と思う)。

考察: 今回は手を動かすのが3人だった。これより増やしてもスケールするだろうか?

人数が増えるということはおそらくコンポーネントも相応に増える状態になっているはずである。そうしなければ意思決定の速度が落ちることになるためだ。もしコンポーネント数を増やせない状態であれば、意思決定のためのコストが急に発生してくるのでたぶん速度はすぐ落ちると思う。意思決定の速度が開発速度を律速しているような気もする。

コンポーネントごとにビルドする

コンポーネントのビルドの側面に注目してみる。疎結合なアーキテクチャを採用したことで、各コンポーネントのライフサイクルはほぼ完全に独立したものとなった。つまり、どのコンポーネントも基本的にいつでも自由にビルドしてデプロイして良いということである。

この特性は、ビルドやデプロイに特段の調整が不要であるという好ましい状態を生み出した。すると不要になった調整時間がそのまま設計と実装の時間に転化し、エンジニアは開発に集中的に取り組むことができるようになった。

注意点として、今回はCloud Functionsなどのフルマネージドサービスを全体的に利用したことで、デプロイ直前の変なタイミングにリクエストが起動してしまい取りこぼす、といったことを防ぐコストを外部に転嫁しているという点がある。自前でやっている場合はもう少し気を付けるポイントが増えていたと思う。

疎結合はリモート時代に適したアーキテクチャなんですかね?

既に何度も巷で議論されていることと思うが、リモートワークだと同期的なコミュニケーションが比較的難しくなる。これが全地球規模で行なわれる場合、同期的なコミュニケーションは根本的に不可能だ。疎結合な場合、コミュニケーションの頻度を下げられる。

また、テキストベースのコミュニケーションが増えるというのもリモートワークの特長である。自分のチームではMeetなどで昼会を実施するなどしていたが、基本的に普段はSlack上でのテキストコミュニケーションを行った。

同期的なコミュニケーションが困難であることとも関連するが、リモートワークだと一斉同報してコミュニケーションをとることが難しい。オフィスであればその場に集合して一気に意思疎通を行えるが、リモートだと難しい。これは同時にコミュニケーションパスの増加という問題も引き起こす。これまでは同時に言っておけばよかったのに、個別に連絡する必要が生じる可能性があるからだ。

こうしたコミュニケーションパスの問題によって、疎結合が必然的に導き出されるのかもしれない。有名な話題としてコンウェイの法則というのがある。

コンウェイの法則: システム設計(アーキテクチャ)は、組織構造を反映させたものになる

今回もひょっとするとコンウェイの法則が発動してこういう結果になったのかもしれない。

とはいえ時代はリモート大時代なのだから、現行の組織構造がどうあれ、リモート時代であれば意図的に疎結合アーキテクチャを採択したほうがスムーズなのでは?(逆コンウェイ)という気もしている。これはさすがに強い仮定すぎる?

今回は既存のプロジェクトをどうこうする話ではなく、新規に何かを作るという感じのプロジェクトだったので、ステークホルダーがきわめて少なかったというのも考慮しないといけない。既に動いているプロダクトをどうこうする場合、疎結合なシステムだとどのくらい楽、あるいは困難なのかは、未だ経験したことがない領域だ。

「ほかの」疎結合を選べるか?

今回は完全にディレクトリを隔離した強い疎結合を選んだが、モジュールとしては同一で内部でパッケージなどを分ける、という、やや弱い疎結合(?)だとどうなるだろう?

モジュールとしては同じなので、つまりビルドのライフサイクルは同一になってしまう。これだとCI/CDの運用が面倒なことにならないだろうか。かえって考えることが増えてしまうのではないか、という気もする。

まとめ

  • リモートワーク環境で疎結合なプロダクトを書いた
  • 3人チームでは意思決定と実装が爆速で進められてうまくいった
  • 再現性があるかはわからない。変数がたくさんある

マイクロサービス素人なので、そういう本をたくさん読みたいね、と思いました。

*1:厳密に計測したわけではない

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?