配布の問題とは、実際は「配布後の問題」です。配布されるのは「仕組み」が実装されたExcelワークブックです。継続的に利用を繰り返すExcelでの仕組みの場合、その「仕組み」の改訂が必要となった時どのように対処するかがここでのテーマで、改訂要件が発生してから考えるのでは遅いのです。
「配布の問題」の根底は「バージョン管理」です。  
私にとっては「配布の問題」は「Excelでお仕事!」のメインテーマです。
この章で説明しているのは20年来試行錯誤してきた結果です。


マクロを配布する以上は「どこにどのバージョンを配布したか」を管理する必要があります。
これはどんな仕組みであってもマクロの改訂が「絶対にない」とは言い切れないからです。

さらに問題なのはこのバージョン管理を「台帳」を作成するなどで管理したとしても、Excelワークブックである以上その「コピー」が別の所に渡ってしまうことが防御できないことです。 マクロの改訂が発生して「台帳」で管理している配布先への入れ替えは確認できたとしても、その「コピー」が別の所に渡っていた場合はそこまでの入れ替えは確認できなくなってしまいます。
ですから、配布先が管理できないのであれば「管理できない前提」に立って対策を行なう必要があります。

これらのことからすると、マクロを作成する側が、そのマクロがどのように配布されて利用されるのかを拡大的に想定して、マクロの変更が発生した時の作業を最小限の作業で確実に行なえる対応を初段階から実装させておくことが「自分を守る」ことになるということを認識しておく必要があるというのがこの章の提言です。

「不具合がなければマクロの変更は発生しない」ということは余りに安易な発想です。少なくともワークシートのレイアウトが変われば以前に作成したマクロでは正しい結果が得られないのは明確だし、ワークブックの配置先に依存するマクロなら置き場所やファイル名が変われば動かなくなります。現時点の要求仕様を満たしていればそれで良いという考え方では企業内で継続利用されるマクロは維持できません。

社内に便利なマクロを作ってくれる人がいて...

たいていはこんなシチュエーションから始まります。
貴方がその「便利なマクロを作ってくれる人」かも知れません。 「便利な機能ができたので、皆さんに使ってもらおう」ということだと思います。
ですが、どの部署の誰にどのマクロを配布したのか管理できていますか?
渡した先からさらにコピーが別のところにいったのか把握できてますか?
渡した先の人が異動したら「持って行ったか」「置いていったか」判りますか?(両方かも知れません)

そのマクロに変更が起きたとき配布先全てを同期を取って更新できますか?
ということがこの章の問題提起なのです。

便利な機能マクロを各署に配布して業務合理化を図ること自体はむしろ歓迎すべきことだと思うのですが、 やるからにはこのページで提起している問題に直面することになることを含めて考える必要があります。

しかもこれは「マクロを作る本人」だけの問題ではありません。
「社内に便利なマクロを作ってくれる人がいて...」というのは、その人が退職してしまうと後の対応ができなくて、 以前便利だったマクロも使えなくなってしまった、などということも良く聞く話です。

本来なら、関連部署内のものであっても「こういう方法で業務合理化ができる」と提言して作成するマクロを「公」のものにすべきです。 さらにその前後での作業工数や残業時間数などで効果が測定できればもっと良いです。 その上で作成者はしかるべく「評価」を得られるべきだと思います。

ですが、一般にはこのことでの「評価」というのは一過性のものを除くとあまりありません。
なぜなら、その「便利な人」が異動や退職した後のことを部署や企業側で対応できる保証ができないからです。 効果が「工数削減」であれば「≒人減らし」となってしまうことに警戒感を持つ上長だっているはずです。 それなら上記の「効果」が発表できる状態で、後継を育成するとか、社内でマクロの学習を行なうとかまで持っていけるのであれば最高でしょう。
そうでないとしても、どこにどのようなマクロが存在するのかを含めて、後継の人に引き継げるだけのドキュメントはきちんと整備しておくべきです。


バージョン管理とは「記録」だけのことではありません。

