神のコード(God Class)を葬る:VB.NETリファクタリングの極致
数千行の `Form1.vb`。そこに鎮座する、もはや誰も全貌を把握できない巨大なビジネスロジック。
「動いているから触るな」という恐怖が、技術的負債という名の腐敗を加速させる。
私は数多くのレガシーシステムを解体してきた。VB6の悪夢から .NET の泥沼まで。今日語るのは、単なるデザインパターンの教科書的な説明ではない。「いかにしてシステムを破壊せずに、モダンなアーキテクチャへと脱皮させるか」という、実戦的な外科手術の手法だ。
—
1. なぜ「God Class」は死を招くのか
Windows Formsのコードビハインドに書かれたビジネスロジックは、UIスレッドと密結合している。これは単なる設計ミスではない。メモリの寿命と論理の寿命を強制的に同調させているという大罪だ。
- 単体テストの不可能: UIコンポーネントをインスタンス化しないとロジックを動かせない。
- メモリリークの温床: イベントハンドラが解除されず、GCが回収できないオブジェクトの残骸がヒープを汚染し続ける。
- 保守の崩壊: `Button_Click` イベントの中にSQLクエリが直書きされている状態は、エンジニアのキャリアにとって致命的だ。
—
2. MVPパターンによる「分離」の戦略
MVP(Model-View-Presenter)は、Windows Formsにおいて最も合理的な解だ。MVVMのようなバインディングの魔法に頼るのではなく、インターフェースを介した「厳格な対話」を強いることで、論理をUIから完全に切り離す。
構造の解体プロセス
1. Viewの薄膜化: UIは「表示」と「ユーザー入力の伝達」だけに徹する。
2. Presenterの抽出: フォーム内のロジックをクラスへ移行し、インターフェースを通じてViewを操作する。
3. Modelの独立: データの永続化とビジネスルールを、依存関係を持たない純粋なクラス群へ分離する。
—
3. 実践コード:保守性の極限へ
以下のコードは、密結合したロジックを分離するための最小単位のスケルトンだ。
Viewインターフェースの定義 (IView.vb)
‘ UIの具象クラスに依存させないための抽象化
Public Interface IMainView
Property DisplayText As String
Event ExecuteAction As EventHandler
End Interface
Presenterの実装 (MainPresenter.vb)
Public Class MainPresenter
Private ReadOnly _view As IMainView
Private ReadOnly _repository As IDataRepository
‘ DI (Dependency Injection) を活用し、テスト時にモックを差し込めるようにする
Public Sub New(view As IMainView, repository As IDataRepository)
_view = view
_repository = repository
‘ イベントの購読
AddHandler _view.ExecuteAction, AddressOf OnExecute
End Sub
Private Sub OnExecute(sender As Object, e As EventArgs)
‘ ビジネスロジックをここに集約
Dim data = _repository.GetData()
_view.DisplayText = $”Result: {data.Value}”
End Sub
End Class
—
4. レガシー環境を生き抜くための「深淵の知見」
オブジェクトのライフサイクルとメモリ解放
レガシーなVB.NET環境では、`IDisposable`の実装を疎かにしてはならない。特にWindows API(`User32.dll` 等)を直接呼び出している場合、アンマネージリソースの解放は `Finalize` に任せるな。
‘ 確実にリソースを解放するパターン
Protected Overrides Sub Dispose(disposing As Boolean)
If disposing Then
‘ イベントハンドラのデタッチ(メモリリークの主犯を排除)
RemoveHandler _view.ExecuteAction, AddressOf OnExecute
If components IsNot Nothing Then components.Dispose()
End If
‘ アンマネージリソースの解放
MyBase.Dispose(disposing)
End Sub
パフォーマンスの最適化:Boxingの回避
VB.NETのコードで最も見落とされがちなのが、ループ内での `Integer` と `Object` 間の変換によるBoxing(ボクシング)だ。数千行のロジックが繰り返される環境では、これが積み重なり、GCの回収頻度を無駄に高める。
- 対策: `Option Strict On` を強制せよ。暗黙の型変換を許すコードは、技術的怠慢の証明だ。
—
5. 伝説のアーキテクトからの助言
リファクタリングとは「書き直し」ではない。「理解」のプロセスだ。
巨大なクラスを壊すときは、まず 「そのクラスが何を知っているか(依存)」 を書き出せ。そして、Presenterを介してその依存を一つずつ剥がしていく。
最初は苦痛かもしれない。しかし、Presenterが完成した瞬間、あなたはUIを一切起動せずにビジネスロジックを単体テストできるようになる。その瞬間に、あなたのシステムは「レガシーの墓場」から「保守可能な資産」へと変貌を遂げる。
コードは、書いた人間を映す鏡だ。
美しく、かつ厳格な構造こそが、開発者の知性を証明する唯一の手段であることを忘れるな。
次のステップとして、DIコンテナ(`Microsoft.Extensions.DependencyInjection`)の導入を検討せよ。それがレガシー脱却への最終兵器となるはずだ。
