命名規則 (プログラミング)
命名規則(めいめいきそく、naming conventions)とは、プログラミングを行う際にソースコード上の識別子(identifier)の名称となる文字列を決定するためのルールを定めたもの。ネーミング規則、ネーミング規約、あるいは命名規約とも呼ぶ。
通常は、ソースコードの可読性や視認性の向上、プログラミング効率およびメンテナンス性の改善などを目的としている。
命名規則は、プログラミング言語の仕様、メモリサイズ等のハードウェア的な制約、エディタや統合開発環境 (IDE) の機能などに影響を受けていることがある。
命名規則を決めた場合の潜在的利点としては、以下のものが挙げられる。
識別子の使用法に関して追加情報(メタデータ)を名前に含めることで、ソースコード自体をドキュメント化することができる。
変数の使いまわしによる可読性の低下やバグの発生を防ぐことができる。
プロジェクトおよび開発チーム内で命名について一貫性を持たせることができる。生産性やメンテナンス性の向上につながる。
潜在的な曖昧さを回避し、違いを明確化することができる。
検索置換ツールで間違える可能性を減らすことができる。
ツールによるリファクタリングの自動化が容易になる。
成果物に美しくプロフェッショナルな見た目を与えることができる(短すぎる名前、長すぎる名前、可愛い名前、面白い名前、ローマ字、略語を排除するなど)。
複数のチームが開発したものを統合・再利用するような場合に、名前が衝突(コンフリクト)することを防ぐことができる(名前空間参照)。
== 課題 ==
命名規則の選択とその実施は、論争になりやすく、各人がどんな命名規則が最善かについて意見を持っていることが多い。
さらに、よく知られている命名規則を採用したとしても、全体に実施を徹底させることができなければ、一貫性がなくなり、混乱が生じる。
このような課題は、その命名規則が一貫しておらず、記憶しづらく、利点よりも欠点が多いような場合には、さらに悪化する。
ソフトウェアシステムやアプリケーションソフトウェアのエンドユーザーが識別子名の良し悪しを意識することはほとんどない。ソースコード上の識別子名は、通常ユーザーインターフェイスに表出することはないからである。しかし、システムを引継いでいく開発者やアナリストにとっては、識別子が適切に選定されていることで、システムが何をしているかを理解したり、さらには新たなビジネス所要に応じてソースコードをどのように修正・拡張すればよいかを判断したりすることが極めて容易となる。
例えばC言語による例として、
というコードは文法的に間違っているわけではないが、その意図・意味は見当もつかない。どのようにも解釈することができる。少なくともコメントがなければ、各変数が何を意味しているのか、計算式は何を意味しているのかが分からない。
これに対して、
というコードは、各変数名に意味が込められていることで、たとえコメントがなくとも、少なくともシステムやアプリケーションの基本的な前後関係を理解している人には意味・意図が分かりやすくなる(monthly_pay_jpy = 月給[円]、hours_worked = 勤務時間、hourly_pay_jpy = 時給[円])。
また、各種APIや外部で開発されたサードパーティ製のライブラリを利用する場合も、適切な識別子命名規則に基づいて整理されたAPI・ライブラリのほうが、機能を類推しやすくなる(インターフェイス自体がマニュアルとなる)ため、生産性の向上にもつながる。
ソースファイルや、そのソースファイルを配置するディレクトリの命名規則もまた重要である。適切な命名と分類・階層化をすることで、どのファイルにどのような機能が実装されているのか、ということが分かりやすくなり、メンテナンス性の向上につながる。C++やC#のようなクラスベースのオブジェクト指向プログラミング言語では、一般的にそのソースファイル内で記述される主要なクラスの名前をファイル名にすることが多い。Javaの場合は最上位(トップレベル)のpublicクラスを定義するソースファイルの名前は、そのクラスの名前と同じでなければならないという言語仕様上の制約がある。
C/C++のライブラリは、モジュールとともに関数宣言や型定義を含むヘッダーファイルを公開インターフェイスとして提供することが多く、ヘッダーファイルの命名規則も重要となる。
命名規則は実際には、開発する対象や環境に依存する。しかし、多くの命名規則に共通に見られる要素がいくつか存在する。
命名規則の最も基本的な規則のうちのひとつは、識別子の長さに関するものである(長さの限度および識別子に使える文字の種類)。数値を挙げて上限を設定する場合もあれば、もっと緩やかなガイドラインを設定する場合もある。
識別子長の規則は議論の的になりやすく、学術的な議論にもなっている。適切な長さはケースバイケースであり、一概には決まらない。
考慮すべき点:
タイピングしやすいため、短い識別子が好まれる傾向がある。ただしIDEの入力支援機能(コード補完)が使える場面では、あまり問題とならない。
あまりにも短い識別子(a や i など)は、識別が困難である。
短い識別子では暗号的な名前になるなど意味情報が十分に込められないとして、長い識別子を好む場合もある。
長い識別子はスクリーン上に占める面積が増え、コード全体を素早く読めなくなることから、敬遠される場合がある。
たとえ長い識別子を使っても、そのうち1文字しか差異がない2つの識別子などは一見して区別が困難なこともある。
略語は混乱を招くため控えたほうがよいが、長すぎる正式名称を使うと可読性を損なう。
変数や関数のスコープに応じて長さを変えることもある。
スコープが広い場合は(グローバル検索しやすく衝突しにくい)長い名前が好ましいが、スコープが狭い場合は短い名前でもかまわない、など。
初期のリンケージエディタには、メモリ使用量を抑えるために変数名などを6文字以内に制限していたものがあり、そのために古いプログラムで識別子が短く制限されていたという事実もある。後発のプログラミング言語および処理系でも、識別子の長さに制限が設けられている場合があるが、実用的な範囲では通例問題にならない上限である。
命名規則によっては、大文字と小文字の使い方を制限しているものもある。また、大文字も小文字も使えるが、それらに意味を与える場合もある。アルファベット、数字、両方を混合した英数字の使い方を指定した命名規則もある。プログラミング言語によっては大文字と小文字を区別しないものもある。
一般に「意味のある識別子」が推奨される。1つの単語では意味がわかりにくい場合もあり、複数の単語を識別子に使用することになる。結果として、命名規則には、複数の単語を連結する場合の方法が指定されることになる。各プログラミング言語で定められている予約語(キーワード)と衝突しにくくなる効果もある。
多くのプログラミング言語は識別子内に空白を許さない。そのため、空白以外で単語の区切りを示す方法が必要となる(区切りを示さないと、可読性が低くなる)。
英数字で記された単語を特定の区切り文字(デリミタ)で連結する。一般に、この目的で使われる文字は、ハイフン(-)かアンダースコア(_)である(例えば、two words を two-words とか two_words と記述する)。ハイフンはCOBOLやLISPでよく使われる。Cascading Style Sheets でもセレクタ名にハイフンが使われることが多い。他の言語(C言語やPascal系など)はハイフンが引き算の記号と同じであるため、識別子には使わない(使えない)のが一般的である。区切り文字で連結された文字列が蛇や鎖のように見えることから、スネークケースやチェーンケースと呼ばれることもある。
大文字/小文字による単語の切り分け
単語の頭文字を大文字、それ以外を小文字にする。例えば、two words は twoWords や TwoWords と記述される。これをキャメルケース(lower camel, upper camel)などと呼ぶこともある。アッパーキャメルはPascalで利用されていた経緯から、パスカルケースと呼ばれることもある。
命名規則によっては、特定のプロジェクトや問題領域に必要とされる規則や必要条件というだけでなく、ソフトウェアアーキテクチャによって定義される原則、根底にあるプログラミング言語やプロジェクト横断的な方法論などを表す大きな枠組みを提供する。
COMインターフェイス名のI接頭辞(プレフィックス)など、フレームワークによってルールが定められているものもある。
最もよく知られている命名規則としてハンガリアン記法 (Hungarian notation) がある。これには、「目的」を名前に含める方式(アプリケーションハンガリアン)と、「データ型」を名前に含める方式(システムハンガリアン)に分けられる。
非常に短い(8文字以下)長さで識別子を形成する場合、桁位置ごとに意味を持たせることがある。例えば、LCCIIL01 という名前で、先頭の LC は「信用状(letter of credit)、次の C は COBOL、IIL は 特定のプロセスサブセットを表し、01 がシーケンス番号となっている。
このような規則はメインフレームでのJCLなどで今でも使われている。また、MS-DOSでのファイル名(8文字+拡張子3文字という制限がある)でも見られる。
初期の命名規則として、IBMが1980年代にIMS(Information Management System)のマニュアルで採用した "OF Language" がある。
これは、PRIME-MODIFIER-CLASS(主要部-修飾部-クラス)の形式で、例えば "CUST-ACT-NO" という名前で "customer-account-number"(顧客-口座-番号)を表す。
PRIMEの単語は、システムが対象とする主な実体を指す。MODIFIERの単語は、補助的な具体化をしたり、可読性を向上させる役目を持つ。CLASSの単語は理想的にはデータ型を表す短いリストである。典型的なCLASS単語として、NO(number)、ID(identifier)、TXT(text)、AMT(amount)、QTY(quantity)、FL(flag)、CD(code)、W(work)などがある。実際、CLASS単語としては2ダースほどの単語がリストアップされている。
CLASS単語は一般に右端(接尾辞)に置かれ、ハンガリアン記法(システムハンガリアン)の接頭辞と同じ役目を果たしている。
CLASS単語の目的は、一貫性を保つだけでなく、プログラマにデータフィールドのデータ型を指示する意味がある。BOOLEAN(two values only)が登場するまでは、FL(flag)が二値だけをとるフィールドを示していた。
C言語とC++はともに大文字/小文字を区別する言語だが、キーワードや標準ライブラリ(標準Cライブラリ、標準C++ライブラリ)の識別子の多くは小文字である。C++の設計者Bjarne Stroustrupは、言語組み込みの型および標準ライブラリの型と、ユーザー定義の型を区別できるように、ユーザー定義の型の名前は大文字で始めることを推奨している。また、すべての文字を大文字にした名前は、慣例的にプリプロセッサマクロでの使用に予約されているので、マクロシンボルではない識別子の名前には絶対に使用してはいけないと助言している。
C言語の場合、次の名前が実装系(コンパイラおよび標準ライブラリ)のために予約されている。
グローバルスコープを持ち、_で始まる名前
_で始まり、その次が大文字の名前
__で始まる名前
C++の場合、次の名前が実装系のために予約されている。
グローバルスコープを持ち、_で始まる名前
_で始まり、その次が大文字の名前
__を含む名前
予約された名前をユーザー定義の識別子に利用した場合は未定義動作となるため、ユーザー定義の識別子に使ってはならない(例えば、__reservedや_Reserved、ファイルスコープの_reservedなど)。
C言語は名前空間をサポートしないため、代わりに各種APIの関数や型、定数シンボルには固有の接頭辞(プレフィックス)を付けて、衝突を防いだり判別しやすくしたりすることがある(例えばOpenGLのgl/GL/GL_など)。
定数名を表す際に、数学や自然科学などにおける定数のアナロジーから、k接頭辞を用いるルールも存在する。
Smalltalkでは、大域変数(クラス名も含む(クラスも大域変数であるため))は大文字からはじまるキャメルケース、局所変数、メンバーとなる変数は小文字からはじまるキャメルケースを使用する。これは、言語仕様でも決まっており、存在しない大文字で始まる変数を参照するコードを書いても翻訳時にエラーとはならないが、存在しない小文字の変数を参照するコードを書いていると翻訳時にエラーとなる。また、メソッドが存在するセレクター(関数名のようなもの)は、小文字で始まるキャメルケースを使い、メソッドが存在しないセレクターには大文字で始まるキャメルケースを用いることが慣習になっている。これは、名前空間の解決等でメソッドが存在しないセレクターを使おうとした時、基底クラス等にメソッドが存在するとメソッドを呼んでしまうためである。後発のJavaなどはこの規則を強く継いでいる。ただし、Smalltalkにはプリプロセッサは存在しないため、全部大文字の識別子を使う慣習は存在しない。
Javaでは、言語仕様および標準ライブラリの設計時点から、クラスやメソッド、定数や変数などの命名における大文字/小文字の使い分けといった規則が決められている。例えば、クラス名は大文字で始める (upper camel)、メソッド名や変数名は小文字で始める (lower camel)、また定数名はすべて大文字でアンダースコア区切りとする、などである。
JavaBeansからの影響を発端として、特定の接頭辞を付けたアクセッサメソッド (getter/setter) が定義され、カプセル化に利用されることも多い。
なお、Java 9ではアンダースコア1文字の識別子_は予約済みのキーワード(予約語)となったため、ユーザーコードで識別子として使用することはできなくなった。
BASICは、C言語と違って大文字/小文字の区別をしない言語である。処理系は大文字/小文字の違いを無視してシンボルの識別をしている。これはVisual Basic (VBAを含む) およびVisual Basic .NETにおいても受け継がれている。したがって、例えば form.show, Form.Show, FORM.SHOW はすべて同じ意味になる。ただし、識別子名は人間にとって読みやすいほうが好ましいため、VB/VB.NETでは通例シンボルの宣言時に大文字/小文字を使い分け、シンボルを利用する際も宣言に応じて区別する命名規則が採用される(IDEによるコード補完や自動フォーマットの際も宣言名が利用される)。型名やメソッド名、プロパティ名は大文字で始めるアッパーキャメルが採用されている。
かつてVB/VBAでは、GUI要素(コントロール)などの変数名に、略語の接頭辞(ハンガリアン記法)を使う命名規則が推奨されていたが、VB.NET (Windows FormsおよびWPFなど) ではそのようなガイドラインは存在せず、ハンガリアン記法は非推奨となっている。
Delphi言語は、PascalおよびVB系の言語と同様、大文字/小文字の区別を行なわないが、下記の命名規約が推奨されている。
レコード型、オブジェクト型、クラス型、およびtypeキーワードによる型のエイリアスなど、型を表すシンボルは'T'で始める。
インターフェイス型名は'I'で始める。
クラスのフィールド名は'F'で始める。
ルーチン名、メソッド名は大文字で始めて、大文字で単語を区切る(Pascal形式)。
C#言語および.NET Frameworkは、もともとDelphiの文法や言語機能およびVCLがベースになっていることもあり、Microsoftによる標準的な命名規約も(C/C++よりはむしろ)Delphiに似たものを踏襲している。
C#はC/C++やJava同様に大文字/小文字を区別するが、VB.NETを始めとする他の言語との相互運用性の観点から、大文字/小文字の違いしかないシンボル群をAPI外部に公開することは避けるべきとされている。