[OutSystems]Architecture Specialization (ODC)のサンプル問題について解説 2/2 (#6-#10)

Architecture Specialization (ODC)はODC向けのアーキテクチャ知識を認定する試験。
この試験の発表とともに、ODCを対象とするProfessional認定条件が発表された。Architecture Specializationはその条件の1つ。受験の前提がAssociate Developer (ODC) で、2024/4時点では未発表の残り2試験を合格すると、Professional Web Developerとして認定される。

試験情報のPDFと一緒にダウンロードできるサンプル問題を解説する。
全部で10問で、この記事では6問目-10問目が対象。
[Architecture Specialization (ODC)のサンプル問題について解説 1/2 (#1-#5)](https://qiita.com/jyunji_watanabe/items/10dcf659adefd6951ee9)

サンプル問題は、
https://www.outsystems.com/learn/certifications/
の、「Architecture Specialist (ODC) 」項目のリンク「Exam Details」でダウンロードできる資料から。「Sample Exam」がついているのファイルが該当する。
ここでは2024/4にダウンロードしてきたファイルを使って解説していく。
サンプル問題は英語しかなかったので、この解説は英語版を見ながら書いている。

各問題のタイトルは、Details SheetのCategories & Topicsで、問題に対応していそうなものを選んでいる。

# 6 Naming Best Practices
[Architecture Fundamentals in ODC - Naming Best Practices](https://learn.outsystems.com/training/journeys/architecture-fundamentals-559/naming-best-practices/odc/4106)という動画で解説されている内容についての問題。

動画で推奨されているベストプラクティスは
- App名はBounded Context名。Appが複数のBounded Contextを含むなら、適切な業務用語（Business Term）を利用する
- Library名はその目的を判別できるものにする
- App内のフォルダ名は、Concept単位で各要素をまとめる（問題の例なら、Customer, Order, Productがフォルダ名の候補）。もし、App内に複数のBouded Contextが含まれるなら、「Bounded Context名＋Concept名」にする
- 個別の要素名は、Concept名でプレフィックスする

ということを踏まえて、各選択肢を見ていく。
ちなみに、この例では、
- Boundede Context = Order Management
- Concept = Customer, Order, Product
- Library = Salesforce

A. ✕：App名は基本的にはBounded Context名で、複数のBounded Contextを含むAppのみBusiness Termを名前に使う。Libraryは業務からは分離した要素を含めるので、Business Termは名前につかない。また、LibraryにはURLはない（Consumer Appに含まれて動作するので）
B. ✕：フォルダ名はConceptを使う。Bounded Contextが複数あるAppであれば、Bounded Contextをプレフィックスにするが、このAppはBounded Contextは1つのみ。よってフォルダ名は、Customer・Order・Productのいずれかになるだろう
C. ◯
D. ✕：「The applications should be named after the bounded context they represent」の部分は正しい。Libraryは再利用可能な要素を含めるので、名前に利用されるコンテキストは含めないと思われる。よってLibrary名はOMSalesforceではなくSalesforceなどになるはず

よって正解はC。

# 7 Libraries Reussability
UI Pattern (業務から独立したUI部品）をどこに配置するか？　という問題。
まず、UI PatternはLibraryに実装する。
よって、Appに格納するとしているAとBは✕。

CとDは共にUI PatternをLibraryに格納するとしている。違いは、UI Pattern用の新しいLibraryを作る（C）か、既存のTheme用Libraryの新しい要素としてUI Patternを作るか（D）。

問題の条件で今後もUI Patternの追加が予期されている点に注意。Themeはめったに更新されないことが予想されるため、更新頻度が異なるThemeとUI Patternを同居させると不必要な更新をConsumerに要求して良くない。また、部品としては役割ごとに分離するほうがクリーンと言えるだろう。
よって正解は、選択肢C。

# 8 Integration
「near real-time integrationでコールバックのエンドポイント」というのは、[Architecture Patterns in ODC - Integration Patterns](https://learn.outsystems.com/training/journeys/architecture-patterns-581/integration-patterns/odc/627)の、「Integration with Cold Cache and Real-Time Sync」というパターンのことと思われる。

「Libraryが提供するServer Actionが外部システムのREST APIを呼ぶ」という基本のIntegrationパターンを修正し、「Consumer Appにキャッシュ用のEntityを足したもの」が「Integration with Cold Cache」パターン。このパターンではCacheを作るためにそれなりの頻度で（Timerを使って）外部システムのAPIを呼び出す。
この頻度を下げるため、「外部システムで更新が発生したとき、ODCに用意したREST APIを叩いてもらい、更新内容の通知を受ける」のが「Integration with Cold Cache and Real-Time Sync」パターン。

つまり、コールバックは、「外部システムで発生したデータの更新を、都度通知してもらうもの」なので、正解は選択肢B。

# 9 Sharing Data
あるAppが公開するデータをどの形式で提供すべきか、という問題。
データを他Appに公開する場合、そのデータの性質によってどうすべきか、という点については、[Architecture Patterns in ODC - Sharing Data Patterns](https://learn.outsystems.com/training/journeys/architecture-patterns-581/sharing-data-patterns/odc/628)に解説がある。

ざっくり言うと
- Public Entityで提供する：業務との関わりの無いデータ。業務データであっても、変化の頻度が低いものや利用にあたって深い業務知識が不要なもの
- Service Action：上記以外のもの（即ち、業務との関わりが深く、利用に業務知識が必要であったり変更の頻度が高いもの）

問題文の例では、「The consumer apps use Aggregates to fetch the data and **perform calculations with it based on complex business rules**. 」とあるので、利用に複雑な業務知識が必要な業務データであるからService Actionとして公開するのが望ましい。

つまり、選択肢Aが正解。

# 10 Distributed Transactions
複数のAppにまたがる分散トランザクションにおけるベストプラクティスを聞く問題。
SagaにはOrchestrationとChoreographyの2パターンがあるが、現在（2024/04/09）時点でOutSystemsの公式で解説されているのはOrchestrationのみ。
[Architecture Patterns in ODC - Distributed Transactions Patterns](https://learn.outsystems.com/training/journeys/architecture-patterns-581/distributed-transactions-patterns/odc/629)で解説されている。

Orchestration SagaをODCで実装する際のポイントは、
- 各Appが公開するService Actionは、HTTPSベースの通信になるため、呼び出し元とは別のトランザクションになる
- 分散トランザクションは、画面から直接呼び出すServer Actionが、複数のAppのService Actionを、コントロールすることで行う
- Server Actionから更新を伴うService Action複数の呼び出しを行っていき、どこかでエラーとなった場合、別トランザクションであるからRDB任せできれいにロールバックはできない。コミット済みの操作については反対の更新を行うことによって既存の更新を取り消さなければならない。これを補償トランザクション (Compensating Transaction) という
- ただし、ベストプラクティスでは、ネットワークエラー等に起因する失敗の場合、失敗したリクエストをリトライすることによってうまくいく可能性がある。そのため、補償トランザクションを開始する前に失敗したリクエストをリトライしてみることが勧められている

この最後のポイントに関する問題。

リトライに言及しているAとBが候補。Bは全トランザクションをリトライするとしているが、リトライは直前に失敗したリクエストが対象。それより前のリクエストは別トランザクションであり、コミット済みのため。リトライ失敗後、コミット済みのトランザクションで生成したレコードを消すことにのみ言及している。しかし、RDBの更新はINSERTのみでなくUPDATEやDELETEもある。その場合は削除ではもとに戻せない。

よって選択肢Aが正解。Aでは、リトライに失敗したあと、失敗したリクエスト以前に完了しているGet Customer Details/Subscribe Policyのうち、後者のみ補償トランザクションの対象としている。これは前者はGETであり参照系なのでもとに戻す必要がないため。

なお、Event Driven Architectureがリリースされたため、今後はChoreography Sagaの解説が出てくるかもしれない。