【OutSystems】Associate Reactive Developer試験の勉強日記

# はじめに
Outsystemsの公式では試験準備のために以下を推奨しています。
試験対策に向けて「[リアクティブWeb開発者への道](https://learn.outsystems.com/ja-jp/training/journeys/web-developer-662)」の動画の最後にあるテストの中の、特に気になった問題についてまとめようと思います。
また、PDFで配布されたサンプル問題についても各章に記載します。
間違いがありましたらすみませんと同時にご指摘頂ければ幸いです。
~~明日試験です。~~ 試験終わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/afe93b12-4136-dd0d-6b89-1249e703f5df.png)

下図の各章の最後の問題を解いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/6d282c83-c142-ef8d-2693-b224849b9f12.png)


## Outsystemsでの開発の概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/c18be60a-da5a-1a6a-0f42-f5e0dd69b217.png)
上記の問題ではOutsystemsがコンパイルで何を生成し、どのように動くのか気になりました。
公式サイトでは
> 最適化された標準コード（JavaScript、HTML、CSS、C#、標準SQL）にコンパイルされます

とあるので、基本的に既存の技術に置き換えられると考えました。
そのためフロントエンドやバックエンドの挙動についても既存の技術に置き換えて回答すればよいと感じます。

**クロスデバイスアプリ**
OutsystemsのリアクティブWebは情報を複数のデバイス間で引き継ぐことができるクロスデバイスアプリとの事です。
クロスプラットフォームとの違いは謎です。
Webアプリ、iOsアプリ、Androidアプリなど異なる形式で配信してもDBを通して情報を共有できるのでしょうか。不明なので後日追記します。


**シングルページアプリケーション(SPA)**
OutSystemsのフロントエンドはReact.jsベースのSPA（Single Page Application）アプリとしてコンパイルされるとの事。
SPAはクライアントとサーバー間の最初のリクエストでWebサイトのレンダリングに必要な情報をjsでやり取りする方法で昨今のフロントエンドでよく見られます。
ルーティングに伴うデータのやり取りが少ないのでサクサク動きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/2e44654a-0017-a29d-eb47-d716c704a2d4.png)
[SPA(Single Page Application)の基本](https://qiita.com/takanorip/items/82f0c70ebc81e9246c7a)

**同期/非同期処理**
おそらくOutsystemsでもAjaxを利用してサーバーとデータのやり取りを行っていると思うのでデータフェッチなどのサーバーアクションは基本的に非同期処理になるのではないでしょうか。
しかし、レスポンスを待たず処理を進めてはいけない部分もあるのでasync/await的な何かで必要な部分は処理を待つようなjsコードに変換されている気がします。
- 画面Aggregateの非同期処理について別の問題で言及されていました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/2250f71a-2645-d375-b0fd-520c6acc8513.png)


## データのモデリング

### 動的エンティティ(通常のエンティティ)
**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/5c1fadba-c2e3-396c-0d4b-5218e13d8819.png)
D以外正解に見えますが、なんとIdはText型にも変更できます。
当然自動採番ではなくなりますが一意の値でなければDBエラーが発生します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/54f29645-ab93-43ed-1c22-9459101a7b93.png)

またエンティティ識別子(ID)について
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/a347a48d-9e3c-abd9-07bd-170621f94203.png)
なんとIDを持たないエンティティも作成可能でした。
またその場合、Createアクションのみ使用可能になるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/dd1991f2-1c66-ee70-5173-26203815b207.png)

### 静的エンティティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/d9f988d2-fb83-cba0-aaa6-e7b429073222.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/738ec9ed-0368-1296-f204-b4da6f5e3c9b.png)
上記の2つは静的エンティティについての問題ですが、不正解の選択肢も含め静的エンティティについての情報が読み取れます。
私は動的エンティティと比べ使う事が少ないですがよく固定値のリストみたいな使い方をします。

- 静的エンティティサンプル
サンプルとしてDBに静的エンティティを作成しレコードを３つ追加した画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/324caad4-2904-9911-c271-7c6a10bd26d1.png)
静的エンティティの性質
- 各RecordはId,Label,Orderなど追加、編集可能なアトリビュートを持つ
- Getアクションのみをもつ
- アクションによる追加/削除/変更ができない(開発者のみが可能)

