BluePrismの開発規模が大きくなった時に、BluePrismそのものを効率化できるコードステージ

## はじめに
この記事は、[RPAに関するよもやま話 Advent Calendar 2020](https://adventar.org/calendars/4992)の１５日目の記事です。
大変遅くなってすみません。。

以前、古代からある生命保険会社２社でRPA（ビズロボとBlue Prism）の導入と全社展開をリードしていました、みやともと言います。
※この記事は所属していた会社とは一切関係なく、個人としての知見を述べるだけのものです。

今はInsurTechの[株式会社hokan](https://hkn.jp)というスタートアップに勤めていて、SaaSの開発を行っています。
今回、前職を退職する時になんかBlue Prismに関するナレッジをQiitaに書くぞ、と言いつつ全く書いていないことに心を痛めまして（嘘）、ちゃんと書くことにしました。

### この記事はなんですか？
この記事では、老舗RPAベンダーである [Blue Prism](https://www.blueprism.com/japan/) のプロジェクトが大規模になってきたときに起こりがちな課題の紹介と、
それを解決する方法として、Blue Prismをリバエンが効果的な状況もあるよ、という内容を記載します。
なお、この記事ではBlue Prism6.4あたりを対象としているため、最新のバージョンではメソッドなどが異なる可能性があり、オンプレ版のみを対象としています。

また、この記事に掲載しているコードはあくまでサンプルなので、DLLが不足していたりする可能性はあるので、ご注意願います。

## RPA、BluePrismについて
RPAについては [こちら](https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%9C%E3%83%86%E3%82%A3%E3%83%83%E3%82%AF%E3%83%BB%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%83%BB%E3%82%AA%E3%83%BC%E3%83%88%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) を参照してください。
また、Blue Prismについては [こちら](https://rpa-bank.com/service/blue_prism/) を参照してください。


## Blue Prismの規模が拡大することによって発生する問題
Blue Prismを運用していて、リソースPCが50台を超えるくらいの規模になったあたりから、下記のような課題が出始めます。
※サーバのスペックをあげれば発生しないこともありますが、基本的にRPAの開発と運用のコスト対効果を考慮すると概ね発生すると考えて良いと思います。

| # | 環境 | 問題 | 影響 |
|:-----------|------------|------------|------------|
|1|本番|コントロールパネルの各操作が異常に重くなる|本番運用がとにかく遅れる|
|2|両方|オブジェクトの最新版がちゃんとリリースされてるかわからない|「とりあえずリリースしとくか。そして炎上へ」がやたら増える|
|3|開発|リリースタブが余りにも重くなる|開発が遅れる。リリースだけで長時間拘束される|

## 上述の問題が発生する原因と課題について
色々な原因があるんですが、基本的にBluePrismがデータベース参照した後に画面に描画する処理がかなり重たいんじゃないかと推測しています。

当時のメンバーと考えたのが、コードステージでBlue Prismのサーバープログラムを呼び出せないかなと考えました。
で、なんか色々やってたら、Blue Prismのサーバー側のプログラム、オブジェクトとかで呼べるじゃん、と気づきました。

今回、かなり危険ではありますが、そのコードステージの設定を紹介します。

## 解決策としてのコードステージ
### 基本
BluePrismでRPAを作る、みたいな文脈としての基本では全くありません！
本当のBlue Prismの基本は、[こちらの記事](https://qiita.com/irohamaru/items/374bca9d46211f16a4f1) をぜひご参照ください。

#### Initializeページ
Initializeページで 下記のDLLを読み込みます。

```C#:Initialize
AutomateAppCore.dll
BluePrism.Core.dll
BPCoreLib.dll
```

#### BluePrismサーバの呼び出し方

下記のコードをコードステージに設定すると、 `IServer` というBlue Prismのサーバーとの通信ができるインターフェースを取得できます。
これを使えば、例えば `CreateCredential`（クレデンシャルの新規作成）、のような普段Blue PrismのGUIを通して実行している様な機能がコードステージで実行できる様になります。

```VB:コードステージ共通
'Blue Prismのサーバーを呼び出すインターフェース
Dim server = BluePrism.AutomateAppCore.app.gSv
```

また、Blue Prismのサーバのモデルは、凡そ下記のような形式でクラスが定義されています。
代表的なもので、 `BluePrism.AutomateAppCore.clsRelease` などがあります。

```VB:コードステージ共通
'BluePrismの各振る舞いに対するクラス
BluePrism.AutomateAppCore.clsXXXXX
```


## オブジェクトのアイデア
基本的に、上記を呼び出せば、かなり色々なことができる様になるのですが、
代表的で便利そうなのは下記の様なものです。

### リリースパッケージのエクスポート
このコードステージでは、下記の手動作業を自動化できます。
1. リリースタブを開く
2. 特定のパッケージを選択
3. リリースファイルを指定したフォルダに新しく生成する。
　ファイル名は、 `{パッケージ名}-YYYY-MM-DD-hh-mm-ss.bprelease` とする。

```VB:ExportPackage
'[input]
'  pkgname:パッケージ名
'  exportFilePath: bpreleaseを出力するパス

Dim filename = pkgname & DateTime.Now.ToString("-yyyy-MM-dd-hh-mm-ss")
Dim pkg = BluePrism.AutomateAppCore.app.gSv.GetPackage(pkgname)
Dim release = new BluePrism.AutomateAppCore.clsRelease(pkg, filename, True)
BluePrism.AutomateAppCore.app.gSv.CreateRelease(release).Export(New FileInfo(exportFilePath & "\" & filename & ".bprelease"), False)
```

### パッケージのインポート
このコードステージでは、リリースファイルのインポート作業を自動化できます。

```VB:ImportPackage
'[input]
'  importFilePath:インポートするbpreleaseファイルのパス
Dim job = BluePrism.AutomateAppCore.clsRelease.Import(New FileInfo(importFilePath))

' 非同期的に完了するので、Jobの監視が必要（実装間に合わなかった。。）
```

### コントロールパネルのセッション管理の下部「環境」の情報取得
このコードステージでは、下記の手動作業を自動化できます。
ちょっとコードステージが雑なのですが、参考程度としてください。。
これが使える様になれば、例えばWarningのプロセスだとか、停滞してるプロセスとかを探しやすくなります。

1. コントロールパネルタブを開く
2. 下部の「環境」を確認する。
3. 色々起きてないか探す。

```VB:GetSession
'[output]
' resources: コントロールパネルのセッション管理の下部「環境」と同等のコレクション

resources.Columns.Add("ProcessName")
resources.Columns.Add("ResourceName")
resources.Columns.Add("UserName")
resources.Columns.Add("Status")
resources.Columns.Add("SessionStart", Type.GetType("System.DateTime"))  
resources.Columns.Add("SessionEnd", Type.GetType("System.DateTime"))
resources.Columns.Add("LastStage")
resources.Columns.Add("LastUpdated")

Dim sessions = BluePrism.AutomateAppCore.app.gSv.GetActualSessions()
for each session as Object in sessions
	if session.ResourceName.IndexOf("_debug")>=0 Then
		Continue For
	End If
	Dim SessionStart As DateTime
	if session.SessionStartText<>"" Then
		SessionStart = DateTime.Parse(session.SessionStartText)
	Else
		SessionStart = Nothing
	End if
	
	Dim SessionEnd As DateTime
	if session.SessionEndText<>"" Then
		SessionEnd = DateTime.Parse(session.SessionEndText)
	Else
		SessionEnd = Nothing
	End if
	
	resources.Rows.Add(new object() {session.ProcessName, session.ResourceName, session.UserName, session.StatusText, SessionStart, SessionEnd, session.LastStageText, session.LastUpdatedText})

next
```

### コントロールパネルのセッション管理の右上部「リソース」の情報取得
このコードステージでは、下記の手動作業を自動化できます。
ちょっとコードステージが雑なのですが、参考程度としてください。。
これが使える様になれば、例えばMissingになってるリソースとかを探しやすくなります。

1. コントロールパネルタブを開く
2. 右上部の「リソース」を確認する。
3. 色々起きてないか探す。

```VB:リソース取得
'[output]
' resources: コントロールパネルのセッション管理の右上部「リソース」と同等のコレクション

Dim input_resource = BluePrism.AutomateAppCore.app.gSv.GetResources(0, 1)
resources.Columns.Add("ResourceName")
resources.Columns.Add("Fqdn")
resources.Columns.Add("DbConnectionStatus")
resources.Columns.Add("ResourceState")

for each item as Object in input_resource.Rows
	Dim resource_name = item(0)
	if resource_name.IndexOf("_debug")>=0 Then
		Continue For
	End If
	Dim attr_id = BluePrism.AutomateAppCore.Resources.ResourceInfo.GetResourceStatusFriendlyName(item(4))
	
	resources.Rows.Add(new object() {resource_name, item(1), item(2), item(4)})

next
```

## まとめ
Blue Prism はRPAで業務を自動化するにあたって、管理面であったり、開発面であったり、とても便利に設計してくれています。
ただ、RPAに掛けられるリソースコストは、RoIがやたら見られるのでやっぱり逼迫しがちです。
そのため、コントロールパネルやリリースなど、一部の機能がかなり重くなってしまう傾向にあると思っています。
（もしかしたら最新版の状況は違うのかもしれません。）

上記のコードステージは、RPAの開発に継続的インテグレーションの概念を導入できる、などかなり大きな変化をもたらすことができると思います。
ただ、かなりリスキーなプログラムを書いてると思うので、ぜひ自己責任としっかりした検証の元に、ご利用いただければと思います！