【良いコードを書くための Tips】導入編. 命名規則編

# 良いコードを書くためのテクニック集

勉強会で作成した資料をまとめました.
例題の言語は、TypeScriptにて記載してますが、TypeScript以外でも利用可能なTipsです

---

# 目次

1. **導入**(<-ここ)
2. **命名規則**(<-ここ)
3. より綺麗にする
4. ロジック
5. 大きなコード作成
6. 最後に
---

# 1. 導入

---

## 人のコードを見るのって大変じゃないですか？

- コードレビュー
- 既存コードの改修
- 既存コードに機能追加

**大半がコードを書くより見る時間の方が長い**

---

## 原因

- 変数名,関数名が単純
  - ex) tmp, information, value
  - 何を表しているかのかがわからないため、コードを追わないとダメ
- 一つの関数メソッドが複数のタスク
  - 関数名を抽象的にしていろいろの機能を盛り込む
- 不要なコード残っている(コメントアウト含め)
  - これは必要なコードなのか？を考える時間が発生
- ロジックが複雑
  - ex) `if(){if(){if()}}`
  - 何がなんだかわからん

---

## 悪いコード(あまり直視しないでください)

```typescript:あるクラスのメソッド
/* メソッドが抽象的で様々なタスクを処理 */
public setSubtitle(index: number) {  /* ネストが多すぎて動作がよくわからない */
        if (this.currentSubtitle != index) { /* currentSubtitleとindexの違いは？ */
            if (this._settings.isIE && this.useSidecar() && this.useOverray()) {
                this.setSubtitleForIE(index);
            } else {
                for (var i = 0; i < this.element.textTracks.length; i++) {
                    if (this._element.textTracks[i].label !== "dummy") {
                        this._element.textTracks[i].mode = 'hidden';
                    }
                }
                if (!!this._captionspan) {
                    this._captionspan.innerHTML = "";
                }
                if (!!this._areaDiv) {
                    this._areaDiv.classList.remove('visible');
                    this._areaDiv.classList.add('hidden');
                }
                if (index != -1) {   /* -1とはどういう状態なのか？ */
                    this.element.textTracks[index].mode = 'showing';
                    if (!!this._areaDiv) {
                        this._areaDiv.classList.remove('hidden');
                        this._areaDiv.classList.add('visible');
                    }
                }
            }
            this.currentSubtitle = index;
        }
    }
```

---

## 改めて目的

なぜ学ぶのか？

**他人が理解するのに時間がかからないコードを書くことは最も大事**

ただ、良いコードを書きたいけど具体的にどうしたらいいの？って人が多いと思います

そんな人に今日からコード上で使えるテクニックを紹介します

---

# 2. 命名規則

クラス、関数、変数、定数、メソッド、プロパティすべてにおいて名前をつける

どのような名前をつけるとよいのかを考えよう

---

## 明確な単語を利用

### 読み込み

```ts
function getPage() {}
```

`get`ではあまり明確な単語ではないのであまり利用すべきでない

より具体的に以下の用に着けると良い

```ts
// インターネットから取って来る
function fetchPage() {}

// ローカルキャッシュから読み出す
function loadPage() {}

// データの復元
function restorePage() {}
```

---

### 追加

`setData`は意味が広いためできるだけ避ける

```ts
// dataを追加
function addData() {}

// データを末尾に追加
function appendData() {}

// データを先頭に追加
function pushData() {}

// データを登録
function resisterStrage() {}
```

---

### 書き込み

```ts
// 既存のページを保存
function savePage() {}

// ユーザ画面にページを出力
function outputPage() {}

// インターネット上へ送信
function sendPage() {}
```

---

### 削除

```ts
// データを削除(復元不可)
function deletePage() {}

// データを除去(復元可能)
function removePage() {}

// データを廃棄(復元可能)
funtion trashPage() {}

// データを初期化
function clearPage() {}

// データを破棄(再利用不可)
fucntion destroyPage() {}

// 先頭のデータを取り出す
function popPage() {}
```

---

### 検証

`checkAccount()`は抽象的なので非推奨

```ts
// 対象のデータがルールを満たしているかを確認
function testAccount() {}

// 対象のデータが正しいか検証
function validateAccount() {}

// 対象のデータを比較する
function compareAccount() {}

// 対処のデータを照合
function verifyAccount() {}
```

---

### 探索

