V字モデルでRPAシナリオ開発を完遂する

内製で大規模なRPAを開発するにあたり、ソフトウェア開発で用いられるV字モデルをRPA用にダウンサイズして適用することで、永く使える高品質なシナリオを目指します。

# 1. この記事が狙う効果

- 開発手法を明確化して属人化を防止する
- ヒアリングの要点を押さえて手戻りを抑制する
- ドキュメントを整備して棚卸に備える
- ディレクトリ構成のテンプレートを用意して開発/本番環境を分ける

# 2. 解決したい課題

ネット上のRPA記事は、自動化を進めるためのミクロな問題(xxを解決するためにどのコードを使えばいいか、等)や、管理・経営するうえでのマクロな問題(トップダウン型ボトムアップ型問題、等)が多く、社内で内製のRPA開発部門を設けた時に具体的にどうするかについての記事が少ないように思えます。

自分はVBAをちょこちょこいじるだけの非エンジニアの頃にRPA開発者として任命され、独学で開発していました。
当時は動きさえすればいいと考え、設計書も書かず、現場担当者からもらった最低限のドキュメントだけ保存して「ヒアリング→実装→リリース」(小文字のv字モデル(笑))を繰り返しました。

その結果、過去のドキュメントが未整備のまま4年間が過ぎていました。

そのため、本家のシステム開発を参考に、RPA開発の負担にならず、かつ棚卸に苦労しないようにRPA開発手法としてまとめました。
もしこの記事を読む人がこれからRPAを始める人なら、この手法を参考にしてみてください。

# 3. V字モデルを参考にしたRPA開発手法

RPA開発における基本はシステム開発プロジェクトにおける開発工程とテスト工程の対応関係を表したモデル、**V字モデル**を参考にします。

