ラベル #VBA_TIPS の投稿を表示しています。 すべての投稿を表示
ラベル #VBA_TIPS の投稿を表示しています。 すべての投稿を表示

2023年1月25日水曜日

【マクロVBA】VBA_TIPS-03 マクロの可読性

社内ツールの問題点 

よく社内DXや社内ツール、社内マクロ等で問題となる以下の事象があります。

・前任のSEが作ったツールのドキュメントが無い
・前任が作ったツールを改修したいが解読が難しい


社内ツール作成後、きちんと仕様書を残してくれれば後任は助かるのですが、たいていの場合作って「はい!終わり!」がほとんどだと思います。

また社内SEが社員ならまだ人事異動しても社内に残っているので聞ける可能性もありますが、社内SEが派遣社員だった場合、契約満了後は聞くことすらできなくなります。
実際、過去に私のいた部署で大規模なシステムを構築した際に、ドキュメントが無いままSEがいなくなり、そのシステムを改修をするのに3名の派遣SEを雇いましたが結局解読できずじまいだった。
そんなことも往々にしてあるようです。

作った本人は「なんでSEなのに読み解けないの?」だと思いますし、解読する側は「なんでこんなわかりづらい書き方するの?」だと思います。

それぞれのSEの技術の差があれど、仕様書等のドキュメントを残さないのであれば可読性の高い書き方(誰でも読めばわかる書き方)をすべきだと思います。


なぜ可読性が低いのか?

ネットに載っているコードのコピペ

プログラムを書く際に、ホームページ等のコードを参考にすることも多いかと思います。

ただプログラムを書く人はたいてい書き方にクセが出てくるので、同じようなコードのようでも変数の使い方や関数の使い方が微妙に違ったりします。
ネットのコピペを行うと、いろいろな人のクセが入り混じったコードになるので解読が難しくなります。

例えば以下のようなコードがあったとして、メッセージボックスに表示されるのはどれだかパッと出ますか?

Sub TEST()

Range("F5").Value = "鈴木"
Range("V5").Value = "佐藤"
Range("M5").Value = "田中"

MsgBox Cells(5, 13).Value

End Sub








正解は

正解は田中


きちんと見ればわかるのですが、RangeとCellsが混在しているだけでも少し混乱しませんか?
このようにネットのコピペばかり使うと統一感が無くなってしまうので、可読性は低くなります。


ドキュメント作らないくせに効率重視

プログラムに慣れてくるとどうしても効率を優先してしまう場合があります。

例えばこんなデータがあったとして

会員情報

以下のように1行ずつデータを処理しある要素をメッセージボックスに表示させるとします。

Sub TEST2()

Dim Arry() As String
Dim y As Long
Dim x As Integer

ReDim Arry(8)
For y = 2 To 2
    For x = 1 To 9
        Arry(x) = Cells(y, x).Value
    Next x
    MsgBox Arry(5)
Next i

End Sub
このとき表示されるのは”2023”ですが、この2023は対象期間(前)?それとも対象期間(後)?どちらでしょう。

こんな感じでドキュメントを残してくれればすぐわかるのですが、

配列名インデックス内容
Arry()0会員番号1
1会員番号2
2会員番号3
3会員番号4
4会員氏名
5対象期間(前)_年
6対象期間(前)_月
7対象期間(後)_年
8対象期間(後)_月

ドキュメントが無い場合はやはり解読に時間がかかります。

このようにドキュメント作らないくせに効率を求めたコードを書くと、後任がすごく困ります。


可読性を高くするには

変数の仕様書だけでもあると、SEは解読にさほどの時間がかかりませんが、それが無い(もしくは作らない)のであれば、これからのSEはたとえクソコードと言われようとも初心者でもわかるコードの書き方をすべきだと思います。

変数の統一

できるだけ変数はルール化しておくと理解が早くなります。

たとえば

Integer型ならintHogehoge
String型ならstrHogehoge

のように変数名の前に型の略称を入れておくと変数を見ただけで「これは文字列型」と理解が早くなります。

また、周回用のカウンタではiやcがよく用いられますが、Excelマクロで縦横周回させるようであれば縦y横xと誰もが学生時代に習ったxyを使用するとより理解度が増します。


たとえ行数が増えても、簡単な書き方を心がける

