エンジニア

すごいVBAをLambda+HTML帳票+Puppeteerに置き換えた話

すごいVBAをLambda+HTML帳票+Puppeteerに置き換えた話

2019/10/4 追記:本APIのCI/CDについて触れた続編を書きましたので、よければ併せてご覧ください。

CRMチームのyktakaha4です。

今日は、私たちが日々開発・運用しているハンズネットにおけるレガシーマイグレーションの現場をお届けします。

みなさんは、Excel、とりわけVBAはお好きでしょうか?

方々のエンジニアから親の仇のように忌避されながらもなぜだか中々無くならず、今日においても大小様々な企業で使われ続ける不思議な存在です。
嘘だとお思いでしたらInxxxxやレバxxxで「VBA」で検索してみてください。年収700万円も夢じゃないみたいですよ…?

私はExcelもVBAも好きです(でした)。

Officeの入ったWindowsがあれば使えるという可搬性に加え、
ユーザーフォームやExcel関数、CreateObjectやDeclareまで駆使すれば、控えめに言ってどんな処理でも実現できます。
また、Numbersやスプレッドシートの関数名、GASにおける各種オブジェクト名なんかを見ても、彼らがいかに広く浸透した概念であるか分かります。

前職では金融系の社内システムを開発していたのですが、資格を取得するくらいには活用していました。
もちろん不満・力不足に思う部分も沢山ありますが、エンドユーザと同じコンテキストを共有できて、どこでも使えて何でも作れるって、それ普通に全エンジニアの夢じゃないかと思うのですが…!

しかしながら、潮目は少しずつ、でも着実に変わってきています。
過去にはExcelでPythonが使えるようになるかもというニュースがあったり(結局JavaScriptになったんでしょうか?)、東急ハンズでも各種RPAツールの導入や、G Suiteの利用を推進していたりと、その利用の場は減っています。
令和の時代にはきっと新たな何かが世を席巻し、その陰に消えゆく運命にあるのでしょう…

そんなVBAに最後の餞として用意されたかのごとく、東急ハンズでExcelとVBAが大活躍する業務がありました。

そう、ハンズネットの荷札発送業務です。

ハンズネットは、すごーく大まかに言って、東急ハンズ新宿店の在庫をバックヤードで梱包してヤマト運輸経由で発送しています。
ヤマト運輸で商品を発送するためには、所定の送り状にお届け先の情報を印字してダンボールに貼り付ける必要がありますが、
この荷札の作成及び印刷をExcelとVBAマクロを駆使しておこなっていたのです。

図にあらわすと以下のような感じです。

出荷担当者目線では「梱包作業の時間になったらWebの画面にボタンが出るんで、押したら荷札が出てくる」程度のものですが、
システム担当者からすると、業務ロジックに基づいた荷札種類の決定、データへの書式設定、mm単位での微調整が必要なレイアウト、バーコードの生成、複数プリンタを指定する必要のある印刷処理などが渾然一体となったすごいやつ(尊敬)を保守し続けなければならず、
私含むエンジニアのほぼ全員がMacbook Proで開発を行なっている現状においては、環境を用意するだけでも一苦労…という状況でした。

そんな中、今年の10月に施行される消費増税、とりわけ経過措置としての軽減税率導入へ向けた対応の中で、当マクロの改修が必要なことが分かりました。
東急ハンズでは軽減税率対象となる食料品を一部扱っており、税率を分ける必要がある→荷札と一緒に添付する領収書で表示する税額を分けたり、商品ごとの税区分を明示する必要があったんですね。

現行のマクロを改修するという逃げの一手もありましたが、CRMチームのエンジニアリーダであるwatarukuraさんの判断もあり、この機会に保守が容易な別の仕組みに置き換えようという運びとなりました。
(私見ですが、こうした判断をエンジニアサイドから自発的におこなえるのは弊チームの良いところの一つだと思います。こちらもよければご覧ください)

今回は、マイグレーションによってコードを保守可能なものに置き換えることと、複数システムにまたがる税対応の中でスピード感を持って改修することを優先し、
外部サービスやパッケージを使うといった抜本的な運用変更までは考えず、既存と同等の荷札を別の仕組みで出力できるようにする…という方向性で改修方針を立てました。

改修後は以下のようになりました。

