VBA技術解説
プログラミングの基本~ロジックの組み立て

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2014-11-18 最終更新日:2021-08-20

プログラミングの基本~ロジックの組み立て


プログラミングの基本というと、プログラミング言語の基本文法についての解説と思われるかもしれませんが、
ここでは、プログラミングする上で最も大切な考え方、ロジックの組み立て方について解説します、
本来は言語は問わないのですが、VBAのサイトですのでVBAを例に解説します。



前処理、主処理、後処理

何かをしようとしたとき、どのような手順になるか…
これが重要です。
「何かをする」何でも良いです、例えばDSでゲームをするとしましょう。
この時の行動手順を書くと、

・DSを取り出す(しまってあるところから持ってくる)
・遊ぶゲームのカードを入れる
・電源を入れる
・ゲームで遊ぶ(ここは細かいことは省略します)
・電源を切る
・ゲームのカードを抜く
・DSをかたずける

細かい事は抜きにして、大抵はこのような感じになります。
これをもっと大まかに簡潔に書くと、

・前準備
・目的の行動
・後片づけ


この3ステップになります。
プログラミングにおいても、DSで遊ぶことと同様に、この手順が必要になります。
これは、あらゆることにおいて共通していることです。
DSで遊ぶとか、プログラミングだけの話ではなく、あらゆる事柄において存在する手順です。
この3ステップをプログラミング用語として書き直すと、

・前処理
・主処理
・後処理


となります。
このように書くと、最近の言語学習者は、古い昔のパッチ処理の話かと思われる人もいるかもしれません。
しかし、けっしてそうではなく、人の行動・考えがそのようにできているのです。
小学校時代から、
準備→目的の行動→後片付け
この、準備と後片付けは、いやというほど教えられてきたはずです。
まさしく、すべての事が、この3ステップに分解できるのです。

そこで、
プログラミングする時のロジックの組み立てにおいて、この3ステップを強く意識すると良いのです。
これは、細分化していっても、その細分化された中に発生します。
主処理を分解すると、
・主処理の中の前処理
・主処理の中の主処理
・主処理の中の後処理

このように分解できるのです。

つまり、
・前処理
・主処理
 ・主処理の中の前処理
 ・主処理の中の主処理
 ・主処理の中の後処理
・後処理

もちろん、分解できない程度の小さなものは別ですが。
逆に、規模が大きくなれば、前処理の中でさえ、3ステップに分解できることもあります。
ただし、処理内容によっては、前処理または後処理のどちらか、または両方が存在しない場合もあることは承知しておいてください。

ブログラミング言語を問わずに、この3ステップの役割を書くと、

・前処理
入力チェック
出力領域の初期化
主処理で必要となる領域の生成と初期化
・主処理
必要な処理の記述
・後処理
結果の出力
領域の解放

大体こんな感じになります。
言語によって、領域の生成・初期化・解放の部分はかなり違いが出てくることにはなりますが、記述の問題であり考え方としては共通です。

VBAでの3ステップ例

では、具体的にExcelマクロVBAにおいて、どのようになるかを見てみましょう。
ごく簡単な例で、3ステップを見てみましょう。

以下の表において昨年対比を計算するマクロVBAになります。
C列はの%表示は事前に設定してあるとします。

マクロ VBA サンプル画像

少しだけ丁寧に書いてみました。
多少の書き方の違いはあるにしても、大体はこんな感じになります。

Sub sample()
  Dim i As Long
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet
  
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
    Next
  End With
  
  Application.ScreenUpdating = True
  MsgBox "完了"
End Sub

これなら説明も必要ないとは思いますが、
・前処理
・主処理
・後処理

この3ステップが明確に表れています。

Sub sample()

前処理
  Dim i As Long
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet

主処理
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
    Next
  End With

後処理
  Application.ScreenUpdating = True
  MsgBox "完了"

End Sub

少し複雑な処理にしてみるとしましょう。
昨年対比が100%未満の場合、昨年対比を赤字にしてみましょう。

Sub sample2()
  Dim i As Long
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet
  
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      .Cells(i, 3).Font.ColorIndex = xlAutomatic
      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
      If .Cells(i, 3) < 1 Then
        .Cells(i, 3).Font.Color = vbRed
      End If
    Next
  End With
  
  Application.ScreenUpdating = True
  MsgBox "完了"
End Sub

これを3ステップに分解してみると、

Sub sample2()

前処理
  Dim i As Long
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet

主処理
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row

 主処理の中の前処理
      .Cells(i, 3).Font.ColorIndex = xlAutomatic

 主処理の中の主処理
      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
      If .Cells(i, 3) < 1 Then
        .Cells(i, 3).Font.Color = vbRed
      End If

 主処理の中の後処理
