Posted at

[コーディングスタイル]識別子を日本語に切り替えていく

More than 3 years have passed since last update.


はじめに

 日本語で思考していたり、仕様書が日本語の場合、翻訳したり対訳表を作ったりする作業が無駄なのはあきらかなので、わざわざ英語に訳して識別子を命名し日本語のコメントを付ける必要はありません。

Q. E. D.

 しかしながら、歴史的経緯のようなものによって英語が得意で無い人でも英語で識別子を命名しようと言うのが多数派のようです。(※要出典)

 例えば「進捗を確認してboolを返す関数」を英語で命名する事考えて下さい。

すぐに適切な関数名が英語で思いつきますか?日本語なら簡単に適切な関数名が思いつくはず。

constexpr bool 進捗どうですか?()

{
return false;
}

 簡単だし分かりやすい!!!

わざわざ英語に翻訳するのが無駄な事は明らかですね。

※注意:コメントも識別子も英語だよって人は対象にしていません。それは英語のままにした方が良いです。

※Qiitaのマークダウンが日本語識別子に対応してないのか表示が乱れますが、これはまともなコンパイラなら大丈夫なコードです。javaでは表示が乱れないので、報告しといた方が良いかな。


日本語の識別子

 英語の識別子の命名規則は、キャメル、パスカル、スネーク、大文字スネーク云々、それを型名、変数名、関数名、マクロ等でそれぞれ統一する云々という事が多いです。

 例えば、「定数以外はスネーク、定数は大文字スネーク」あるいは、「型名と関数名はパスカル、変数はキャメル、定数は大文字スネーク」とか、人によって多少の違いはありますが、どういう規則にすればよいかみたいな知見は大体の人が持っているでしょう。

 しかしまともに日本語を使う事を考慮した命名規則を適用した経験がある人はいたりいなかったりするため、どうするのが良いかパッと思いつく人は少ないと思います。かといって日本語識別子をルール無しで使いはじめると書き方が高確率でバラバラになり、カオスで楽しいのですが、読みにくくなります。

bool 進捗どうですか?();

bool Is進捗();
bool 進捗を確認する();
bool 進捗確認();

 みたいな感じに人によって命名方法がバラバラになるため、なんかウワーッってなって、関数名を覚えたり推測しにくくなって、ウワーッウワーッ。

using 整数 = int;

#define もしも if

 こういう本末転倒なコードを書き出す人が出るかも、流石にないか?

 そんなこんなで、コメントが日本語だし識別子に日本語を使ってみようと思う人向けに。

「本当に使えるのか」

「コーディング規則はどうするか」

 あたりを解説したいと思います。

 サンプルや用語や解説はC++のものになりますが、別にC++以外でも似たような話になると思います。

一応実際の経験を元にしたノウハウとなっています。

※再注意:コメントも識別子も英語だよって人は対象にしていません。それは英語のままにした方が良いです。


識別子に日本語を使う前に


識別子に日本語が使えるプログラミング言語って普通なの?

 プログラミング言語によって微妙に異なる※1が、一般的なプログラミング言語は言語仕様上ASCII範囲内の文字以外にUTF-8の範囲内の文字が識別子に使える、使えない言語は少ないしもし使えないとしたらそれは非実用的な言語※2か古い言語か仕様のバグだと思われます。

 あと日本語以外に数学記号等も普通に使えます。

(※1.言語によって、「てにをは」を含む識別子に制限がある、句読点が使えない、絵文字が使えたり使えなかったりと言った細かい違いはあります)

(※2.非実用的な言語の例:WhiteSpace、Brainfuck)


プログラミングの流儀的にどうなの?

 多くのプログラミング言語がそういう風に設計されている以上、頭の中で日本語で考えていたり仕様書が日本語なら日本語で命名、英語でなら英語、ドイツ語ならドイツ語で識別子を命名するのが自然なプログラミングスタイルであると言えます。

 キーワードが英語っぽいから識別子も英語にすべきとか言ってる人を見たことはありますが、日本語の文章に英単語が混ざるのはNormalなので何のProblemもNothingでしょう。

(※英語とローマ字が混ざると分かりにくいように、例えばアルファベットを使うエスペラントネイティブの人とかだと話は変わってくるかもしれません)


