この記事は 『CRESCO Advent Calendar 2018』 20日目の記事です。

 

はじめまして!
RPAチームに新規参入しました、AI&ロボティクスセンター あきやまです。

Pepper等のロボットを主に担当していたら、「RPAもロボットだから対象だね」と言われました。
「そうですね、もちろんです」と回答しました。
長いものには巻かれます。

などと言いつつも、話題のRPAは前々から参加したかったので、ワクワクしてます。
これを機に一人前のRPAエンジニアを目指します。

Bad Practice集

さて、必死に勉強を進める中、RPAチームの先輩メンバーがBAD Practiceを提供してくれました。
本日はその中から、いくつかご紹介したいと思います。
始めたばかりの頃は取り合えず期待通りに動いてしまうと、そのまま正解だと思いがちですね。
さらに、一度正解だと思い込んでしまうとより良い方法に気づけないものです。

今後ロボットの設計・実装を行う上で、効率的、且つ可読性の高い開発を行う為の参考になれば幸いです。

1.「Sequence」アクティビティ内での大量の分岐

例えば、以下のような条件分岐のプロセスを実装する際、「Sequence」「Flowchart」どちらのアクティビティを使用しますか?

例) たかし君の昼ご飯事情
・たかし君の所持金が1000円以上の場合、たかし君は外食をする
・たかし君の所持金が1000円未満かつ500円以上の場合、たかし君はコンビニでご飯を買う
・たかし君の所持金が500円未満かつ朝8時前に起床していた場合は、お弁当を食べる
・たかし君の所持金が500円未満かつ朝8時より後に起床した場合は、何も食べない

まずは、「Sequence」を使用した場合のワークフローを見てみましょう。

Sequence」アクティビティの中には「IF」アクティビティしか使用できないため、分岐の中にさらに分岐が生じるような場合は、画面が煩雑になり可読性が下がりますね。

複雑な条件分岐を実装する際は、「Flowchart」アクティビティを使用することをオススメします。

どうでしょう、「Sequence」を使用した場合と比較して、各段に見やすくなりましたね。

さらに「Flow Decision」アクティビティは、True/Falseラベルの表示名を変更することで、より可読性を向上できる事もメリットの一つですね!

ぜひ、今後の可読性の向上に役立ててください。

2.例外の追跡はException.Sourceを使おう

UiPathでエラー発生元を特定するときは、Exception.Sourceを使いましょう。

例えば、Main.xamlからSub.xamlを呼び出す処理でSubで例外を発生させてみます。

例外キャッチでメッセージボックスを表示させています。
まずはException.StackTraceから。

何がなんだかわかりませんね。

.net系のエンジニアは、エラーの詳細原因をログ出力するときにはexception.StackTraceを頻繁に利用します。
ですが、UiPathでStackTraceを出力すると、UiPathFrameworkの内部構造のエラーが出力されるため、基本的には使えません。

次にException.Sourceの中身を見てみましょう。

これはわかりやすいですね。

ちなみに、「Subから例外をスロー」という文字は「Throw」アクティビティのDisplayNameの内容そのままです。
そのため、UiPathでの実装ではDisplayNameに一意な文字を設定し、例外の表示はException.Sourceで行います。

Exception.SourceException.Messageでログ出力するようにすると、エラー発生アクティビティとエラー内容が表示されるので、お勧めです。

3.While文による無限ループ

「While」アクティビティで無限ループが起きていませんか?よくわからずに「While」 アクティビティを使っていませんか?

指定した条件になるまで繰り返し処理する」While構文は使い方に注意しましょう。
使い方によっては、何回繰り返しても指定した条件にならず、永久に抜け出すことができないいわゆる「無限ループ」に陥ることがあります。

While文を使うことに慣れていない場合は、使用しないことを推奨します。

繰り返す回数が決まっている場合、「ForEach」ループを使うことができます。
画面に指定したElementが表示されるまで待つ場合は「Retry Scope」を使うことができます。

「While」アクティビティを使わなければ処理ができないケースはほとんどないと思いますので、見直してみましょう。

4.セレクターでidxが含まれるまま使用している

セレクターにidxという属性が含まれているまま使用していませんか?

<html title='UiPath Bad Practice' />
<webctrl idx='2' tag='DIV' />

これは、要素を特定するための情報が足りておらず、苦し紛れに要素の連番をそのまま使っているようなもので、安定性にかける場合が多いです。

こういった場合は、Ui Explorerを使って、要素が一意に特定できるセレクターにチューニングをかけていく必要があります。
要素が一意に特定できるセレクターになった場合は、自動的にidx属性はセレクターから削除されますので、諦めずにチューニングをしてみましょう。

5.ArrayやListの値一覧をログに書き出す方法

配列の中身をログに書き込むためだけに、「ForEach」ループで処理してませんか?
以下ロジックを使えば、配列の要素をカンマ区切りで1行ログに出力することができます。

string.Join(",",arr)

6.行数が多いDataTableへのループ処理速度向上

Excelから取得した、DataTableの特定の行に対してループ処理を実施したいとき、常に「ForEachRow」を使っていませんか?
もしExcelの行が何千行もあった場合、膨大な時間がかかってしまう危険性があります。

その様な時は、「ForEach」を使います。

まず、処理を行いたい対象行をSelectで取得しましょう。

TargetRows = DataTable.Select(“カラム1 = ‘100’ AND カラム2 = ‘True'”)

それから、取得したTargetRowsに対し、「ForEach」でループ処理を行いましょう!
対象行のIndexを使いたい場合には以下のコードで取得可能です。

DataTable.Rows.IndexOf(row)

元のExcelに更新行のみ書き込みたいという場合にも、行番号を指定して書き込むことができます。

ワークフローはこのようになります。

最後に

如何でしたでしょうか?
やってしまっていた!と言う内容もあったのでは無いでしょうか。

様々なプログラムでも同様ですが、「〇〇は使っちゃダメ!」では無く、「こう言う時は〇〇は使わない!」の様に、目的に応じた方法を用いる事が大切ですね。

Best PraticeやBad Practiceは、新しい手法の開発や、ツール自体の更新で変わっていく事がありますが、常に「効率的で可読性が高い」ものを作る事を意識していきたいものです。

この記事が皆様のRPAライフの一助となれば幸いです。