[OutSystems]悩んだところ・躓いたところ100選

## はじめに
株式会社メディアテック所属の @mt-h2 です。
普段は OutSystems を利用したローコードでシステム開発を行っています。

今回は業務に就いてから OutSystems を触り始めて1年弱。
この間に悩んだところ・躓いたところをどう対応したかも含めて共有したいと思います。

:::note info
対象バージョンは OutSystems 11 となります。
:::

## 悩んだところ・躓いたところ100選
100個はありません。随時追加していきます。

### 日本語が非対応
2024/7/31 時点で OutSystems は日本語に対応していません。
[公式ドキュメント](https://success.outsystems.com/ja-jp/documentation/)は日本語対応を進められていますが、Service Studio 等については英語のみとなっています。

#### 悩んだところ
私のような中学レベルの英語も危うい人間にとって日本語対応されていないというだけで非常に食指が伸びづらく、本当に業務としてやっていけるのか？と不安で仕方ありませんでした。（面接の際にも英語しか対応していないので不安ですがなんとかします！的な事を言った記憶があります）

#### どう解決したか
まず、公式ドキュメントについてはそこそこ日本語化されているので大きな問題はありませんでした。一部英語のみのページが残っていましたが、そこは[DeepL先生](https://www.deepl.com/ja/translator)に助けていただきました。
一部問題となったのが、動画レッスンが完全に英語のみで日本語テキストもないものがありました。こちらについては私の聞き取り能力では理解不可能だった為、スキップしたところもあります。が、ごくわずかであったため支障となるものはありませんでした。

次に IDE などの UIについてですが、過去に他の IDE を使用して開発した経験があれば困る事は無いと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/ecd4f073-c476-f010-b189-dea409a4d212.png)
基本的な開発に必要な IDE 操作メニューが揃っており、文言も私でも理解できるレベルの単語で表示されています。組み込み関数などが少し分かりづらいと感じましたが、こちらについては[公式ドキュメント](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_language/logic/built_in_functions/)があるので、翻訳しながら確認できるため問題ありませんでした。

### 独特の言い回しがそこそこある
OutSystems は他言語では見ない独特の言い回しが目につきます。
- Entity：DBテーブルの事
- Event：デリゲートの事（OnReadyなどの一般的な"Event"も"Event"と呼んでいるのでややこしい）
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/35d2b4a0-3536-1108-608a-55e6fa8f5a44.png)
- Raise：Throwの事。Pythonでもこの表現のようなので通じる人に通じる

等など、細かい所でこれは何を指しているんだろうと思う事が多々ありました。

#### 悩んだところ
公式テキストで学習している時に説明の意味が分からず、学習に時間を要しました。また、OJTの際にも同様の事が起こり進捗を出せない事がありました。

#### どう解決したか
OutSystems 公式の [OutSystemsの用語](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_language/) を読み込みました。
が、正直な所今回の目的としては効果が出しづらいと思います。理由は、単語・用語集ではなくあくまでそれらのリファレンスであるため、一覧でざっと覚えるには適していないからです。
タイミングが合えば一覧で確認できる記事を作りたいとなぁと思っています。

### enum が無い
OutSystems には enum の概念が存在しません。

#### 悩んだところ
マジックナンバーは極力使いたくないが enum が使えない。

#### どう解決したか
公式サイトの [列挙型を作成・使用する](https://success.outsystems.com/ja-jp/documentation/10/developing_an_application/use_data/data_modeling/create_and_use_an_enumerate/) にもある通り、OutSystems で enum を使用したい場合は Static Entity の利用を推奨しているため、Static Entity で実装しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/dc5fbb6d-9d37-d084-974e-39e41de5d768.png)
※ ただし、これはあくまで DB に値を保存しているので割とコストが掛かるなぁと感じています。Structure はあるのに enum を実装しない理由は何なのだろう

### namespace が無い
例えば汎用的な GetHoge という Client Action を作成します。
次に任意の Screen 上に GetHoge という Screen Action を作成します。
すると作成した Screen Action の名称が GetHoge2 にリネームされます。
これは OutSystems には namespace の概念が無いため、同名 Action を作成させないための仕様となります。

#### 悩んだところ
例えば Hoge という Entity を作成すると、いくつかの Entity を操作する Action が自動で作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/b266b8a5-ce01-7916-bba4-2aa544ebac03.png)
この Action をセキュリティ上の理由で別モジュールから直接呼び出す事を禁じています。
利用したい時は対象 Action をラップした Action を作成して呼び出すようにしていましたが、汎用的な Action 名は既に使用されているので困っていました。

#### どう解決したか
Create=Register、Delete=Remove のように各単語を置換して Action を作成しています。ラップしたものと分かるように CreateHogeWrapper などでも良いかもしれません。
願わくは、namespace が実装されることを…！

### バイナリデータを多数格納しているモジュールのロードが遅い
バイナリデータを多数格納しているモジュールを開こうとすると、読み込みに時間がかなりかかります。
平均2～3秒もあれば大抵のモジュールを読み込みが完了しますが、バイナリデータを多数格納しているモジュールは15秒程度かかりました。

#### 悩んだところ
検証用データを生成する API 用モジュールには、データ生成に利用する画像が100個程度 Resources フォルダに配置しています。このモジュールを開こうとすると、毎回15秒程度かかってしまいます。

