[OutSystems]Web Developer Specializationのサンプル問題について解説 1/2(#1-#5)

Web Developer Specializationは2023/3に追加された試験で、ReactiveのProfessional認定の条件の1つ。

試験情報のPDFと一緒にダウンロードできるサンプル問題を解説する。
全部で10問で、この記事では1問目-5問目が対象。

[Web Developer Specializationのサンプル問題について解説 2/2(#6-#10)](https://qiita.com/jyunji_watanabe/items/98bf3998f3eb76f8f2ec)

サンプル問題は、
https://www.outsystems.com/learn/certifications/
の、「Web Developer Specialist」項目のリンク「Exam Details」でダウンロードできる資料から。「Sample Exam」がついている方のファイルが該当する。
この記事では、zipを展開したときに、ファイルの更新日時が2023/04/05 9:15のものを使って各問題を見ていく。

残念ながら、2023/04/08時点では英語のみ。

# Professional Web/Mobile Developer Certification
今回公開された試験で、Reactive Web Appでも、Professionalレベルの認定を受けられるようになった。
条件は、

- Associate Reactive Developer
- Security Specialization
- Web Developer Specialization
- Architecture Specialization

の各試験を合格すること。
上記に加えて

- Mobile Dev Specialization

も合格すると、Professional Mobile Developer Certificationを受けられる。

[Web Developer SpecializationのAnnouncement](https://www.outsystems.com/forums/discussion/87003/the-web-developer-specialization-and-professional-certifications-are-now-live/)に体系図が載っているので、参考までに。

# 1 長時間実行されるTimerのベストプラクティス
## 問題文の検討
たくさんのデータを外部システムに同期するTimerのロジックで、ベストプラクティスに従っていない部分を指摘するもの。

Action Flowを見ると、Entityで取得したレコードをFor Eachでループ。
各ループで、
1. Action（おそらく外部システムにアクセス）を呼ぶ
1. Entity Actionでレコードを作成
1. CommitTransaction Actionでコミット実施

をしている。
これを見ると気付くのは、
1. OutSystemsのベストプラクティス[タイマーおよびバッチジョブの長期-実行を避ける](https://success.outsystems.com/documentation/best_practices/performance_and_monitoring/performance_best_practices_logic/#avoid-long-running-timers-and-batch-jobs)に違反している（なぜか日本語ページにリンクできなかったので英語のページ）
1. 1レコードごとにCommitTransaction発行するのは頻度が高い

## 選択肢の検討
A. ×：問題は明らかにある
B. ×：Timeout in Minutesは20分程度にするのがベストプラクティスなのでスクリーンショットにある20より大きい値にするのは推奨されない。同じサーバーのリソースを食いつぶさないためTimerの同時実行数には制限がある（デフォルトではPlatform Serverあたり3）ため
C. ×：CommitTransactionが多いのは事実だが、それがだめかどうかは、各ループで呼んでいる外部処理による。少なくともTimerの最後にループの外でCommitするのはベストプラクティスで推奨されている事項ではない。コミットは、ループ中にIfを置いて一定の回数や経過時間等で行うのがよい。Timerの最後に到達するとOutSystemsが自動的にコミットを行うためその位置で明示的にCommitTransactionを行うのは意味があるとは言えない
D. 〇：これがベストプラクティスに従った実装。こうした実装の例は[Asynchronous Processing with Timers - Best Practices on Timers](https://www.outsystems.com/training/lesson/2207/best-practices-on-timers)で紹介されている

# 2 Consume REST APIのInput Parameter
## 問題文の検討
Consume REST APIエラーに渡すInput Parameter "Phone Number"がある。
実行時に“The PhoneNumber attribute must not be null”というエラーが発生するのでこれを解決する方法を聞かれている。

スクリーンショットを見ると、PhoneNumber項目のSend Default Value=Noが設定されている。この設定をすると、該当Parameterがデフォルト値の場合、「項目自体を省略する」。エラーメッセージと併せて考えると、PhoneNumberが空白の値であるために、API呼び出し時に項目自体を渡さなかったために発生したエラーと思われる。

他の条件として
- 対象APIは他のInput Parameterを正しく受け取っている -> ネットワークや対象API自体には問題が起きていない
- PhoneNumber自体はmandatory**ではない** -> PhoneNumberを必須にするのは望ましくない

## 選択肢の検討
A. ×：PhoneNumberのDefault Valueをどんな値にしようとも、たまたまその値が設定された場合、実行時に項目が省略され、同じ問題が発生する。また未指定時に適切なPhoneNumberのデフォルト値があるという情報が与えられていない
B. 〇：これが正解。Send Default Value=Yesにしておけば、未指定の項目も省略されなくなる
C. ×：OnBeforeRequestはConsume REST APIのCallbackで、外部APIを呼ぶ直前に割り込んでHTTP通信の内容を書き換えることができる。よって選択肢に書いた通りのことは実現可能だが、選択肢Bの方が明らかに自然で簡単な方法なので、Bがある以上はこの選択肢は×
D. ×：問題文の検討で見た通りMandatoryにするのは望ましくない

# 3 Merge
## 問題文の検討
Publishを行ったときにCompare and Mergeダイアログが表示され、conflictの存在が示されている（背景色が赤い部分）。conflictがある行でどちらも選択しないままMerge and Publishボタンをクリックした。

conflictが残ったままなのでService Studioは自動でマージを行えない。そのため、選択肢Dが正解。

# 4 Exception HandlerとTransaction
## 問題文の検討
1. Consume REST API呼び出し
1. "UpdateCustomerDB"という名前のAction (名前からしてEntityの更新があるのだろう）呼び出し

で構成されるActionがある。1を終えて、2でエラーが起きて、Exception Handlerに捕捉された。なお、Exception HandlerのAbort Transaction=Yesになっているため、補足された時点でトランザクションはロールバックされる。

## 選択肢の検討
この問題の状況では、2.のUpdateCustomerDBはロールバックされるが、1.のConsume REST API呼び出し先のトランザクションはロールバックされない。外部サービスはOutSystemsのトランザクション管理から独立しているため。

各選択肢は以下の通り
A. 1, 2共にロールバックされる
B. 1, 2共にコミットされる
C. 1はロールバックされず、2はロールバックされる
D. 1はロールバックされ、2はコミットされる

↑の説明に合うのは、選択肢C。

# 5 大きいテキストデータやバイナリデータを分離する
## 問題文の検討
あるEntityにDescriptionという属性がある。この属性のデータ型はTextで桁数が2000を超える。

この状況はベストプラクティスにある[大きいテキストデータやバイナリデータを分離する](https://success.outsystems.com/documentation/best_practices/performance_and_monitoring/performance_best_practices_data_model/#isolate-large-text-and-binary-data)に該当する。日本語のページへのリンクはなぜか機能しないため英語のページへのリンク。

ポイントは
- Binary Data型の属性を含むEntityは更新に時間がかかるため、Binary Data型を分離して別のEntityに切り出す
- このEntityは元のEntityのIdentifierを自分のIdとして持つ（元のEntityと分離したEntityは1:1の関係にある）
- 長さが2000を超えるText型属性も背後のRDB内ではBinaryのデータとして扱われるため同じ注意が必要

## 選択肢の検討
上記ベストプラクティスから、元のEntityと1:1の関係にある新しいEntityを作り、Description属性はそちらに移動することになる。

よって、選択肢Bが正解。