作成したマクロの規模はいろいろあるでしょうが、そのマクロが社内各署に配布されたとして、問題が起きるのは改訂が発生した時です。
複雑な機能のマクロだとするとその改訂も複数回発生するかも知れません。
Excelワークブックはマクロの有無にかかわらず、簡単に「コピー」ができて持ち出されてしまいます。 あちこちに作成したマクロが含まれるワークブックがあるとして、全てがすぐに最新バージョンに入れ替わるのであればここで言う「バージョン管理」はあまり意味がなく、 単に開発部門内だけの履歴上の問題で済みます。ですが、そうでない方が相当多いことだと思います。

つまり、マクロを配布する場合は、その初段階から後で起きる「改訂」の対策を考えておく必要があるのです。
運用部署に既に渡されたマクロの側から見ると自分のバージョンは下記の方法で簡単に判りますが、最新バージョンか必要バージョンをどこからか判定しないと 「改訂」の要/不要は判りません。 運用する担当者が何かの操作をする必要がなく自動的に最新バージョンに置き換わるのであれば何の問題もないのですが、 そうでないとすると、運用側では「どのバージョンだと何が問題なのか」を判断して処置するようなスキルも手段も持ち合わせていないことになります。

従って、マクロを提供する側は、最初にマクロを配布する段階でこの「改訂」を意識した対応(実装方法)を考える必要があります。
1回実行するだけで、以降継続利用することがない場合はこのような配慮は不要なはずですが、 一旦運用側に渡してしまうと翌年になって「昨年作っていただいたものが動かない」などという問合せとなってしまうこともあります。 1回しか使わない約束で作成するならそのようなドキュメントも記述して、 実行するExcelワークブックは運用側には渡さないなどの処置が必要です。


まず、最低限必要なことは...


マクロの作成側で念頭に置く必要があるのは以下の各項目です。

マクロのソースコードに変更履歴を明記する。あるいは改訂に関する台帳を更新する。
メインとなるソースコードの先頭コメント部分に更新履歴(バージョン、更新日、更新内容)を11行で記述して変遷が確認できるようにします。 これにより、どのバージョンで何が更新されたのかが判るようになり、実行バージョンが最新でない場合は何が問題なのかが判るようになります。
同じ日付や同じバージョンで複数の変更を行なった場合は、それぞれを別行で記述します。
以下は短期間に紆余曲折があった「カレンダー及び日付処理(祝日含む)関連関数」の例です。
ここには「誰が」は記載されていませんが、担当者が固定されていない場合は「誰が」も追加した方が良いでしょう。

'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'18/02/07(1.00)新規作成
'18/02/08(1.10)カレンダーテーブルに振替区分(0=通常、1=振替休日を行なわない)を追加する対応
'18/02/08(1.10)「カレンダーテーブル作成(当月+前後の3ヶ月用)」を追加
'18/02/10(1.20)クラス化移行のため、本モジュールはユーザー定義のみとする
'18/02/18(1.30)動作改善のため再作成(クラス化は廃止)
'18/02/21(1.40)GetCalendarTable3に当月開始・終了INDEXを返す引数(Option)を追加
'18/02/21(1.40)名称変更(g_typCalendar2⇒g_typAboutCalendar2) ※他との重複対応
'18/02/28(1.50)会社休日適用時に会社休日が振替休日や国民の休日と重なる時は法制休日を優先させる対応
'18/03/07(1.60)各関数にチェック処理をスキップするオプションを追加(事前チェックが済んでいる前提です)
'18/03/08(1.61)「週数」のカウント誤りを修正
'18/06/14(1.62)祝日パラメータチェックで開始年が処理日年+3を許可するように修正
'***************************************************************************************************
大きな仕組みの場合はモジュール単位の更新履歴だけでは済まないので、仕組み全体の変更要件単位の更新履歴として別の管理表を作成する必要があり、 この場合、モジュールの先頭に記述する更新履歴はそのモジュールに関する場合の更新履歴となります。
また、次項で利用するバージョン値の定数を用意して更新履歴と併せて最新値に更新するように管理します。

'***************************************************************************************************
' 現在バージョン情報
Public Const g_cnsCurrentVersion As String = "1.62"                 ' 現在バージョン
Public Const g_cnsVerUpdateDate As Date = #6/14/2018#               ' バージョン更新日

