【実務・中級編】レガシーVB.NETコードのリファクタリング手法:巨大なコードビハインド(God Class)をMVPパターンで分離しテスト容易性を高める – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

「神クラス」の呪縛を解け。VB.NETコードビハインドをMVPパターンで再構築する極意

数千行の `Form.vb`。ボタンをクリックすればDBを叩き、計算を行い、UIを直接書き換える。修正するたびに別の箇所でバグが湧き出す——。そんな「神クラス(God Class)」と化したレガシーコードに頭を抱えていないか?

業務自動化の現場において、VB.NETは強力な武器だ。しかし、「動けばいい」という甘えは、数年後のメンテナンスコストという名の負債として必ず跳ね返ってくる

今日は、Visual Basicのレガシーなコードを、テスト可能なクリーンアーキテクチャへと昇華させる「MVP(Model-View-Presenter)パターン」によるリファクタリングを伝授する。

1. なぜ「コードビハインド」は悪なのか

Windows Formsにおいて、UIロジックとビジネスロジックを分離しないことは、「UIイベント」と「データ処理」を密結合させることを意味する。

  • テスト不能: メソッドを実行するためにUI(画面)をインスタンス化する必要がある。
  • 変更の伝播: DBの仕様変更がUIコードの修正を強制し、予期せぬ画面崩れを招く。
  • 属人化: コードが長すぎて、誰がどのロジックを担当しているのか判別不能になる。

これらを解消するのが、役割分担を明確にするMVPパターンだ。

2. MVPパターンの役割定義

MVPは、UIを「ただの表示箱」に格下げし、ロジックをクラスに追い出す設計思想だ。

1. View (Form): UIのみを担当。入力を受け取り、Presenterへ通知する。
2. Presenter: 中核。Viewの通知を受け取り、Modelを操作し、Viewを更新する。
3. Model: データ処理やDB操作を担当。UIの存在を知らない。

3. 実践:リファクタリングのプロダクションコード

例として、ユーザー名を入力し、データベースから保存する単純な機能をリファクタリングする。

Step 1: Model(ロジックの分離)

まずは、UIに依存しない「純粋なビジネスロジック」を作る。

‘ Model: データベース操作とバリデーションをカプセル化
Public Class UserDataModel
Public Function SaveUser(userName As String) As Boolean
If String.IsNullOrWhiteSpace(userName) Then Return False
‘ ここで本来はSQL ServerやSQLiteへの接続を行う
‘ UIには一切触れないのが鉄則
Return True
End Function
End Class

Step 2: View(インターフェースによる抽象化)

Formが直接Presenterを呼ぶのではなく、インターフェースを介すことでテスト容易性を確保する。

Public Interface IUserView
Property UserName As String
Sub ShowMessage(message As String)
End Interface

Step 3: Presenter(司令塔の構築)

ここがリファクタリングの心臓部だ。

Public Class UserPresenter
Private ReadOnly _view As IUserView
Private ReadOnly _model As UserDataModel

Public Sub New(view As IUserView, model As UserDataModel)
_view = view
_model = model
End Sub

Public Sub HandleSaveClick()
If _model.SaveUser(_view.UserName) Then
_view.ShowMessage(“保存成功”)
Else
_view.ShowMessage(“バリデーションエラー”)
End If
End Sub
End Class

Step 4: Viewの具象化(Formの実装)

最後は、Formをシンプルにする。

Public Class MainForm
Implements IUserView

Private _presenter As UserPresenter

Public Sub New()
InitializeComponent()
‘ Presenterに自身(View)とModelを渡して紐付け
_presenter = New UserPresenter(Me, New UserDataModel())
End Sub

Public Property UserName As String Implements IUserView.UserName
Get Return txtUserName.Text End Get
Set(value As String) txtUserName.Text = value End Set
End Property

Public Sub ShowMessage(message As String) Implements IUserView.ShowMessage
MessageBox.Show(message)
End Sub

Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
_presenter.HandleSaveClick()
End Sub
End Class

4. 現場のプロが教える「失敗しない」3つの鉄則

1. DBアクセスは「Repositoryパターン」で包め
Modelの中に直接 `SqlConnection` を書くのは避けろ。データベース操作専用のクラス(Repository)を切り出し、Modelはそれを呼び出す構成にせよ。これにより、DBが使えない環境でも「モック(偽物)」に差し替えてテストが可能になる。
2. 「UIスレッド」の意識
VB.NETのマルチスレッド処理で、別スレッドからViewを直接操作しようとすると例外が発生する。`Invoke` をPresenterに書くとUI依存が発生するため、`SynchronizationContext` を利用してUI更新をラップするのがスマートだ。
3. インターフェースを過信しすぎない
すべての処理をMVPにする必要はない。単純なUI表示切り替え程度のロジックまでPresenterに持ち込むと、逆にコードが肥大化する。「ロジックが複雑で、テストが必要な箇所」から優先的にリファクタリングせよ。

最後に:コードは「資産」か「負債」か

巨大な `Form.vb` を見つめて溜息をつくのはもう終わりにしよう。
コードの分離は、最初は面倒に感じるかもしれない。しかし、Presenterクラスを一つ作るごとに、君のコードは「誰が読んでも理解できるもの」に変わり、バグの温床が消滅していく。

良いエンジニアは、動くコードを書く。伝説のエンジニアは、誰が触っても壊れないコードを書く。

さあ、エディタを開いて、その巨大なクラスを断片化することから始めよう。君のプロダクトは、まだもっと速く、もっと堅牢になれる。

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