見ただけで情報を読み取れる命名を心がけよう

# はじめに
先日、「**名前設計**」についてに下記の記事を執筆しました。
界隈で有名な方が執筆するような大した記事ではないですが、名前を適切に設定することの重要性を私なりに解釈して執筆させていただきました。

https://qiita.com/bamboo_wood/items/d9a569147a6767827eb6

「センス良く、かつ適切な名前を設定する」って簡単に聞こえます。
ですが、実際の開発現場では変数や関数の命名に悩まされることが多々発生するように思えます。

その問題の手助けをしてくれる本が「**リーダブルコード**」という本です。
エンジニア界隈で一番有名な本と言っても過言ではないですね。

もしこの本を読んだことがないという方がいるのであれば、この記事を読むよりリーダブルコードを読んだ方が有意義な時間を過ごせるでしょう。

この記事はリーダブルコードの2章から3章の一部について書いていこうと思います。

- **2章 名前に情報を詰め込む**
- **3章 誤解されない名前**



# 目次
1. [名前に情報を詰め込む](#名前に情報を詰め込む)
1. [誤解されない名前](#誤解されない名前)
1. [参考文献](#参考文献)








# 名前に情報を詰め込む
まず具体的な動詞や名詞を選定する前に、根本的な命名の考え方を頭に入れておかなければいけません。
リーダブルコードには6点の考え方があると記載されています。

> 1. 明確な単語を選ぶ
> 2. 汎用的な名前を避ける
> 3. 抽象的な名前より具体的な名前を使う
> 4. 接尾辞や接頭辞を使って情報を追加する
> 5. 汎用的な名前を避ける
> 6. 名前のフォーマットで情報を伝える

その中でも
- 明確な単語を選ぶ
- 汎用的な名前を避ける

を見ていきましょう。

### 明確な単語を選ぶ
```swift:.swift
func getUser(from: String) -> User {
    // ...中略
}
```
この関数はユーザーの情報を取得して返却してくれる関数だな！と読み解くことができます。
ですが、上記の関数の命名は不明確と言えます。
なぜなら、「どこからユーザーの情報を取得するのか」
の情報が`getUser(from: String)`だけでは読み取ることができないからです。

#### 改善する

https://php-archive.net/php/words-in-function-names/

この記事を見てみると取得系だけでも14個の類義語があります。

もしこの関数が、API経由でユーザー情報を取得するような関数の場合は下記のコード適切なのではないかと考えます。
```swift:.swift
// 🐤 改善前
func getUser(from: String) -> User {
    // ...中略
}

// 🐔　改善後
func fetchUser(url: String) -> User {
    // ...中略
}
```
`getXXXX`という動詞自体が便利が故に、呼び出し側の想像力を無駄に働かせてしまいます。
類語辞典で調べたり、命名についての記事を読んでみたりして適切な命名を心がけてみましょう。







### 汎用的な名前を避ける
```swift:.swift
func euclideanNorm(vector: [Double]) -> Double {
    var returnValue = 0.0
    vector.forEach { returnValue += $0 * $0 }
    return sqrt(returnValue)
}
```
ユークリッドノルムって何だろうと思った方は下記の記事をご覧ください。
https://manabitimes.jp/math/1269
~~並んだ実数をそれぞれ二乗して足し合わせた値の平方根が「ユークリッドノルム」と言うものらしいです。~~
~~理系ではないので、詳しいことは良くわかりません。~~

さて、このコードの何が良くないでしょうか。
それは`returnValue`です。
この命名から伝わる情報は、この「関数の戻り値であること」だけです。
ですが実際に`returnValue`が格納している値は「二乗の合計値」です。


#### 改善する

`returnValue`という汎用的な名前から、具体的な名前に変更しましょう。
```swift:.swift
// 🐤 改善前
func euclideanNorm(vector: [Double]) -> Double {
    var returnValue = 0.0
    vector.forEach { returnValue += $0 * $0 }
    return sqrt(returnValue)
}

// 🐔　改善後
func euclideanNorm(vector: [Double]) -> Double {
    var sumSquares = 0.0
    vector.forEach { sumSquares += $0 * $0 }
    return sqrt(sumSquares)
}
```
`sumSquares`という変数を見て、「二乗された合計」が格納されているんだなと名前だけで理解することが出来ます。

この改善には嬉しい副作用があります。それは、バグの検知がしやすくなる点です。
例えば下記のバグコードがあるとしましょう。

```swift:.swift
func euclideanNorm(vector: [Double]) -> Double {
    var sumSquares = 0.0
    vector.forEach { sumSquares += $0 } // 二乗されていない👿
    return sqrt(sumSquares)
}
```
変数で`sumSquares`を定義しているおかげで
「二乗された合計なのにシンプルに合計をしている・・・！？」という発見の手助けになることがあります。

`returnValue, value, foo, bar, org, tmp...`
汎用的な名前の変数を見つけた際には、それが具体的な名前に置換することが出来ないか常に考えるようにしましょう。

#### 汎用的な名前って絶対に使っちゃいけない？

リーダブルコードでは**汎用的な名前**が全て悪だとは記載されていません。
> 汎用的な名前が役に立つこともある。

と記載されています。気になる方は、ぜひ読んでみてください。








# 誤解されない名前
自分の中で納得のいく命名を施した関数が、他人の誤解によりバグを生み出してしまうケースがあります。

- 限界値を含めるときは`min`と`max`を使う
- 範囲を指定するときは`first`と`last`を使う
- 包含/排他的範囲には`begin`と`end`を使う
- ブール値の名前
- ユーザーの期待に合わせる
- 複数の名前を検討する

最初の1つだけご紹介させていただきます。

### 限界値を含めるときは`min`と`max`を使う
```swift:.swift
class Cart {
    let items: [Items]    
    let CART_TOO_BIG_LIMIT = 10
    
    func add(item: Item) throws -> Cart {
        if items.count >= CART_TOO_BIG_LIMIT {
            throw CartError.exceedItems
        }
        // ...商品カートに商品を追加
    }
}
```
このコードにはバグがある。
それはカートの商品に10個目を追加した時点で例外を投げてしまうからである。
修正するには下記のようにすればいいだろう。
```swift:.swift
if items.count > CART_TOO_BIG_LIMIT {
    throw CartError.exceedItems
}
```
#### 改善する
ロジックを変更すれば確かに意図した動きになるでしょう。
ですが、根本的な問題解決には至っていないと思います。
なぜバグを書いてしまったのか、その原因を解決することが根本的な問題解決と言えるでしょう。

原因は`CART_TOO_BIG_LIMIT`です。
`CART_TOO_BIG_LIMIT`この曖昧な命名が「**未満なのか以下なのか**」が分からないからです。

```swift:.swift
// 🐤 改善前
class Cart {
    let items: [Items]    
    let CART_TOO_BIG_LIMIT = 10
    
    func add(item: Item) throws -> Cart {
        if items.count >= CART_TOO_BIG_LIMIT {
            throw CartError.exceedItems
        }
        // ...商品カートに商品を追加
    }
}

// 🐔　改善後
class Cart {
    let items: [Items]    
    let MAX_ITEMS_IN_CART = 10
    
    func add(item: Item) throws -> Cart {
        if items.count > MAX_ITEMS_IN_CART {
            throw CartError.exceedItems
        }
        // ...商品カートに商品を追加
    }
}
```
適切な名前を付けましょう。



# 最後に
リーダブルコードは特にプログラマになりたての方に特に読んでほしい書籍だと考えています。
この本を読む前と読んだ後では、コードへの向き合い方がまるで変わるかと思います。
人によっては、この本を読んだ後に自分のコードを見たら恥ずかしくなって目も当てれないでしょう。






<a id="#reference"></a>
# 参考文献
- [リーダブルコード](https://www.oreilly.co.jp/books/9784873115658/)