マクロのソースコードを開かなくても現在のバージョンが判るようにする。
対象ブックを開いた時にWorkbook_Openイベント等でマクロのソース側で管理しているバージョンをワークシートのどこか、もしくはステータスバーに表示するなどで利用者に視覚的に判るようにします。利用者はこのバージョンに対する意識はほとんどないわけですが、特定シートのセルに配置できて、その状態が保存されていれば変更要件が発生した時に各ワークブックを探索して未対応のバージョンのワークブックを見つけるなども可能になります。

'***************************************************************************************************
'* 処理名 :Workbook_Open
'* 機能  :ワークブックが開いた時のイベント
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2018年02月18日
'* 作成者 :井上 治
'* 更新日 :2018年02月18日
'* 更新者 :井上 治
'* 機能説明:バージョン情報をステータスバーに表示
'* 注意事項:
'***************************************************************************************************
Private Sub Workbook_Open()
    '-----------------------------------------------------------------------------------------------
    ' バージョン情報をステータスバーに表示
    Application.StatusBar = "Ver" & g_cnsCurrentVersion & _
                            "(" & Format(g_cnsVerUpdateDate, "yyyy/MM/dd") & ")"
End Sub
利用者側はそのマクロのバージョンがいくつなのかということに意識は全くないのが当たり前ですが、 何かの不具合等で開発側に問い合わせがあったとして、開発側の担当者が「どこに表示されているバージョンはいくつなのか」を質問し、 利用者がそこを見て返答ができるようにしておけば、バージョンの入れ替えができていないことによる不具合なのか等の判断材料にもなります。

データベースのテーブルの更新やファイル出力を行なう場合は、バージョン値の更新項目も用意する
これは、更新日時も併せれば出力されたデータ側から見て「どのバージョンのマクロでいつ出力されたのか」が後から判別できることになるので重要な要素です。 あるバージョンでの変更に問題が見つかったような場合に、対象バージョンが出力したデータを分類して、場合によってはデータ修復に役立てる場合がある他、 「配布の問題」の原点からすると「依然として古いバージョンのマクロでデータが出力されている」というケースの発見にもつながります。

マクロの変更が発生した時に利用中のマクロを確実に入れ替えられる手段を持つ。
マクロのモジュールの入れ替えという作業が人的作業となる場合は、Excelの一般ユーザーの知識範囲外のことです。従って、マクロを作成した側が行なわなくてはならない作業になります。
ここでは、その対象となるワークブックの数が問題となる場合があることを意識しなければなりません。
しかも、入れ替え対象となるワークブックが、マクロの作成者が参照できる範囲外に持ち出されている場合も想定する必要があります。場合によってはマクロが起動された情報をログとして出力するような手段を講じる必要があるかも知れません。
本件については次の「バージョンの判定や入れ替え手段」で説明します。

配布する各バージョンの「原本」を世代保存する。
マクロの実行環境が複数箇所となる場合や、機能改変が発生することが予想される場合は、実行側に引き渡す各段階(各バージョン)の「原本」や「開発ブック」を バージョンごとのフォルダを作るなどで保管させます。
最新バージョンに不具合があって1世代前に戻す場合や、実行環境に複数のバージョンが混在してしまうケースで以前のバージョンでの動作確認を行なう場合に対応するためです。
私のところでは、以前のバージョンに戻したことは一度もありませんが、かなり時間が経過してから過去の改訂の問題が発見されてその時点の改訂前後のバージョンの比較を行なうということが発生したことがあるので、 既に運用側に残っていないバージョンであっても各バージョンでの「原本」や「開発ブック」の退避(世代毎保存)については重要視しています。

ドキュメントを残す。
マクロの作成者がいつまでも同じ部署にいるとは限りません。
異動や退職に備えて、後任に「仕様」に関するドキュメントを残す必要があります。
「何を作成したか」に始まって、保存場所や仕様、状態を説明する中でバージョン管理や入れ替え方法も記述に加える必要があります。


バージョンの判定や入れ替え手段


既に各署に配布されているマクロを持つワークブックのマクロをどのようにして最新状態に更新するかの説明です。
ここでの説明は下記のどれかは採用すべきでしょうという説明です。 利用者数やプログラム規模、運用する期間の長さや今後の機能改訂の可能性の有無などでどの方法が良いかの判断は異なると思います。

