こんにちは、なかぜんです。Access アプリに長く手を入れていると、「動いてはいるけれど、何をしているのか自分でも把握できない」ような膨大な VBA コードに直面すること、ありませんか?
今日はそんな“コードの迷宮”から脱出するための、上級者向けリファクタ手順をご紹介します。整理されて読みやすくなったコードは、あなた自身の自信にも、次の改修にも役立ちますよ。
目次
- なぜ肥大化が問題か?メリットを再確認
- ステップ1:コード構造の可視化と目的の整理
- ステップ2:共通処理の抽出とモジュール分割
- ステップ3:ネーミングとコメントで意図を明示
- ステップ4:単体テスト的な動作確認ルーチン
- よくあるミスと注意点
- 応用ポイント:より洗練する工夫
- まとめと次のステップ
1. なぜ肥大化が問題か?メリットを再確認
「動いているから大丈夫」と思いがちですが、膨れ上がったコードには以下のようなリスクがあります:
- 可読性低下:何をしているのか理解しづらくなり、改修ミスの温床に。
- 再利用性の低さ:同じ処理を何度も別箇所に書いてしまい、修正時に手間が増える。
- 保守の難易度アップ:他のメンバーが手を入れづらく、運用体制にも影響。
この状態から脱することで:
- コードが読みやすく、自信をもって修正できる
- 共通処理をまとめられ、コード量の削減&品質向上
- 将来的な拡張や他チームとの共有がスムーズに
といったメリットが得られます。安心できる未来を想像しながら進めましょう。
2. ステップ1:コード構造の可視化と目的の整理
まずは現状のコードを“見える化”します。大まかな手順は:
- 全てのモジュール・フォーム・レポートを一覧化
- 各コードの目的をコメントや図で整理(フローチャートも効果的)
- 重複処理がありそうな箇所にマークをつける
たとえば、こんなコード片があったとします:
Private Sub cmdSave_Click()
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT * FROM tblData WHERE ID=" & Me.txtID)
If Not rs.EOF Then
rs.Edit
rs!Value1 = Me.txtValue1
rs!Value2 = Me.txtValue2
rs.Update
End If
rs.Close
Set rs = Nothing
Call msgSuccess "保存しました"
End Sub
これを読みながら、目的を可視化してみましょう:
- テーブルへレコード取得 → 属するフィールドへの代入 → 更新 → 終了 → メッセージ表示
ここまではシンプルですが、もし他のフォームでも似たような処理があれば、共通化の対象になりそうですね。
3. ステップ2:共通処理の抽出とモジュール分割
違う画面で似たコードを見つけたら、標準モジュールに共通処理としてまとめましょう。例:
' 標準モジュール modCommon.bas
Public Sub SaveRecord(tblName As String, id As Long, _
ParamArray fieldsAndControls() As Variant)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim i As Long
Set db = CurrentDb()
Set rs = db.OpenRecordset("SELECT * FROM [" & tblName & "] WHERE ID=" & id)
If Not rs.EOF Then
rs.Edit
For i = LBound(fieldsAndControls) To UBound(fieldsAndControls) Step 2
rs(fieldsAndControls(i)) = Nz(fieldsAndControls(i + 1), rs(fieldsAndControls(i)))
Next i
rs.Update
End If
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
解説:
ParamArray
を使うことで、可変長のフィールド名+値の組を扱えるように。- 更新しない場合の既存値保持に
Nz
を活用。 - どのテーブルでも使える汎用的な保存処理になります。
フォーム内ではこのように書くと、ずいぶんすっきりします:
Private Sub cmdSave_Click()
Call SaveRecord("tblData", Me.txtID, _
"Value1", Me.txtValue1, _
"Value2", Me.txtValue2)
Call msgSuccess("保存しました")
End Sub
4. ステップ3:ネーミングとコメントで意図を明示
上級者にこそ大事なのが、ネーミングとコメントです。例:
' modCommon.bas
' 保存処理を汎用化する関数
Public Sub SaveRecord(tblName As String, id As Long, ParamArray ... )
' db取得
' レコードセット取得
' 編集 -
' フィールド代入ループ -
' 更新 -
' 後始末
End Sub
ポイント:
- “SaveRecord” は何をするのか名前で伝える
- 各ブロックにコメントを入れることで、意図を明示
- 必要であれば引数の説明もコメントしておくと親切
5. ステップ4:単体テスト的な動作確認ルーチン
Access VBA に本格的なユニットテストは仕込みづらいですが、“個別動作確認用フォーム”を一つ用意すると効果的です。
例:
' フォーム frmTestSave にこんなボタンを配置
Private Sub btnTestSave_Click()
SaveRecord "tblData", 123, "Value1", "テスト1", "Value2", "テスト2"
MsgBox "テスト保存を実行しました。テーブルを確認してください。"
End Sub
こうすると、複雑な処理だけを切り出して動かせるので、修正後の動作確認がすごく楽になります。
6. よくあるミスと注意点
- 共通化しすぎて可読性逆に低下
インターフェースを複雑にしすぎると、結果読みにくくなることも。 - 過度な汎用化
すべてを汎用関数で賄おうとすると、引数が多くなりすぎて逆に使いにくくなる場合も。 - リファクタ途中で機能破壊
テストフォームでこまめに動作確認を入れるのが大切。
7. 応用ポイント:より洗練する工夫
- エラーハンドリングの共通化
標準モジュールにTry…Catch
的な処理(On Error GoTo ErrHandler
)をまとめておく。 - DAO から SQL パラメータ化への移行
SQL を構築するときに、パラメータを使うことで SQL インジェクション対策や可読性向上。 - クラスモジュールの活用
DAO.Recordset まわりをラップするクラスを作れば、より OOP 的に管理できて拡張も楽になります。 - 定数化・Enum への置き換え
ハードコードされたフィールド名や ID は定数や列挙体にまとめると安全性アップ。
8. まとめと次のステップ
今回のリファクタ手順は:
- 可視化 →
- 共通処理抽出 →
- ネーミング・コメント整理 →
- 動作確認フォームによるテスト →
- 応用ポイントでさらに洗練
読みやすく、理解しやすいコードは、あなたの業務効率にも、チームとの協調にも貢献します。ぜひ「やってみたい!」と思っていただけたら嬉しいです。
次のステップとしては、DAO ベースから SQL パラメータ化への移行や、クラスモジュールによる設計改善などにも挑戦してみましょう。
最後までお読みいただきありがとうございました。なかぜんでした 🙂