## セクション：ロジック

### アクションとフロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/1d12147f-6ede-5186-d9f2-4b7a4c5837c0.png)
上記の問題ですが、Screen上で作成するクライアントアクションとLogic上で作成するクライアントアクションで出力パラメータの有無が異なるという事を初めて知りました。
- 画面上のクライアントアクション：入力パラメーター、ローカル変数
- クライアントアクション：入力パラメーター、出力パラメーター、ローカル変数
- サーバーアクション：入力パラメーター、出力パラメーター、ローカル変数

が使用可能です。

画面上で作成したクライアントアクション
※Output Parameterは設定できない(これは知ってた)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/988b0b9b-9215-cf3e-c3b5-64a631f751ce.png)

Logicで作成したクライアントアクションとサーバーアクション
※クライアントアクションにOutput Parameterが設定できる(知らなかった)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/1b25d9f8-6352-3932-5390-9f59615ec773.png)

さらにLogicで定義するクライアントアクションのFunctionをYesに設定するとExpression内で利用可能となります。
その際の注意点としては算出用の関数で使用するという性質上、複数のOutput Parameterを設定できなくなるという事です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/c1ebaaed-76d7-8810-6cc8-ab39320a0606.png)


### Switch文
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/4354a299-6147-2f54-8c5d-34abfcd95cac.png)
上記の解説の中でTrueとなった最初のブランチを判別するために各分岐には番号が振られています。
True分岐が複数の場合この番号で優先順位が決まると思います。

Switchサンプル
3つの分岐に対して各種インデックス振られ、分岐に該当しない場合Otherwiseが実行されます。
分岐条件は全てTrueのためこの場合最初の分岐1が実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/0b872e33-2fd5-9bde-8295-86e6e77766dc.png)

### 例外処理
- 例外処理サンプル
分岐などによって例外を発生させ対応する特定のフローに移動させる事ができるようです。

　既存のコードベースの開発では、Try-Catch文を使いTryスコープで発生した例外クラスやエラークラスをCatchスコープでキャッチし対応する例外処理を実行するのだと思います。
Outsystemsでは通常の分岐処理の中で例外を選んで発生させ対応する処理に移動するようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/66056826-6132-39b0-da14-55381b49aa78.png)

　疑問に思ったのですが開発中、エンティティのDelete Rule違反やアクションのタイムアウト、オブジェクト型の不一致など色々なエラーが親切にアラートでアプリ画面に表示されるのを見ましたが、そういった例外やエラーをなんとかキャッチする方法があるのでしょうか。後日追記します。

※追記です
当然ですが各種Expectionが対応する例外を拾ってくれていました。
デフォルトでは以下のOn expection がCommonに設定されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/63c34dc0-3f06-f9cb-65a9-b1db2b7b473a.png)

また例外を拾う際の優先順位はExpectionが設置されている場所によりそうです。
同一ロジック内>呼び出しロジック内>UI FlowのOn Expectionのようになるような気がします。後日追記。

## Aggregateの基本
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/177c0267-2dd8-87ee-1212-294b2a65402a.png)

AggregateのSortingタブでは各属性に対するソート基準を設定することができる
- 降順/昇順が設定可能
- 各種データ型に対して降順/昇順の基準がある
- 優先順位が設定可能
- 動的ソート(Add Daynamic Sort)が設定可能
※これはText型で"Sample.Name DESC"のように指定するらしい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/37b84731-06df-e521-8021-611c47295c1c.png)

### データのリレーションモデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/fdbf6eed-9fd1-50fa-9b22-9899ffd74a59.png)
今まで、一対一も一対多と同様にリレーション先のテーブルに主キーと一致する属性を作成する方法を取ってましたが、一対一のリレーションのみに限定するには一方の主キーをもう一方の主キー型と一致させることが必要だと思います。

下図でHelloエンティティの主キーはWorldエンティティの主キー型に設定したので一対一となります。
また多分HelloエンティティはWorldエンティティに依存する形になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/941bbf17-1569-8473-f847-e78922b2d895.png)