移植性について

 ここ数年でUTF-8の対応状況はかなり良くなっており、文字コードの問題が起こる事はそんなにないです、文字コードで問題を起こすようなソフトはダメダメと言える状況になっています。

 とはいえ自分が使っているソフトがダメダメな事はよくあるので、識別子に日本語を使いたい方は事前に使っているソフトがUTF-8に対応しているか確認した方が無難です、適当にUTF-8にしか存在しない文字を入れれば対応してるかは簡単に確認出来ると思います。

(©マークと著作者の表記を入れるのがオススメ)

 ちなみにUTF-8が使えると公式に書いてあるからと言って互換性があるとは限りません。

BOMの有無や改行コードの違いがあったりするので、実際に確認を取りましょう。

 あとファイル名の仕様はOS毎にバラバラでややこしいです。移植性を考慮した上でファイル名を日本語にしたい場合はわりと面倒そうです。


C++におけるコンパイラの対応状況

 C++ではエンコーディングに規定が無いので、規格上はUTF-8でエンコードしたファイルをコンパイル可能かは実装依存です。さらに言えばパンチカードしか対応していないコンパイラも合法だったりします。

 しかしながら主要なコンパイラはUTF-8でエンコーディングされたファイルに対応しています、ユニバーサル文字列リテラル入った時点でUTF-8対応しないってのは流石にないかと思います。

 ただUTF-8に対応しているとは言ったものの、2014年10月現在、識別子のサポートについてはバラバラです。

・MSVC:絵文字や句読点等も使える

・Clang:Annex Eの規格通り

・g++:識別子名はASCIIとユニバーサル文字名のみ

・ICC:持ってないです(※要出典)

 Clangが対応したのも2013年の夏頃だったりで、古いコンパイラを使わざるを得ない場合、ツール側で別の文字に変換してからコンパイルするみたいな工夫が必要です。

 よく分かりませんが、MSVCは次期規格を見据えて実験的に拡張してるんだろうか?

g++はさっさと対応しろと言わざるを得ない。

(ちなみgccの中でもgddやghcは識別子のUTF-8対応しているようです)

規格上使える文字は、1236P辺りを参照して下さい。

n3337.pdf

C++以外は各自で調べて下さい。


g++でどうしても動かしたい場合

 解説は以下が詳しい。

名古屋313の日記:日本語フィーバー開発

 要約すると「あ」はプリプロセスでユニバーサル文字名「\u3042」に変換されるけど、この変換処理は単純なのでエディタやIDE側でも出来る、ちょっとプラグイン作って「HOGE3042」に変換してからコンパイラに渡せばASCIIしか対応していないコンパイラでもOKだよみたいな理屈です。ちなみに最新のg++であればユニバーサル文字名に変換しても大丈夫なようです。

 この方法を使えば、アセンブラや周辺ツールがエラーを吐いても回避出来ると思います。


使われてない事もない

 最初に日本語識別子は少数派だと書きましたが、使われている事もあるようです。

 テストの分野では有名な書籍に日本語の方が楽だよみたいな事が書かれたのもあってわりと普通らしく、データベース分野なんかでもわりと普通らしいです、あとはぴゅう太とかなでしことか。

こちらが参考になります。

日本語テストメソッドについて


日本語識別子は止めた方が良い場合

 社内公用語や仕様書が英語、オフショア開発している等の例では日本語識別子を使う理由はありません。使ってるツールの文字コード対応がお粗末だけど使わざるを得ない場合や大半のメンバーが日本語より英語が得意な場合も識別子は英語で良さそうですし、古いコードをなんとか保守している場合等も規則を変えるのは逆効果になるでしょう。

 こういった場合は英語を勉強して英語で命名出来るようになった方が良いでしょう。


他の人を説得出来るかどうか

