今年10月に出版された『Microservices Patterns With examples in Java』という本を読んだ。面白かったので紹介したい。
はじめに
著者は、マイクロサービスパターンのサイト microservice.io を運営している Chris Richardson という人。Cloud Foundry の創設者でもあり、最近では Eventuate というマイクロサービス用のプラットフォームを提供してるらしい。コンサル経験も豊富らしく、本の中でもそこで得られた知見が盛り込まれている。
microservice.io でもマイクロサービスパターンはカタログ化されているが、この本ではサンプル事例で肉付けされて具体的に解説される。関連するトピックも豊富で勉強になる。
ここが面白い
問題領域のカタログとして役立つ
初心者が考えるマイクロサービスのイメージといえば、その人の得意分野によってけっこう偏りがちなのではないだろうか。
例えばドメインモデリングに関心が高い人は、サブドメインによるサービス分割や、マイクロサービス間を Domain Event で連携する手法などをまず思い浮かべる一方で、インフラ周りの検討事項が抜けているかもしれない。
一方で、インフラに強い人はサービスメッシュやサーバレス技術の活用については、最新トレンドを踏まえつつ上手く構想できるのに、アプリケーション層やドメインモデルの課題についてはピンと来ていないかもしれない。
またアプリケーション層とインフラ層の両方について見識のある人でも、自動化テストやリファクタの問題については意識が薄いかもしれない。
こんな風に、マイクロサービスをやるに当たっては、考慮すべき検討事項が様々な層や局面に及ぶので、解決策のカタログ以前に、そもそもの問題領域の一覧にも需要があると思う。この本は「それ考えてなかったわー」からの後の祭り状態を予防するのに、かなり効果がありそうに見える。
もちろんソリューションのカタログとしても役立つ
マイクロサービスの開発初期に悩むような素朴な疑問への解答は、大体載ってる気がする。
特に有名なパターンについては、具体的な実装法、そのバリエーション、活用のための注意点などについても丁寧に解説されていて、聞いたことはあるが詳細までは分からないといった人にも役に立つと思う。同じ問題への解として複数のパターンがある場合にも、それぞれのメリット・デメットや選択の勘所などがよく書かれている。
ドメイン駆動設計の関連本としても面白い
マイクロサービスもドメイン駆動設計も、複雑性への対処という目的が根底にあるので、もともと親和性が高い。実際、DDD からの応用パターンも多く、DDD の知見をさらに深めたい人にもきっと面白く読めるのではと思う。
というわけで以下、パターン言語としての形式にはこだわらず、パターン一つにつき1・2ツイートくらいの文量で要約してみる。章ごとにではなく、問題領域でくくって構成してみた。10% くらい主観が入るかもしれない。
アーキテクチャの問題領域
モノリスか?マイクロサービスか?
この問題領域では、アーキテクチャに関する一般論、マイクロサービスと SOAとの比較、ヘキサゴナルを題材にしたレイヤード・アーキテクチャについての解説などから始まる。
《関連キーワード》: The 4+1 View Model of Software Architecture, アーキテクチャスタイルの定義, Layered Architectural Style, Hexagonal Architecture Style, Loose Coupling
Monolithic Architecture
単一のコンポーネントでアプリケーションを構成するパターン。いわゆるモノリス。
これはこれでアーキテクチャの一つのあり方であって、それなりの長所もあるし、実際うまく動いている事例もあるが、年月を経るうち様々な理由でモノリス地獄になりがち。
Microservice Architecture
独立してデプロイ可能なマイクロサービス群により、粗結合なアプリケーションを構成するパターン。
「マイクロ」と言ってもサイズ自体は本質的に重要ではなく、小規模チーム+最短リードタイム+最小チーム間連携コストで開発できれば、それがちょうど良いのだという。
決して銀の弾丸ではないし、それどころか複雑度が増大したり、自明でない設計判断や要考慮ポイントが多かったり、素朴にイメージするよりも難度が高いが、モノリス地獄克服のための一つの選択肢にはなりうる。
《関連キーワード》: The Scale Cube, 逆コンウェイ戦略, Process- Organization-Architecture の三角形
Database per Service
マイクロサービスがプライベートなデータストアを各々持つパターン。他の多くのパターンがこの Database per Service を前提にしたり、あるいはこのパターンから出てくる課題を補う形で、問題領域への解を構成する。これと逆に、各サービスがデータベースを共有するのが Shared Database パターンで、SOA ではこれが多く採用されていたらしい。
サービス分割の問題領域
どんな切り口でマイクロサービスに分割するか?
Decompose by Business Capability
ビジネス・ケイパビリティ単位でサービスを分割するパターン。
「ビジネス・ケイパビリティ」はビジネス・アーキテクチャ・モデリングの用語で、ビジネスの構成要素を、移ろいやすい how ではなく、比較的安定した what で捉えたもの。例えば小切手の入金なら、窓口に出向くとか、ATMを使うとか、スマホで処理するといった how にかかわらず「小切手入金」という what は変わらない。これをビジネスケイパビリティとして把握する。
ビジネスケイパビリティは階層を成すが、階層のどのレベルでサービスにするかについては、微妙な設計判断になるという。
Decompose by Subdomain
DDD のサブドメイン単位でマイクロサービスを分割するパターン。
サンプル事例を見ると、ビジネス・ケイパビリティによる分割と結果的にはあまり変わらないらしい。入り口の観点は違っても、うまく分割できれば似たような形に落ち着くのかもしれない。すでに DDD の知見があるならサブドメイン分割で良いのではないだろうか。この本でも "DDD and the microservice architecture are in almost perfect alignment." という形で称揚している。
《関連キーワード》: Ubiquitous Language, Bounded Contexts, SRP: Single Responsibility Principle, CCP: Common Closure Principle
メッセージングスタイルの問題領域
同期か?非同期か?
この問題領域では、プロセス間通信のパターンの紹介に先立って、メッセージフォーマットやインタラクションスタイルといった基礎知識についても解説される。
《関連キーワード》: API-first design, Semantic Versioning, ロバストネス原則, Protocol Buffers, Avro, XML schema, JSON Schema
Remote Procedure Invocation
REST や gRPC などを使って同期でリモート呼び出しするパターン。
《関連キーワード》: REST 成熟モデル, HATEOAS, Open API / Swagger, RPC
Messaging
サービス宛のメッセージをクライアントが非同期でポストするパターン。メッセージブローカを使うブローカベースと、使わないブローカレスの2タイプがある。
《関連キーワード》: message, channels, point-to-point, publish-subscribe, ZeroMQ, ActiveMQ, RabbitMQ, Apache Kafka, AWS SQS
信頼性の問題領域
マイクロサービスで構成されたシステムの信頼性(Reliability)をどう担保するか?
Circuit Breaker
同期リクエストの先で一部のマイクロサービスに障害があると、クライアントやその先の「クライアントのクライアント」までブロッキングが波及することになりかねない。
この問題を、クライアントと実サービスの間に Circuit Breaker と呼ばれるプロキシを介在させて、実サービスの呼び出し失敗が一定基準を超えると、クライアントからのリクエストを即座にリジェクトさせて、ブロッキング連鎖を解消するパターン。
《関連キーワード》: Netflix Hystrix、.NET Polly
サービス・ディスカバリーの問題領域
サービスのネットワークロケーションをクライアント(API Gateway や他のサービス)が、どうやって見つけるか?
Service Registry
サービスのインスタンスとネットワークロケーションの対応付けをデータベースに登録するパターン。Health Check などの機能を持つこともある。
《関連キーワード》: Netflix Eureka
Self Registration
サービス自身がサービスレジストリに登録するパターン。次の Client-Side Discovery パターンと併用して Application-Level Service Discovery を構成する。
《関連キーワード》: Netflix Eureka
Client-Side Discovery
クライアントがサービスレジストリを検索して使用可能なインスタンスのリストを受け取るパターン。ロードバランスやキャッシュなどの機能も考慮すべきポイントになる。
3rd party Registration
デプロイメントプラットフォームがサービスを自動的に登録するパターン。次の Server-side discovery パターンと併用して Platform-Provided Service Discovery を構成する。
Server-Side Discovery
デプロイメントプラットフォームが提供するルーターに、クライアントがサービスのインスタンスを問い合わせるパターン。負荷分散などもデプロイメントプラットフォームが行う。
トランザクショナル・メッセージングの問題領域
非同期メッセージを、DBトランザクションの一環として発行するにはどうするか?(つまりトランザクション失敗時にはメッセージが発行されないようにしたい)
Transactional Outbox
トランザクションの中で、DB内のメッセージキューに見立てた "OUTBOX" テーブルにメッセージを入れるパターン。MessageRelay と呼ばれるコンポーネントが OUTBOX からメッセージを読み出して、メッセージブローカーに発行する。OUTBOX の読み方の違いで、次の2つのパターンがある。
Polling Publisher
MessageRelay が、OUTBOX を定期ポーリングしてメッセージを発行するパターン。パフォーマンスや負荷の面で望ましくない場合もある。
Transaction Log Tailing
MessageRelay(ここでは Transaction Log Miner と呼ばれる)が、OUTBOX テーブルのトランザクションログを tail してメッセージを発行するパターン。Polling Publisher に比べて洗練された手法とされている反面、DB製品ごとに異なる低レベルコードを書くなどの複雑さを導入することにもなりうる。
《関連キーワード》: Debezium, LinkedIn Databus, DynamoDB streams, Eventuate Tram
データ整合性の問題領域
複数マイクロサービスにわたるワークフローのデータ整合性をどうするか?
モダンなウェブ系システムには、XA/2PC等の分散トランザクションは適さない事がまず説明される。下の Saga だけではなく他のパターンでもこれが前提となる。
Saga
各マイクロサービスのローカルトランザクションを、非同期メッセージングでつなげてフローを構成するパターン。下記のようなポイントについて詳説される。
- シンプルなフローに向いたコリオグラフィー型と、複雑なフローにも耐えうるオーケストレーション型
- ローカルトランザクションの3種類: Compensatable、Pivot、Retriable
- Compensation(補償)メッセージの扱い
- ACID から Isolation がとれて ACD になるために生じる不整合と解決策
- 不整合: Lost updates, Dirty reads, Fuzzy/nonrepeatable reads
-
解決策: Semantic lock
, Commutative updates, Pessimistic view, Reread value, Version file, By value
※ 考慮点も多く技術的にも面白い章なので、別途記事を書いた。
《関連キーワード》: Optimistic Offline Lock
ビジネスロジックデザインの問題領域
ビジネスロジックはどう構成するか?
PoEAA や DDD からの引用パターンが、マイクロサービスとの兼ね合いも含めて改めて解説される。
Aggregate
一群のオブジェクトのグラフである Aggregate を整合性の境界とするパターン。DDD の Building Blocks パターン群の中では特に重要なもので、「ガチ DDD 勢以外には無視されがち(意訳)」だけど「Aggregate の識別こそがドメインモデリングの鍵(意訳)」という記述もある。
トランザクション単位としても重要で、モノリスな開発では 1トランザクション内で複数 Aggregate 更新するようなゆるい DDD もありがちだったが、各サービスのローカルトランザクションをつなげてフローを構成するマイクロサービスアーキテクチャでは、「1Aggregate :1トランザクション」が必須のルールとなる。ちなみに今年流行った Robert C. Martin の『Clean Architecture』でも「ソフトウェアアーキテクチャとは、境界線を引く技芸である。」という一文があった。
Domain Event
Aggregate が生成・変更された時に非同期メッセージを発行する DDD のパターン。この Domain Event を介して各サービスのローカルトランザクションが連携することで、Saga が組み立てられる。本書では関連して、イベントに着目したモデリング・ワークショップである Event Storming も紹介されている。
Domain Model
ビジネスロジックを、状態とふるまいを持つクラス群から成る、オブジェクト指向的なドメインモデルで構成するパターン。もともと PoEAA で、Transaction Script と対比されていた。
本書の記述はサンプルコードも Java + Spring で、どっぷりとオブジェクト指向ベースだけど、最近では以前紹介したような関数型ドメインモデリングもある(個人的にはそちらが好ましい)。
Event Sourcing
Aggregate の永続化を Domain Event のシーケンスとして表現するパターン。Saga や CQRS と併用したり、Audit Logging としても使える。長くなるイベントシーケンスについては中間状態のスナップショットを定期的に取るなどの、実用的なテクニックも紹介されている。
《関連キーワード》: Event Store, Lagom, Axon, Eventuate
Transaction Script
各リクエストごとに、ビジネスロジックを手続き型のトランザクションスクリプトで構成するパターン。
アンチパターンとして捉えられていることが多いが、もともとの PoEAA の記述でも複雑なドメインに適用するのはは止めましょうと言ってるのであって、決して全否定ではなかった。特に、Serverless で実行されるような充分に小さなマイクロサービスなら、むしろトランザクションスクリプトが適した場面もあるかもしれない。
クエリーの問題領域
複数のマイクロサービスにまたがるデータ取得をどうするか?
API Composition
API Composer というコンポーネントが、複数サービスへのアクセスと、そのレスポンスの組み立てを行うパターン。API Gateway に API Composer の役割を持たせてもよいし、専用のコンポーネントで実装してもよい。シンプルに実装できる反面、オンメモリでの join のため負荷が増大したり、可用性が低下したりといった問題もある。
CQRS (Command Query Responsibility Segregation)
コマンドサイドとクエリサイドで、別々にモデルとデータストアを用意して、イベントハンドラで同期するパターン。関心事の分離という一般的な利点の他に、マイクロサービス環境では分散クエリがやりやすくなるというメリットがある。本書では、クエリサイド・データストアのプロダクト選定のポイントや、ビュー(クエリサイドのモデル)の追加・変更の方法・考慮点などが解説されている。
外部 API の問題領域
外部クライアントからのアクセスの受口をどのように作るか?
外部APIクライアントの種類としては、Web アプリケーション、ブラウザ上の JavaScript アプリ、モバイル端末のアプリ、公開APIの利用者などがある。これらがシステム内の個々のマイクロサービスにアクセスしていると、パフォーマンスやUXの面から、また内部構成への依存による柔軟性低下などからも問題がある。以下、これを解消するためのパターン群。
API Gateway
システムの入り口に、API Gateway と呼ばれる GoF の Facade のような専用コンポーネントを置くパターン。リクエストルーティング、API Composition(上述)、プロトコル変換、クライアント専用API、エッジファンクションといった機能を提供する。
どのチームがこれを開発するかという問題も議論されていて興味深い。API Gateway チームがすべて開発する案と、中のモジュールを API Gateway チームと外部APIクライアントチーム各々で分担する案(Netflix案)があり、後者が推薦されている。これをさらに進化させたバリエーションとして、下の Backends for Front-Ends パターンがある。
《関連キーワード》: Facade パターン, edge function, Zuul, AWS API Gateway, AWS ELB Application Load Balancer, Kong, Traefik, Spring Cloud Gateway, GraphQL
Backends for Front-Ends
各外部APIクライアントのために、それぞれ専用の API Gateway を置くパターン。Phil Calçado という人が発案。
《関連キーワード》: Netflix Falcor
自動化テストの問題領域
どうやってマイクロサービスをテストするか?
サービスのサイズが小さくなることにより、単品としてのテストはシンプルになる一方、サービス間の協調のテストが困難かつ重要になってくる。またデプロイメント・パイプラインに組み込むためにも、「自動化」は必須になる。そのためのテストパターンが紹介される。
ここで自動化の重要性について "absolutely essential" として特に強調されていて、「自分のコンサルティング経験上、テスト自動化について無知な人が多すぎるので、マイクロサービスと直接には関係ないけど基礎から解説しとく(意訳)」ということで、自動化テストそのものの説明に一つの章をほぼ丸ごと使っている。なのでこの自動化テストパターンの記述だけ分量が多く、Part 1・2と2つの章にまたがっている。
ちなみに「自動化テストこそがリードタイムを短くする唯一の方法」、「モノリス地獄に至る一番の早道は自動化テストを書かないこと」とも書かれており、『レガシーコード改善ガイド』にある「レガシーコードとは単にテストのないコードです(中略)これが本書を通じて詳しく述べていきたい核心です。」というフレーズを彷彿させて興味深い。
《関連キーワード》: テストピラミッド, テストの4象限, テストケース, 自動化テストの4フェーズ, Solitary unit test /Sociable unit test
Consumer-Driven Contract Test
サービスが「契約」を満たしている事のテストを、コンシューマ(サービスを使う側)開発者が書いて、サービスのコードベースにコントリビュートするパターン。マージされたテストは、サービスのデプロイメントパイプラインの中で実行される。網羅的なテストではなく、ヘッダの構成やメッセージの形式など "shape" をテストするとよいと言う。
《関連キーワード》: Spring Cloud Contract, Pact Foundation, contract test, deployment pipeline, Solitary unit test /Sociable unit test
Consumer-Side Contract Test
クライアントがサービスの仕様に従っている事を、スタブを使ってテストするパターン。上の Consumer-Driven Contract Test とともに contract test を構成する。
Service Component Test
Integration Test と E2E (End-to-End) の中間層の位置づけで、サービス単品の受け入れテストを書くパターン。実用上、正味の E2E よりはるかにコスパが良いという。
《関連キーワード》: Gherkin, user journey test
セキュリティの問題領域
どうやってセキュアなマイクロサービスを構築するか?
セキュリティ施策はモノリスにおけるそれと共通点が多いが、サービス間でのユーザの識別情報受け渡しなどは、マイクロサービスらしいものになる。
Access Token
外部からのリクエストに API Gateway が介在して、ユーザの識別情報やロールを含むトークンを、その先のマイクロサービスに渡すパターン。
《関連キーワード》: Authentication, Authrization, Audit, Secure interprocess communication, opaque token / transparent token, JWT, Spring Security, Apache Shiro, Passport, OAuth 2.0
横断的関心事の問題領域
マイクロサービスアーキテクチャの横断的関心事 (cross-cutting concern) にどう対処するか? 横断的関心事には、セキュリティ、監視、サービスディスカバリー、信頼性などがある。
Externalized Configuration
環境ごとの設定情報(DB接続など)を、実行時に外部からサービスに与えるパターン。環境変数などで与える push 型と、コンフィグレーションサーバに設定する pull 型がある。
《関連キーワード》: Spring Cloud Config Server, Hashicorp Vault, AWS Systems Manager Parameter Store
Microservice Chassis
横断的関心事をサポートする既成のフレームワークの上に、マイクロサービスを構築するパターン。
言語に依存することが欠点にもなりうると指摘されている。
《関連キーワード》: Spring Boot/Spring Cloud, Go Kit, Micro
監視の問題領域
マイクロサービスのロギングとモニタリングをどう実装するか?
Health check API
生存確認用のエンドポイントをサービスに持たせるパターン。エンドポイントの実装方式と、デプロイ先インフラからの呼び出し方式の、2つのポイントが解説されている。
《関連キーワード》: Spring Boot Actuator, HealthChecks .NET, Netflix Eureka, Docker, Kubernetes
Log Aggregation
全てのサービスのログを、検索機能やアラート機能を持つロギングサーバに集中するパターン。
《関連キーワード》: ELKスタック (Elasticsearch, Logstash, Kibana), Fluentd, Apach Flume, AWS CloudWatch Logs
Distributed Tracing
外部からのリクエストにユニークIDをふって、複数マイクロサービス間にわたるワークフローのログ出力を、可視化・分析機能を持った分散トレーシングサーバに集めるパターン。
《関連キーワード》: B3 standard, Spring Cloud Sleuth, Open Zipkin, AWS X-Ray
Application Metrics
アプリケーションの各種メトリクスを、集約、可視化、アラート機能をもったメトリクスサービスに集めるパターン。push モデルと pull モデルがある。
《関連キーワード》: AWS Cloudwatch, Prometheus, Grafana
Exception Tracking
例外ログを、重複除去や対応状況管理などの機能を持つ例外トラッキング用のサービスに、レポートするパターン。
《関連キーワード》: Honeybadger, Sentry
Audit Logging
カスタマーサポートやコンプライアンスなどの目的で、ユーザの挙動に着目してロギングするパターン。ビジネスロジックへのハードコードや AOP のような従来の方式に加えて、EventSourcing を活用する方式もある。
デプロイの問題領域
どうやってマイクロサービスをデプロイするか?
Language-Specific Packaging Format
言語特有のパッケージング単位で、ホスト上のアプリケーションサーバなどに複数のサービスをデプロイするパターン。あるサービスが同居する別のサービスに悪影響を与える状況を防止できないなどの難点がある。
《関連キーワード》: JAR/WAR/EAR, WebSphere, WebLogic, Tomcat, Jetty, OSGI
Single Service per Host
ホスト上で一つのサービスだけを稼働させるパターン。ホストが VM か コンテナかで、下記の2つのサブパターンに分けられる。Language-specific packaging format の欠点であった、サービスの独立性の問題などはこのサブパターンで解消される。
Deploy a Service as a VM
Single Service per Host の一つで、サービスを VMイメージにパッケージングしてデプロイするパターン。パブリッククラウドに親和性が高いなどの利点がある一方、デプロイにかかる時間や、管理タスクの負荷などの難点が残る。
《関連キーワード》: EC2 AMI, Digital Ocean, Virtual Box, VMware, Netflix Aminator, Packer
Deploy a Service as a Container
Single Service per Host の一つで、サービスをコンテナイメージにパッケージングして、コンテナランタイムにデプロイするパターン。Deploy a service as a VM の利点に加えて、さらにビルドもデプロイも速いというメリットがある。
《関連キーワード》: Docker, Solaris Zones, AWS ECR, Kubernetes, Istio
Sidecar
横断的関心事を、サービスと並走する「サイドカー」コンテナーで実装するパターン。コンテナデザインパターンでも言及されていた。
《関連キーワード》: Istio Envoy
Serverless Deployment
パブリッククラウドが提供するサーバーレス技術を使って、サービスをデプロイするパターン。上述の
Language-Specific Packaging Format、Deploy a Service as a VM、Deploy a Service as a Container のいずれも、プロビジョニングやOS・言語環境の管理などが、開発チームの責務としてまだ残っていたが、Serverless ではこれらの作業から開放される。
用途を選ぶ面がかなりあるが、デプロイ方式を検討する際には、Serverless → Container → VM → 言語依存パッケージの順がよいという。
《関連キーワード》: AWS Lambda, AWS API Gateway, Google Cloud functions, Microsoft Azure Functions, Apache Openwhisk, Fission for Kubernetes, Serverless
Service Deployment Platform
パッケージのデプロイ先に自動化されたデプロイインフラを使うパターン。Single Service per Host, Serverless Deployment で利用される。サービスディスカバリーのパターンに相当する機能が提供されることもある。
《関連キーワード》: Docker, Kubernetes, AWS Lambda, Cloud Foundry, AWS Elastic Beanstalk
Service Mesh
横断的関心事のうちインフラ/ネットワーク層に当たる部分を Service Mesh に任せるパターン。通信の秘匿という意味ではセキュリティの問題領域への解でもあり、「デプロイとリリースの分離」に使えるという意味ではデプロイの問題領域への解でもある。Microservice Chassis の担っていた責務のうち、インフラ層でできることをこちらに移管することで、Microservice Chassis の扱いをシンプルする効果もある。
《関連キーワード》: Istio, Linkerd, Conduit
リファクタリングの問題領域
どうやってモノリスからマイクロサービスにリファクタするか?
《関連キーワード》: The Law of Holes
Strangler Application
モノリスの周囲にインクリメンタルにマイクロサービスを作って、徐々にモノリスの機能を吸収していくパターン。(1) 新規機能をマイクロサービスとして作る戦略、(2) フロントエンドを切り離す戦略、(3) 既存機能を切り出してマイクロサービスとする戦略のそれぞれについて解説されている。
特に(3)については、そもそもモノリスの中身は "messy" な状態であることが多く、ふつうは困難な作業になるので、労力に見合う価値があるかよく吟味すべしとある。具体的なタスクとしては、ドメインモデルの分割と、データベースのリファクタが含まれるが、後者については Scott Ambler の『Refactoring Databases』を参考に、徐々に新スキーマに移行する手法などが紹介されている。
ここでもやはり、ちょっとずつインクリメンタルというのが重要らしく、“the only thing a Big Bang rewrite guarantees is a Big Bang!”という Martin Fowler の言葉が紹介され、Big Bang Rewrite は厳に戒められている。また Amazon.com が 2年かけてモノリスを小さなサービス群に分割した逸話も紹介されている。
Anti-Corruption Layer
切り出した新設マイクロサービスと元のモノリスの間に防腐レイヤーを挟んで、洗練させた新モデルと旧モデルの差分を吸収するパターン。よく知られた DDD のパターンの応用。
おわりに
当然ながら、やはり考えておかなければいけない観点が多い。自分でも得意な分野と不勉強な分野でムラが大きすぎるのを自覚する。ただ、一人で全てのエキスパートになる必要はないはずで、最低限、この本に書いてる程度のポイントは留意しておいた上で、あとはメンバー間で補い合ったり、「学習しながら実行する」アプローチで進めたり、普通にチーム力で対処していけばいいと思う。たぶん、Netflix や Amazon もそうやってきたのではなかろうか。