テックカリキュラム

エンタープライズVBアーキテクチャ設計

エンタープライズVBアーキテクチャ設計

本章では、大規模な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業務ルール原則なし
InfrastructureDB、ファイル、APIApplication / 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業務システムを、長期保守可能な構造で設計できるようになることです。 アーキテクチャは目的ではなく、業務システムを安全に変更し続けるための手段です。 システム規模、業務重要度、変更頻度、移行計画に応じて、現実的で効果のある設計を選択することが重要です。