・・・今回はありません

後処理
  Application.ScreenUpdating = True
  MsgBox "完了"

End Sub

処理内容がシンプルなので、各ステップが短いですが、3ステップの構造を確認してください。
ここで、3ステップを意識せずに書くと、
主処理の中が、

      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
      If .Cells(i, 3) < 1 Then
        .Cells(i, 3).Font.Color = vbRed
      Else
        .Cells(i, 3).Font.ColorIndex = xlAutomatic
      End If

このようになることがあります。
もちろん、この程度の処理であれば、これでも問題はありません。
しかし、今後の拡張性を考慮した場合、保守性を考えれば前者の方がよりよいと言えます。
つまり、
初期化→主処理
このステップを明確にしておくのです。

ではさらに、プロシージャーの分割についても少しお話ししておきます。
各処理の中が複雑になる場合、プロシージャーの分割に進みます。
ただし、一応説明を加えておきますが、プロシージャーの分割は必ずしも複雑だから分割するということばかりではなく、
可読性・保守性・汎用性・可用性 これらの向上が重要ですし、さらには、機能分割(機能により分ける)も必要になってきます。
では、先のプロシージャーを分割すると、

Sub sample3()
  Dim i As Long
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet
  
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      Call sample3_main(ws, i)
    Next
  End With
  
  Application.ScreenUpdating = True
  MsgBox "完了"
End Sub

Sub sample3_main(ByVal ws As Worksheet, ByVal i As Long)
  With ws
    .Cells(i, 3).Font.ColorIndex = xlAutomatic
    .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
    If .Cells(i, 3) < 1 Then
      .Cells(i, 3).Font.Color = vbRed
    End If
  End With
End Sub

または、

 Sub sample4()
  Dim ws As Worksheet
  Application.ScreenUpdating = False
  Set ws = ActiveSheet
  
  Call sample4_main(ws)

  Application.ScreenUpdating = True
  MsgBox "完了"
End Sub

Sub sample4_main(ByVal ws As Worksheet)
  Dim i As Long
  With ws
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      .Cells(i, 3).Font.ColorIndex = xlAutomatic
      .Cells(i, 3) = .Cells(i, 1) / .Cells(i, 2)
      If .Cells(i, 3) < 1 Then
        .Cells(i, 3).Font.Color = vbRed
      End If
    Next
  End With
End Sub

このサンプルでは、どちらでが良いというほどの差異はありませんが、
一般的には、後者のsample4が書かれることの方が多いように感じます。
しかし、私は、どちらかというと前者のsample3を書くことの方が多い気がします。
(あくまで、ざっくりしたイメージなので、その時々で変わります)

理由としては、
主処理がさらに複雑になり、複数のプロシージャーに分割する必要が出てきたとき、
sample3の方が分割しやすく、全体の可読性が良いと思うからです。

    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      Call sample3_main1(ws, i)
      Call sample3_main2(ws, i)
      Call sample3_main3(ws, i)
    Next

このように、機能追加しやすいのではないかと思います。
もちろん、全体としての処理内容に依存しますので、一概には言えませんが、そういう場合が多いかなということです。


最後にまとめ

最後に、再度記載しておきます。

常に意識すべきことは、処理を3ステップで考える

・前処理
・主処理
・後処理


そして、プロシージャーを分割するときは

・可読性
・保守性
・汎用性
・可用性


これらを常に意識してプログラムしていくことで、より良いプログラムが書けるようになりますし、コーディングの速度も上がっていくものです。




同じテーマ「マクロVBA技術解説」の記事

プログラミングの基本~ロジックの組み立て
実は奥が深いIfステートメント
論理積(And)論理和(Or)と真(True)偽(False)の判定
If条件式のいろいろな書き方:TrueとFalseの判定とは
VBAでの括弧()の使い方、括弧が必要な場合
VBAにおけるピリオドとカンマとスペースの使い方
変数とプロシージャーの命名について
文字列置換の基本と応用(Replace)
データクレンジングと名寄せ
ForとIfのネストこそがVBAの要点


新着記事NEW ・・・新着記事一覧を見る

ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
累計を求める数式あれこれ|エクセル関数応用(2024-01-22)
複数の文字列を検索して置換するSUBSTITUTE|エクセル入門(2024-01-03)
いくつかの数式の計算中にリソース不足になりました。|エクセル雑感(2023-12-28)
VBAでクリップボードへ文字列を送信・取得する3つの方法|VBA技術解説(2023-12-07)
難しい数式とは何か?|エクセル雑感(2023-12-07)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.変数宣言のDimとデータ型|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.並べ替え(Sort)|VBA入門
8.条件分岐(IF)|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.マクロとは?VBAとは?VBAでできること|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