[Java] 内部的にunicodeだから日本語つかえるけど・・・いくら英語苦手だからって・・・

 割合は不明ですが、積極的な賛成派、自分は使わないけど別にありじゃね?、テストコードのみOK、マルチバイト文字にトラウマがある、まで色んな人がいます。コメントを見ると日本語識別子有用派って多数派なんじゃないかとも感じます。

 そのため「VBだと普通に使ってたけどC++でも出来るようになってたのかー、次のプロジェクトから命名規則変えるかー」みたいな感じになることもありえますが、「英語のライセンス文が分からないからBoost使うな、でも識別子を日本語にするのはださいから英語にしろ!!!」とかダブルスタンダードを適用して来る事もあり得ます。

 大半の人が別に日本語で良いよなと思っている状況であなたの発言がきっかけとなる可能性もあるかもしれませんが、説得出来るかは運と政治力次第なので、なんとも言えませんし異端者扱いされても知りません。

 今となっては夏場にネクタイを外すのは普通ですが、一昔前にそんな事を提案したら罵倒される事すらありました。日本語識別子は現状そういう感じかもしれないので、生産性が上がったり移植性に問題が無い事を説明してもどうにもならないかもしれません。

 でも、職場の圧力なんかに絶対負けない!!!


職場じゃ駄目だったよ…

 職場で駄目なら趣味でOSS等の開発をしましょう、他にコミッタもいないため自由な規則でコードが書けます!

 it is done.


識別子に日本語を使うメリット

 というわけで自分しかコミッタのいないOSS(あるいは運良く職場)で、日本語識別子を使う方針に転換しましたが、先も言ったとおり何も考えずに日本語を濫用するとメリットと共にデメリットが発生します。最大のデメリットは非論理的な反発が起こりうる事なのですが、そこはクリアしているとします。

 目的は識別子に日本語を使う事では無く、あくまで生産性を上げ楽をする事です。

そのためにはメリットは出来るだけ受け、デメリットを受けない事が大事となります。


メリット-翻訳が不要

 先ほどの「進捗どうですか?」のように、よほど英語が出来る人でも無い限りちゃんとした英語の識別子名を付けるのは時間がかかります。

 またcoolをイケてるじゃなくて冷蔵と訳すような感じで辞書引いた上でも誤訳する事もあります。最悪の場合可読性の低いローマ字識別子を使う人まで現れます。

 つまり識別子の翻訳をやめれば、分かりやすい識別子を短時間で付ける事が可能になるわけです。

 「カーッ、識別子を素晴らしい英語で命名するのに半日かかっちまったぜー、ツレー」みたいなのが1分で出来るようになったりするので局所的には生産性100倍とかになります。

 さらに英語で正しい識別子を付けられたとしても、残念ながら英語が得意でない人は辞書を引かないと読めないので、結局日本語のコメント付けるみたいな意味が良く分からない事が起こります。

/*進捗を確認する*/

constexpr bool CheckProgress()
{
return false;
}

上のように辞書を引いて関数名を付けたが、辞書を引かないと意味が分からないので日本語でコメントを付けた変なコードを見かける事があります。

if(CheckProgress())

{
CPP();
}

 呼び出し元に直訳コメントなんて書かないし、書くとしてもすごく面倒なので、

「CheckProgress?どういう意味だろ、えーっとコメントになんて書いてあるかな、あー進捗確認ね」

とかになります。

 関数名が日本語で書いてあれば

「進捗どうですか?どういう意味だろ...」とかならないので。読むスピードが上がります。


メリット-ローマ字が消える

 例えば、侍の正しい英訳はSwordsmanでなくSamuraiです。

英語縛りだと固有名詞は全てローマ字にするのが正しいのです。

 つまり日本語の固有名詞が出てこないとか、英語版を先に開発するとか言うパターンでも無い限り、ローマ字の識別子は高確率で必要になります。

 ローマ字はぱっと見で、英単語と区別がつかなかったり云々で可読性が低いのは同意が取れるでしょう。日本語の識別子を使えばローマ字の識別子が消えます。やったぜ!!!


メリット-コメントが減る

 ドキュメントは自動生成したいですね。

 英語のドキュメントが欲しい場合はコメントが不要ですが、日本語のドキュメントが欲しい場合、英語の識別子に対して翻訳コメントを書く事になったりします。

 こういう事をすると、引数を変更した時のコードの修正箇所が増えるため、ドキュメントの品質が低下しやすくなり。さらに出力されるドキュメントが無駄に冗長になる弊害もあります。

/** HSVフィルター処理をかける.

@param fileName 処理する画像ファイル名
@param hue 色相
@param saturation 彩度
@param value 明度 */

