新人がUiPathでのRPA開発を1年間経験して編み出した開発ナレッジ

#概要
この記事は、

- 1年で20業務のRPA化を行ってきた程度の新人が
- UiPathアカデミー修了後/VB.Netがちょっとしかわからなかった超新人の自分に向けて
- 「もっと早く知っておきたかった！」というようなナレッジをまとめた記事です。

思いつきでつらつら書いていきます。

#教育時によくあった質問
###○○ってアクティビティどうやって使うんですか？
アクティビティをクリックしてオレンジ色になっている状態にしてF1キーを押すと、ブラウザでアクティビティガイドが開きますよ。

###SequenceとFlowchart どっちを使えば？
Flowchartを推奨します。
それぞれ分岐に使うアクティビティが、
Sequence は If
Flowchart は Decision
となっておりますが、Decisionアクティビティが分岐構造を視覚的に捉えやすいのに対して、
Ifアクティビティは使えば使うほど横幅が広がっていって混乱しやすいです。

###SetTextとTypeInto どっちを使えば？
TypeIntoを推奨します。
両方ともテキスト入力に使うアクティビティですが、
TypeIntoがテキスト入力信号を送信するのに対して、
SetTextは、HTMLタグのtext属性を直接編集します。
あくまでWebサイト側は、キーボードを入力や、ペーストを想定して作られているため、SetTextを使用した場合、予期しない動作を招く可能性があります。

###"The UiElement is no longer valid"って何さ
この例外が発生したら、画面遷移完了待機に問題があります。
例外が発生したアクティビティの直前の状況を確認してください。

特定のセレクタに対して何らかのアクティビティを実行中に、指定のセレクタがページ上から消失してしまった際に発生する例外です。
「画面遷移後に、画面遷移前と後に共通して存在するエレメントにアクティビティを実行」していませんか？
その場合、画面遷移完了までしっかり待機できておらず、画面遷移前に指定セレクタを補足してしまっています。
そしてアクティビティ実行中に画面遷移したことにより、UiElementが消滅し、例外が発生しています。

#スムーズに開発するためのテクニック
###使えるホットキー
Shift + F10 右クリックメニュー開く


###テキスト入力に関する豆知識

- TypeIntoでText欄に"[k(enter)]"とセットするとエンターキーを入力しますが、
"[d(enter)]"とするとキー押し込みのみ、"[u(enter)]"とするとキーを離す動作のみ行います。
　例）"[d(ctrl)]ac[u(ctrl)][k(tab)][d(ctrl)]v[u(ctrl)]" 
　　→ 全選択、コピーを行い、タブキーにより次のテキストボックスにフォーカスを移してペースト

- ソフトウェアキーボードを出してクリックでテキスト入力・・・Win+r押下、「ファイル名を指定して実行」に"osk"と入力しEnter押下
- Set to clipboardアクティビティ+SendHotkey（ctrl+V）という入力手段もあります。
- SetTextはその性質上、プルダウンの入力などにも使えます。

###画面遷移やエレメントの出現待機
タイムアウト変数にNow.AddSeconds(30)をセット
ElementExistsのタイムアウトを200ms（0.2秒）などに設定
下画像のようなフローを作成すれば、成功時/失敗時共に即時反応し、30秒経ってもどちらの結果も得られなかった場合例外終了することができる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/396608/81183935-6948-6ead-f24a-54857625119a.png)

###Webページ内に存在するものの、非表示のエレメントに反応しないセレクタの作成方法
css-selectorを活用しよう
例: divタグの中で、style属性に"display: block;"が含まれている要素
```<webctrl css-selector='div[style*="display: block;"]' />```


cssセレクターの詳細は下記サイトを参考に
CSS Selector Reference
https://www.w3schools.com/cssref/css_selectors.asp


###ツールを使わずzipの圧縮解凍！　※2019/5/21追記
**※xamlファイルをテキストエディタで書き換える必要があります！必ずコピーを取ってから書き換えてください！**
テキストエディタでxamlファイルを開いて、2～3回ぐらいスクロールホイールを回すと
`<AssemblyReference>～<AssemblyReference>`
というような記述がずらっと並んでいるかと思われます。
その中に下記記述がなかったら、足します。
`<AssemblyReference>System.IO.Compression</AssemblyReference>`
足したら保存して、UiPathStudioで書き換えを行ったxamlファイルを開いてください。
圧縮
![圧縮.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/06237de2-b1d0-1521-c551-a319334255f4.png)
解凍
![解凍.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/f55e1e31-a4e5-d5f5-a62f-0e96ec4910e6.png)

こんな感じで可能になります！