昔のPCはCPUやメモリが貧弱だったので、より効率よくプログラムを書く必要がありましたが、今の時代オフィス業務をやるにしては高性能なCPU、オフィス業務では絶対使いきれないメモリ容量と正直PCの性能が上がりすぎてあまり効率的に書く必要性が無くなってきたと思います。

例えば↑で書いた

Sub TEST2()

Dim Arry() As String
Dim y As Long
Dim x As Integer

ReDim Arry(8)
For y = 2 To 2
    For x = 1 To 9
        Arry(x) = Cells(y, x).Value
    Next x
    MsgBox Arry(5)
Next i

End Sub

ですが、

配列名インデックス内容
Arry()0会員番号1
1会員番号2
2会員番号3
3会員番号4
4会員氏名
5対象期間(前)_年
6対象期間(前)_月
7対象期間(後)_年
8対象期間(後)_月

があれば解読は簡単ですが無い場合はやはり解読に時間がかかります。

しかし以下のように記載すると

Sub TEST3()

Dim y As Long
Dim str会員番号1 As String
Dim str会員番号2 As String
Dim str会員番号3 As String
Dim str会員番号4 As String
Dim str会員氏名 As String
Dim str対象期間_前_年 As String
Dim str対象期間_前_月 As String
Dim str対象期間_後_年 As String
Dim str対象期間_後_月 As String

For y = 2 To 2
    str会員番号1 = Cells(y, 1).Value
    str会員番号2 = Cells(y, 2).Value
    str会員番号3 = Cells(y, 3).Value
    str会員番号4 = Cells(y, 4).Value
    str会員氏名 = Cells(y, 5).Value
    str対象期間_前_年 = Cells(y, 6).Value
    str対象期間_前_月 = Cells(y, 7).Value
    str対象期間_後_年 = Cells(y, 8).Value
    str対象期間_後_月 = Cells(y, 9).Value
    MsgBox str対象期間_前_年
Next i

End Sub

変数の内容も、メッセージボックスに表示される内容も一目瞭然です。


仕様書がきちんとあれば正直効率よくコードを書いてドキュメントを残す。これが一番きれいだと思いますが、社内SEの大きな利点は口頭で

社員「こういうの作ってほしい」
SE「できましたー」

だと思うので、仕様書を必ず作る必要はないと思いますが、ならばぜひコードの書き方を工夫するのも良いと思います。


↓よろしければクリックをお願いします!

TOPページに戻る


■関連ページ

【マクロVBA】VBA_TIPS-02 Select文とIf文


2022年11月28日月曜日

【マクロVBA】VBA_TIPS-02 Select文とIf文

今回はSelect文とIf文の使い分けについて話します。

例えばAの値に2が入っているとして、このAの値によって処理を変えるとします。
これをSelect文で表現すると
A = "こんにちは"
Select Case A
    Case "おはよう"
        MsgBox "Aはおはようです"
    Case "こんにちは"
        MsgBox "Aはこんにちはです"
    Case "こんばんわ"
        MsgBox "Aはこんばんわです"
    Case "おやすみなさい"
        MsgBox "Aはおやすみなさいです"
    Case Else
        MsgBox "Aはそれ以外です"
End Select
となります。If文で表現すると
A = "こんにちは"
If A = "おはよう" Then
    MsgBox "Aはおはようです"
ElseIf A = "こんにちは" Then
    MsgBox "Aはこんにちはです"
ElseIf A = "こんばんわ" Then
    MsgBox "Aはこんばんわです"
ElseIf A = "おやすみなさい" Then
    MsgBox "Aはおやすみなさいです"
Else
    MsgBox "Aはそれ以外です"
End If
となります。

どちらで書いても結果は
メッセージボックス Aはこんにちはです

で変わりません。
ではSelect文とIf文をどのように使い分ければよいのか?どちらを使うべきなのか?ですが、Select文を使えるのであればSelect文のほうが処理が速いので良い。という話を聞いたことがあります。
恐らく今のPC性能だとあまり気にする差ではないと思いますが、私はたまに100万行とかのCSVファイルを扱うときがあるので、なるべくSelect文を使うようにしています。

ではSelect文とIf文の明確な違いは何か?ですが、
Select:変数は1つしかできない
If   :変数を複数使うことができる
ですね。

Select文の場合はAの値から選ぶしかできず、例えば
Select Case A
とした場合、
Case A="こんにちは"
だとAがこんにちはのとき
Case A<>"こんにちは"
だとAがこんにちはでないとき
という感じでSelect Caseで決めたものに対して選ぶことしかできません。

