社員ブログ
HOME  社員ブログ

アーカイブ

‘VB’ カテゴリ

VB6によるアーキテクチャ設計 その2 - エラー処理と関心事の分離

2014年08月27日 6時57分50秒

こんにちは。プリーストです。

前回の投稿からやや時間が空いてしまいましたが、前回に引き続きVB6での開発のお話です。

前回は、主にシステムの前提制約とVB6の特徴、そしてプロジェクトの分割と共通クラスを用いてポリモーフィズムを使用した時のように、該当プロジェクト固有の値を使って共通クラスで処理させる方法を書きました。

VB6によるアーキテクチャ設計 - VB6でオブジェクト指向プログラミングはどこまでできるか?


今回は、以下のVB6の特徴の4番を使用したエラー処理について主に書きたいと思います。

○VB6の特徴(実装中に気づいたもの)
1. クラスを定義できる。ただし、提供される機能はカプセル化のみで継承、ポリモーフィズムはサポートされない。
2. モジュールには変数と静的なプロシージャのみ定義できる。静的クラスのような使い方ができる。
3. Formはクラスであり、newしてインスタンスを生成できる。インスタンス化しなくても使用できる。
4. try~chatchは無いが、On Error~を用いることで例外補足が可能。
5. 自分で定義した構造体をプロシージャの引数に取ることはできない。
6. 要素数0の配列を定義できない。
7. コレクションが使用できる。速度は配列より速いとのこと。
8. コレクションはJavaのジェネリクスのように要素の型を指定できない。コレクションを引数にするとプロシージャ側から見ると何が格納されているかは保証されない。
9. 10進数の計算で精度が必要な場合には、Variant型の変数にCDec関数で数値をDecimal型に変換して格納する。Decimal型の変数は定義できない。


VB6でのエラー処理は一般的に、

Private Sub subXxxxx()

    On Error GoTo ErrorHandler

    ‘ エラーが発生する可能性のある処理
        
  Exit Sub

ErrorHandler:
    ‘ メッセージ表示などのエラー処理
    
End Sub

等と書きます。
しかし、エラー処理をプロシージャ毎に書いていたのでは記述が冗長なばかりか、エラーハンドリングに変更を加えたい場合に工数が膨らみます。
そこで、エラー処理を共通化する試みをしました。方法は単純で共通のプロシージャを用いるということです。


○全プロシージャ共通の実装イメージ
Private Sub subXxxxx()
    On Error GoTo ErrorHandler

    ‘ エラー情報クリア
    Call subClearError
        
    ‘ エラーが発生する可能性のあるサブプロシージャ
    Call subYyyyy()
    If gobjError.ErrorCode <> “” Then GoTo ErrorHandler
     :
     :
     :   
ExitHandler:
    Call subEndProcces
    Exit Sub

ErrorHandler:
    Call subErrorProcces
    
End Sub


○エラーを発生させたい処理
Private Sub subYyyyy()
    On Error GoTo ErrorHandler

    ‘ エラー情報クリア
    Call subClearError
    
    ‘ エラー処理
    If (……) Then
        gobjError.ErrorCode = “ERR001”
        gobjError.ErrorMessage = “エラーメッセージ”
        GoTo ErrorHandler
    End If

    ‘ 途中で正常終了したい場合
    If (……) Then
        GoTo ExitHandler
    End If
    :
    :
ExitHandler:
    Exit Sub

ErrorHandler:
    Call subErrorProcces
    
End Sub

というように書きます。ここで注意すべき点は、
・サブプロシージャを呼び出した後は必ずエラー有無の確認を行う。
・エラー情報は独自のオブジェクトで管理する。
・正常時、異常時両方にラベルを定義し、特に処理がなくても全プロシージャでテンプレートのように使用する。

○エラー情報クラス
‘ エラー情報保持クラス
‘ EXE全体のエラー管理及びエラーリスト処理クラスのデータとして用いる。
‘ 構造体で定義するとコンパイルエラーとなる為、クラスで定義する。

Public ErrorCode            As String   ‘ エラーコード
Public ErrorMessage         As String   ‘ エラーメッセージ
  :
  :


○グローバル定義
‘ 共通エラー情報クラスオブジェクト(アプリケーションで唯一のインスタンス)
Public gobjError                As New ErrorInfo       ‘ 共通エラー情報


○クリア関数
エラー情報インスタンスクリア

Public Sub subClearError()
    ‘ メッセージクリア
    gobjError.ErrorCode = “”
    gobjError.ErrorMessage = “”
End Sub


○エラー処理関数
実行時エラーなどを独自に定義したメッセージに変換する処理などを行う。

