こんにちは! 日々の開発、本当にお疲れ様です。
ExcelのVBAや古いマクロの記録から一歩踏み出し、「よし、本格的なVB.NETでアプリケーションを作ろう!」と意気込んでいるあなたへ。
今回は、VB.NETを学ぶ誰もが最初に直面する、そしてシステムの運命を分ける極めて重要なテーマについてお話しします。
そう、それは「Module(モジュール)」と「グローバル変数」の正しい使い方です。
「どこからでも変数を呼び出せて、関数も自由に置けるModuleって、魔法のように便利だな……」
そう思っていませんか?
実はその便利さの裏側に、保守性をズタズタにする巨大な罠が潜んでいます。ここをクリアすれば、あなたの書くコードは「動くおもちゃ」から「プロ仕様の堅牢なシステム」へと劇的に生まれ変わります。さあ、一緒に本質を学んでいきましょう!
—
1. VB.NETの「Module(モジュール)」とは何か?
VB.NETにおける `Module` は、一言で言えば「インスタンス化(new)しなくても、中身をどこからでも呼び出せるカプセル」です。
通常、オブジェクト指向言語である.NETの世界では、処理を行うためにはまずクラスを実体化(`New`キーワードを使用)しなければなりません。しかし、Moduleの中に書いた変数やプロシージャ(SubやFunction)は、プログラムのどこからでも `Module名.メンバー名` (あるいは直接メンバー名)で呼び出せます。
VBA(Visual Basic for Applications)の標準モジュールに近い感覚で使えるため、初心者にとっては非常に親しみやすい存在です。
便利な使い方:共通関数(ユーティリティ)置き場
Moduleの最も正しい使い道の一つが、「どこからでも使いたい純粋な共通関数(ユーティリティ)」をまとめることです。
‘ 良い例:状態を持たない純粋な関数(引数だけで結果が決まる)
Module StringUtils
‘ 文字列が空かどうかを安全にチェックする関数
Public Function IsNullOrEmpty(ByVal value As String) As Boolean
Return String.IsNullOrEmpty(value)
End Function
End Module
このような「入力値に対して計算結果を返すだけ」の関数(副作用がない関数)を置く場所としては、Moduleは非常に優秀です。
—
2. なぜ「グローバル変数」の乱用は悪なのか?
しかし、Moduleの利便性に甘えて、次のようなコードを書くようになってはいけないと、伝説のアーキテクトたちは口を酸っぱくして言います。
VB
‘ 危険な例:すべてをModuleのグローバル変数で管理しようとする設計
Module AppData
Public CurrentUserId As String
Public IsLoggedIn As Boolean
Public DatabaseConnection As SqlConnection
Public RetryCount As Integer
End Module
これの何が問題なのでしょうか? 初心者が陥りがちな3大リスクを見てみましょう。
① 「誰が・いつ・どこで」書き換えたか分からない(追跡不可能の呪い)
グローバル変数は、プログラムのどこからでも読み書きが可能です。
もし「`CurrentUserId` が突然空っぽになってエラーになる」というバグが発生したとき、数万行あるコードのどこがこの変数を書き換えたのか、犯人を探すのは至難の業です。デバッグ地獄の始まりです。
② テストが不可能になる(結合度の罠)
プログラムのパーツ単体でテスト(単体テスト)をしようとしたとき、グローバル変数に依存しているコードは「特定の順番で変数に値が入っている状態」を作らないと動きません。環境や実行順序に依存するコードは、自動テストの最大の敵です。
③ マルチスレッド時代への完全な逆行
現代のPCやサーバーはマルチコアCPUが当たり前で、複数の処理を同時に行います(マルチスレッド)。グローバル変数は複数の処理から同時に書き換えられる可能性があり、データが破損する致命的なバグ(競合状態)を引き起こします。
—
3. オブジェクト指向に基づいた安全な設計へのステップアップ
では、グローバル変数を使わずに、どのようにデータを管理すればよいのでしょうか?
答えは簡単、「データを必要とするオブジェクト(クラス)に責任を持たせる」ことです。
先ほどの「ログインユーザー情報」を例に、グローバル変数に頼らないモダンなクラス設計を見てみましょう。
ステップ1:データを保持するクラスを作る(データモデル)
‘ ユーザー情報をカプセル化するクラス
Public Class UserSession
‘ プロパティを使って安全にデータを保持
Public Property UserId As String
Public Property UserName As String
‘ コンストラクタで初期化を強制する
Public Sub New(ByVal id As String, ByVal name As String)
Me.UserId = id
Me.UserName = name
End Sub
‘ このデータに関する振る舞い(メソッド)も持たせられる
Public Function IsAdmin() As Boolean
Return Me.UserId = “ADMIN_001”
End Function
End Class
ステップ2:必要な場所に「依存性」として渡す
グローバル変数から勝手に値を取るのではなく、「使う人に必要なものを渡す(依存性の注入)」という設計にします。
Public Class OrderProcessor
‘ フィールドとしてセッション保持用の変数を定義
Private ReadOnly _session As UserSession
‘ コンストラクタ経由で依存するオブジェクトを受け取る
Public Sub New(ByVal session As UserSession)
_session = session
End Sub
Public Sub ExecuteOrder()
‘ グローバル変数を見に行かなくても、手元の安全なインスタンスから値が取れる!
Console.WriteLine($”{_session.UserName} さんが注文を実行しました。”)
End Sub
End Class
このように設計することで、「誰がこのセッションを持っているか」「どのユーザーの権限で処理が行われているか」がコードの契約(シグネチャ)として明確になり、バグの入り込む余地が劇的に減ります。
—
4. まとめ:Moduleとどう付き合うべきか?
ここまでの話を整理しましょう。
- Moduleの正しい使い道
- 状態(変数)を持たない、純粋な共通関数(Math系やString処理など)の置き場。
- アプリケーション起動時のエントリポイント(`Main`メソッドなど)。
- 避けるべき使い方
- アプリケーションの状態(ユーザー情報、設定値、フラグなど)をグローバル変数として保持すること。
「手軽だから」とModuleとグローバル変数に逃げると、コードが成長したときに必ず自分自身の首を絞めることになります。
マクロの記録やVBAのラフな記述から脱却し、クラスやインスタンスという「オブジェクト指向の武器」を手に入れたあなたなら、もう大丈夫。
「変数は必要なスコープに閉じ込め、責任の所在を明確にする」――この原則を胸に、安全で美しいVB.NETコードを書き上げていきましょう。
ここをクリアしたあなたなら、VB.NETの基本はもうバッチリです!
次回の解説もお楽しみに。お疲れ様でした!