#### どう解決したか
こちらについては未解決になります。
調べた内容としては、Service Studio の仕様でモジュールを開くたびに全リソースをダウンロードしているのでは？と思い調べましたがそれらしい情報が見つからず。
画像容量はそれぞれバラバラですが、全て合わせるとおおよそ 20MB 程度になり、社内回線があまり太くないのでこれだろうと踏んでいるので、それであれば解決手段は色々見つかりそうです。

### n 回ループができない
OutSystems では [For Each](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_language/logic/implementing_logic/logic_tools/for_each/) アクションを使って配列のループ処理を簡単に実装する事ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/089cd9b0-fc46-2392-2fb5-d5f82d4b2d51.png)
が！任意の処理を n 回実行したいといったときに、それを実現するためのアクションが用意されていません。

#### 悩んだところ
初期データ生成処理で、同一内容のデータを生成したい時に n 個データを作成するときにどう実現したらいいのか悩みました。

#### どう解決したか
OutSystems 公式フォーラムの以下スレッドの内容を元に実現しました。

[How to create a loop but not For Each loop?](https://www.outsystems.com/forums/discussion/53044/how-to-create-a-loop-but-not-for-each-loop/)
> Hi Long!
> 
> You could use an If widget with the condition of a variable used as a counter (for example: Counter <= n-1). One branch contains the loop logic that goes back to the If widget, the other branch continues into the rest of the server/screen action. Set an assign before that If widget so that you can set the Counter to an initial value.
> 
> Kind regards,
> Joseph Enriquez

直訳すると、``if使ってがんばれ！``との事。
なのでifを使って頑張った！
特に凝ったことはしておらず、ループ回数をループ上限値と比較して人力ループさせているだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/90ae0fd9-1bec-b363-edde-843314a9707d.png)
需要はありそうなアクションなのに初期アクションとして存在しないのは何故だろう。

### ループでbreakできない
For Each アクションの中で何らかの理由で break したい時があると思いますが break アクションは存在しません。

#### 悩んだところ
For Each で配列の値を変更していき、特定の値になった時にループを抜けたいが For Each を抜けるアクションが存在せず全てのループが終わるまでループを抜ける事が出来なかった。

#### どう解決したか
OutSystems 公式フォーラムの以下スレッドの内容を元に実現しました。

[How can i break my foreach loop ?](https://www.outsystems.com/forums/discussion/78053/how-can-i-break-my-foreach-loop/)

直訳すると、``if使ってがんばれ！``との事（またか…）
なのでifを使って頑張った！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/9f909046-4e7d-64af-80c9-0ae88a5c3c09.png)
が、これは最終的に不採用としました。
理由として、恐らく break した後に後続処理も走らせたいと考える事が多いと思います。
実際そうやってみると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/b4f90ca1-8f61-c3c7-89fe-1c7f01cc1c07.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/51af9097-d719-2f92-e4f1-ae8b46d9b9e5.png)
怒られました。どうやら For Each の途中で処理を抜けた場合は処理を終わらせる必要があるようです（GoTo的な懸念？）これでは後続処理が実行できないのでこの部分だけ別アクションとするしかないがそれも面倒。
結論として、For Each を使わず If で実装しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/8300e906-c712-0ad3-19ac-8470610d21c7.png)
これで警告も出なくなりました。
「配列を全回ししたい」という要件でのみ For Eeach を使い、それ以外の事がしたい場合は If で実装した方がよさそうです。

### ミリ秒が計測できない
OutSystems 11 にはミリ秒を計測する手段が初期状態では用意されていません。

#### 悩んだところ
前回の記事の [OutSystems 11でミリ秒を計測：前置き](https://qiita.com/mt-h2/items/80a17186823980a462a3#%E5%89%8D%E7%BD%AE%E3%81%8D) を参照。

#### どう解決したか
前回の記事の [OutSystems 11でミリ秒を計測：実装](https://qiita.com/mt-h2/items/80a17186823980a462a3#%E5%AE%9F%E8%A3%85) を参照。

### StringSplit の結果に空文字配列が複数存在する
OutSystems の [TextAPI](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_apis/text_api/) に用意されている [String_Split](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_apis/text_api/#String_Split)
このアクション引数である Delimiters の扱いでハマっていました。

#### 悩んだところ
Delimiters の公式ドキュメントが理解できず、何故このような現象が起きているのか調査に時間を要しました。

#### どう解決したか
解決までの経緯を [[OutSystems] String_SplitのDelimitersの罠にハマった](https://qiita.com/mt-h2/items/4f2bb1c195e4d17bc414) の記事に投稿しました。
結論として Replace で対象を 1Character にして、それを Delimiters で指定する事で解決しました。

## あとがき
今回は OutSystems 歴1年未満の開発者目線から、OutSystems で悩んだところ・躓いたところをどう解決したかも含め記載させていただきました。
書き始めは100個書いてやるぜ！と思っていましたが、気力ゲージが消失しそうになったため随時追記という形としました。今後も何かあればこちらの記事に追記していきたいと思います。

## さいごに
株式会社メディアテックでは絶賛 [開発メンバを募集中](https://www.mediatech.jp/recruit) です。
ローコード開発だけではなく、RPAやBIエンジニア諸々多数の募集をしておりますので、みなさまのご応募をお待ちしております。