**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/dc63405d-cd35-ab1a-7af5-14eda055edd2.png)


### Delete Rule(削除規則)
参照整合性
参照先のレコードに対する削除処理に関する設定
例えば下図でOrderレコードが参照するCustomerレコードが削除されると、Orderレコードは参照先を失ってしまうという事になるのでその時のルールだと思います。

参照元のエンティティの参照先IdカラムにDelete Ruleを設定します。
下図ではOrderエンティティのCustomerIdに設定します。

- Protect
参照先を失う事を許さないから削除させない設定。
CustomerレコードはOrderレコードに参照されているので削除されず処理を終了する。
(DBエラー発生。DB Expectionで拾えます)
Customerレコードを削除するにはOrderレコードによる参照を削除する必要がある。

- Delete
参照先を失う事を許さないから参照元も削除する設定
Customerレコードを削除しようとすると参照元のOrderレコードも自動で削除される。
(カスケード削除)

- Ignore
参照先を失ってもいい設定。参照整合性は保証されない。
Orderは存在しないCustomerIdを持つことが許されるのだと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/d4eb3bfa-5245-edc8-7a6a-10e34f93d7ae.png)

[データのモデル化・削除規則](https://success.outsystems.com/ja-jp/documentation/11/developing_an_application/use_data/data_modeling/entity_relationships/delete_rules/)

## ウェジェット

### Form
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/27f59cd8-561e-1138-1365-51ddbb8d31a2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/9e9ef1f8-8f66-4b9b-59dd-6c0ae29a3517.png)

Formのウェジェットの役割
- 入力ウェジェットのグループ化
- グループ化した入力ウェジェットの検証

Formウェジェットの内部に各種Inputを含めることにより、フォーム内の全てのInputウェジェットの値に対するバリデーションの結果を保持する事ができ、Form.Validのパラメータで取得ができます。

下図でForm内部の入力ウェジェットのバリデーション結果(Valid)がTrueとなれば、それらを含むForm.Validの値がTrueになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/1a402ea4-e166-1045-383d-ff909bc4fd1a.png)
また各種入力ウェジェットもバリデーション結果(Valid)とバリデーションメッセージを持っています。

### Built-in Validation
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/98c635a7-e79d-92ad-85f8-2e48045665e9.png)

フォーム内にButtonを設置すると、Built-in Validationというオプションを選択できYesに設定すると「必須設定にした入力ウェジェットに値が入力されているか」と「紐づけた変数に対してデータ型が一致しているか」を検証し、Buttonによるクライアントアクションの前にその結果を上記のValidとValidation Messageに自動的に入れてくれるみたいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/3279e934-b796-6170-1de9-e2587bcdf9c3.png)

## 高度なAggregate

### テーブル結合
**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/b4ed02cd-db94-be87-9ab3-694f51e6c0f0.png)
OrderStatusとPriontyアトリビュートに値を持つレコードのみ取得される。
Employeeアトリビュートは持っていても持っていなくても取得される。


- With or whithout：Left Join
主(左)のエンティティレコードは全て取得されもう一方のエンティティに対してリレーションを持つレコードについては結合する
リレーションのない主(左)エンティティレコードがあるかもしれない
- Only With：Inner join
双方のレコードもの中でリレーションを持つもののみ取得される
お互いリレーションのないレコードは存在しない
- With：Full Outer join
双方の全てのレコードを取得してリレーションのあるものは結合される
リレーションのない主(左)エンティティレコードも副(右)エンティティレコードもあるかもしれない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/3cf772ac-298a-8e58-1a12-f1968c05a036.png)

### アトリビュートの集計

**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/2bf7a4ac-9041-29ee-abe0-7f80f1263226.png)
余談ですがNew Attributeで値を算出する際はFunction：Yesに設定したサーバーアクションが使用可能でした。
逆にクライアントアクションは使用できません
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/fe4bb5a6-f7d6-8a1f-8540-02c01fecb348.png)

### Fetchのタイミング
**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/0b2d1035-e5e6-44e9-1aab-ca73ec9f8b61.png)