bool HsvFillter(const char* fileName , int hue , int saturation , int value);

/*コメント不要.*/
bool HSVフィルター処理(const char* 処理する画像ファイル名,int 色相,int 彩度,int 明度);

 雛形は自動で生成するような仕組みを作ったとしても、ライブラリに関数が数百個あって、それぞれの引数が数個あった場合、仮引数名を日本語にするだけでコメントが数千行単位で減らせる計算になります、これは文句無しに楽。

あと一般的なIDEのヒント機能的にも仮引数を日本語にした方が見やすいです。


メリット-そのほか

 英語だとやたら冗長な単語が日本語だと短くて分かりやすい事がそれなりにあります。

「min_inclusive」だと長くて分かりにくいけど、「以下」だと短くて読みやすいとか。

 英語は日本語で言えばひらがなしかないような物なのでtypoに気づきにくいけど、漢字だとわりと気付きやすいとか。

 この辺は単語によっては英語が有利なので、重要ではないかもしれません。


メリット-まとめ

 結局の所、翻訳と言う行為が無駄なので、翻訳を止めたら良くなると言うだけです。

なので日本語を使うと分かりやすくなると言うより、英訳して分かりにくくなる事がなくなると言った効果があります。


デメリットについて

 あえて得意でも無い英語を使う事にもなんらかのメリットは存在するよと言った話。


デメリット-入力が面倒

 キーが数千個あるような変態キーボードを使っていない限り、日本語入力は変換が必要です。

英語であれば基本的には変換は不要なので入力は早くなります。

 とはいえ辞書を引くほうがあきらかに面倒なので、無意識で入力切り替え出来るようになれば殆ど気にはなりません。

 IMEに日本語を入力すると変換候補に英訳を出すみたいな機能を追加すれば辞書を引く回数は減らせるそうですが、それだったら日本語で良くね?って感じです。

日本語コメントを入力する手間もなくなってる分、ヘタすると入力が楽になる事もあります。

 英語であれば一文字目からIDEが候補を出してくれますが、日本語だと変換を確定させないとIDEは候補を出せません。日本語であれば英語に比べて関係無い候補が減って見やすくなるメリットはありますし、IMEの予測変換機能がほぼ同じ事をしてくれる事もありますが、標準ライブラリやキーワードは英字なのもあって、多少入力速度は下がると思います。

 あとなんらかの理由でまともなIMEが使えず、変なIMEを使わざるを得ない場合、まともなIMEに比べてかなり面倒に感じます。

 とはいえコード読んでる時間の方が長いので、特に問題無いですね。


デメリット-大文字と小文字がない

 例えば純粋仮想関数を持つクラスの接頭語に"I"を付ける事がよく有ります。

 IEnemyと書いてあれば、最初のIが接頭語であることが分かりやすいですが、抽象な敵とか敵のインターフェースとか書くと接頭語っぽくないです。あるいはI敵でも良いんですが、こうするとウツクシサガ-とか言う人が出てくる可能性が高まります。慣れればなんとかなるかもしれませんが、ぱっと見でどの部分が接頭語か分かりにくくなるのは良くないかと思います。

 あとは全部大文字だったら定数かマクロなどの表現も出来なくなります。良い代替方法も無いので、元のコード規則によっては悩む所です。


デメリット-英語の方が良い事あれこれ

 英語が得意で無いとはいえ、全く英語が出来ないなんて事はないので辞書を引かなくても誰でも分かる英単語はたくさんあります。そういう単語は英語で良いじゃんとなります。95%の単語は辞書引かなくてもわかるけど、5%は分からないとか言う状態も普通にあります。

 また英語でも日本語でも意味が知られていない単語は、英語だろうが日本語だろうが可読性が変わりませんし、外来語はカタカナで書くより英語で書いた方が分かりやすい事もよくあります。

 あとはString型に変換する関数とかを日本語にするのは良くないでしょう、「文字列型に変換する()」と「ToString()」では後者が適切です。「String型に変換する()」は冗長に感じます。


デメリット-表記のゆれ

 最初にかいた

bool 進捗どうですか?();

bool Is進捗();
bool 進捗を確認する();
bool 進捗確認();
bool 確認_進捗();

みたいな問題が起こります。