①利用者に「マクロの入れ替えが必要」だと通知する。
バージョン入れ替えが必要だと判断されたら、利用者のその旨と作成部門への連絡を表記したメッセージを表示させます。
この仕組みをマクロの初段階に実装させておけば古いバージョンのマクロが実行されることを防御できます。
(実際はマクロは実行されるが初段階で停止するという動作)
ここではバージョンが「古いかどうか」の判定が必要となりますが、これは例えば社内ネットワーク上の「決まった場所」に最新バージョン値だけを書き込んだテキストファイルを格納しておき、ワークブック側のマクロが実行された時にソースコードのバージョン定数とこのテキストファイルのバージョン値を比較して、テキストファイルのバージョン値の方が新しい場合は警告メッセージを表示させるなどの対応を採ることができます。
但し、実際のマクロの入れ替えは、運用現場の利用者に行なわせるのは不可能であって、開発担当側が作業する必要があります。 これは運用現場の利用者に開発系の知識がないことだけではなく、VBAプロジェクトに対してパスワード保護を掛けていた場合にそのパスワードを公開しないと作業ができないという問題もあるからです。
やり方のよっては、古いバージョンのマクロが実行されたことをシステム管理者にメール等で通知するなどの方法を採ることも可能です。 この場合、「誰がどこで」に関してはコンピュータ名、IPアドレス、WindowsログインIDを補足情報として付加させる必要があります。

②マクロの起動場所を限定する。
作成したマクロが特定の部署でしか利用しないものという限定ができるのであればという前提になりますが、「そのコピーが別の所に渡ってしまう」ということを避ける工夫としては、そのワークブックの保存場所のコンピュータ名やフォルダ名をマクロの起動時に判定して当初の取り決め以外だったらエラーメッセージを表示して中止してしまうように仕組む方法があります。 この方法が適用できるなら、そのフォルダにある各ワークブックのマクロを入れ替えてしまえばバージョン更新の作業は一応は完了となります。
絶対に単一ファイルに限定させ複製からの起動を防ぐのであれば、取り決めたファイル・フォルダ名をフルパスで定数などに登録させておき、これと異なる場合は動作させないようにします。
但し、元の利用部署の環境が変わった場合はすべてのマクロがエラーになるという懸念もあります。

③主機能マクロを「マクロブック(又はアドイン)」に分離する。
多数に配布される、あるいはコピー・増殖がどこで行なわれるか把握できないような場合に推奨できる方法です。
前項(2項目)では「利用中のマクロを確実に入れ替えられる手段を持つ」ということに対して確実とは言えませんでしたが、この方法は確実と言えます。 ある程度のテクニカルレベルが要求されますが、バラバラに配布してしまった各ワークブックに対して後から機能が入れ替えられる方法であり、さらに各ワークブック側のマクロ部分が「アドイン呼び出し」のみになるので 対象ワークブックが多数になる場合は全体のリソース削減にも寄与できます。
まず、主機能マクロを「マクロブック」に分離し、主機能のマクロを収容した「マクロブック」を社内ネットワーク上の「決まった場所」に格納しておき、データを格納するワークブックにはこの「決まった場所」の「マクロブック」を呼び出すマクロだけを持たせる方法に切り替えます。

ワークブックからマクロの主要部分を切り離す。

