2023/10/18に開かれたOutSystems User Group TokyoのイベントOutSystems Connect: LTで繋がる技術者の夜!で行ったLTの内容にちょっと追記したもの。
要旨
ODCでは、O11からプラットフォームのアーキテクチャが変更されたため、ほぼマイクロサービス設計が強制される。
マイクロサービスの恩恵がいらない組織であっても。
(さほど複雑でないシステムはマイクロサービス化の恩恵を受けられないとよく言われる)
ODCの製品としてマイクロサービス化にあたって必要な手間を減らしてくれたとしても、依然としてマイクロサービスであることによる設計上の制約や困難がある。
そうした影響を軽減するために、開発標準や設計ガイドラインの整備が必要。
アーキテクチャ設計に関連するODCの変更点
変更点①ModuleはAppとLibraryの2種類に整理された
- OutSystems11ではモジュールは、Reactive Web App/Traditional Web/Mobile/Service/Library/Extensionなどがあったが、ODCではAppとLibraryに整理された
- App: OutSystems 11でいうEnd Userレイヤーモジュールに相当するものApp。App単位でコンテナに分離される
- Library: OutSystems11のFoundation Layerのモジュールに相当するものがLibrary。 Entityを含むことはできない。Libraryはコンテナにはならず、コンパイルされたものはLibraryを参照するAppのコンテナ内に格納される
- よってO11のCore Serviceモジュールに対応するものは必然的にAppになる
変更点②Applicationがない
- O11で複数のモジュールの入れ物であり、リリースの単位であったApplicationが無くなった
- リリースは1App単位ずつ行う
- 開発環境でPublishをした段階でコンテナが準備されレジストリに登録されている。リリースはそのコンテナをコピーするだけなので高速
変更点③Appは弱い参照のみ公開できる
- Appが公開する要素への参照はすべて弱い参照になり、実行時にはHTTPS通信を介して行われる
- Libraryが公開する要素を参照すると強い参照になり、呼び出しはメモリ内で行われる
まとめると
UIを提供するのはApp
O11でいうCore Serviceのように、Entityを持ってActionを外部に提供するものもApp
1つのAppは1つのコンテナに分離される
⇒UIやサービスを提供するコンテナをAppとして作っていく
Appがマイクロサービスに該当する
ODCでのアーキテクチャ設計で注意する点
アーキテクチャ設計の注意点①Architecture Canvasはそのままでは適用できない
恐らく、多くのOutSystems導入企業で、OutSystemsが提供していたArchitecture Canvasを利用したアーキテクチャ設計を標準やガイドとして採用しているのではないか。
- 現状、公式ドキュメントやコースを見る限り、Architecture Canvasは利用されない
- ODCに合わせた設計ルールを確立する必要がある
- ただし、公式ドキュメントやコースには、ODC向けの設計手順の解説はあるので、これを元に開発標準や設計ガイドラインを修正(まだなければ作成)することになる
- 基本的な流れやバリデーションルールは共通する部分が多い
アーキテクチャ設計の注意点②Roleの配置
ODCでは、RoleをPublicにできない。
- Roleを一か所で定義して各Appで共有する、ということができない
- では、どうするかというと
- RoleをService Actionとして提供する(User Idを受け取って、RoleがGrantされているかどうかを返す)
- 同名のRoleを必要な全てのAppに作成し、必要なユーザーにはその全てのAppのRoleを割り当てる
- OutSystemsが公式の動画で進めているのは後者(Service ActionはHTTPS経由でアクセスすることになるため、オーバーヘッドがあるから)
アーキテクチャ設計の注意点③UIの配置
マイクロサービスアーキテクチャではあるが、マイクロサービス毎にUIの一部(OutSystemsではBlock)を作成し、ページ内に組み上げる方法(よく言われるマイクロフロントエンド)はOutSystemsではとりにくい。Blockの組み込みはPublishの段階で決まってしまうため、Blockを変更したり新たにページを組み込もうと思うと、親画面のリリースが必要になるため。
開発規模に応じ、以下のような構成になるのではないか
- シングルApp構成:1つのApp内に全てのUIを詰め込む
- モノリシックUI:複雑になったので機能を別のサービスに切り出すが、UIは1Appに収める
- ページ単位のマイクロフロントエンド:システムのメニューはLibrary内のBlockとして定義。メニューの一部(例えばトップレベルのメニュー)ごとに異なるAppを割り当てる
アーキテクチャ設計の注意点④サービスをまたがるトランザクション
ここが、ODCがマイクロサービスを強制することによる問題点のうち、最大のものだと思う。
App間のI/FはHTTPS通信になる→トランザクションも当然別になる
- UIからのリクエストで始まった一連の処理が複数のService Actionを読んでいる場合(下図①②③)
- ある処理中に例外が発生すると、「そのサービスだけ」ロールバックされる(下図③)
- それ以前に呼ばれていたService Actionの処理はコミットされたまま(下図②)
こういった問題に対応するのがSaga
- Sagaというのは、複数のサービスにまたがるトランザクションを、ローカルトランザクションのつながりとして実現する方法
- あるローカルトランザクションでエラーが発生したら、それより前にコミット済みの処理に対して、逆の処理を行うことで取り消す
- よくあるSagaの説明では、ローカルトランザクションの連鎖にはMessage Brokerを使う(1つのローカルトランザクションが終わったら、対応するMessageを発行し、次のトランザクションはそれに反応する)
- OutSystemsの公式動画では、UIから直接呼ばれるServer Actionが各Service Actionの実行と(エラーの場合の)コミット済みトランザクションの取り消しを行うパターンが紹介されていた。Sagaの実装方法としてはお手軽だが、OutSystems開発としてはだいぶ負荷が高い