逆にIf文を使うと
A = "こんにちは"
B = "こんにちわ"
If A = "おはよう" Then
    MsgBox "Aはおはようです"
ElseIf A = "こんにちは" And B = "こんにちわ" Then
    MsgBox "AもBもこんにちはです"
Else
    MsgBox "Aはそれ以外です"
End If
のように1つのIf文で複数の変数から条件を設定することが可能です。

このようにSelect文とIf文の違いを理解しておくことで、場面場面によって最適なやり方を考えることができるようになります。




2022年11月27日日曜日

【マクロVBA】VBA_TIPS-01 RangeとCells

 今回は案件で実際に使ったマクロのコードについて紹介します。


VBAの本やサイトだと仮にB2セルを指定する場合

ActiveSheet.Range("B2").Select

と記載される場合が多いですが、今回

ActiveSheet.Cells(2,2).Select

とRangeのところをCellsで記載しています。


この違いと便利な使い道について紹介します。


■Rangeオブジェクト

Excelの標準の表記(列をA~XFD、行を1~1048576で表した形式)なります。

ActiveSheet.Range("B2").Select

となる場合は、

”B"列目の"2"行目

を表すことになります。

RangeオブジェクトのB2セル

ダイレクトにセルを指定する場合にはわかりやすいので便利ですが、For文等で各行・列を周回する場合などセルの位置が可変である場合にはあまり適しません。

例えばA1セルからD1セルまでそれぞれ連続で選択していくとすると、

ActiveSheet.Range("A1").Select
ActiveSheet.Range("B1").Select
ActiveSheet.Range("C1").Select
ActiveSheet.Range("D1").Select

と記載するか、Offsetを利用して

For x = 1 To 3
    ActiveSheet.Range("A1").Offset(0, x).Active
Next x

と記載する必要があり、少々面倒です。

そこで使用するのがCellsオブジェクトによる記載方法になります。


■Cellsオブジェクト

こちらはExcelのオプションで設定できるR1C1参照形式による表記になります。

Excelの[ファイル]-[オプション]-[数式]から選択できます。

R1C1形式の設定方法

こちらをチェックするとExcelの表示がこう変わります。
R1C1形式のExcel

で、こちらはR1C1形式(R:Rows=行、C:Columns=列)となりますので、RagngeオブジェクトでB2を表現する場合は

”B"目の"2"

だったものが

R1C1形式では

”2"目の"2"

と行列が逆になります。

CellsオブジェクトはこのR1C1形式での表記となりますので、先ほどのA1~D1セルを連続で選択数場合

For x = 1 To 4
    ActiveSheet.Cells(1, x).Select
Next x

で良くなります。


このように、セル番地が可変になる場合にはCellsオブジェクト、不変の場合はRangeオブジェクトを使用するのが良いと思います。

※正直、Cellsで統一したほうがきれいなのは確かですが。


■範囲の指定

マクロで罫線を引いたり、セルを塗りつぶしたりする場合があります。

しかもセルの位置が可変の場合はどうすればよいか?

そう、そんなときはRangeとCellsの合わせ技です。


例えばB2~C3セルを範囲で選択したい場合、Rangeオブジェクトであれば

ActiveSheet.Range("B2:C3").Select

で良いのですが、Cellsオブジェクトだと

ActiveSheet.Cells(2,2).Select

だとB2セルしか選択できず、複数範囲の選択ができません。


Cellsオブジェクトを使用して複数範囲を選択する以下の場合は

Cellsオブジェクトを使って範囲指定する場合のイメージ

範囲選択できるRangeオブジェクトの中にCellsオブジェクトを入れることで範囲が表現できます。

ActiveSheet.Range(Cells(2,2),Cells(3,3)).Select

このCellsの部分を変数で可変にすることで、範囲指定を複数回実施したりすることが可能になります。


DXを進めるうえで、自動で表を作ったり、自動でグラフを作ったり、自動でやる部分が多くなってきます。

そういったときにこの可変でも範囲指定ができることを知っているかどうかで、仕事の質が変わってきますので、ぜひ覚えておいてください。


TOPページに戻る


■関連ページ

【マクロVBA】VBA_TIPS-02 Select文とIf文

【マクロVBA】VBA_TIPS-03 マクロの可読性