ユーザ目線では、従来Web画面でボタンを押下した際に自動的に荷札が印刷されていたのが、
出荷対象の全ての荷札が印字されたPDFファイルがダウンロードされるのでそれを印刷する…という形になっています。
印刷方式についてはチーム内でも議論がありましたが、業務部門のOKをもらった上で、今回の作業スコープからは一旦外すこととしました。
(運用がこなれてきたらより良い形を考えて、改めて提案したいですね…!)

業務的な話とは別に、本対応のキモであるVBAをPDF生成APIに置き換えた部分をもう少し詳しく紹介しておきます。

大枠では、VBAに組み込まれていた業務ロジックとデータへの書式設定をNode.jsに置き換えた上で、Excelでレイアウトしていた荷札をテンプレートエンジンであるEJSを用いたHTML帳票として出力し、それを更にGoogle ChromeのヘッドレスブラウザのPuppeteerでPDF化する…という感じです。
HTMLならVBAよりは修正にかかる心理的負荷を軽減できますし(WinMergeを使えば…とかあるかもしれませんが、コードでそのまま比較できるのはデカいと思います)、PDFはフォントや画像埋め込みもできて環境差異が出づらく、かつ業務部門にとってもある程度扱えそうなものだったため、利用技術として選定しました。
Puppeteerを使ったのは、公式で活発に開発が行われていたからというのもありますが、東急ハンズではGoogle Chromeを社内標準のブラウザとして定めており、色々知見が溜まれば今後に活かせそうに思えたからです。

また、今回の業務要件特有の話になりますが、1日の間に締め時間が数回あり、その時点までに受け付けた注文をなる早で荷札出力する必要がある…という課題がありました。
一回の締め処理で扱う注文数は、業務的な繁忙期も考慮すれば最大で約1000注文程度を想定しなければならず、
処理量に応じていい感じにスケールアウトしつつ、出荷のない夜間帯などはお金が掛からない仕組みを構築したいと考えていました。
あと、細かい話ですが、プリンタがジャムったり締め処理後に注文情報が変更になった時用に、個別に荷札を再印刷する機能も作らなければならず、バッチ・Webの双方から呼び出し可能なAPIである必要もありました。

これについては、社内でも幾つかのプロジェクトで利用実績のあったServerless Frameworkを使って、APIとしてリクエストを受ける親のLambda関数と、EJSによるレンダリング〜PuppeteerでPDF出力までを担う子のLambda関数をそれぞれ別に定義し、処理量に応じて子Lambda側の並列実行数を増やして対応することとしました。

平行処理については、作る前は苦戦しそうかな…?と思っていた部分だったのですが、結果的にはほとんど詰まるところがなく、改めてマネージドサービスは便利ですごいな…と思い知りました。
また、Serverless Frameworkについても、ソースコードのパッケージングからデプロイ、関数毎のメモリ使用量やタイムアウト秒数まで面倒見てもらえるので、本番デプロイなどコマンド1発で済んでしまい、大変助かりました。

最後に。
ご参考まで、対応前後の荷札サンプルも貼っておきます。今まで単に荷札と説明してきましたが、右部は商品明細になっていて、切り取ってダンボールの中に入れるようになっています。
上が対応前(VBA)、下が対応後(PDF)です。開発中の写真で位置調整が甘いですが、なんとなく雰囲気は分かってもらえるのでないかと思います。

VBA版
PDF版

余談ですが、従来バーコードコントロール9.0でおこなっていたバーコード出力はJsBarcodeを使うようにしました。フォントもおなじみMSゴシックからNoto Sansに変えたので、なんとなく見やすくなった感じがしますね。

現在は、従来のExcelバージョンとPDFバージョンを双方出力できるような状態で本番化して、処理量と処理速度を監視しつつ、業務部門に不都合がないか最終確認してもらっている段階となっています。
消費税対応のためにはじめたマイグレーション作業でしたが、これをきっかけに、実は他にも荷札で直したいところがあって…というような依頼もいくつか頂くようになり、業務改善にも寄与できそうでいい感じです。

っていうか、ようやく税対応のスタート地点に立つことができたという話なので、
これがキャリア最後のVBA対応になることを強く願いつつ、もう一息頑張っていきます…!

一覧に戻る