体言止めをどうするかとかGetやSetやIsなどをどうするか、てにおはの省略をどうするか等を決めておけば問題は減らせますが、慣れるまでつらそうです。

 とはいえ英語でも発生する問題なので、これはレビューをちゃんとすれば良いだけだと思われます。


デメリット-ファイル名

 クラス名を日本語にした場合、対応するファイル名も日本語にしたくなります。

 ドキュメント内のエンコードはUTF-8にしておけば大体大丈夫なんですが、ファイル名を日本語にすると対応しているOSやツールが減ります、単一のOSで動作すれば良いなら問題ありませんが、移植を考慮したい場合ややこしくなります。

 エディタで前処理してファイル名を変換してどうのこうのする事も理論上おそらく可能ですが、面倒です。ファイル名だけローマ字にするとかにしても良いですが分かりにくいでしょう。


デメリット-現実が辛い

 趣味でコード書いて日本語識別子楽しいいいいいいい、でも職場では禁止!となった場合。

こんな快楽知らなければよかった、ツラポヨみたいになります。


デメリット-まとめ

 メリットに比べるとデメリットは大した事なさそうなので、気にしなくても慣れればなんとかなりそうですね。


命名規約を考える

 最後にまとめとして、どんな感じの命名規則が良いか案をいくつか書いてみます。

規則名はすこぶる適当に付けました。


忍者スタイル

 キーワードや一般的な訳語が存在しない英語以外は全て日本語にするスタイルです。

int型に変換する、とか言う場合だけアルファベットを使います。カタカナ英語は出来るだけさけます。例えば、Fontは書体。Fileはファイルになります。

 このスタイルの欠点はカタカナにするか日本語にするかが分かりにくい所、関数名の表記がばらけやすい所。入力がそれなりに面倒な所。大文字小文字で見分けるスタイルが取れないので、変数名なのかクラス名なのかがぱっと見分けにくく、プレフィックスやサフィックスを用いた命名規則に慣れた人との相性が悪い。ファイル名がローマ字になる、関数名の文体を統一しにくい等があります。

慣れればなんとかなるとは思います。


忍殺スタイル

 忍者スタイルを改良し「別に英語と日本語が混ざっても良いのでは?」という考えから生み出された近代的なスタイルです。

 一部の命名はアルファベットを使う事にします。

プレフィックスは英字にし、名前空間も造語なので英大文字にします。

//大体こんなイメージ

namespace NINJYA
{
class I;
bool Is進捗();
void Set音量(int デジベル);
class ファイル;
class 書体;
}

 大分問題は解消されるのですが、書体にするかフォントにするかとかを悩む部分はそのままです。

またI敵とかのファイル名をローマ字にするとitekiとかなって意味不明になりますし、関数名の文体を統一させるのが難しいと言った欠点も残ります、高度な日本語力を要求されます。

慣れればなんとかなるとは思います。


ルーランゲージスタイル

 仮引数とテストコードだけ日本語にするスタイルです。

 この2つは高確率でコメントを付けるので効果が高いです。さらにテストコードは直接呼び出さず、仮引数名も呼び出し元には関係がありません、そのため命名方法が人によって微妙に違った場合も違和感が少ないです。

 ライブラリの利用者が増えたので、仮引数を英語にしたバージョンも出してみようみたいな事も比較的楽です。

導入も楽なのでお勧めのスタイルです。


修正版ルーランゲージスタイル

 ドメイン固有の語句はローマ字になるので、テストコードと仮引数に加えてそれらも日本語にします。

それに加えて日本語のコメントを書きそうになったら識別子を日本語にするのを検討していきます。

規則を決めるがややややこしくなりますが、わりとお勧めです。


まとめ

 もはや開発環境を理由にして、英語を使わざるを得なかった時代は終わりを告げています。

 あきらかに英語が不得意なプログラミング初心者に「変数名は大事だから辞書を引いて付けるべき」とか明後日の方向のアドバイスをするのは止めて、「英語が不得意なのに意味も無く英語にするな日本語にしろ!英語にしたいならネイティブ並の英語力を付けろ!識別子を英語にするのは英語の勉強としては効率が悪い!」とアドバイスするようにしましょう。


参考にしました

日本語識別子の必要性