## ブロックとイベント
**サンプル問題より**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/fd666aba-f4f7-7cc7-bed4-f67411dea7c0.png)
OutsystmesのフロントエンドはReactベースとの事だが上記の挙動はVue.js(vue2)におけるPropsダウンとEventアップに非常によく似ていると感じた。
親から子へのパラメータの受け渡しではパラメータの変化を自動的に感知しパラメータを使用するブロック内のUIに即座に反映される。
またパラメータの変化に伴う処理を特別に行いたい場合はOn Parameter Changedに設定する。
一方、子から親へアクションを行う際は、子がイベントをトリガーし親にパラメータを渡し親は渡されたパラメータを使用して設定された処理を行う。


## リアクティブプログラミングモデル

### 画面イベント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/28ecffa1-e1ab-5306-5d83-323ee5b7528e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/0f5386a8-bf5c-022c-d84f-b427ba6ae381.png)

Outsystemsの画面ライフサイクル
- Initialize
- Ready
- Remder
- Destroy
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/1808ee69-40b5-dbdf-08a5-507cb4e366c9.png)
上記ライフサイクルでトリガーされるイベント
- On Initialize
Roleによる画面アクセス検証のみ完了している段階
DOMの読み込み、Aggregateやアクションの前段階

    **ユースケース**
    ・ローカル変数の初期値を設定する
    ・ユーザーのRoleに対応したリダイレクトを行う
    
On Ready/On Render
DOM読み込みが完了した段階
静的なパラメータや初期化された変数は準備が完了している
Aggregateやアクションによるデータフェッチ、変数の算出は完了していない場合がある  
- On Ready
最初の画面描画の際のみ実行される
    **ユースケース**  
    ・Outsystems UIなどDOMに関する初期設定
    ・OM要素にリスナーを追加する

- On Render
DOMに関連する変数、Aggregateなどのデータが変更され再描画される度に発生
**ユースケース**
・データ変更に伴うUI操作
疑問：After Fetchの時点ではDOMの準備が未完了の場合があるのでしょうか？
私の想像ですがReactive Webというくらいなのでフロント部分はUIに関わる変数の変化を感知してUIの状態が更新されるReactive っぽい動きをしています。
なので上記の図ではAfterFechの時点でDOMは準備されているものと考え…後日追記します。

- On Destroy
下図によると画面遷移に伴い新しい画面が描画される際、次の画面が用意されてから遷移を行う事でUXを向上しているように思えます。
その際、On Destroyでは前の画面、次の画面両方のDOMにアクセルできるタイミングであるとの事です。
**ユースケース**
公式の説明ではイベントリスナーの削除など、コンポーネントを破棄したときにロジックを実装するために使用できるとの事(よく分からないので後日…)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/3cc0dac7-fbd8-0c01-07e7-467a73a89f28.png)

**サンプル問題**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/7981601f-ef66-b92f-7b27-ffe9a351bc0c.png)



### クライアント変数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/4db7f46a-cc59-0539-25ba-7b0ac85f3b9d.png)
調査したところクライアント変数はブラウザのLocalStorageに生の値で保持されていました。
そのためユーザーに容易に閲覧、変更されるためAggregateに使用するエンティティ識別子や機密情報は保存してはダメみたいです。

### サイトプロパティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/92040a81-c54f-b442-9ca4-ebd51ef4f367.png)
こちらは環境変数のような使い方が適しているとの事です。
実際外部APIを使用するForgeのドキュメントにはLifeTimeでサイトプロパティに作成したAPIのAPIキーをセットするような手順が多かったです。
サーバーアクションのAssignでサイトプロパティを更新できますが全ユーザーが共有する値なので大変危険だと感じました。

# テスト結果
~~テストを受けた後、結果と感想を記載する予定です。~~
合格でした。良かったー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/b48b4369-763c-16f3-5987-90a647bb7d01.png)

しかし正答率84％なので50問中8問は落としたのだと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/c0c83290-e7b4-a6f7-c6f9-30911ba02f7b.png)
数日の間にテストに関する詳しいフィードバックを頂けるようなので認識が違っている部分があったら記事を修正します。