【実務・中級編】【上級】バージョン管理システム(Git等)と連携したステンシル配布の自動化 – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

ステンシル管理の終焉、そして「資産」としての自動同期へ:Git連携によるステンシル配布の極限設計

「最新のステンシル、どこにありますか?」
「あ、昨日メールで送ったやつです」
「え、それ、先週の修正が入ってないかもしれません……」

もし、あなたのプロジェクトでこのような会話が一度でも交わされたことがあるなら、あなたはエンジニアとして、あるいは自動化の責任者として、致命的な設計ミスを犯している。

ステンシル(.vssx)は単なる「図形の集まり」ではない。設計思想が詰まった、エンジニアリングにおける「構成管理対象(Configuration Item)」である。これをメールや共有フォルダのコピーでやり取りする行為は、ソースコードをメモ帳で書いてメールで送るのと同義だ。

本稿では、Visio VBAを単なる「操作の自動化」に留めず、Git等のバージョン管理システム(VCS)と密結合させ、チーム全体のステンシル環境を「常に最新かつ整合性が保たれた状態」に強制同期させる、プロフェッショナルなアーキテクチャを伝授する。

1. 凡庸な設計と、卓越した設計の境界線

多くの開発者が陥る罠は、「VBAだけで全てを完結させようとすること」だ。

VBAは優れた自動化言語だが、Gitのクローン、プル、コンフリクト解消といった高度なVCS操作を行うには、ランタイムの制約やネットワーク制御の面であまりにも不向きだ。VBAで無理にGitコマンドを叩こうとすれば、エラーハンドリングは泥沼化し、ユーザーの環境(パスの設定やSSHキーの管理)に依存した脆弱なツールが完成する。

破綻する設計(Anti-Pattern)

  • VBAによる直接的なファイルコピー: 共有サーバのファイルを直接上書きしようとして、誰かがVisioで開いているだけでアクセス拒否(Permission Denied)が発生する。
  • タイムスタンプ依存の同期: ファイルの更新日時だけで判断すると、Gitのチェックアウト操作によって意図しない更新検知が走り、無限ループや不要な再読み込みを引き起こす。

堅牢な設計(The Architect’s Way)

我々が採用すべきは、「役割の分離(Separation of Concerns)」である。

1. Source of Truth (Git Repository): ステンシルの正解データ。
2. Sync Engine (PowerShell/Python): Git操作を専門に行う外部スクリプト。VBAから呼び出される。
3. Orchestrator (Visio VBA): Visioアプリケーションのライフサイクルを管理し、Sync Engineを起動し、同期結果に応じてステンシルの再読み込みを行う「司令塔」。

2. プロダクション・アーキテクチャの全体像

この設計では、以下のワークフローを構築する。

1. 起動時検知: Visio起動時、または特定のボタン押下時にVBAが「管理用マニフェストファイル(JSON等)」をチェック。
2. 外部同期のトリガー: マニフェストに差異があれば、VBAはバックグラウンドでPowerShellを起動。
3. 原子的な更新 (Atomic Update): PowerShellがGit Pullを実行。作業ディレクトリへの反映が完了するまで、Visio側は待機。
4. 安全なリロード: 同期完了後、VBAが現在開いているステンシルを一旦閉じ、最新版をロードし直す。

3. 実装:極限のコード例

ここでは、最も実務的で堅牢な「PowerShellによる同期 + VBAによる制御」の構成例を示す。

A. Sync Engine (PowerShell: `Sync-Stencils.ps1`)

VBAから呼び出される「実務担当者」だ。Gitの操作と、エラーハンドリングを一手に引き受ける。

<#
.SYNOPSIS
    Gitリポジトリからステンシルを同期するスクリプト。
    VBAから呼び出され、終了コードで成否を返す。

>

