t-hom’s diary

主にVBAネタを扱っているブログです。

なぜプログラムコードのコメントにはWhyを書くべきなのか。他の4W1Hはどうした?

プログラミングコードのコメントにはWhyを書く。
これは結構いろんなところで言われている気がする。

ビジネスフレームワークでは、5W1Hが大事と言われている。そのうちのひとつである。
なぜコードのコメントには、「Why」を書くべきなんだろうか。他の4W1Hはどうした?

今回はこれに答えてみようと思う。

まずは5W1H

5W1Hとは、What, When, Where, Who, Why, Howの略である。
このフレームワーク、「正直煩わしい」と思ってる人も多いかと思う。
前職で何か上長に報告する時に、5W1Hで報告してください!というのをよく言われたので何か面倒くさいイメージを引きずっているのかもしれない。ひょっとしたら私だけかもしれないが。

とにかく今更耳タコだし、すでに使い古されているし、トレンディではない。
それにそもそも何を当たり前のことを言ってるんだという気がしないでもない。

ただこれ、無理やり埋めるようなものではなくて、それぞれの観点が情報として網羅されているか、あるいはその観点が当てはまらないことをちゃんと確認したかをチェックするツールなんだと気づいてからは積極的に使うようになった。

そしてコーディングにおいても、5W1Hのフレームワークは有効である。

コーディングにおける5W1H

5W1Hを適用するときは、連想ゲームのようにそれぞれのW,Hを適用できる概念を探していく。
コーディングにおけるWhatって何があるだろう。Whenって何かあるだろうか?そういう感じ。

私なりの観点で整理してみた。

項目 観点 表現・記録・管理の手段
What 何をする関数なのか?
何の為のプロシージャなのか?
何の為の変数なのか?
何を変更したのか?
識別子名をしっかり考えて付ける
→つまりコード自体の守備範囲。
バージョン管理システムのコミットコメント
→つまりGitHubの守備範囲。
When いつ作成されたか?いつ変更されたか? バージョン管理システムを使う
→つまりGitHubの守備範囲。
Where どこで定義されているか?どのモジュールの命令か? 名前空間や親オブジェクトを明示する
→つまりコード自体の守備範囲。
Who 誰が作成したか?誰が変更したか? バージョン管理システムを使う
→つまりGitHubの守備範囲。
Why なぜそう書いたのか。なぜ変更したのか? コメントに書く!
How どのような処理か。どのように変更したか? コードを分かりやすくリファクタリング / バージョン管理システムを使う
→つまりコード自体およびGitHubの守備範囲。

Why以外はコードそのもので表現できたり、バージョン管理システムの守備範囲に入ってくることが分かる。
つまりWhyだけは、コメントに書くしかないのだ。

これが、Whyを書けと言われる所以である。

他の項目を書いてはいけないという訳ではないし、書いた方が良い場合もある。
しかし、そのコメントはあまりよろしくない習慣をカバーするための苦肉の策になっていないだろうか。

識別子を適当につけたためにやむを得ずコメントで補足せざるを得ない状況だったり、いまだにバージョン管理をコード上でやっていたり。

Why以外の項目をコメントしたくなったとき、本当にコメントの守備範囲で合っているか、実際のところ識別子の名前や処理の流れのほうを見直すべきではないか、自問が必要かと思う。

実例

今日は久々にVBAをいじったので、私がコードに書いているコメントをいくつか実例として挙げておく。

私は普段、Why以外はあまりコメントしていない。
処理の要約をするケースもあるけど、たいていの場合はプロシージャにまとめて適切なプロシージャ名を付ける方がより良いコードだと思っている。あとはやむを得ずトリッキーなコードを書いてしまったときにコメントするくらいか。
まぁ私の場合は将来の自分が楽々読めればそれで良いので、あまり鵜呑みにせず参考程度に見ていただければと思う。

'DEBUG_MODEがTrueのとき、参照設定した型を使用するように
'ディレクティブで制御する。Falseの時はObject型を使用する。
#Const DEBUG_MODE = False
        'フォントを明示的に指定しないとテーマフォント扱いになり、別ブック化したときにフォントが変わってはみ出す為。
        With ClickedShape.TextFrame2.TextRange.Font
            .NameComplexScript = "MS ゴシック"
            .NameFarEast = "MS ゴシック"
            .Name = "MS ゴシック"
        End With
    For Each s In ActiveSheet.Shapes
        '次のIf文はもともと操作ボタンをフォームに貼り付けていた頃の名残で、
        '普通のシェイプは消すが、ボタンは例外として消さないための策。
        '現在はリボンに移行したので必須ではないが、そもそも消したいのは普通のシェイプだけなのであえてこのまま。
        If s.Type <> msoFormControl Then
            s.Delete
        End If
    Next
    'もともとはChartSheetを先にコピーして生成されたActiveWorkbookに対して操作を行うコードだったが、
    '環境によってはSheets(1)等でシートにアクセスできないエラーが発生した為に、
    '一旦シートを保存してから開き直して操作する方針に変更した。
    'しかし更に別の環境ではこの方法で別のエラーが出たため、
    'ブック内でひとまずシートを複製して操作を完了してから切り離すよう処理を変更した。
    '他のブックでこんなことは無かったので、原因不明。
    '■エラー発生を確認した環境
    '   OS 名 Microsoft Windows 10 Home
    '   OSバージョン 10.0.17134 ビルド 17134
    '   Excel 2013(15.0.5101.1000) MSO(15.0.5101.1000) 32 ビット
    'ひょっとしてマクロが記載されたシートだと不具合が出るのかと思って
    '一度コピーしたブックをxlsx形式で保存し、閉じてから開き直したらシートに対して正常に操作できた。
    ChartSheet.Copy after:=ChartSheet
    Dim sh As Worksheet: Set sh = ActiveSheet
    'いくつかの環境で、ribbon.ResetModeを実行するとエラーが発生することが判明した。
    'EnableEventsをFalseにしたり、DoEventsを挟んでみたり、実行の位置を変えてみたが、
    '別名保存したファイルを閉じると改善することが判明。
    'ただ同じプロシージャ内で開き直すとまたエラーになることが判明し、
    '現在のプロシージャとは切り離すための苦肉の策としてOnTime実行呼び出しとしている。これは成功する。
    '注意) 殆どの環境ではこんなことをしなくてもうまくいく為、本件についてこうしたらうまくいったというアドバイスは特に募集しない。
    Call Application.OnTime(Now + TimeValue("00:00:01"), "'OpenSavedFile " & """" & fileName & """'")

引用元

前述のコメントは2年前に作成したフローチャート作成マクロから引用した。
github.com

ちょうど先ほどまでメンテナンスしていたのでブログネタにちょうど良いかと思い今回記事にしてみた。

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。