この方法ならデータを格納するワークブックがどのように「増殖」しても呼び出される「マクロブック」はひとつだけに限定できるわけで、このマクロに変更の必要が発生してもあるひとつの「マクロブック」を更新するだけで済んでしまいます。利用者側から見れば呼び出される「マクロブック」が常に最新のものになるという図式が成立するわけです。
データを格納するワークブック内にもマクロは残りますが、「マクロブック」の呼び出し記述だけなので変更要件が発生することは非常に少なくなると思います。
この「マクロブック」を「アドイン(*.xla、*.xlam)」にしておけば、Excelにウィンドウ表示されないという利点があります。
ウィンドウ表示されないのでワークシートは見られませんが、マクロ側からアドイン内のワークシートを参照することは可能です。 2019年、2020年は祝日の変更があり、当サイトでは「祝日パラメータ」シートでの祝日判定機能を提供していますが、 この「祝日パラメータ」シートはアドイン内に配置してしまっても機能できます。 というか、カレンダー作成モジュールがアドイン内に配置されるわけですから「祝日パラメータ」シートもアドイン内に配置しなければ動作しません。
このようにして、実行ワークブックが社内の各署に配布される状態であっても、主機能マクロを「マクロブック」あるいは「アドイン」として一元的な場所に配置されたものを呼び出す構造ができれば、 一元的な場所にある「マクロブック」あるいは「アドイン」を新しいものに上書きさせるだけで各実行ワークブックの機能の改訂が行なえるというものです。
この場合の「マクロブック」あるいは「アドイン」がWindowsから見えるファイルサーバ上に配置できない(例えば全社から一元的に参照できるサーバがないなど)の場合は、Webサーバ上に配置する方法でも構いません。 「マクロブック」あるいは「アドイン」は読み取り専用で開くため、ワークブックとして見た場合の保存の動作はなく「http://」から始まるURLで開くことも可能です。
アドインについては後方の章で説明しています。

④マクロを入れ替えるマクロを実装する。
(この方法は現在ではセキュリティ上の理由で全くおすすめできません)
上記の「マクロブック(又はアドイン)」化ができない、あるいは社内で一元的にアドインを配置できる場所がない場合の方法です。
念のため、ここでの説明に加えておきますが、以前(かなり昔)はこの「マクロでマクロを入れ替える」が可能でした。

モジュール自動更新の確認メッセージ

現在でも100%不可能になったわけではありませんが、VisualBasicプロジェクトにパスワードが掛けられないし(掛けると動作に失敗する)、悪意があるマクロをワークブックに仕込むのと同じレベルのことなので、現在ではセキュリティ上で規制されています。セキュリティセンター(トラストセンター)でこの規制を解除できますが、解除したとしてもメモリ上に読み込まれているマクロを強制的に書き換える動作はその後のExcelの挙動を不安定にする可能性がありお勧めはできません。(画像もExcel2000時代のものです)

実行時エラー '1004': プログラミングによる Visual Basic プロジェクトへのアクセスは信頼性に欠けます

Office内のセキュリティ設定だけでなく、セキュリティソフトからも「動作のあやしいマクロ(≒マクロウィルス)」と判定され動作停止させられる場合もあります。 また、VBAプロジェクトに対してパスワード保護を掛けている場合は、パスワードが判っていてもマクロからVBAプロジェクトのパスワード保護を解除する方法がないので、 この方法は使えません。
基本的にこの方法は除外すべきでしょう。⑤の方法で充当できる(すべき)ものです。

⑤既存ワークブックのデータを新しい原本ワークブックに貼り替える。
同様に上記の「マクロブック(又はアドイン)」化ができない、あるいは社内で一元的に配置できる場所がない場合の方法です。
前項が既存ワークブックのマクロ部分を入れ替えようとすることに対して、逆に新しいマクロを持つ原本ワークブックに既存ワークブックのデータを貼り替えて元の既存ワークブックのファイル名に上書き保存させるという仕組みを用意すれば結果的に「最新状態」になります。
この「入れ替え」機能のマクロを別途作成します。フォルダを指定してそのフォルダにある各ワークブックに対して以下のような機能を連続実行させる仕組みとします。
 ①処理対象ワークブックを開きます。後で保存させるのでファイル名を別の変数に退避させておきます。
  ⇒処理前のワークブックを退避させておく必要があれば開く前に「_SAVE」等のサブフォルダを作ってコピーしておくと良いでしょう。
 ②そのワークブックがマクロ入れ替え対象かブック名、シート数やシート名、特定セルの値などで調べます。
   対象でなければそのワークブックに対しての③以降の処置は行ないません。
 ③新しいマクロを持つ原本ワークブックを開きます。
 ④処理対象ワークブックから原本ワークブックへ各シート上のすべての登録データを転記させます。
 ⑤処理対象ワークブックを閉じて削除します。
 ⑥原本ワークブックを退避してある処理対象ワークブック名で保存させて閉じます。
入れ替え対象が特定フォルダ内に大量にある場合には有効な方法だと思います。
この方法は処理対象ワークブックがどういう種別のものかが入れ替え処理マクロ側で判別できることと、入れ替え対象ワークブックの所在が明確になっていることが前提となります。 また、入れ替え済みかどうかが判るようにマクロのバージョンを表示するような機能を当初から実装させておいて下さい。