param ( [string]$RepoPath, # ローカルリポジトリのパス [string]$StencilDir # ステンシルが配置されるディレクトリ ) $ErrorActionPreference = "Stop" try { if (-not (Test-Path $RepoPath)) { Write-Error "Repository path not found: $RepoPath" exit 1 } # 1. リポジトリへ移動 Push-Location $RepoPath # 2. Git Pullの実行 # --ff-only を指定することで、コンフリクトによる意図しないマージを防ぐ git pull --ff-only if ($LASTEXITCODE -ne 0) { throw "Git pull failed with exit code $LASTEXITCODE. Manual intervention required." } # 3. シンボリックリンクまたはコピーによる配置 (ここでは単純な同期を想定) # 本来はリポジトリ内の特定のディレクトリをStencilDirへ同期させる処理を書く Pop-Location Write-Host "Sync Successful" exit 0 } catch { Write-Error $_.Exception.Message exit 1 }

B. Orchestrator (Visio VBA)

司令塔であるVBA。ここでの肝は、「ファイルが使用中(Locked)である場合の挙動」をどう制御するかだ。

Option Explicit

' --- 設定定数 ---
Private Const REPO_PATH As String = "C:\Dev\StencilRepo"
Private Const SYNC_SCRIPT As String = "C:\Dev\Scripts\Sync-Stencils.ps1"
Private Const STENCIL_FILE As String = "C:\Dev\Stencils\Standard_Parts.vssx"

''' <summary>
''' ステンシルの同期と再読み込みを統括するメインルーチン
''' </summary>
Public Sub SynchronizeStencilEnvironment()
    Dim shell As Object
    Dim exec As Object
    Dim exitCode As Integer
    Dim command As String
    
    Set shell = CreateObject("WScript.Shell")
    
    ' 1. PowerShellの呼び出しコマンド構築
    ' 引数はダブルクォートで囲み、パスの空白によるエラーを防止する
    command = "powershell.exe -ExecutionPolicy Bypass -File """ & SYNC_SCRIPT & _
              """ -RepoPath """ & REPO_PATH & """ -StencilDir """ & Left(STENCIL_FILE, InStrRev(STENCIL_FILE, "\")) & """"

    Debug.Print "Executing: " & command

    ' 2. 同期スクリプトの実行 (WaitOnReturn = True で完了を待機)
    ' 0: 正常終了, 1: エラー
    exitCode = shell.Run(command, 1, True)

    If exitCode <> 0 Then
        MsgBox "ステンシルの同期に失敗しました。ネットワーク接続またはGitの状態を確認してください。", vbCritical, "Sync Error"
        Exit Sub
    End If

    ' 3. 同期成功後のファイル操作(ここが技術的な見せ所)
    HandleStencilReload
End Sub

''' <summary>
''' ファイルのロック状態を考慮した、安全なステンシルの再読み込み
''' </summary>
Private Sub HandleStencilReload()
    Dim doc As Visio.Document
    Dim isLoaded As Boolean
    Dim i As Integer
    
    isLoaded = False
    
    ' 現在開いているドキュメントを確認
    For i = 1 To Application.Documents.Count
        Set doc = Application.Documents.Item(i)
        If doc.FullName = STENCIL_FILE Then
            isLoaded = True
            Exit For
        End If
    Next i

    On Error GoTo ErrorHandler
    
    If isLoaded Then
        ' 重要:開いているステンシルを閉じる。
        ' 保存せずに閉じる (msoFalse) ことで、ユーザーの意図しない変更の混入を防ぐ。
        doc.Close msoFalse
    End If

    ' 最新版をロード
    Set doc = Application.Documents.Add(STENCIL_FILE)
    
    MsgBox "ステンシルを最新版に更新しました。", vbInformation, "Sync Complete"
    Exit Sub

ErrorHandler:
    MsgBox "ファイルのリロード中にエラーが発生しました。ファイルが他のプロセスによってロックされている可能性があります。" & vbCrLf & _
           "Error: " & Err.Description, vbCritical, "Reload Error"
End Sub

4. 設計の要諦:なぜこの書き方なのか

なぜ `shell.Run(command, 1, True)` なのか?

第3引数を `True` に設定することで、VBAはスクリプトの終了を同期的に(待機して)待ちます。これにより、「同期が終わっていないのにファイルをリロードしようとしてエラーになる」という、非同期処理に起因する典型的なバグを完全に排除しています。

なぜ `git pull –ff-only` なのか?

自動化ツールにおいて、最も避けるべきは「ユーザーへのコンフリクト解消の要求」です。`–ff-only` を使うことで、もしローカルで誰かが勝手にステンシルを書き換えていた場合、マージを試みずエラーとして返します。これにより、「意図しないマージによるバイナリの破損」を防ぎ、管理者に通知する仕組みを担保しています。

なぜ `doc.Close msoFalse` なのか?

ステンシルは「マスター」であり、個々の図面が「インスタンス」です。ステンシル自体を編集することは本来避けるべきであり、万が一編集されていたとしても、同期プロセスにおいては「最新の正解(Git)」を優先すべきです。`msoFalse` を指定することで、古い状態の変更を破棄し、クリーンな状態を維持します。

5. さらなる高みへ:スケーラビリティの確保

この仕組みを大規模組織へ展開する場合、以下の拡張を検討してください。

1. マニフェストによるバージョン管理:
Gitリポジトリ内に `version.json` を配置し、VBAが起動時にその `version` フィールドを読み取る。現在のローカルバージョンと不一致の場合のみ、同期プロセスを走らせる。これにより、起動時のオーバーヘッドを最小化できる。
2. CI/CDとの連携:
ステンシルを修正してGitにPushした際、GitHub Actions等で「ステンシルファイルの破損チェック(Visioのコマンドラインインターフェースを用いた検証)」を自動実行し、壊れたファイルが配布されるのを未然に防ぐ。

結論

業務自動化のエンジニアリングにおいて、ツールは「動けばいい」ものではない。「壊れないこと」「整合性を保てること」「運用コストが低いこと」が絶対条件だ。

Visio VBAを、単なるマクロ言語として扱うのをやめなさい。外部の強力なエコシステム(Git/PowerShell)を指揮するオーケストレーターとして再定義すること。それが、プロフェッショナルな業務自動化への第一歩である。

タイトルとURLをコピーしました