VB.NETで「地獄の修正」を終わらせる:インターフェイスと抽象クラスによる疎結合アーキテクチャの極意
業務システム開発において、最も恐ろしいのは「一箇所の修正が、なぜか全く関係ない機能のバグを誘発する」という悪夢だ。これを引き起こすのは、コードの書き方ではない。「設計の怠慢」だ。
多くのVB.NET開発者が、クラスをただの「機能の寄せ集め」として扱っている。だが、真に堅牢な業務基盤を作りたいのであれば、「インターフェイス(Interface)」と「抽象クラス(MustInherit)」の使い分けを骨の髄まで理解する必要がある。
今回は、数年後の自分やチームが泣かないための、疎結合なコンポーネント設計を伝授する。
—
1. なぜ「具体的なクラス」に依存してはいけないのか
初心者はよく、`DatabaseManager` クラスを直接呼び出してSQLを発行する。だが、将来的に「SQL Server」から「Oracle」へ、あるいは「API連携」へ移行する必要が出た瞬間、コードの至る所を書き直す羽目になる。
「依存の逆転の原則」を適用せよ。上位のビジネスロジックは、具体的な実装(DatabaseManager)ではなく、抽象(Interface)に依存すべきだ。
—
2. 実践:インターフェイスと抽象クラスの使い分け
設計の指針を明確にする。
- インターフェイス (Interface): 「何ができるか(契約)」を定義する。クラスが何をサポートしているかの「能力」を示す。
- 抽象クラス (MustInherit): 「共通の骨格(テンプレート)」を提供する。ロジックの再利用を目的とする。
【プロダクションコード例】データ出力基盤の設計
例えば、CSV出力やExcel出力、API送信を共通化するケースを考える。
”’
”’
Public Interface IDataExporter
Sub Export(data As List(Of String))
End Interface
”’
”’ ログ出力などの「変わらない処理」をテンプレートとして保持する。
”’
Public MustInherit Class BaseExporter
Implements IDataExporter
‘ テンプレートメソッドパターン:処理の流れは固定する
Public Sub Export(data As List(Of String)) Implements IDataExporter.Export
Try
WriteLog(“出力開始”)
ExecuteExport(data) ‘ 子クラスで実装させる
WriteLog(“出力完了”)
Catch ex As Exception
WriteLog(“エラー発生: ” & ex.Message)
Throw
End Try
End Sub
‘ 実装は子クラスに委譲
Protected MustOverride Sub ExecuteExport(data As List(Of String))
Private Sub WriteLog(msg As String)
‘ 共通のログ処理。ここに書くことで重複を排除する。
Console.WriteLine($”[{DateTime.Now}] {msg}”)
End Sub
End Class
—
3. 実装クラス:保守性を最大化する
上記の基盤を利用して、具体的なCSV出力機能を実装する。
Public Class CsvExporter
Inherits BaseExporter
Protected Overrides Sub ExecuteExport(data As List(Of String))
‘ ここには「CSVとして書き込むロジック」のみを書く
‘ ログ出力やエラーハンドリングは親クラスが担保しているため、コードが極めて短い
System.IO.File.WriteAllLines(“output.csv”, data)
End Sub
End Class
この設計の何が優れているのか?
1. 疎結合: ビジネスロジック側では `IDataExporter` しか知らない。`CsvExporter` を `ApiExporter` に差し替えても、呼び出し側は一行も修正不要だ。
2. 堅牢性: `BaseExporter` にログ処理や例外処理を集約しているため、出力方式が増えても「ログの漏れ」や「例外処理の書き忘れ」が発生しない。
3. テスタビリティ: インターフェイスがあることで、テスト時にモック(偽物)を容易に差し込める。
—
4. 業務自動化エンジニアが教える「陥りやすい罠」
- 過剰な抽象化: インターフェイスを何でもかんでも作ると、コードを追うのが困難になる。「1つのクラスに対して1つのインターフェイス」が常に正しいわけではない。「差し替える可能性があるか?」という基準で判断せよ。
- ファイルI/Oの直書き: `File.WriteAllText` を至る所に書くな。必ず「出力先を抽象化したオブジェクト」を介して実行せよ。でないと、将来クラウドストレージ対応などが求められた時に地獄を見る。
- Disposeの忘れ: `IDisposable` を実装したオブジェクトを扱う際は、必ず `Using` ステートメントを使うこと。メモリリークは「設計の美しさ」を全て台無しにする。
—
結論:コードは「資産」か「負債」か
疎結合な設計は、書くときは少し手間がかかる。しかし、半年後に「仕様変更」のメールが飛んできたとき、その手間は「1分で終わる修正」という圧倒的なリターンになって返ってくる。
VB.NETは古臭い言語ではない。正しく設計すれば、エンタープライズレベルの堅牢性を実現できる強力な武器だ。
今日から、`Public Class` を書く前に一度手を止めろ。「これはインターフェイスにすべきか?」と自問自答すること。それが、一流のエンジニアへの第一歩だ。