```ts
// 情報を検索(発見可能前提)
function findData() {}

// 情報を探索(発見するとは限らん)
function searchData() {}

// ある条件で抽出する
function extractData() {}

// ある条件で除外する
function excludeData() {}
```

---

### 更新

```ts
// 修正する
function modifiedData() {}

// 最新にする
function updateData() {}

// 適用する
function applyData() {}

// 変更する
function changeData() {}
```

---

### 真偽値

```ts
// bad
let loadFlag = false;
```

flag は用途を表すだけで、意味や状態を表現できないため使うのは避ける

`errorflag`は、falseがエラーなのか、trueがエラーなのかわからない。

お決まりパターンがあるので従うと良い

```ts
// is + 形容詞
let isEmpty;

// is + 過去分詞
let isHidden;

// is + 主語 + 過去分詞
let isViewLoaded;

// has + 名詞(データやプロパティを持っているか)
let hasParent;

// can + 動詞(処理ができる)
let canLoad;

// 動詞
let existsGoogle; // Listにgoogleが存在する
let containsGoogle; // Listにgoogleが含まれている

// should + 動詞(命令を実行するべきか)
let shouldLoad;
```

---

### そのほかの単語

参考 URL

https://murashun.jp/article/programming/naming-conventions.html

---

## 汎用的な名前は使用しない

意味が広いため理解しにくい

```ts
// bad
let tmp;
let val;
let it;
```

---

## 汎用的な名前は使用しない

ただ、イテレータで使用する`i`, `j`, `k`は OK

```ts
for (let i = 0; i < animals.length; i++) {
  animalAges.push(Number(animals[i].age));
}
```

TypeScript だと`forEach`を使うと良い

```ts
animals.forEach((animal: { name: string; age: string }) => {
  animalAges.push(Number(animal.age));
});
```

---

## 具体的な名前にする

より具体的な名前がつけられるようにメソッド分割

例)

```ts
// bad
setSubTitle(){}

// ok
paarseSubTimeType(){}  // 字幕の種類を解析
fetchSubTitleData(){}  // 字幕情報取得
formatSubTitleData(){} // 取得した字幕情報を整形
outputSubTitle(){}     // ユーザーに表示
```

---

## 名前に情報を詰める

単位をつける

```ts
const delayTime_ms = 10; // 遅延時間10ms
const imageSize_mb = 100; // 画像サイズ100MByte
```

---

## 名前の長さを決める

ガイドライン

- スコープが小さいものは短い名前で OK
- スコープが大きいものは情報を詰め込み長い名前にする

```ts
// nameだけでも意味が伝わる
if (user) {
  const name = loadUserName(user);
  outputUserName(name);
}
```

---

## 限界価

最大値、最小値は max, min をつける(包含関係)

```ts
const MIN_ITEMS_IN_CART = 1; // カートに入れれる最小は1アイテム以上
const MAX_ITEMS_IN_CART = 10; // カートに入れれる最大は10アイテム以下

if (shoppingCart.items > MAX_ITEMS_IN_CART) {
  // 11アイテム以上はエラー
  alert("カートにある商品数が多すぎます");
  return;
}
if (shoppingCart.items < MIN_ITEMS_IN_CART) {
  // 0アイテム以下はエラー
  alert("1アイテム以上で選択してください");
  return;
}
```

---

## 範囲

範囲は、start, last を使用(包含関係)

```ts
function outputConsole(start: number, last: number) {
  for (let i = start; i <= last; i++) {
    console.log(i); // 2, 3, 4
  }
}
outputConsole(2, 4);
```

---

## 排他的範囲

排他的範囲 begin(以上), end(未満)を使用(排他的関係)

```ts
function outputConsole(begin: number, end: number) {
  for (let i = begin; i < end; i++) {
    console.log(i); // 2, 3
  }
}
outputConsole(2, 4);
```

---

## フラグは肯定形

肯定にすることで可読性アップ

```ts
// ok
let isPlaying;

// bad
let isNotPlaying;
```

---

## 2. 　まとめ

- より明確な英単語を使用する
- イテレータは、`i`, `j`, `k`で大丈夫だが、複数の場合は`use_i`等にして付加情報をつける
- 具体的な名前にするため、メソッドを細分化
- 時間サイズ等には単位をつける
- スコープが大きいほど長くしてより具体的な名前をつける
- 限界値、範囲の名前を適切にする
- フラグは肯定にする
---