リーダブルコード・PSRから学ぶ 命名規則

先日の社内ランチ勉強会にて発表した内容をまとめます。

リーダブルコードはJavaやC++等で書いてあり、サンプルコードがしっくりこないことがあります。
今回は私が最も馴染みがあるPHPに落とし込んで読んでいきます。

# 参考資料
- [リーダブルコード(2章 名前に情報を詰め込む)](https://www.amazon.co.jp/%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89-%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF-Theory-practice-Boswell/dp/4873115655)
- [PHP Standards Recommendations](https://www.php-fig.org/psr/)
- [PSR-0, 1, 2を日本語に翻訳してみました](https://www.infiniteloop.co.jp/blog/2012/10/psrphp/)

# 1. 命名規則(フォーマット)
### ① キャメルケース
先頭文字を除いた単語の頭文字を大文字にする記法を指します。

 - ローワーキャメルケース(lower Camel Case)
 - アッパーキャメルケース(Upper Camel Case)
 
### ② スネークケース(snake_case／SNAKE_CASE)
単語と単語の間をアンダースコアで接続する記法を指します。

 - ローワースネークケース(lower_snake_case)
 - アッパースネークケース(UPPER_SNAKE_CASE)
   
### ③ ケバブケース(kebab-case)
単語と単語の間をハイフンで接続する記法を指します。

# 2.PHPで使用する命名規則(フォーマット)
PSRで定義されている各フォーマットを紹介します。
### ① クラス名
アッパーキャメルケース(Upper Camel Case)で定義しなければなりません。

### ② メソッド名
ローワーキャメルケース(lower Camel Case)で定義しなければなりません。

### ③ 定数
アッパースネークケース(UPPER_SNAKE_CASE)で定義しなければなりません。
定数で多く使われるケースとして別名コンスタントケースとも呼ばれています。

### ④変数
PSRで指定されているフォーマットは特にありませんが、
適切なスコープ内で統一する必要があります。

> PSR-1:BasicCodingStandard
https://www.php-fig.org/psr/psr-1/
4.2. Properties
This guide intentionally avoids any recommendation regarding the use of $StudlyCaps, $camelCase, or $under_score property names.

> Whatever naming convention is used SHOULD be applied consistently within a reasonable scope. That scope may be vendor-level, package-level, class-level, or method-level.


個人で使う分は好みでフォーマットを採用して良いですが、
チームで開発する場合は予め「どのフォーマットを採用するか」とルールを作ることで可読性高いコードに繋がると思います。


今回はローワーキャメルケースを採用します。


# 3. PHPで読むリーダブルコード 
## 2章 名前に情報を詰め込む
名前に情報を詰め込むことで、名前は「短いコメント」の役割になります。
必要以上にコメントを書かなくて良いよう、最適な名前を付けていきましょう。

## 1. 明確な単語を選ぶ
例えば、このような関数があるとします。
`public function getImages(url)`
この関数を見て「画像をゲットする」という情報は得ることが出来ますが、
どこからどんな画像の情報を取ってくるかが伝わってきません。

余計な憶測を生まない為にも、この関数で「どこからどんな情報をどのように取ってくる処理なのか」を明確に命名することが大切です。

仮に「インターネット上のECサイトから商品画像URLを取得する処理」なのであれば、下記にリネームします。
`public function fetchProductImageUrlsFromECSite(url)`

これで処理の中身を見ずとも、「この関数では、引数に入っているURLから商品画像URLを取得する処理を行っているんだな」という情報が分かります。

### カラフルな単語を使う
`get`は比較的簡単な処理を指すことが多く、上記の例では「外から取得する」意味を明確にするために`fetch`を採用しました。
他にも「画像をネット上からダウンロードしてサーバに保存する処理」であればgetより`download`が適切です。
このように、命名には役割に合わせた明確な単語を選ぶ必要があります。

| 単語 | 言い換え |
|:-----------|:------------|
| size | height, MemoryBytes, fileSizeInMb |
| make | set up, build, add, new |
| start | open, begin, create |

同じ単語を使い回してしまいがちですが、処理の役割に応じた単語を選ぶことで、名前から想像できる情報が限定的になります。


## 2. 汎用的な名前を避ける
例えばfor文。下記からは十分に情報が伝わってきません。
`❌の例：for($i = 0; $i < maxRow; $i++)`

仮に、「ユーザ番号を0から最大行数まで1ずつ加えるという処理」をしている場合は、`i`を`userNumber`に変更するだけで情報が加わります。
`⭕ for($userNumber = 0; $userNumber < maxRow; $userNumber++)`

汎用的な名前`tmp, foo, it, retval, i, j, k
`を使用する際は、使用する状況を選ぶ為慎重に判断する必要があります。

「生存期間が短くて、一時的な保管の為に使っている」など、
それ相当の理由がある場合はこれらの汎用的な名前を使ってもOKです。
しかし多くの場合は、その変数がどのような情報を持っているかを加え明確な名前に変更すべきだと思います。


## 3. 抽象的な名前よりも具体的な名前を使う
`❌の例：$user = self::getUser();`
上記の処理を見た時、`user`だけではどのような情報を持つuserかわかりません。

仮にログインユーザを指すのであれば、下記に変更します。
`⭕ $loginUser = self::getLoginUser();`

使う側と使われる側で齟齬が生じないよう、
抽象的すぎず役割が判断しやすい名前にする必要があります。

## 4. 名前に情報を追加する
❌の例`$colorCode`の場合、どのようなカラーコードであるかを明確にするため、下記のように情報を追加します。
`⭕ $hexColorCode $rgbColorCode $rgbaColorCode`


また、❌の例`$now = time();`のようにどのようなデータであるかの情報が不足している場合は、
`⭕ $currentTimeStamp = time();`と命名すると良いでしょう。

## 5. 名前の長さを決める
出来るだけ長い名前を避ける傾向がありますが、短くしすぎて結局その意味が分からなくなってしまうのは本末転倒です。
単語の略称を使う場合は、初見で見て意味が分かるか？という観点で見る必要があります。
固有の省略形は出来るだけ避けましょう。
`⭕ $db, $int`
`❌ $kbn, $tmp, $cnt, $cmt`

関数名を付ける場合、スコープの大きく複雑な処理には長い名称をつけてでもより詳細に命名する必要があります。
しかし、冗長的にならないように不要な単語は削除しましょう。

```
function fetchProductImageUrlsFromECSite(string ECSiteurl)
↓
function fetchProductImageUrlsFrom(string ECSiteurl)
```


## 6. 名前のフォーマットで情報を伝える
[2.PHPで使用する命名規則(フォーマット)](https://qiita.com/aaari95/items/8325131ce328e42e078c#2phpで使用する命名規則フォーマット) にもあるようにPSR指定フォーマットを採用することで、
フォーマットに情報をもたせることが出来ます。

例えば、定数はアッパースネークケースで記述することで、
処理の中でこの名前に遭遇した時に「これは定数だ」という情報がひとめで分かります。

フォーマットは言語によって異なるので、公式のドキュメントを参考に正しいフォーマットで記述することが大切です。

## 最後に
発表後に「更に深堀りした内容の発表が聞きたい」とコメントを頂いたので、
次の発表ではこのテーマを深く掘るか、他のテーマでも命名を強く意識した発表ができればと思っています。

命名にはかなりの苦手意識がありますが、
今は時間をかけてでも良い命名できるよう慣れていきたいです。