開発ノート:レガシーWindowsアプリをElectron化し、バックエンドをクラウド化した実践記

プロジェクト背景と目的
私が関わったのは、製造業向けに長年利用されてきたWindowsデスクトップアプリを、軽量なWebベースのクロスプラットフォームアプリに刷新する案件でした。従来のシステムはWindows 7環境で動作し、社内の生産管理データをローカルDB(Access)で管理していました。しかし、Windowsサポートの切れやOSアップデートの煩雑さ、開発会社が保守していたエンジニアの退職により、新機能追加が停滞し、保守費用が高騰していました。
事業責任者のBさんは「サーバーレス化して予算を圧縮しながら、将来的にmacOSやLinuxでも動くようにしたい」という課題を抱えており、私たち技術チームは要件定義フェーズで次の方針を固めました。
-
フロントエンドをElectronで実装:既存のWin32 UIをなるべく踏襲しつつ、Webテクノロジー(HTML/CSS/JavaScript)で再構築し、「システム利用者の学習コスト」を抑える。
-
バックエンドをクラウド+サーバレスAPI化:Azure Functionsを用いてAPIを構築し、データベースはAzure SQL Databaseへ移行。オンプレミスまで含めた開発会社選びでは、クラウドサービス利用実績とデータ移行ノウハウが重視される。
-
予算・費用管理:レガシー保守費用の相場(年間約500万円)から、初期開発費用(約300万円)+ランニングコスト(年間約100万円)に抑える目標を設定。既存開発会社との契約変更ではなく、クラウドやElectronの経験がある外部ベンダーを相見積もりで比較して選定する。
この構想をもとに、発注候補の開発会社A社とB社にRFPを送付し、要件定義をスタートしました。
要件定義~開発会社選びの苦労
まず、現行Windowsアプリの機能を洗い出し、画面遷移やバッチ処理の仕様をドキュメント化しました。しかし、操作フローや業務ルールが長年の運用で口頭で引き継がれていたため、一部の機能は設計書に記載がなく、担当者のBさんにヒアリングを繰り返すことに。
-
曖昧な要件による追加費用リスク:現行機能を正確に把握できず、開発会社からの見積もりは200万~400万円と幅が広く、相場感がつかみにくかった。
-
開発会社の比較ポイント:A社はElectron実績が豊富だが、クラウド移行経験が乏しい。B社はAzure Functions経験があるが、Electronは初めてという状況。
-
交渉と妥協:最終的には、ElectronとAzure開発を両方手掛けられるC社を探し当て、要件定義~RFP提出のタイミングで「Electronとクラウドサービス利用実績を確認すること」を要件に盛り込んだ。これにより、発注先選びの工数を大幅に減らせた。
要件定義は上流フェーズに当たるため、「システムとして必要な機能」「拡張性」「開発費用の相場」を事前に把握し、RFPにてC社に「機能別工数内訳」「開発会社担当者のスキルセット」「サーバレス移行実績」を明記して提示。C社からは300万円の見積もりが返却され、予算枠内で収まることを確認して発注を決定しました。
Electron化の技術的ポイントと課題
C社では、既存のWinFormsアプリをそのままWeb技術に置き換えるのではなく、以下のポイントに配慮してElectron化を進めました。
-
UI設計とUXの継承:WinFormsで使われていたグリッドコンポーネントは、React+Material-UIのテーブルに置き換え。既存ユーザーの操作方法を踏襲しつつ、WebネイティブのUX向上を図った。
-
IPC(プロセス間通信)設計:Electronではメインプロセスとレンダラープロセスに分かれるため、重いバッチ処理やファイルI/Oはメインプロセスで実行し、レンダラーにはIPCを使ってステータスを通知。バックエンドAPI呼び出しによる待機時間をレンダラーで非同期に表示することで、操作性を向上させた。
-
ビルドと配布戦略:開発会社はElectron-Builderを活用し、Windows用のインストーラー(NSIS形式)とmacOS用のPKGを作成。社内に太いネットワークがない拠点もあるため、インストーラーの差分アップデートを実現し、配布コストを抑えた。
-
自動アップデート機能:ElectronのautoUpdaterを活用し、Azure Blob Storageにホスティングされたアップデート情報を参照して、アプリ起動時に最新バージョンをチェックする仕組みを導入。これにより、ユーザーが旧バージョンを使い続けるリスクを軽減し、導入後の運用保守コストを下げた。
当初、開発会社はElectron開発の相場を「50工数(約100万円)」と見積もり、その後のテストや配布対応も含めて最終的に約120工数(約240万円)となりました。発注前に「ElectronとAzure Functions連携」についてのPoCをC社と一緒に実施し、概ね予算感を把握していたため、大きな金額増加は避けられました。
バックエンド移行とクラウド化の工夫
並行して、バックエンドのDBをAzure SQL Databaseに移行し、APIをAzure Functionsで構築する作業が始まりました。従来はAccessファイル1つで済んでいたためDB移行の相場がわからず、初期見積は150万~300万円と幅が広く設定されていました。そこで我々は次の工夫を行いました。
-
データ移行計画の策定:AccessからSQL Serverへのエクスポートを行い、Azure Data Factoryを使ったインポートジョブを構築。既存データの正規化やインデックス設計をC社と共同で実施し、移行後のクエリパフォーマンスを担保。
-
サーバレスAPI設計:Azure FunctionsはHTTPトリガーとBindingsを使い、関数ごとに役割を分割。CRUD操作用の関数をAPI単位で作成し、Azure API Managementをフロントに置いてAPIキー管理やレート制限を実装。
-
コスト試算とチューニング:Azure Functionsの消費プラン(リクエスト数×実行時間)を利用し、想定利用量(月間10万リクエスト)であれば月額数千円程度と試算。DBはDTUモデルで選択し、最初は中程度のDTU(相場:月額5万円程度)を採用。本番稼働後にモニタリングし、DTUを自動スケールする仕組みを構築した。
-
セキュリティと認証:Azure AD B2Cを使ってユーザーID管理とOAuth 2.0認証を実装。認証機能自体はC社に一括で発注し、工数は20工数(約40万円)程度で収め、セキュリティ要件をクリアすることができた。
これらの移行とAPI開発は合計で約80工数(相場:160万円)となり、Azure Functions+Azure SQL Databaseの費用相場も含めて、初年度のバックエンド運用コストは約120万円に抑えられました。結果として、従来システムの年間保守費用500万円を大きく下回るコスト構造を実現し、事業部門から高評価を得ました。
テスト自動化とCI/CD導入
フロントエンド(Electron)とバックエンド(Azure Functions)の開発が進む中で、品質確保のためにテスト自動化とCI/CDパイプラインを導入しました。これにより、開発会社への発注後の追加テスト工数や保守費用を大幅に削減することができました。
-
フロントエンドテスト:Electron環境向けにSpectronを使ったE2Eテストを構築。画面遷移やボタン操作、ファイルダウンロードなど主要な機能を自動テストし、プルリク時にGitHub Actionsで実行。これにより、「UIバグ発生→リリース後対応費」「ユーザートラブル対応費」を削減できました。
-
バックエンドテスト:Azure Functions用にXUnit(C#)を使ったユニットテスト、Postman CollectionでAPI統合テストを実施。API ManagementのMocks機能でバックエンド呼び出しを擬似し、開発・テスト環境を分離して負荷テスト(k6)も実施。
-
CI/CDパイプライン全体構築:GitHub Actionsをメインに、ElectronビルドとAzure Functionsのデプロイを自動化。Electron用にはArtifactとしてWindows/Mac向けインストーラーを生成し、CDN(Azure Blob Storage)へアップロード、バージョン管理を自動化。バックエンドは「Git push → Functions CI → テスト → ステージング環境、自動デプロイ → テスト合格後に本番展開」というフローを整え、Releaseごとのダウンタイムを最小化。
これらの自動化により、手動QAやデプロイ作業にかかっていたコストを50%以上削減し、年間約50万円相当の工数削減を実現しました。開発会社選びの際に「テスト自動化やCI/CD構築経験」を重視したことで、品質と効率を両立したプロジェクト運営が可能になりました。
メンテナンスと運用保守の取り組み
リリース後の運用保守フェーズでは、以下のポイントを重視して実施しました。
-
障害監視とアラート設定:ElectronではSentryを導入し、クラッシュや例外をキャッチ。Azure FunctionsではApplication Insightsを活用し、失敗リクエストや高レイテンシ時にアラートをSlackへ通知。これにより、ダウンタイム10分未満で初期対応できる体制を整備。
-
ユーザーログと使用状況の分析:Electronアプリからユーザー操作ログを匿名化して送信し、Matomoで集計。どの機能がよく使われているか、どこで操作が中断されているかを可視化し、次期バージョンの機能改善に役立てた。
-
定期的なバージョンアップ:半年に一度のマイナーアップデート、1年に一度のメジャーアップデートを計画。Azure FunctionsのランタイムバージョンアップやElectronのNode.jsバージョンアップが必要になるたびに、開発会社と予算(費用)調整を行いながら、運用保守費用をコントロールした。
-
ドキュメント整備:技術的なドキュメント(API仕様書、Electron設計書、インフラ構成図)をConfluenceに集約し、社内メンバーと開発会社がアクセス可能な状態に。発注時には「納品ドキュメントに含める項目」を明確にしておくことで、後からドキュメント作成費用が発生するのを防げた。
-
予算見直しと相場感のアップデート:リリース後1年目の保守費用予算は約100万円でしたが、実際の運用でAzure Functionsの実行数が増えたため、コストが月額15万円に膨らみました。そこで、キャッシュ機能の追加や関数の統合を開発会社と協力して実施し、月額コストを10万円程度に抑え直すことができました。
この運用保守フェーズを通じて得られた教訓は、以下の通りです。
-
継続的なコストレビュー:クラウド利用状況は常に変化するため、予算と実コストを定期的に比較し、必要に応じてキャッシュ戦略や関数設計を見直す。
-
開発会社との長期的なコミュニケーション:要件変更やインシデント対応が発生した際に、開発会社と円滑に連携できる関係を維持することで、追加費用発生を最小限に抑えられる。
-
ドキュメントと運用手順の整備:リリース時にドキュメントをきちんと整備しておけば、新たにチームに加わったメンバーでも対応しやすくなり、運用コストを抑えられる。
成果と今後の展望
レガシーWindowsアプリをElectron+クラウド化するプロジェクトを通じて、以下の成果を得ることができました。
-
クロスプラットフォーム対応:Windows/Mac/Linux対応を実現し、新規拠点導入の際の環境準備コストを40%削減。
-
導入コスト削減:旧システム保守費用(年間500万円)から、初期開発費用(約540万円)+運用コスト(年間120万円)へシフトし、2年目以降は年間維持費を380万円削減。
-
開発スピード向上:PoCから本番リリースまで約4カ月で完了。開発会社選び段階で「Electron+Azure実績」を要件にしていたことで、学習工数を最小化できた。
-
追加機能開発の効率化:テスト自動化とCI/CDにより、毎月機能追加やバグ修正リリースを行える体制を構築。
-
ユーザー満足度向上:UI/UXを刷新し、操作性が向上。ユーザーからは「操作が直感的になった」「リモートでの利用が簡単になった」と好評を得た。
今後は、ElectronアプリをPWA化してオンラインブラウザでも利用可能にする計画や、Azure Static Web Appsへの移行検討を行い、さらなるコスト最適化とユーザー利便性向上を目指します。
この開発ノートが、同じようにレガシーシステムを刷新しようと考えている技術リーダーやプロジェクトマネージャーの皆様の参考になれば幸いです。
PWA(プログレッシブウェブアプリ)化の検討と課題
Electronアプリをオンラインブラウザでも使えるようにするには、PWA化が最適な選択肢です。PWA化するメリットは、インストール不要でURLさえあればすぐ利用できる点にありますが、Electron環境とブラウザ環境ではいくつか技術的な差異があります。まず、ElectronではNode.jsのモジュールやファイルシステムアクセスが標準で利用できましたが、PWAにはそれらの機能がありません。したがって、PWA化に向けて以下の対応を検討しました。
-
ファイルI/Oの代替手段:Electronではファイルをローカルディレクトリに保存していましたが、PWAではブラウザストレージ(IndexedDBやCache API)を活用。既存のファイル入出力ロジックを、IndexedDBへのデータシリアライズ処理に置き換えました。
-
ネイティブ機能の代替:Electronで使っていたプリンター連携やシステム通知などのネイティブ機能を、ブラウザ側のWeb API(Web Notifications、WebUSBなど)への対応に修正。特にWindows向けの工程報告PDF出力機能は、サーバーサイドでPDFを生成し、PWAからダウンロードさせる方式へ変更しました。
-
Service Worker とキャッシュ戦略:PWAではService Workerを活用して静的リソースやAPIレスポンスをキャッシュし、オフライン時でも基本的な操作が可能になるように設計。キャッシュTTLは1時間に設定し、更新頻度が高いデータ(最新生産実績情報など)はバックグラウンドフェッチで定期更新し、キャッシュと同期する仕組みを組み込んでいます。
-
レスポンシブUIとアクセシビリティ:Electron版ではデスクトップ前提の固定レイアウトでしたが、PWA対応でスマートフォンやタブレットにも対応しました。Flexible Gridレイアウトを採用し、画面サイズに応じてグリッドやボタン配置を動的に変更。さらに、社内SEの声を反映し、色覚バリアフリーにも配慮した配色設計やキーボード操作だけでも利用できるアクセシビリティ要件を実装しました。
これらの対応を行った結果、PWA化のための追加工数は約40工数(相場:80万~100万円)となりました。発注段階で「PWA対応要件」「IndexedDB移行」「Service Worker設計」を明記していたため、開発会社とのやり取りがスムーズで、予算内に収めることができました。
リアルタイム同期機能の実装と課題
Electronアプリ時代はローカルDBを利用し、クラウド同期はバッチ処理でしたが、PWA移行後はオンライン接続が必須となり、リアルタイム同期機能が求められました。既存運用では「日次バッチ」でのデータアップロードでしたが、PWA版ではユーザー操作後すぐにサーバーへ反映され、他のユーザーが即時確認できる仕組みを導入しました。具体的には、以下のアーキテクチャを採用しました。
-
Firebase Realtime Database または Azure Cosmos DB Change Feed:最初はFirebaseのRealtime Databaseを検証しましたが、機密性が高い生産データの扱いを考慮し、最終的にはAzure Cosmos DBのChange Feed(変更フィード)を採用し、データ更新をWebSocketでプッシュ配信する方式に変更しました。開発会社は「Cosmos DB Change Feed+Azure SignalR Serviceの実装例」を要件に含め、PoCフェーズでリードタイムを確認。
-
オフラインキャッシュと再同期戦略:PWAではネットワーク断を想定し、IndexedDBにローカルキャッシュを保持しつつ、接続復帰時にChange Feedを参照して差分同期を行うフローを構築。差分同期ロジックを設計する工数は約20工数(相場:40万~60万円)でした。
-
競合解決(Conflict Resolution):同一レコードを複数ユーザーが同時更新した場合の競合を避けるため、クライアント側にタイムスタンプを持たせ、最終更新時刻を比較して最新データを優先するルールを設計。ただし、業務要件によっては「ロールバック」「承認フロー」を挟む必要があるため、C社と協議のうえでトランザクション設計を要件化しました。
これにより、ユーザーは入力後ほぼリアルタイムで他メンバーのデータ更新内容を反映できるようになり、組織全体の生産性向上に寄与しました。ただし、Change Feed連携とSignalRの設計ミスで初期はデータ漏れや重複配信が発生し、開発会社とともにロギング強化とユニットテストの追加(10工数=20万円)を行い、安定性を確保できました。
カスタムプラグイン開発とデバッグの難易度
ElectronとPWAのハイブリッド環境では、Electron版で利用していたネイティブライブラリをPWAでも動作させるために、カスタムプラグインを作成する必要がありました。たとえば、現行システムではRFIDリーダー連携をネイティブDLLで行っていましたが、PWAではWebUSB APIを用いてブラウザ側からUSBデバイスへアクセスする設計に変更しました。しかし、社内標準ブラウザ(Internet Explorer互換モード)ではWebUSBが利用できないため、Electronのみで利用するカスタムモジュールと、PWA向けに別実装のモジュールを共存させるマルチプラットフォーム対応を行いました。
-
共通ビジネスロジックの分離:API呼び出しやDBアクセスなどのビジネスロジックは共通モジュールとして整理し、Electron用プラグインとPWA用プラグインはインターフェースのみを実装。これにより、保守性を確保しつつ、将来的に別のネイティブ機能を追加しやすい構成にしました。
-
ビルドフローの複雑化:Electron用とPWA用ではツールチェーンが異なるため、Webpackの設定を二重管理し、Electronビルド用にNode.jsモジュールをバンドル。PWAビルドではNode.jsモジュールを外して、代わりにWebUSBやIndexedDB用スクリプトを取り込むように設定。開発会社の提案で「mono repo 管理」を採用し、両者のビルド設定を一元化した結果、CI/CD構築工数は追加で20工数(40万~60万円)が発生しました。
-
デバッグ時の検証手順:Electron環境ではChromiumベースのDevToolsが使えますが、PWAではブラウザのデバッグツールを使う必要があるため、開発チームはChromeとEdgeで動作検証を実施。特にWebUSB実装部分は、ブラウザ間で挙動差が大きく、User-Agentごとにテストケースを用意し、バグを逐次潰す工数が約10工数(20万)かかりました。
これらのカスタムプラグイン実装とデバッグ対応によって、初期想定よりも追加工数が発生しましたが、発注時に「ネイティブ機能の共存要件」を明記していたため、C社との契約範囲内で対応でき、予算オーバーは最小限に抑えられました。
セキュリティ強化と脆弱性対応
レガシーWindowsアプリ時代は社内LAN内のみでの利用を想定し、外部アクセスや脆弱性診断を行っていませんでした。Webベースにしたことで、セキュリティリスクが格段に増加したため、次の対策を実施しました。
-
OWASP Top 10 対策:フロントエンドのXSS(クロスサイトスクリプティング)対策として、Reactテンプレートのエスケープ機能を活用。APIではSQLインジェクション防止のため、パラメータ化クエリを徹底しました。
-
脆弱性診断とペネトレーションテスト:リリース前に第三者ベンダーによる脆弱性スキャン(Dynamic Application Security Testing)を実施し、XSSやCSRFなどの脆弱性を洗い出しました。診断費用は相場10万~20万円でしたが、早期に修正を行ったため、本番リリース後のインシデントはゼロでした。
-
認証強化:Electron版ではActive Directory連携でしたが、PWA化に伴いAzure AD B2Cを導入。OAuth 2.0とOpenID Connectで認証を行い、既存のオンプレミスユーザーIDをAD SyncでB2Cに同期。これにより、セキュリティ要件をクラウドベースで担保し、追加開発工数は15工数(30万~40万円)でした。
-
通信暗号化とネットワーク制御:バックエンドはすべてHTTPS+HSTS必須とし、API ManagementでIPフィルタリングを設定。特に、オンプレミスからクラウドAPIへの接続はVPNで行うことで、中間者攻撃のリスクを排除しました。
これらのセキュリティ対策は要件定義段階から開発会社に通知し、「認証/認可方式」「脆弱性診断」「VPN構築」などを開発範囲に含めることで、後から追加費用が発生するリスクを抑えています。
プロジェクトの振り返りと教訓
本プロジェクトの成功要因と得られた教訓を整理します。
-
要件定義の明確化と相見積もりの活用
あらかじめ「Electron化」「クラウド移行」「PWA化」「リアルタイム同期」「セキュリティ強化」という複数フェーズの要件を詳細に洗い出し、開発会社C社に対して段階発注を行いました。これにより、各フェーズごとの費用相場を把握し、予算オーバーを防止できました。 -
PoCでの技術検証と予算調整
ElectronとAzure FunctionsのPoCフェーズを設けたことで、エンジニアリングリスクを早期に発見できました。PoC工数が約30工数(60万~80万円)かかりましたが、これで学習コストを抑えられたため本番フェーズの工数と費用を正確に見積もることができました。 -
テスト自動化とCI/CDで品質と効率を両立
SpectronやGitHub Actionsを早期に導入し、手動テスト工数を約半分に削減。結果として、年間約50万円相当の工数削減効果が得られ、開発会社への追加テスト費用を抑えられました。 -
開発会社との継続的なコミュニケーション
週次定例会議とSlackでの情報共有を徹底し、仕様変更やタスクの優先度を適時調整。発注時に「変更分工数×単価で対応可」と合意済みだったため、緊急で追加要件が発生してもスムーズに対応し、コスト増を最小限に抑えられました。 -
運用保守への備えとドキュメント整備
リリース直後から運用保守フェーズに備え、ドキュメント(API仕様書、Electron設計書、運用手順書)をConfluenceで整備。これにより、新しいメンバーでも対応可能となり、運用保守コストを約20%削減できました。
これらの教訓を意識すれば、同様のレガシーシステム刷新プロジェクトで発注ミスや予算超過を防ぐことができます。特に、発注時に以下を明文化することが重要です。
-
機能別工数内訳と単価
-
要件変更時の対応方針(単価×工数)
-
テスト自動化/CI構築要件
-
運用保守に必要なドキュメント納品要件
-
セキュリティ診断、バックエンド連携方式の明示