Agent Grow Advent Calendar 2017 13日目を担当するとっつぁんです。
アドベントカレンダー折り返し地点ですね。
キリがいいところなので、それにふさわしい(?)記事にしたいと思います。
テーマは
ハンガリアン記法について思うこと
です。
かなり個人的な見解なので ( ´_ゝ`)フーン と思いながら読んでみてください。
※ ちなみに上の絵は本編と全く関係ないハンガリーの画像です。
ハンガリアン記法ってなんぞや?
ハンガリアン記法とは、変数の命名規則の一種です。
HWND CreateWindowEx( DWORD dwExStyle, // 拡張ウィンドウスタイル LPCTSTR lpClassName, // 登録されているクラス名 LPCTSTR lpWindowName, // ウィンドウ名 DWORD dwStyle, // ウィンドウスタイル int x, // ウィンドウの横方向の位置 int y, // ウィンドウの縦方向の位置 int nWidth, // ウィンドウの幅 int nHeight, // ウィンドウの高さ HWND hWndParent, // 親ウィンドウまたはオーナーウィンドウのハンドル HMENU hMenu, // メニューハンドルまたは子識別子 HINSTANCE hInstance, // アプリケーションインスタンスのハンドル LPVOID lpParam // ウィンドウ作成データ );
※ MSDNよりCreateWindowExの関数定義を抜粋
ここの引数のところにある dwExStyle とか lpClassName のように、変数名の前にその変数の属性や型を示すプレフィックス1)本来つけたい名前の前方に付与する文言をつける命名規則がハンガリアン記法です。
変数名を見れば何の型か とか どんな情報を持っている変数なのかがわかりやすい!というのがメリットです。
動的型付けの言語が全盛になった今そうそう見なくなった記法ですが、私は昔windowsアプリを作っていたので結構見ることがありました。
もうだいぶ古い思想になっていると思いますが、ふと思いついたのでいろいろ思っていることを書いていこうと思います。
言いたいことの本題
ということで早速本題です。
2種類の記法がごっちゃになっている
いきなりですが、ハンガリアン記法には2種類あります。
この2種類の記法のうち、よりいまいちなほうが使われたり議論されることが多いためもやもやします。
アプリケーションハンガリアン
こちらが大元のハンガリアン記法です。
金額計算情報を持つ変数を例にとると(以降cとかjava的な言語のイメージで書いています)
int jpyWallet1 = 50; // 円の金額 int jpyWallet2 = 70; // 円の金額 int usdWallet1 = 70; // 米ドルの金額 int usdWallet2 = 100; // 米ドルの金額
↑のように、変数が示す意味合いを変数名のプレフィックスにするイメージです。
このような変数がある場合、
int jpyNewWallet= jpyWallet1 + usdWallet2 ; // 円と米ドルの計算
↑のように異なる単位を示す値の演算をパッと見て把握しやすくなります。
おかしな演算を見つけやすくするという観点では、アプリケーションハンガリアンは有効な命名規則といえます。
システムハンガリアン
アプリケーションハンガリアンを元に誤った意図で派生した記法です。
一般に流通しているハンガリアン記法はこちらではないかと思います。
int iValue = 12; // int型のプレフィックスは i bool bIsClickable = true; // bool型のプレフィックスは b int* pRefValue = &iValue; // ポインタのプレフィックスは p unsigned int uiValue = 100; // unsigned int型へのプレフィックスは ui char szString[255]; // 文字列を格納する変数のプレフィックスは sz
↑のように、型に対応したプレフィックスを付けるイメージです。
※ 10年くらい前の記憶で書いているので怪しいところもあるかも・・・
こちらの場合変数名を見れば型がわかるというメリットはあります。
しかしプログラミング中に変数の型を変更する場合、同じ変数の名前をすべて変更する必要があり修正がつらくなるデメリットもあります。
どちらにしても正直あんまりうれしくない
個人的にはアプリケーションハンガリアンはまだアリかもなぁと思っていますが、プレフィックスでごまかすくらいなら適切な変数名を付けたほうが確実に読みやすくなると思います。
適切な変数名を付けることで略称のリストが必要なほどの暗号的なプレフィックスを変数名に着けなくてもよくなります。
※ ハンガリアン記法を使わない適当な例
int dollar = 10; // 米ドル int dollarPeryen = 113; // 1ドルの円価格 printf(”%d”, dollar * dollarPeryen ); // 10ドルの価格を表示
どんな名前がいい名前なのかは code complete や リーダブルコード を読んでいただきたいと思いますが、ざっくりいうと「名は体を表す」ようになっているのがいい名前だと思います。
特にシステムハンガリアンには勘弁していただきたい
システムハンガリアンについては、個人的には害悪だと考えています。
正直いいところは何一つないと考えています。
チームのルールでこれを採用しなければならない場合、猛烈に反対するかチームを抜けることを本気で検討すると思います。
以下で理由を説明します。
変数の型が変わってしまった場合に地獄を見る
システムハンガリアンで書かれた変数の型を変更する場合を想像してみましょう。
見通しがいいシステムであれば開発環境のリファクタリング機能や文字列置換で何とかなるかもしれませんが、何年も増改築を重ねたレガシーシステムではこの対応が取れない場合が多いです。
※ システムハンガリアンでの変数の型変更が辛い実装の例
mapParams[”fCalcMethod”] = PLUS; // 足し算するための定数を設定 mapParams[”iValue1”] = 3; mapParams[”iValue2”] = 6; // mapParamsを使って計算するsomeFuncを実行する int result = obj->callFunc(”someFunc”, mapParams); ・・・ int someFunc(int iValue1, int iValue2, bool fCalcMethod){ なんやかんや処理する }
このように実行する関数を文字列として指定する実装は抽象度が上がるし一見自由度が高くなるように見えるのでついやりたくなりますが、何も知らず後からやってくる人にとっては追いづらいソースになることが多い印象です。
※ 個人的には実行時に処理する関数を指定するよりは、依存性の注入で処理を切り替えれるようにしたり、用途ごとに子クラスを作って実装するほうが好きです
この場合、someFunc 関数の引数の型を変更するときに callFunc で呼んでいる箇所を開発環境のリファクタリング機能で置換することはほぼでできないでしょう。
その代わりとしてmapParamsのキー名で文字列置換しようとすると、今度は同名のまったく関係ないキーや変数まで文字列置換してしまう可能性があります。
地獄の作業内容
では実際に変数名を変更する対応を行うことを想定していましょう。
someFunc関数で使っているiValue1とiValue2の型をdouble型に変更することを想像します。
その場合の作業内容は以下のようになると思います
- someFunc関数の仮引数となっているiValue1, iValue2の型を変更し、変数名もdValue1, dValue2へ変更する
- someFunc関数を使用している箇所を全件検索する
- そこから同名の別関数を省いてひとつづつ確認していく
- 3.で見た関数が変更対象なら、引数として渡すiValue1, iValue2の変数名(添字)をdValue1, dValue2へ変更する
- 3.と4.を繰り返す
この場合本当に全部対応したか地道に確かめる必要がありますし、漏れた個所でバグが発生するプレッシャーが常に付きまといます。
プレッシャーによる人為的ミス、増える修正工数、増えるテスト項目、リリース後に発覚する変更漏れ、増大するプレッシャー・・・
幸運にも自動テストが導入されていれば幾分かマシになるかもしれませんが、私としては控えめに言ってもこの状況は地獄だと思います。
保守性が高いコードを書こうぜ!
昔はこのような書き方が主流となっている時代もありましたが、昨今あまりみない命名規則となってきました。
きっと「この記法保守しづらいよね」と思う人が多かったのでどんどん減っていったのだろうと想像しています。
開発効率を上げるための理屈がないのであれば、このように誰にとってもうれしくない規則はさっさとご退場願いたいものですね。。。
ハンガリアン記法のような書き方を採用するかどうかはともかくとして、半年後や一年後の自分が見た時に辛くならないコードを書きましょう。
そうすればシステムは変更に強くなるし、周りの人は修正しやすくなるし、自分は仲間に尊敬されるようになるしで結果みんなハッピーになれますよ!
(無理やりまとめた感)
クロージング
ふと思い立ったので、いまどきハンガリアン記法なんて使ってるところないでしょ と思いながら記事を書きました。
無理やりまとめましたが、保守性が高いコードを書こうぜ!というのは常々思うことなのでつい書いてしまいました。
偉そうなことを書いたところで終わります。それではまた次の機会に。
注訳はこちら
↑1 | 本来つけたい名前の前方に付与する文言 |
---|