本章では、大規模なVB.NET業務システムを長期保守可能な構造で設計するための、エンタープライズアーキテクチャについて学習します。
VB.NETは、Windows FormsやWPFを使った業務アプリケーション開発で長く利用されてきました。 小規模なツールであれば、画面イベントに処理を書いても成立する場合があります。 しかし、利用者が多く、画面数が多く、DBや外部システムと連携し、長期間運用される業務システムでは、場当たり的な実装では保守が困難になります。
大規模業務システムでは、画面、業務ロジック、データアクセス、外部連携、認証、ログ、設定管理などを適切に分離し、 変更に強い構造を作る必要があります。 そのために重要になるのが、レイヤードアーキテクチャ、クリーンアーキテクチャ、依存関係の制御、ドメインモデル設計です。
本章のゴールは、単にクラスを分けることではありません。 大規模VB.NET業務システムを、長期保守、テスト、拡張、移行に耐えられる構造で設計できるようになることです。
1. エンタープライズアーキテクチャとは
エンタープライズアーキテクチャとは、企業の業務システムを長期的に運用・拡張・保守するための全体設計の考え方です。 単一画面や単一機能だけでなく、システム全体の構造、責務分離、依存関係、データの流れ、外部連携、運用性まで含めて設計します。
VB.NET業務システムでは、以下のような課題が発生しやすくなります。
- 画面クラスに業務ロジックが集中している
- DBアクセスが複数画面に直接書かれている
- 同じ入力チェックが複数箇所に重複している
- 外部APIやファイル連携が画面処理に混在している
- テストしづらい構造になっている
- 仕様変更時の影響範囲が分かりにくい
- 特定担当者しか理解できない処理が存在する
これらの問題は、個別のコードの書き方だけでは解決しきれません。 システム全体として、どこに何を書くべきか、どの層がどの層に依存してよいかを設計する必要があります。
エンタープライズ設計で重視すること
- 責務分離
- 依存関係の制御
- 業務ロジックの保護
- テスト容易性
- 変更容易性
- 再利用性
- 運用性
- 段階的な移行可能性
大規模システムでは、「今動くこと」よりも「将来安全に変更できること」が重要です。
2. レイヤードアーキテクチャ
レイヤードアーキテクチャとは、システムを役割ごとの層に分けて設計する方式です。 VB.NET業務システムでは、最も理解しやすく導入しやすいアーキテクチャのひとつです。
代表的なレイヤー構成
| レイヤー | 役割 | 例 |
|---|---|---|
| Presentation層 | 画面表示、入力受付、画面遷移 | Windows Forms、WPF View |
| Application層 | ユースケース、業務処理の流れ | Service、UseCase |
| Domain層 | 業務ルール、業務概念 | Entity、Value Object、Domain Service |
| Infrastructure層 | DB、ファイル、外部APIなど技術的詳細 | Repository実装、API Client、File Writer |
レイヤーを分けることで、画面の変更、DBの変更、業務ルールの変更を分離しやすくなります。
悪い例:画面にすべて書く
Private Sub btnRegister_Click(sender As Object, e As EventArgs) Handles btnRegister.Click
If txtUserName.Text = "" Then
MessageBox.Show("ユーザー名を入力してください。")
Return
End If
Using connection As New SqlClient.SqlConnection(connectionString)
connection.Open()
Dim sql As String = "INSERT INTO Users (UserName) VALUES (@UserName)"
Using command As New SqlClient.SqlCommand(sql, connection)
command.Parameters.Add("@UserName", SqlDbType.NVarChar, 50).Value = txtUserName.Text
command.ExecuteNonQuery()
End Using
End Using
MessageBox.Show("登録しました。")
End Sub
このコードでは、画面制御、入力チェック、業務処理、DBアクセスがすべてPresentation層に混在しています。 小さな画面では動作しますが、機能が増えるほど保守が困難になります。
良い例:レイヤーを分離する
Private Sub btnRegister_Click(sender As Object, e As EventArgs) Handles btnRegister.Click
Dim request As New RegisterUserRequest With {
.UserName = txtUserName.Text,
.Email = txtEmail.Text
}
Dim result = _registerUserUseCase.Execute(request)
If result.Success Then
MessageBox.Show("登録しました。")
Else
MessageBox.Show(result.Message)
End If
End Sub
画面側は、入力値をRequestに詰めてApplication層へ渡し、結果を表示するだけにします。 業務処理やDBアクセスの詳細は画面から隠します。
レイヤードアーキテクチャのメリット
- 責務が明確になる
- 画面変更の影響を業務ロジックに波及させにくい
- DBアクセス処理を共通化しやすい
- 単体テストしやすくなる
- 機能追加時の配置場所を判断しやすい
注意点
- 層を増やしすぎると過剰設計になる
- 単なる処理の横流しクラスを増やさない
- 依存方向を守らないと構造が崩れる
- 小規模ツールでは簡素化した構成にする判断も必要
3. クリーンアーキテクチャ
クリーンアーキテクチャは、業務ルールを外部技術から独立させることを重視する設計思想です。 画面、DB、Web API、ファイル、フレームワークなどの技術的詳細に、中心となる業務ロジックが依存しないようにします。
VB.NET業務システムでは、Windows FormsやDataTable、SQL Server、COMコンポーネントなどに業務ロジックが強く依存しているケースが多くあります。 この状態では、UI変更やDB変更、Web化、クラウド移行が非常に難しくなります。
クリーンアーキテクチャの基本思想
- 業務ルールを中心に置く
- 外側の技術詳細に依存しない
- 依存方向は外側から内側へ向ける
- 内側の層は外側の層を知らない
- 抽象を使って外部依存を反転させる
層のイメージ
Presentation
↓
Application
↓
Domain
↑
Infrastructure
重要なのは、Domain層がPresentation層やInfrastructure層に依存しないことです。 DB保存がSQL Serverでも、Oracleでも、ファイルでも、業務ルールそのものは変わらないように設計します。
依存してはいけない例
Public Class Order
Public Sub Save()
Using connection As New SqlClient.SqlConnection(connectionString)
' DB保存
End Using
End Sub
End Class
この例では、Orderという業務概念がSqlConnectionに依存しています。 Domain層がDB技術を知ってしまっているため、クリーンアーキテクチャの考え方には反します。
改善例:Repositoryインターフェースへ依存する
Public Interface IOrderRepository
Sub Save(order As Order)
End Interface
Public Class RegisterOrderUseCase
Private ReadOnly _orderRepository As IOrderRepository
Public Sub New(orderRepository As IOrderRepository)
_orderRepository = orderRepository
End Sub
Public Sub Execute(request As RegisterOrderRequest)
Dim order As New Order(request.CustomerId, request.OrderDate)
order.Validate()
_orderRepository.Save(order)
End Sub
End Class
Application層はIOrderRepositoryという抽象に依存し、具体的なDB保存処理はInfrastructure層で実装します。
Infrastructure層での実装例
Public Class SqlOrderRepository
Implements IOrderRepository
Public Sub Save(order As Order) Implements IOrderRepository.Save
Using connection As New SqlClient.SqlConnection(_connectionString)
connection.Open()
' SQL Serverへの保存処理
End Using
End Sub
End Class
この構成にすると、業務ロジックはDB実装から切り離されます。 将来的に保存先を変更したり、テスト用Repositoryに差し替えたりしやすくなります。
4. Presentation / Application / Domain / Infrastructure分離
大規模VB.NET業務システムでは、Presentation、Application、Domain、Infrastructureの4層に分けて考えると整理しやすくなります。
Presentation層
Presentation層は、ユーザーとの接点を担当します。 Windows Forms、WPF、Web画面、API Controllerなどが該当します。
Presentation層の責務
- 画面表示
- 入力値の取得
- ボタンの有効・無効制御
- メッセージ表示
- 画面遷移
- Application層の呼び出し
Presentation層に書くべきでない処理
- 複雑な業務判断
- DBアクセス
- 外部API通信の詳細
- トランザクション制御
- 帳票データ生成の業務ロジック
Application層
Application層は、ユースケースを実現する層です。 「ユーザーを登録する」「注文を承認する」「CSVを取り込む」「請求書を発行する」といった業務処理の流れを制御します。
Application層の責務
- ユースケースの実行
- 入力DTOの受け取り
- Domainオブジェクトの生成
- Repositoryの呼び出し
- トランザクション制御
- 外部連携処理の呼び出し
- 処理結果DTOの返却
Domain層
Domain層は、業務ルールや業務概念を表現する中心的な層です。 Entity、Value Object、Domain Serviceなどが含まれます。
Domain層の責務
- 業務ルールの表現
- 業務上の状態管理
- 不正な状態を防ぐ
- EntityやValue Objectの定義
- 業務判断の実装
Infrastructure層
Infrastructure層は、DB、ファイル、外部API、メール送信、ログ出力などの技術的詳細を担当します。
Infrastructure層の責務
- DBアクセス
- SQL実行
- ファイル入出力
- 外部API通信
- メール送信
- 設定ファイル読み込み
- ログ出力の具体実装
4層構成の例
MyApp.Presentation
UserForm.vb
OrderForm.vb
MyApp.Application
RegisterUserUseCase.vb
ApproveOrderUseCase.vb
ImportCsvUseCase.vb
MyApp.Domain
User.vb
Order.vb
Money.vb
OrderStatus.vb
MyApp.Infrastructure
SqlUserRepository.vb
SqlOrderRepository.vb
CsvFileReader.vb
MailSender.vb
プロジェクトを完全に分けるか、フォルダで分けるかは規模によって判断します。 重要なのは、物理的な分割よりも責務と依存方向を守ることです。
5. 業務ロジックの配置設計
大規模業務システムで重要なのは、業務ロジックをどこに配置するかです。 業務ロジックが画面、DB、共通関数、ストアドプロシージャに分散すると、仕様変更時の影響範囲が非常に分かりにくくなります。
業務ロジックの例
- 承認済みデータは編集できない
- 在庫が不足している場合は受注できない
- 請求締め後の売上は変更できない
- 管理者のみユーザー削除できる
- 合計金額が一定以上の場合は上長承認が必要
- 退職済み社員には権限を付与できない
悪い配置例
| 場所 | 問題 |
|---|---|
| 画面イベント | 別画面やAPIから再利用できない |
| SQL文 | 業務ルールがDBに埋もれる |
| 巨大共通関数 | 責務が曖昧になりやすい |
| 帳票出力処理 | 表示用処理と業務判断が混在する |
配置方針
- 画面固有の表示制御はPresentation層に置く
- ユースケースの流れはApplication層に置く
- 業務上の不変ルールはDomain層に置く
- DBアクセスの詳細はInfrastructure層に置く
- 外部サービス呼び出しの詳細はInfrastructure層に置く
Domain層に置く例
Public Class Order
Public Property OrderId As Integer
Public Property Status As OrderStatus
Public Property TotalAmount As Decimal
Public Sub Approve()
If Status <> OrderStatus.Applying Then
Throw New BusinessException("申請中の注文のみ承認できます。")
End If
Status = OrderStatus.Approved
End Sub
End Class
「申請中の注文のみ承認できる」というルールは、画面ではなくOrderという業務概念に近い場所に置きます。 これにより、画面、API、バッチのどこから承認処理を呼んでも同じルールを適用できます。
Application層に置く例
Public Class ApproveOrderUseCase
Private ReadOnly _orderRepository As IOrderRepository
Public Sub New(orderRepository As IOrderRepository)
_orderRepository = orderRepository
End Sub
Public Sub Execute(orderId As Integer)
Dim order = _orderRepository.FindById(orderId)
If order Is Nothing Then
Throw New BusinessException("対象の注文が存在しません。")
End If
order.Approve()
_orderRepository.Save(order)
End Sub
End Class
Application層では、注文を取得し、業務ルールを実行し、保存するという処理の流れを制御します。
6. UI依存・DB依存の排除
長期保守可能な設計にするためには、業務ロジックからUI依存とDB依存を排除することが重要です。
UI依存とは、業務ロジックがTextBox、DataGridView、MessageBox、Formなどに依存している状態です。 DB依存とは、業務ロジックがSqlConnection、SqlCommand、DataTable、SQL文などに直接依存している状態です。
UI依存の悪い例
Public Class UserService
Public Sub Register(txtUserName As TextBox)
If txtUserName.Text = "" Then
MessageBox.Show("ユーザー名を入力してください。")
Return
End If
' 登録処理
End Sub
End Class
このコードでは、ServiceがTextBoxとMessageBoxに依存しています。 そのため、画面以外から再利用できず、単体テストもしづらくなります。
UI依存を排除した例
Public Class RegisterUserRequest
Public Property UserName As String
End Class
Public Class UserService
Public Function Register(request As RegisterUserRequest) As ProcessResult
If String.IsNullOrWhiteSpace(request.UserName) Then
Return ProcessResult.Fail("ユーザー名を入力してください。")
End If
' 登録処理
Return ProcessResult.Success()
End Function
End Class
Serviceは画面コントロールではなくRequest DTOを受け取ります。 結果もMessageBoxで直接表示するのではなく、ProcessResultとして返します。
DB依存の悪い例
Public Class OrderService
Public Function CanApprove(orderId As Integer) As Boolean
Using connection As New SqlClient.SqlConnection(connectionString)
connection.Open()
Dim sql As String = "SELECT Status FROM Orders WHERE OrderId = @OrderId"
Using command As New SqlClient.SqlCommand(sql, connection)
command.Parameters.Add("@OrderId", SqlDbType.Int).Value = orderId
Dim status As String = CStr(command.ExecuteScalar())
Return status = "申請中"
End Using
End Using
End Function
End Class
このコードでは、承認可否の業務判断とDBアクセスが同じ場所に混在しています。
DB依存を排除した例
Public Class Order
Public Property Status As OrderStatus
Public Function CanApprove() As Boolean
Return Status = OrderStatus.Applying
End Function
End Class
Public Interface IOrderRepository
Function FindById(orderId As Integer) As Order
End Interface
Public Class OrderService
Private ReadOnly _orderRepository As IOrderRepository
Public Sub New(orderRepository As IOrderRepository)
_orderRepository = orderRepository
End Sub
Public Function CanApprove(orderId As Integer) As Boolean
Dim order = _orderRepository.FindById(orderId)
If order Is Nothing Then
Return False
End If
Return order.CanApprove()
End Function
End Class
業務判断はOrderに置き、DBアクセスはRepositoryに分離します。 これにより、業務ルールをDBや画面から独立させられます。
7. ドメインモデル設計
ドメインモデルとは、業務上の概念やルールをコードで表現したものです。 VB.NET業務システムでは、DBテーブル構造に合わせた単なるデータ入れ物だけでなく、業務ルールを持つモデルを設計することが重要です。
貧血モデルの例
Public Class Order
Public Property OrderId As Integer
Public Property Status As String
Public Property TotalAmount As Decimal
End Class
このOrderクラスは、データを持っているだけで業務ルールを持っていません。 承認できるか、キャンセルできるか、金額が妥当かといった判断は、別のServiceに散らばることになります。
業務ルールを持つドメインモデル
Public Class Order
Public Property OrderId As Integer
Public Property Status As OrderStatus
Public Property TotalAmount As Decimal
Public Sub New(orderId As Integer, status As OrderStatus, totalAmount As Decimal)
If totalAmount < 0 Then
Throw New BusinessException("合計金額は0以上である必要があります。")
End If
Me.OrderId = orderId
Me.Status = status
Me.TotalAmount = totalAmount
End Sub
Public Function CanApprove() As Boolean
Return Status = OrderStatus.Applying
End Function
Public Sub Approve()
If Not CanApprove() Then
Throw New BusinessException("申請中の注文のみ承認できます。")
End If
Status = OrderStatus.Approved
End Sub
End Class
このように、Order自身が注文に関する業務ルールを持つことで、ルールの重複や分散を防ぎやすくなります。
Value Objectの例
金額、メールアドレス、電話番号、日付範囲など、単なる文字列や数値ではなく意味を持つ値は、Value Objectとして表現できます。
Public Class Money
Public ReadOnly Property Amount As Decimal
Public Sub New(amount As Decimal)
If amount < 0 Then
Throw New BusinessException("金額は0以上である必要があります。")
End If
Me.Amount = amount
End Sub
Public Function Add(other As Money) As Money
Return New Money(Me.Amount + other.Amount)
End Function
End Class
Moneyクラスを使うことで、負の金額を作れないようにできます。 業務上ありえない値を型で防ぐ設計が可能になります。
Enumによる状態表現
Public Enum OrderStatus
Draft
Applying
Approved
Rejected
Canceled
End Enum
状態を文字列で管理すると、”Approved”、”承認済み”、”APPROVED”などの表記ゆれが発生します。 Enumを使うことで、不正な状態を防ぎやすくなります。
ドメインモデル設計のポイント
- 業務上重要な概念をクラスとして表現する
- 不正な状態を作れないようにする
- 文字列や数値だけで業務状態を表現しすぎない
- 状態変更メソッドに業務ルールを閉じ込める
- DBテーブル構造に引きずられすぎない
- 画面表示用DTOとDomainモデルを分ける
8. 既存VBシステムへの段階導入
既存のVB.NET業務システムに、いきなりクリーンアーキテクチャやドメインモデルを全面導入するのは危険です。 特に、長年運用されているWindows Formsアプリケーションでは、画面、DB、業務ロジックが密結合していることが多いため、段階的に改善する必要があります。
段階導入の基本方針
- いきなり全面改修しない
- 変更頻度が高い機能から改善する
- 障害が多い箇所から改善する
- 新規機能から新しい構造を適用する
- 既存機能は小さく安全に分離する
- リグレッションテストを用意する
第1段階:画面イベントから処理を切り出す
まずは、巨大なボタンクリックイベントから入力チェックや業務処理をメソッドへ切り出します。
Private Sub btnRegister_Click(sender As Object, e As EventArgs) Handles btnRegister.Click
Dim request = CreateRequestFromForm()
Dim result = _userService.Register(request)
ShowResult(result)
End Sub
この段階では、完璧なアーキテクチャを目指すよりも、画面イベントの肥大化を止めることを優先します。
第2段階:Serviceを導入する
業務処理の流れをServiceまたはUseCaseに移動します。 画面はServiceを呼び出すだけにします。
Public Class RegisterUserService
Public Function Register(request As RegisterUserRequest) As ProcessResult
' 入力チェック
' 業務ルール
' DB登録呼び出し
Return ProcessResult.Success()
End Function
End Class
第3段階:Repositoryを導入する
SQLやDBアクセス処理をRepositoryへ分離します。
Public Interface IUserRepository
Sub Save(user As User)
Function FindById(userId As Integer) As User
End Interface
最初はインターフェースなしのRepositoryでも構いません。 その後、テストや差し替えが必要な箇所からインターフェースを導入します。
第4段階:Domainモデルを育てる
最初からすべてのEntityを高度なDomainモデルにする必要はありません。 重要な業務ルールを持つクラスから、少しずつDomainモデルへ移行します。
- 注文
- 請求
- 承認
- 在庫
- 権限
- 契約
第5段階:新規機能は新アーキテクチャで作る
既存機能をすべて直すのではなく、新規機能や大規模改修機能から新しい構造を適用します。 これにより、移行リスクを抑えながら、システム全体を徐々に改善できます。
段階導入のイメージ
既存Form直書き
↓
Form + Service
↓
Form + Service + Repository
↓
Presentation + Application + Domain + Infrastructure
↓
一部機能からWPF化 / Web API化 / .NET移行
アーキテクチャ改善は、一度で完成させるものではありません。 既存業務を止めずに、改善範囲を見極めながら段階的に進めることが重要です。
9. プロジェクト構成設計
大規模VB.NETシステムでは、プロジェクト構成も重要です。 すべてを1つのプロジェクトに入れると、依存関係が曖昧になり、層の分離が崩れやすくなります。
プロジェクト分割例
Company.Product.Presentation.WinForms
Company.Product.Application
Company.Product.Domain
Company.Product.Infrastructure
Company.Product.Tests
各プロジェクトの役割
| プロジェクト | 役割 | 依存先 |
|---|---|---|
| Presentation | 画面、UI制御 | Application |
| Application | ユースケース | Domain |
| Domain | 業務ルール | 原則なし |
| Infrastructure | DB、ファイル、API | Application / Domainの抽象 |
| Tests | 単体テスト、結合テスト | Application、Domainなど |
依存関係の基本
Presentation → Application → Domain
Infrastructure → Application / DomainのInterface実装
Domain → どこにも依存しない
Domain層がPresentationやInfrastructureへ依存し始めると、アーキテクチャの中心が崩れます。 Domain層は、業務ルールの中心としてできるだけ独立させます。
小規模システムの場合
小規模な業務ツールでは、プロジェクトを細かく分けすぎると管理が重くなる場合があります。 その場合は、同一プロジェクト内でフォルダを分けるだけでも効果があります。
/Presentation
/Application
/Domain
/Infrastructure
/Common
重要なのは、分割の数ではなく、責務と依存方向を守ることです。
10. 共通処理の設計
大規模VB.NETシステムでは、共通処理の扱いが品質に大きく影響します。 日付処理、文字列処理、ログ、設定、エラー処理、認証、ファイル処理などは共通化されやすいですが、設計を誤ると巨大なCommonクラスが生まれます。
悪い共通クラスの例
Public Class CommonUtil
Public Shared Function FormatDate(value As DateTime) As String
Return value.ToString("yyyy/MM/dd")
End Function
Public Shared Sub SaveUser()
' ユーザー登録処理
End Sub
Public Shared Sub ExportInvoice()
' 請求書出力処理
End Sub
Public Shared Function CanApprove()
' 承認判定
Return True
End Function
End Class
このようなCommonUtilは、責務が曖昧です。 日付処理、ユーザー登録、帳票出力、承認判定が混在しており、変更影響が分かりにくくなります。
共通処理の分割例
- DateTimeFormatter
- StringNormalizer
- ApplicationLogger
- FileNameGenerator
- AuthorizationService
- CsvWriter
- InvoiceReportService
共通化は、「どこからでも使える箱」を作ることではありません。 同じ責務を持つ処理を、意味のある単位で再利用可能にすることです。
共通処理設計のポイント
- CommonやUtilに何でも入れない
- 責務ごとにクラスを分ける
- 業務ロジックを汎用Utilに入れない
- Sharedメソッドを乱用しない
- テストしやすい形にする
- 名前から役割が分かるようにする
11. アーキテクチャ設計でありがちな失敗
層を分けただけで責務が分かれていない
プロジェクトやフォルダを分けても、実際にはすべての層でDataTableを使い回していたり、 Application層が単なるRepository呼び出しになっていたりすると、設計上の効果は小さくなります。
Domain層がDBや画面に依存している
Domain層がSqlConnection、DataTable、TextBox、MessageBoxなどを知っている場合、 業務ルールが外部技術に依存してしまいます。
インターフェースを作りすぎている
すべてのクラスに対して機械的にInterfaceを作ると、かえって複雑になります。 差し替えが必要な箇所、テストでモック化したい箇所、外部依存を抽象化したい箇所を中心に導入します。
DTOが多すぎて変換地獄になる
Presentation DTO、Application DTO、Domain、DB Entityを分けすぎると、変換処理が増えすぎることがあります。 システム規模や変更頻度に応じて、現実的な粒度にすることが重要です。
新規設計を既存システムへ一気に適用しようとする
既存の大規模VBシステムに、いきなり理想的なアーキテクチャを全面導入すると、影響範囲が大きくなりすぎます。 新規機能や変更頻度の高い箇所から段階的に導入するべきです。
アーキテクチャが目的化している
アーキテクチャは、保守性、変更容易性、テスト容易性を高めるための手段です。 設計を複雑にしすぎて、開発効率や理解しやすさを損なっては意味がありません。
12. アーキテクチャ判断の実務基準
どの程度アーキテクチャを厳密にするかは、システムの規模や重要度によって変わります。 すべてのVB.NETアプリケーションに同じ設計を適用する必要はありません。
厳密な設計が必要なケース
- 利用者が多い
- 画面数が多い
- 長期運用が前提
- 業務ルールが複雑
- DB更新が多い
- 外部システム連携が多い
- 監査やセキュリティ要件がある
- 将来的なWeb化やクラウド移行を考えている
簡素な設計でもよいケース
- 一時的な社内ツール
- 利用者が非常に少ない
- 画面数が少ない
- 業務ルールが単純
- 長期保守を想定していない
- DB更新をほとんど行わない
判断ポイント
| 観点 | 設計を厚くする理由 |
|---|---|
| 変更頻度 | 頻繁に変わる箇所は分離しておく価値が高い |
| 業務重要度 | 止まると困る機能はテストしやすくするべき |
| 複雑性 | 複雑なルールはDomain層へ集約する価値がある |
| 外部依存 | DBやAPIはInfrastructure層へ分離するべき |
| 移行可能性 | 将来Web化するならUI依存を減らすべき |
良いアーキテクチャとは、常に最も複雑な設計を採用することではありません。 業務リスク、保守性、開発効率のバランスを取ることが重要です。
13. 演習課題
演習1:既存画面の責務を分解する
ユーザー登録画面を想定し、現在Formに書かれている処理を、Presentation、Application、Domain、Infrastructureに分類してください。
演習2:レイヤードアーキテクチャで設計する
注文承認機能を対象に、画面、UseCase、Domainモデル、Repositoryを設計してください。 それぞれのクラス名と役割を整理してください。
演習3:UI依存を排除する
TextBoxやMessageBoxに依存しているServiceクラスを、Request DTOとProcessResultを使う形に修正してください。
演習4:DB依存を排除する
Service内に直接書かれているSqlConnectionやSqlCommandをRepositoryへ分離し、 ServiceはRepositoryインターフェースに依存するように修正してください。
演習5:ドメインモデルを設計する
注文、請求、承認、在庫のいずれかを題材にし、業務ルールを持つDomainモデルを設計してください。 不正な状態を作れないようにすることを意識してください。
演習6:既存VBシステムへの段階導入計画を作成する
巨大Form、SQL直書き、DataTable依存がある既存VB.NETシステムを想定し、 5段階でアーキテクチャ改善を行う計画を作成してください。
演習7:プロジェクト構成を設計する
大規模業務システムを想定し、Presentation、Application、Domain、Infrastructure、Testsのプロジェクト構成を設計してください。 それぞれの依存関係も整理してください。
14. まとめ
本章では、大規模VB.NET業務システムを長期保守可能な構造で設計するための、エンタープライズアーキテクチャについて学習しました。
大規模業務システムでは、画面イベントにすべての処理を書くような構造では、仕様変更や機能追加に耐えられません。 Presentation、Application、Domain、Infrastructureのように責務を分け、依存関係を整理することが重要です。
レイヤードアーキテクチャは、VB.NET業務システムに導入しやすい基本的な構成です。 画面、業務処理、業務ルール、DBアクセスを分離することで、保守性とテスト容易性を高められます。
クリーンアーキテクチャでは、業務ルールを中心に置き、UIやDBなどの外部技術に依存しない構造を目指します。 これにより、将来的なWPF化、Web化、クラウド移行、DB変更にも対応しやすくなります。
業務ロジックの配置設計では、画面固有の処理、ユースケースの流れ、業務ルール、技術的詳細を明確に分けることが重要です。 特に、承認、請求、在庫、契約、権限などの重要な業務ルールは、画面やSQLに散らばらせず、Domain層へ集約することが望ましいです。
既存VBシステムへ新しいアーキテクチャを導入する場合は、いきなり全面改修するのではなく、 画面イベントから処理を切り出し、Serviceを導入し、Repositoryを分離し、重要な業務ルールからDomainモデルへ移行するように段階的に進めます。
また、プロジェクト構成や共通処理の設計も重要です。 CommonUtilのような巨大な共通クラスに何でも入れるのではなく、責務ごとに意味のあるクラスへ分割することで、保守性を高められます。
本章のゴールは、大規模VB.NET業務システムを、長期保守可能な構造で設計できるようになることです。 アーキテクチャは目的ではなく、業務システムを安全に変更し続けるための手段です。 システム規模、業務重要度、変更頻度、移行計画に応じて、現実的で効果のある設計を選択することが重要です。