*追記(2019/5/21)*
圧縮、解凍共に、第三引数にEncoding型で文字コードを指定しなかった場合、出力されるファイルに文字化けが発生する可能性があるので、留意してください。
下記に目を通しておくとよいと思います。
[ZipFile.ExtractToDirectory Method](https://docs.microsoft.com/ja-jp/dotnet/api/system.io.compression.zipfile.extracttodirectory?view=netframework-4.8)
[ZipFile.CreateFromDirectory Method](https://docs.microsoft.com/ja-jp/dotnet/api/system.io.compression.zipfile.createfromdirectory?view=netframework-4.8)


#VB.Net関連で知っておくべきこと！

###LINQでのコレクション操作！
UiPathでもLINQが使えます。使う頻度も高いです。
無名関数か、後述のデリゲートで条件を指定して、DataTable.AsEnumerableを含むコレクションから特定の項目のみ抽出することができます。

```vb
'datTestテーブル内の カラムAの値がhoge または カラムBの値がpiyo である行の有無をbooleanで返す
datTest.AsEnumerable.Any( _
    Function(x) x("カラムA").ToString.Contains("hoge") _
        OrElse x("カラムB").ToString.Contains("piyo") _
)

'datTestテーブル内の カラムAの値がhoge または カラムBの値がpiyo である行の配列を返す
datTest.AsEnumerable.Where( _
    Function(x) x("カラムA").ToString.Contains("hoge") _
        OrElse x("カラムB").ToString.Contains("piyo") _
).ToArray
```

###UiPathでもデリゲートを使いたい！
デリゲートとは、ざっくりいうと変数に関数そのものを代入することです。
「InvokeWorkflowで呼び出す共通部品のここの動作だけ、呼び元によって変えたいなぁ・・・」
というようなときに、関数そのものを渡すことで処理を変えたりできます。
注意：乱用すると、関数の処理内容がどこに書いてあるのかわからなくなりますので、よく考えてから使いましょう。

①引数の数に応じた型を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/94d590b9-017b-b045-83b4-c6aba095e741.png)

②InvokeCodeのArgumentsに変数をセット！（例なので適当ク○ネーミングです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/6466df13-4e8e-7f62-24e7-840e70be8661.png)

③InvokeCode内で変数に関数を格納（何がしたいねんこの関数は）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/9af62747-915d-1582-f5f6-396873fbc2f9.png)

④変数に引数を与えて関数を実行することが可能に！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/9fb69777-3cf2-1c63-3c78-4d885a4ea566.png)

###豆知識
```vb
'''既定のプリンタ名の取得（String）
(new System.Drawing.Printing.PrintDocument).PrinterSettings.PrinterName
```


#保守しやすいシナリオを作成するためのテクニック
###例外は握りつぶさず一番外までRethrowする
一番外までRethrowされてきた例外は最終的に、UiPathのグローバル例外ハンドラにキャッチされます。
この時、UiPathが勝手にエラーログを出力します。このログですが、発生したアクティビティのDisplayNameを教えてくれます。
~~私が調べた限り、Log Messageアクティビティによって出力するログに、DisplayNameの情報を載せるのは不可能なので、
UiPathのグローバル例外ハンドラのログが唯一の手段だと思われます。~~ ※

また、上記から分って頂けるとは思いますが、**DisplayNameは保守上とても重要な情報なので、是非記入しましょう**

**※tommybomber様よりコメントでご指摘いただきました**
>Invokeworkflowの呼び出し先で例外が発生した場合にはExceptionのsourceにDisplayNameをセットしてくれますよ。
なのでtryの中はInvokeworkflowがベストプラクティスかもしれません。

とのことです。
実際の業務内容を記述したWFを、実行用WFでラッピングし、実行用WF側でキャッチしてロギングする、という構造であれば、
`exception.source`で例外が発生したアクティビティのDisplayNameを参照可能でした。
（この場合でも、「業務内容を記述したWF」側では、例外を握りつぶさず、一番外までRethrowする必要があります。）


###例外をcatchしたら、すかさずスクリーンショットを撮ろう
Take screenshotアクティビティ + Save imageアクティビティ でスクリーンショットをファイルに保存できます

RPAはフロー上のあらゆる場所で例外が発生する可能性があり、どういった状況で例外が発生したか把握しにくいという特徴があります。
その上、停止したRPAに気付いた現場の人間が「あれれぇ？おかぴーぽー？」と、RPA実行端末をガチャガチャ操作した場合、例外発生当時の状況を特定するのがより困難になります。
是非撮影しましょう。

###ワークフロー上の注釈について
ワークフロー上のアクティビティを右クリックし、Annotations（注釈） → Add Anotation（注釈の追加）と選択
アクティビティ横に付箋のようなものが表示されたら右上の画鋲マークをクリック
下記画像のようにコメントを表示できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/83c3019c-8782-f8d1-e6e1-fcd4c398a1c4.png)


#注意すべきポイント/やらないほうがいいこと
###TerminateWorkflow
RPAを即時終了するアクティビティですが、RPAの終了地点を無闇に増やすと、どこで止まったかわかりにくくなります。
考えなしに使うのはやめましょう。

###Delay
基本的にDelayアクティビティで固定秒数待機しないといけない状況はあまり発生しないはずです。
前述「画面遷移やエレメントの出現待機」の例などを参考に、できる限り使用は避けましょう。

#その他実際にあったわかりにくいエラー
###印刷画面において、SelectorNotFound Exceptionが発生する
開発端末では問題なく動作したのに、現場にリリースしたら・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396608/04e971ab-15ba-58e6-d049-a20a2c544e5b.png)
この画面で例外が発生。
環境によって、印刷ウインドウのセレクタが異なる可能性があります。
>64 ビット版の Windows で 32 ビット アプリケーションから印刷を実行する場合には、32 ビット アプリケーション上にプリンター ドライバーを読み込むことが	
>できないために、SplWow64.exe と呼ばれる中間プロセスにプリンター ドライバーを読み込んで動作する(iexplore.exe→splwow64.exe)	
>参考:https://support.microsoft.com/ja-jp/help/2729178