SES おじさんが VBA アプリを Python でモダン化した話


はじめに

わくさくさんに似ているとよく言われる客先常駐 SES おじさんが年季の入った ACCESS VBA アプリケーションをPythonに移植してみたお話です。

SES おじさんのスペック

金融畑のエンジニア。小規模な EUC から基幹やパッケージまでやったけど、ユーザーの近くでEUCやってた時間が一番長いかも。老眼が気になってくるぐらいの年齢。

Python に手を出したきっかけ

Pythonに手を出したきっかけは2つあって、まず現場の隣の席にいた客先社員さんが普通に Python やってたこと。この方は海外の大学でコンピュータサイエンスを専攻されてたらしく、傍から「すごいなぁ」って感じで眺めてた。さらに非エンジニアである他の社員さんも研修の一環で Python の勉強をしたりしていて、そういった方から質問が来たりする。んで当然ながら僕は答えられなかった訳で。なんだか勝手に回りの堀を埋められていく感じと言うか、時代の流れを肌で感じると言うか。その後、PyCon に行って Python の活用事例などの話を聞いてみたりした。

で、そうなると仕事で使ってみたくなる訳です。

何をしようとしたか

お客様先でとあるアプリケーションの開発兼管理者が転職されることに。なのでこれをイチから再構築したいので提案してくれないか、ということになった。

そのアプリケーションは各種レポート (フォーマットはExcel/CSV) を出力して色んな所にメールで送付する ACCESS/VBA アプリケーションで、10年以上稼働している。VBA でジョブスケジューラみたいな仕組みを作り込んであって、自動運用されている。ちなみに私もそのアプリケーションの運用のお手伝いなどをしていました。

最初は ACCESS に代わるプラットフォーム的なものをいくつか検討したけど、どれも重厚長大な感じでフィットしない。先にも触れたけど常駐先の会社は非技術者の社員に Python を奨励していたこともあったので、Python で組んでみましょう、と提案したらあっさり受け入れてもらった。現場をまとめる人に「ここでは .NET がメインだけど他の人がメンテナンスする場合にちょっと不安」という懸念を指摘されたけど、「むしろ Python もできるようになったら技術の幅が広がって良いのではないでしょうか」と答えたら納得してくれた。あと、将来的に非技術者の人でもメンテナンスできるように、という狙いもあった。

それをどうしたか

まずは関係者が集まって機能の棚卸しを行い、一部の機能の廃止や移管をすることとなった。それ以外の必須機能について現行版プラットフォームである ACCESS の各要素 (Database/Forms/VBA) をモダン化することにした。

VBA の代わり

Python 3.7

開発スタート時の最新バージョン。

主なライブラリは以下。
- OpenPyXl : 成果物の出力処理に使った。
- pandas : 集計処理に使った。SQLで集計するよりも便利かも。
- dataclasses : DB使うなら!
- mypy : コードチェック

エディタは VS Code 。これは本家 Visual Studio よりも良いと思いました。

Excelの扱いでちょっと困ったこと

Python からは Excel ファイル保存時にパスワードをかけることができない。当然ながらマイクロソフトはセキュリティに関する部分の仕様を公開していないので、純正アプリケーション以外から Excel ファイルにパスワードをかけることができない。ここは仕方ないので PowerShell から Excel インスタンスを呼び出して対象の Excel ファイルにパスワードをかけて上書き保存するようにした。ちなみに Excel インスタンス終了時に各インスタンス(Sheet, Workbook, Applicaton)を明示的に解放する必要がある。なんでさ。