⑥何でも「Excel(VBA)」でやろうとしない。
ここでは「Excel」でない手段を紹介します。
開発担当者に対する「システム化」の業務要件がどんどん拡大していくような状況である場合は、何でもExcel(VBA)でやろうというのは反って危険です。 Excelである限り各ワークブックにVBAのモジュールが持ち込まれてしまうので、多数の機能のワークブックを作成してしまうと、 それぞれのバージョン管理がある上に作成した「業務要件の種類」が「かけ算」になって押し掛かってきます。
このような状況が予想される場合は、早い段階でExcel(VBA)ではなく、VisualBasic(.NET)への移行をお勧めします。
Excel(VBA)よりは多少スキルレベルが高いので勉強が必要にはなりますが、VisualBasicとしての言語種族は同じなので 記述差異に限って勉強すれば移行は可能です。インプットやアウトプットをExcelで行なうように仕組めば利用者に対する運用変更も低く抑えられる上、 ClickOnceが利用できればここまで説明してきた「バージョン管理」からも解放され、 プログラム自体は各PCにインストールされるにも関わらず、利用者がメニュー等から起動した時に自動的に最新バージョンへの更新が行なわれるような仕組みへと変貌します。
私は、2007~2008年に社内でERPやワークフローのパッケージを導入したことにより、その中に組み込めない周辺業務の作成で「この状況」になり、 また、これらの環境移行によりデータベースサーバ、Webサーバが配備されたこともあって、担当範囲をVisualBasic(.NET)へ移行させました。 方法論について会社側からの言及があまりなかったことも優位に働き、開発言語ソフトライセンスの購入程度しか外から見た費用も発生していません。
VisualBasic(.NET)であれば、コントロール(画面用部品)Excel(VBA)より数倍豊富で、 メールソフトのような画面左にツリーメニューを配置したMDI(MultiDocumentInterface)アプリも作成でき、 既設データベースサーバ内に独自のデータベースやテーブルが追加できる環境になったので、ログイン認証から始めて、ユーザー権限による利用メニューの制限等にも配慮して 全社に公開できる仕組みを作成していき、300を超えるメニューの実装を行なってきました。

Excel(VBA)」で多数の仕組みを配布するのが良くないとされるもう一つの理由。
Excel(VBA)での仕組みを多数作成して各署に配布するという業務運用の問題はもう一つあります。 これはセキュリティ面での問題です。
VisualBasic(.NET)であれば配布物はビルドされた実行ファイルでありそのままではソースコードは見られませんが、 Excel(VBA)VBプロジェクトにパスワード保護を掛けたとしてもパスワードで「蓋」をしただけで「蓋」を外せばソースコードは見られてしまいます。 社内のデータベースにアクセスする仕組みであれば、データベースに対するユーザーIDやパスワードも見られてしまうことになります。
VBプロジェクトのパスワードが知られなければ良いのですが、これを知っている開発側担当者が別部署に異動することもあります。 このようなケースでの対応がExcel(VBA)はやりにくいと言えます。 要はVBプロジェクトのパスワードを以前とは変更しなければならないからです。
最新の開発環境から最新バージョンのVBプロジェクトのパスワードを変更することは可能ですが、これでは配布済のワークブックとパスワードが異なるという結果になってしまいます。 「マクロブック(又はアドイン)」化ができているなら、この被害は少ないですが、 「マクロブック(又はアドイン)」を呼び出すワークブック側のVBプロジェクトのパスワードはどうするのかという問題も残ります。

VisualBasic(.NET)に移行するのであれば、この問題からも解放されます。

さらにVisualBasic(.NET)Excel(VBA)を言語的に比較した場合は、 VBAから見たVB.NETの使いやすさ」のようなこともあるので、 開発部署としても若い社員を受け入れるのにいつまでも古い開発環境を引きずったままというのが良くないということも考えなければならないと思います。
開発済資産が大量にあるなどが移行を妨げる要因かも知れませんが、大量なほど合理化要素が多いので移行後の展開が明るいということでもあると思います。