Public Sub subErrorProcces()

    ‘ エラー設定処理でOn Error句を用いるとErrオブジェクトがクリアされるので用いない。
    
    ‘ 実行時エラー変換
    Select Case Err.Number
        Case 70
            gobjError.ErrorCode = “ERR002”
        Case XX
            gobjError.ErrorCode = “ERRXXX”
          :
          :
        Case Else
    End Select
    
    If gobjError.ErrorCode <> “” Then Exit Sub
    
    ‘ Runtimeエラーメッセージ取得
    Call subSetRuntimeError

End Sub


こうすることで、VB6であってもエラー処理をビジネスロジックと分離し管理できるようになります。これはAOP(Aspect Oriented Programming)が生まれた目的と同じで、ソフトウェア全体を横断する関心事を分離するものです。

もう一つのエラー処理の方法としては、エラーとしたい場合に「Err.Raise 9999(独自に定義した数値)」などとして実行時エラーを発生させ、最上位の呼び出し元で補足して処理するという方法もあります。

その場合、On Error GoTo~などのエラー処理ルーチンを終了すると、Errオブジェクトがクリアされてしまうので、補足するのはあくまで最上位の呼び出し元のみとする必要があります。
これだと、記述量が少なくシンプルになります。ただErrオブジェクトをクリアしないように気をつける必要があるので、小規模案件や少人数のプロジェクト向きかもしれません。

このように、共通クラス定義や広域変数でのインスタンス保持、プロジェクト分割、チーム内のルールや規約などを組み合わせることで、モダンな言語が備える問題の分割や処理の共通化の仕組みをある程度実現できます。

言うまでもなく、言語仕様に元々分割、共通化の仕組みが備わっている方がコードの統括、見通しの良さ共に良いのであくまでもなんらかの事情によりVB6の採用が最適解である場合のコード整理の仕方ということで参考になればと思います。

エラー処理については以上です。また他のトピックについても書いていきたいと思います。

 

それではまた♪


VB, 社員:プリースト , , ,

VB6によるアーキテクチャ設計 その1 - VB6でオブジェクト指向プログラミングはどこまでできるか?

2014年03月16日 12時44分28秒

こんにちは。プリーストです。

今担当しているお仕事では、開発言語にVB6、DBにOracleを使用しています。
VB6!?と思っていましたが、やってみるとこれが割と綺麗に書けたので思考の流れとアーキテクチャ設計指針をここにまとめておこうかなと思いました。
VB6は1998年リリースとのことですが、その時代としてはかなり先進的で画期的な言語だったのではないでしょうか。Windows95、98といいその頃のMicrosoftはすごかったんですね~。

長くなるのでとりあえず、第一回目では概要と方針を書いてみます。

何か参考になれば嬉しいです。

まずは、求められる非機能要件の整理からです。
・現行システムはVB6で作成したクライアントプログラムとOracleのストアドプロシージャで構成される2階層C/Sシステム
・開発するのは割と小規模のサブシステム
・DB操作はほとんどOracleのストアドプロシージャで行うが、保守時のデバッグが難しいことが課題
・使用するのはイントラネット内部のみで通信資源は潤沢
・将来的に.Net等のオブジェクト指向言語でリプレースする可能性がある

お客様に相談して頂いたのがやはり保守時のデバッグ。これがストアドプロシージャで記述してあるとやりづらいとのこと。
VB6のソースコードも読みづらく、保守効率が悪いというよくある相談をされました。
そして、将来的には.Netでのリプレースも考えているとのこと。
続きを読む…


Oracle, VB, Windows, 社員:プリースト , ,

【備忘録】ディストリビューション ウィザード その2

2013年08月30日 12時41分47秒

こんにちは、花鳥諷詠です。

備忘録として、Setup.lstの必要そうなところだけ注釈

$(DLLSelfRegister) – DLLRegisterServer および DLLUnregisterServer が記述されている自己登録ファイル

$(EXESelfRegister) – /RegServer および /UnRegServer をサポートしている ActiveX EXE用

[IconGroups] セクションには、アイコン名、[スタート] メニューの場所などの指定を行う。

[IconGroups]

Group0=Project1

PrivateGroup0=0  グループを [共通(0)] にするか、[個人(-1)] にするかを指定

Parent0=$(Programs)

[Setup] セクションには、インストールするアプリケーションに関する情報を記述

ForceUseDefDir=1 ← インストール先を選択させない指定

※DefaultDir(既定のインストレーション パス)の指定は必要

あとの詳細はこちら

では、また


VB, 社員:花鳥諷詠, 雑記