# Excel終了後にインスタンスを解放
$sheet, $wb, $excel | ForEach-Object {
    if ($_ -ne $null) {
        [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($_)
    }
}

Database (Jet DB) の代わり

SQLite3

現場では Oracle が基幹データベースとして使われていたけれども、移行対象のアプリケーション(データベース)は他から参照や更新されるようなことはなく、スケールなどは全く気にする必要はないのでこれにした。Python にデフォルトでライブラリ入ってるし。ACCESSデータベース(Jet DB) の代替としては必要十分。

MS Forms の代わり

DataTables


※公式サイトのサンプル画面です

PyQt は重いということなので、Web にした。で、やっぱりデータ参照にはスプレッドシートっぽい UI がいいかな、ということで DataTables という JavaScript ライブラリを使うことにした。ACCESS のテーブル画面よりもはるかに使いやすく見やすい。更新機能もあるらしいけど今回は使っていない。

しかし、JavaScript にはちょっと手を焼いた。フロントエンドエンジニアはデザインしつつも JavaScript とも格闘して大変だな〜、と思いました。

Webサーバ

開発用のサーバは無いので Web サーバは部署内にあった IIS を間借り。

SQLite と Web (DataTables) 間の橋渡しは REST API で〜!と意気込んだが、そもそも ASP がどうやら使えない。SQLiteの中にあるデータを一定間隔で JSON ファイルに出力して IIS からブラウザに返すようにした。ここはちょっと雑な作りとなってしまったが、ユーザービリティ的にはまぁ問題なし。時間が余ったらここは改善したい(なんて言うといつまでもやらないやつ)。

やってみてどうだったか

Python は楽しい。

やりたいことをシンプルに書ける。面倒くさい、って思うことはほぼ無い。こういうライブラリがあればいいのに、って思ったライブラリは大抵ある。

なので生産性が良い。

今回は開発開始時点で業務や機能仕様などほぼ把握していて設計工程が殆どなかったためそう感じている部分もありますが。

なので「生産性が良い」というよりは「苦にならない」という表現が実感としては近いかも知れません。

今後も機会があればガンガン Python 使っていきたい!

心がけたこと

この Requests-HTMLに関するブログ記事に「ライブラリ自体は多く仕事をせず、既存ライブラリを組み合わせることに徹する」という一文を読み、なるべく僕も既存ライブラリをうまく使うよう心がけました。自分で書く部分が少なければ少ないほどテストも短くなるし。これはPythonに限った話ではないかも知れませんが。

Python は他の言語と比較してライブラリの数が多すぎて主要なものだけでも把握するのが大変。まだ「ここはあのライブラリ使えばいいのに」といった部分やライブラリそのものをうまく使いこなせてないところは結構あると思います。特に dataclasses のあたりはうまく使いこなせてないかも知れない。

困ったこと

やっぱり変数の型を明示的に宣言できないところ。型アノテーションを使って mypy でチェックしてたけどそれでも型絡みの例外が出ることがあった。今後、mypy の精度がさらに上がることに期待。それまでは単体テストをガリガリ書く。いつか TypeScript みたいに TypePython みたいなやつが出るといいな。

それと SQLite で数値を ROUND すると誤差が出たりもしたけれど、数値計算や集計はなるべく pandas でやるようにして回避した。

それと、なぜPythonはこんなにも遅いのか? という記事を読んで性能面に若干の不安はあったんですが、EUC 領域であれば問題になることは少ないだろうと思いますし、実際あまり問題になるようなことは今回はありませんでした(むしろ自分の書き方が処理性能に大きな影響を及ぼしていたりした)。

それでどうなったか

実装フェーズは終わって、今頃は ACCESS 版と並行運用して検証フェーズに入っているはずだったんですが、このコロナ禍で滞っております...(なのでこの記事を書いたりしている)

これからどうなる

よく言われることですが、自動化したい定形タスクや、メンテナンスできる人がいなくなってしまった EUC アプリケーションってのは世の中には死ぬほどあるそうで。

方や非エンジニアの人でも Python に興味を持っている人がいたりして、今後は非エンジニアの人々にもPython使いが少しずつ増えていくのではないかと期待しています。

これらをかけ合わせると、今後もこういった 既存 EUC の棚卸しや、省力化、モダン化といった仕事が小規模ながらも増えていき、そういった仕事をエンジニアが支援するようなビジネスも出てくるのではないかなと思っています。