はじめに
仕事におけるプログラミングの現場においては「リーダブルコード」を求められることが往々にして多いことでしょう。もちろんアーキテクチャやデザインパターン、流行りの機能、書き方を学ぶことで解決することもありますが、「なんか使ってるんだけどわかりづらいな・・・」と思うことがあったりしませんか?
読みづらいメカニズム
まず読みやすくなるためのテクニックを語る前に、「何故読みづらいのか」を考えてみました。
こう思い返してみると、アーキテクチャやデザインパターンやらに依るところはなかったと言っても過言ではなかったかなと思います。
1. そもそもの処理の認識が誤っている
一見読んだだけで理解できないコードがあったときに、書いた方に「これはどういう処理ですか?」と聞きます。そうすると一定のケースで「説明される内容(日本語)がそもそも正しくない」に分類されることが多いのです。
そうしたときには、その部分の処理を理解するように努めてもらうことから始めます。地道ですが重要なことでしょう。
2. 変数名やメソッド名が英語で正しく表現できていない
この中でも特に頻出しがちなのは下記の2つです。
- 単語、特に前置詞が正しく使われてない
- 単語が雰囲気で羅列されてるため修飾関係がわかりづらい
各々のPJで変数名やメソッド名の命名規則がある場合はそれに従う、で良いかと思いますが、そうでない場合は 英文法に従う と読みやすくなります。(特に修飾関係)
また、 ファイル名、クラス名、変数名は名詞、メソッド名は動詞 になるようにし、それをベースに修飾語をつけるようにします。
class Car
{
// 20230726修正、privateがいいかpublicがいいかは別の議論に任せます
public $type;
public $height;
public function isSedan() {
$this->type === 'sedan';
}
/**
* ・引数を丁寧に命名するなら $absoluteValue になるが、スコープの短さを考えると省略しても自然
* ・「絶対値で高さを変える」からといって `AbsoluteValueHeightChange` とかにすると
* 「絶対値の高さが変える??」みたいな解釈を考えなければいけなくなります
* ・このように「英文法に則っています」ということはそれだけで解釈の幅を少なくすることができます
* /
public function changeHeightByAbsoluteMeter($value) {
$this->height = $value;
}
public function changeHeightByRelativeMeter($value) {
$this->height += $value;
}
}
class Hoge
{
public function fuga() {
$myCar = new Car();
...
if ($myCar->isSedan()){
$myCar->changeHeightByRelativeMeter(0.2); // 今より0.2mシャコタンにする
}
}
}
ここでもう1ステップ読みやすさを向上させるためにできるといいことは ただ名詞や動詞で定義するだけでなく、メソッドを使う側で正しい文章になっている ということが挙げられるでしょう。
この例でいうと
$myCar->isSedan()
と
$myCar->changeHeightByRelativeMeter(0.2)
です。
(2023/07/26 修正)
前者は「この車はセダンである(か?)」とそのまま読むことができ、読みやすさに直結します。
しかし後者は、変更する主語が車ではありません。必ずしもファイル名、クラス名が主語である必要はなく、目的語(この例でいうと change(Car)HeightByRelativeMeter
が略されている状態)であることもありますが、Carクラスの責務が肥大化してたり、メソッド名が長くなっているときは別のファイル、クラスに書くことを検討する価値が出てきます。
例: $engineer->changeCarHeightByRelativeMeter
(この考え方で行くと、そもそもこのメソッドを書く場所をEngineerクラスが正しくなり、クラス分割するメリットが生まれてきます)
3. 正しく表現していくと長くなる
「変に削るより、長くてもいいから正確な命名を」という言説をしばしば見るように感じますし、私も同意です。
ただ本当に長くなった場合には、これこそよく言われている「クラスやメソッドを分割する」を検討してほしいと思います。
自然に適切に分割にできる人もいるのでしょうけど「どのレベルになったらわけるべきなのだろう?」と疑問に思ってる方は、変数名やメソッド名の長さで分割する疑いをもつのも良いかなと思います。
ちょっと無理矢理ですが上記の例を使うならこのようになります。
// 車の高さだけを変える職人
class CarHeightChanger
{
private $car;
function __construct($car) {
$this->car = $car;
}
public function executeByAbsoluteMeter($value) {
$this->car->height = $value;
}
public function executeByRelativeMeter($value) {
$this->car->height += $value;
}
}
class Foo
{
public function bar() {
$myCar = new Car();
$changer = new CarHeightChanger($myCar);
$changer->executeByAbsoluteMeter(1); // メソッド名が抽象的にされてても内容が推測可能だと思うのですがいかがでしょうか?
}
}
まとめ
- 概念を正しく捉えてほしい!
- 英文法に則ってほしい!
- 長くなったら分割を考えるというのも一つの策だと思ってます
さいごに
「コードの読みやすさ」という言葉の通り、ある程度主観が入るのでこれが絶対的なものではないと思います。(割と最大公約的じゃないかなと思ってますが)
私自身昔から上記のような命名ができていたわけではありません。
リーダブルなコードを書くうえで色々な方法論が言われていてちょっとずつ自分も試していきましたが
コードを読む側になり、コードレビューを続けていくうちにやはり「各論の意識はされているが全体として読みづらい」みたいなコードを紐解くと上記問題に行き着くことが多く、筆をしたためました。