[V字モデルとは？](https://webrage.jp/techblog/v_shaped_mode/)
![V字モデル](https://upload.wikimedia.org/wikipedia/ja/6/6d/VModelConcept.png)

ここではRPA開発におけるヒアリングからシナリオ稼働までの流れについて説明します。

## 3.1. 登場人物

![会議](https://1.bp.blogspot.com/-WnXOmjPozrQ/W-0hP1BuHSI/AAAAAAABQQc/phtNaF3by8Yk177dofmtMZNj5T-t-MmXQCLcBGAs/s400/video_kaigi.png)

システム開発プロジェクトでは何十人ものエンジニアがチームを組み、数か月、時には数年かけて１つの製品を開発します。
チームメンバーは大きく以下のような役割に分けられます。

- PM（プロジェクトマネージャー）
  - 開発プロジェクトの取りまとめを行う
- PL（プロジェクトリーダー）
  - メンバーを管理する。小規模では立てないことがある。
- SE（システムエンジニア）
  - 要件の確定や仕様の検討を行う。PGを兼任することがある。
- PG（プログラマー）
  - SEが用意した仕様書をもとにプログラミング・単体テストをする

RPAはシステム開発と比べて小規模のため、小さい案件ならベテラン1人でも(環境が整っている前提で)1週間で終わります。
そのため私は、基本的に1つのRPA案件に対しPMとSEの2人で十分に対応可能と考えています。

V字モデルを参考にしたRPA開発手法の説明にあたり、登場人物を挙げます。

- 現場担当者
  - 効率化をしたい業務を現在受け持っている人。業務内容を詳しく知っている。
- 現場担当者の職制
  - 現場担当者の上司。部下が受け持つ業務内容の概要を知っている。
- RPAマネージャー(PM)
  - RPAの管理を受け持つ人。現場担当者とRPA開発者をつなぐ。
- RPA開発者(SE)
  - RPAシナリオをコーディングする人。

なお1人RPAにおいては「RPAマネージャー」「RPA開発者」は兼任するものとします。

以下の工程で「現場担当者の職制」は必須ではありませんが、「何を」「どのように」自動化するか知ってもらうことで、「**それ、この業務にも応用できるよね**」を引き出し、水平展開への伏線になります。
時間が空いているなら必ず参加してもらうようにしましょう。

## 3.2. 要求分析

- 必須
  - 現場担当者
  - RPAマネージャー
- 任意
  - 現場担当者の職制
  - RPA開発者

要求定義とは、システム「に」求める仕様を定義したものです。
言い換えれば、**RPAシナリオを実行した時のゴール**です。

**あくまで目的であり、手段を含めないようにしましょう**。
[目的を定義する段階で手段を決めてしまうと、手段に囚われてしまう](https://qiita.com/MinoDriven/items/8e4abda43b05cd7a0200#%E3%82%A2%E3%83%B3%E3%82%AB%E3%83%AA%E3%83%B3%E3%82%B0%E5%8A%B9%E6%9E%9C)という現象があります。

例えば、ユーザーから以下のようにヒアリングしたとします。

- Excelを開いて月末棚卸情報をメールで配信したい
- SAP(ERPシステム)にログインして在庫データをExcelで確認したい

ここで目的となるのは

- ~~Excelを開いて~~**月末棚卸情報を**~~メールで配信したい~~**知らせたい**
- ~~SAP(ERPシステム)にログインして~~**在庫データを**~~Excelで~~**確認したい**

月末棚卸情報を知らせたいだけならExcelやメールである必要はありません。
人によってはいちいちメールが送られてくるのが邪魔に思うこともあります。
在庫データを確認したい時、毎回SAP(ERPシステム)にログインする必要があるのか、考えるべきです。

## 3.3. 要件定義

- 必須
  - 現場担当者
  - RPAマネージャー
- 任意
  - 現場担当者の職制
  - RPA開発者

要件定義とは、システム「を」動かすための仕様を定義したものです。

最初に目的を設定したら、以下の項目について聞きましょう。

- 自動化の目的
- 自動化の概要、構成
- 実装する機能（機能要件）
- 求める性能やセキュリティ（非機能要件）
- 導入移行計画
- スケジュール
- 人員の体制
- 出力ファイル情報

つまりここで決めたいのは、RPA開発における**5W**です。

- Why
  - なぜ。自動化の目的。
- Where
  - どこで。どの部署が。**水平展開を考慮するか**。
- Who
  - 誰が。開発者と現場担当者、**メンテナンス人員、例外作業の体制**。
- When
  - いつ。納期スケジュール。
- What
  - 何を。自動化の概要、構成。実装する機能（機能要件）、求める性能やセキュリティ（非機能要件）、導入移行計画。

特に**水平展開の考慮**は見落としがちです。
必ず同じような作業をしている人が他部署にいるか確認し、必要な場合はパラメータ変更で対応できるシナリオにしましょう。

**メンテナンス人員、例外作業の体制**をうやむやにすると後からRPA開発者にしわ寄せがきます。
RPAは特に失敗しやすいシステムなので、ユーザー側で対処可能な例外はユーザー側で対処してもらうよう、責任範囲を明確にしましょう。

## 3.4. 基本設計

- 必須
  - 現場担当者
  - RPAマネージャー
- 任意
  - RPA開発者

要件定義における**What(何を)からHow(手段)に落とし込む**ため、以下についてヒアリングします。

- 画面遷移図
  - 何のアプリケーションをどのように開くか
- (ユーザーのPCでRPAを実行する場合)システムメッセージ
  - メッセージや文字入力の内容とタイミング
- 例外分岐
  - 画面遷移図通りに動かないケースの想定

**例外処理は可能なら起こらないようにしましょう**。
例えば以下のような工夫が考えられます。

- 更新対象のExcelが誰かに開かれていると更新できなくなるので、その時どうするか
  - Excelをビューワとデータに切り分け、データをRPAで更新してPowerQueryを使ったビューワで参照する
- パスワードが期限切れでログインできない場合にどうするか
  - 毎回パスワードを更新するときに、期限切れの2週間前にアラームを付けるようユーザーに要請する

## 3.5. 詳細設計

- 必須
  - RPAマネージャー
  - RPA開発者

基本設計は、大雑把に言えば「お客さまに見えるところ」を考える作業です。
それに対して詳細設計は「**お客様に見えないところ**」を考える作業です。

詳細設計では、基本設計で明確化された「HOW」をさらにプログラマー(RPA開発者)向けに解釈し、詳細化します。

例えば、以下のプロセスをこのように解釈します。

- システムにログインする
  - パスワードを〇〇から読み込み、システムに入力する
  - ログインできなかった場合、パスワードの更新を促すメールを送信する
- ユーザーが指定したパラメータによって処理を変更する
  - パラメータは〇〇.csvで指定する
  - 〇〇.csvには××列、△△列がある
- 未回答者にメールを再送する
  - 指定フォルダに指定した名前のファイルを保存していない場合、未回答者として扱う
  - 未回答者をアドレス帳から検索して、指定する定型フォーマットでメールを送信する

## 3.6. コーディング

- 必須
  - RPA開発者

ここまで設計を煮詰めたら初めてWinActorの出番になります。

コツとしては

- 業務の始まりから終わりまで一気通貫のシナリオはNG
  - 一気通貫のシナリオは異常発生時の切り分けに苦労するため
  - ひとまとまりのプロセスごとに部品を作る。汎用性が高い部品は共通部品にする
  - 共通部品は積極的に利用することで、単体テストの工数を減らせる
- ノードに説明を書く
  - 自分が作ったシナリオも半年経てばほとんど忘れてしまう
  - 第三者が見てもわかるように書く
- エラー出力は怖くない
  - 単体テストでエラーを握りつぶすと結合テストで「どこが悪いのか？」がわからなくなる
  - ライブラリ標準のノードでは検知できないエラーの場合、自分からエラーをthrowすることも考慮する

## 3.7. 単体テスト

- 必須
  - RPA開発者

部品(サブプロシージャ)を一つずつ部分実行し、正常に動作するか確認します。
パラメータに想定外の値を入れた時にはエラーになることも確認しましょう。
(Ex. 数値が入る場所に文字列を入れる、ファイルパス変数に存在しないディレクトリを入れる)

## 3.8. 結合テスト

- 必須
  - RPA開発者

部品(サブプロシージャ)を順番通りに結合し、通して実行した時に問題が無いか確認します。
このとき、画面操作を軽量なGifで録画できる[ScreenToGif](https://dev.classmethod.jp/articles/introduction-screentogif/)や、
一時停止などの再生メディアが使え、高画質なmp4で保存できる[ADGRec](https://machirosan.com/pc-rec-free-ag/)で録画しておくと、
後からシナリオ内容について動画で把握したり、受入テストで共有できます。

## 3.9. システムテスト

- 必須
  - RPAマネージャー
  - RPA開発者

RPAマネージャーと一緒に、通して実行した結果が要求仕様通りになっているか確認します。

## 3.10. 受入テスト

- 必須
  - 現場担当者の職制
  - 現場担当者
  - RPAマネージャー
- 任意
  - RPA開発者

ここでヒアリングを行った現場担当者と合流し、RPAシナリオの仕上がりに問題がないか確認します。
シナリオを録画している場合はここで共有しましょう。

これでRPA開発は終了です。

# 4. RPA開発記録

上記のいずれの工程でも、なるべく内容は記録しましょう。

## 4.1. RPA管理台帳

WinActorのようなデスクトップ型RPAは、現在管理しているRPAシナリオを別個で手動管理する必要があります。
特に職制や経営者は「RPAがどれくらい稼働しているか」「どれくらいの効果を発揮しているか」を気にします。

そのため、管理しているRPAシナリオは全て以下の情報についてExcelに表形式で保存し、開発に着手した時点からデータを更新するようにしましょう。

- シナリオID（通し番号）
- シナリオ名
- 概要
- 実行間隔(毎週火曜日の9:00 等)
- 状態（開発中/稼働中/一時停止中/稼働終了）
- 現場担当者
- 現場担当者部門
- RPA開発者
- 着手開始日
- リリース日
- 開発工数
- 効果時間(シナリオ実行1回あたりの作業削減時間)

## 4.2. 要件定義・基本設計書(README)

要件定義及び基本設計はシナリオごとにREADME.mdにまとめます。

```Markdown:README.md

# 業務名タイトル

業務の目的と内容をざっくり1行で記述
Ex) 残業時間削減のため、データの受け取りと結果出力を自動化する

# 概要
このシナリオが何をするものか

# 目的
シナリオが目指すゴール

# 出力ファイル情報
どこに、いつ、どんなファイルが新規作成または更新されるか

# 実行間隔
毎週火曜日の9:00 等

# 役割

## 通常時の連絡先
## 例外発生時の連絡先
## メンテナンス担当者
## RPA開発担当者

# 納期

## 受入テスト期間
## 最終リリース日

# 基本設計

## 画面遷移図
動作のスクリーンショット、Gifを並べる

## サブプロシージャ一覧
細かいプロセスをひとまとめにした抽象的な部品一覧
後の単体テスト、結合テストにつながる

## 依存関係
作成済みのシナリオを利用したシナリオの場合、
そのシナリオの名前とバージョン情報を記す

# 更新情報

## v1.0
初期リリース

## v2.0
機能追加

```

# 5. ディレクトリ構成

シナリオファイル及び開発記録の保存方法にルールを定めず、適当に保存していると後で棚卸に苦労します。
ここでは、.NET プロジェクトを新規作成する時のテンプレートを参考に、RPA用のプロジェクト新規作成テンプレートを考えます。

- 共通部品A
  - packages
    - 共通部品D - ショートカット
  - config.csv
  - README.md
  - bin
    - Debug
      - 共通部品A.ums7
      - resource.csv
      - debug.log
    - Release
      - 共通部品A.ums7
      - resource.csv
      - debug.log
- 共通部品B
- 共通部品C
- 共通部品D
- ...
- シナリオ1
  - packages
    - 共通部品A - ショートカット
    - 共通部品C - ショートカット
  - config.csv
  - README.md
  - bin
    - Debug
      - シナリオ1.ums7
      - resource.csv
      - debug.log
    - Release
      - シナリオ1.ums7
      - resource.csv
      - debug.log
- シナリオ2
- シナリオ3
- シナリオ4
- ...

重要なのは以下の三点です。

- READMEを作る
- Debug, Releaseフォルダに分けてテスト環境を作る
- 利用している共通部品を明記する

## 5.1. 親フォルダ

シナリオ1, 共通部品Aにはそれぞれ台帳で割り振ったID、またはシナリオ名を入れます。

## 5.2. packagesフォルダ

シナリオ中で利用した共通部品へのショートカットを保存します。

## 5.3. binフォルダ

バイナリーフォルダ。実行ファイルを格納します。
Debug, Releaseフォルダに分けることで、デバッグ用と本番用の環境を切り分けます。

## 5.4. config.csv

シナリオ変数の初期値に代入する値を定義します。
実行ファイルパスやシステムURLなど、Debug, Release共通で利用する変数に対して作成します。

## 5.5. resource.csv

シナリオ変数の初期値に代入する値を定義します。
入出力ファイルパスやメール宛先など、Debug, Releaseで分けて利用する変数に対して作成します。

## 5.6. debug.log(csv)

エラー発生時に、エラーを以下の内容に分けて追記するテキストファイルです。

- ログ出力レベル(Error, Warning, Info, Debug)
- 発生日時
- ノードID(ノード名)
- エラー内容

一つのファイルに集積することでエラーの分析が容易になり、エラーの修正に役立ちます。
csvファイルの場合、エラー内容は1行になるように改行コードを置換しましょう。

## 5.7. シナリオ.ums7

WinActorで作成したシナリオファイルです。

### 5.7.1. 初期テンプレート

前処理に「csvファイル→変数値」ノードを使い、シナリオ.ums7から見て

- 同一のファルダ内にあるresource.csv
- 2つ上のフォルダにあるconfig.csv

から変数の初期値を取得する処理を作りましょう。

また、本処理サブルーチン中にエラーが発生したとき、例外処理として以下の処理を実装します。

- resource.csvで定義した現場担当者にエラー内容のメールを送信する
- debug.logに追記する

### 5.7.2. 開発

開発時は本処理サブルーチンの内容のみコーディングします。

開発着手や機能変更する際はDebugフォルダのシナリオに対し変更を加え、十分にテストしたらReleaseフォルダのシナリオに上書きします。

初期テンプレートとして同一のファルダ内にあるresource.csvから変数の初期値を取得するようにしているので、

- DebugフォルダのシナリオはDebugフォルダのresource.csvを参照する
- ReleaseフォルダのシナリオはReleaseフォルダのresource.csvを参照する

これにより、簡単にテストと本番の切り替えができます。

## 5.8. Gitについて

社内規定に制限が無ければ、Gitによるバージョン管理を導入しましょう。
READMEやconfigなどテキスト形式のファイルの変更履歴を差分付きでバックアップできます。
そのためREADMEに変更があったときに「2021/12/10 変更」のような文言は必要なくなります。

加えて、リリース後の故障で古いシナリオに戻すため、以下のような**ファイル名によるバージョン管理**をしている方もいると思います。
どれが最新なのか、故障があったときにどれに戻せばいいかわからないですよね。

* シナリオ1.ums7
* シナリオ1(最新).ums7
* シナリオ1(テスト用).ums7
* シナリオ1(本番).ums7
* 20211210_シナリオ1(本番).ums7
* 20211212_シナリオ1.ums7

Gitであればファイル名はそのまま、以下のように保存(コミット)する時に理由を付与してブランチ(枝)で管理できます。

- 開発用のdevelopブランチ
  - 初めてのコミット
  - 部品を作成したコミット
  - 結合したコミット
  - バグ修正中のコミット
- リリース用のreleaseブランチ
  - v1.0 最初のリリース
  - v1.1 v1.0のバグ修正
  - v2.0 機能変更
  - v2.1 v2.0のバグ修正

コミットの他にもgitには「プッシュ」「マージ」「プルリクエスト」のようなコマンドがありますが、1人RPAでは不要です。
コードの共有もないので、ローカルリポジトリだけ作りましょう。

ただし、テキストと違いシナリオはバイナリなので差分はとれません。
READMEに追記したり、WinActor ver.7で使える「WinActor Scenario Script」のようにテキストベースでシナリオを開発しましょう。

[サルでもわかるGit入門](https://backlog.com/ja/git-tutorial/)
[いいからgit使え](https://zenn.dev/kanaya/articles/455f5d735f3e83b11bae)

# 6. 終わりに

以上、社内で内製のRPA開発部門を設けた時に具体的にどうするかについての記事でした。
長々と書きましたが、全てこのように堅苦しくする必要はありません。
特にプログラミング初心者のRPA導入1日目は「**適当に作ったら動いた**」ぐらいで十分です。

ただし無計画のまま半年、１年経つと、過去の内容を忘れたり、シナリオ数が多くなってきて首が回らなくなります。
RPAシナリオは実行した分だけ社員の作業を短縮できるという意味で「金の卵を産む鶏」です。
適切な環境を整えて、大切に管理しましょう。

それではよきRPAライフを！