リーダブルコードで読みにくいコードを改善していく ~ 名前編

<p>どうも、ねこきち（<a href="https://mobile.twitter.com/nekokichi1_yos2">@nekokichi1_yos2</a>）です。</p>

リーダブルコード改善シリーズ、第2弾、です。

（詳しくは下記をご参照ください）
[リーダブルコードで読みにくいコードを改善していく ~ 準備編](https://qiita.com/NEKOKICHI2/items/0b7b1de064dd23a725fd)

**今回は変数や関数などの名前を改善していきます。**

## 変な名前を見つける

### ViewController

```swift
var list:Results<MemoObject>!
var text = [NSAttributedString]()
let realm = try! Realm()
let object = list[indexPath.row]
```

**list**・・・Realmのデータを受け取っているけど、何のリストなのかが不明
**text**・・・NSAttributedStringに変換したデータを格納しているが、何のためのテキストかが不明
**realm**・・・Realmのインスタンスだが、Realmのどの機能を担っているかが不明
**object**・・・取得したデータ群から取り出したデータを格納しているが、何のオブジェクトなのかが分からない

### AddMemo

```swift
class MemoObject: Object {
    @objc dynamic var data: Data!
    @objc dynamic var identifier: String!
}
let picker = UIImagePickerController()
@IBAction func leftButton(_ sender: Any)
let memo: MemoObject = MemoObject()
let data = try! NSKeyedArchiver.archivedData(withRootObject: memoTextView.attributedText!, requiringSecureCoding: false)
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[.originalImage] as? UIImage {
            let fullString = NSMutableAttributedString(attributedString: memoTextView.attributedText)
            let pickerImage = image.resized(withPercentage: 0.1)!
            let imageWidth = pickerImage.size.width
            let padding: CGFloat = self.view.frame.width / 2
            let scaleFactor = imageWidth / (memoTextView.frame.size.width - padding)
            let imageAttachment = NSTextAttachment()
            imageAttachment.image = UIImage(cgImage: pickerImage.cgImage!, scale: scaleFactor, orientation: pickerImage.imageOrientation)
            let imageString = NSAttributedString(attachment: imageAttachment)
            fullString.append(imageString)
            memoTextView.attributedText = fullString
        }
}
```


**MemoObject**・・・Realmに保存するためのモデルですが、
・どのようなオブジェクトなのか
・dataは何のデータを保存するのか
・identifierは何の識別子なのか
が明確でない。

**leftButton**・・・Realmにデータを保存する関数だが、そもそもNavigationBarの右側のボタンなのでleftは大間違いで、何の処理かが不明
**memo**・・・Realmに保存するのに使用する変数だが、メモなのはわかるが、何の用途に使うかの情報が足りない
**data**・・・Data型に変換されたtextViewの値を格納してるが、何のデータか分からない

**picker**・・・UIImagePickerだが、UIPickerViewなどと混同しそう
**fullString**・・・textViewの値をMutableAttributedStringに変換してますがAttributedStringだって情報は名前に含める方がいい
**pickerImage**・・・指定した値に圧縮（今回は10%に）してるが、圧縮後であることが分からず、こちらがピッカーで選択した画像だと勘違いする
**imageWidth**・・・pickerで選択した画像の幅だが、わざわざ変数にする必要はない
**padding**・・・textViewに表示する際の隙間だが、何のためのpaddingかが不明
**scaleFactor**・・・画像の拡大比率だが、Factorが表すのは何なのかが不明、そもそも比率だとぱっと見で判別できない
**imageString**・・・AttributedStringに変換した画像だが、imageとstringが連結してるだけで情報も役割も感じ得ない

### DisplayMemo


```swift
var indexPath: Int!
var memo: MemoObject = MemoObject()
var text = NSAttributedString()
```

**indexPath**・・・ViewControllerで選択したindexPath.rowが格納されているが、rowを格納してるか分からず、ViewControllerから渡されたってことが明記されてな
**memo**・・・ViewControllerから渡されたメモのデータを格納しているが、Realmから取得したデータ、保存する用のデータ、などとごちゃ混ぜになって、どういうデータかが分からない
**text**・・・ViewControllerから渡されたattributedStringを受け取っているが、何の値でどこから受け取ったのかを明記すべき

### EditMemo

```swift
extension UIImage {
    func resized() -> UIImage
}
@IBAction func gesture()
@IBAction func complete()
```

**resized**は、画像を圧縮するextensionですが、resizedだと過去形or過去分詞を表すので、resizeやresizingの方がいい
**gesture**は、長押しのジェスチャーで画像を添付する処理を持つが、どういうジェスチャーで何の処理をするのかが分からない
**complete**は、Realmに保存した編集したデータを保存するが、何が完了して、何をするのかが分からない

## リーダブルコードの教え

「名前に情報を含めよ」

情報には、
・扱う値、処理の概要
・扱う値、処理の場所
・扱う値の単位
・時期、タイミング
が挙げられる。

情報を伝える要素として、
・名前の長さ
・接頭辞、接尾辞
・単語、キーワード
・英語の文法（名詞、動詞）
・関連する属性、状態
が挙げられる。

「誤解されない名前とは？」

・とにかく具体的である
・扱う値に応じた単位を用いている
・読み手の勘違いを回避
・Boolを扱う時、疑問形の並びになる
・他の似た処理とどう違うかが明確
・名前から値の中身を想像できる

「長い名前でも問題ない理由」
エディタの単語補完で頭文字を入力すれば、一瞬で呼び出せるから

「1つの単語やキーワードで良い場合とは？」
スコープが小さい場合、なぜなら、使用するor影響する変数や関数が近くにあるから


## 名前の改善する

### ViewController

```swift
var memoList:Results<MemoModel>!
var attributedTextArray = [NSAttributedString]()
let realm = try! Realm()
let selectedMemoObject = memoList[indexPath.row]
```

**memoList**・・・複数のデータをRealmから取得するので、Listを追加
**attributedTextArray**・・・取得したデータのAttributedStringを取り出してるので、末尾をArrayに
**realm**・・・realmInstanceやrealmRefも考えたが、realmに関する変数は他にないので、realmだけで十分だと判断
**selectedMemo**・・・tableViewで選択されたデータを取り出し、Realmに1度は保存したデータなので、ObjectやDataなどの単語は省いた

### AddMemo


```swift
class MemoModel: Object {
    @objc dynamic var data: Data!
    @objc dynamic var identifier: String!
}
let imagePicker = UIImagePickerController()
@IBAction func addMemo(_ sender: Any)
let memoObject: MemoModel = MemoModel()
let archivedAttributedText = try! NSKeyedArchiver.archivedData(withRootObject: memoTextView.attributedText!, requiringSecureCoding: false)
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let pickerImage = info[.originalImage] as? UIImage {
            let mutAttrMemoText = NSMutableAttributedString(attributedString: memoTextView.attributedText)
            let resizedImage = pickerImage.resizedImage(withPercentage: 0.1)!
            let width = resizedImage.size.width
            let padding: CGFloat = self.view.frame.width / 2
            let scaleRate = width / (memoTextView.frame.size.width - padding)
            let imageAttachment = NSTextAttachment()
            imageAttachment.image = UIImage(cgImage: resizedImage.cgImage!, scale: scaleRate, orientation: resizedImage.imageOrientation)
            let imageAttributedString = NSAttributedString(attachment: imageAttachment)
            mutAttrMemoText.append(imageAttributedString)
            memoTextView.attributedText = mutAttrMemoText
        }
}
```

**MemoModel**・・・Realmに保存するためのモデルで、中の変数（data,identifier）はクラス名でメモのモデルだって明示してるので、名前を変更しないことにした。
**imagePicker**・・・UIImageのピッカーであることを示す。
**addMemo**・・・Realmにデータを追加するので、saveではなくaddをにした。
**memoObject**・・・Realmに保存する前の仮のデータなので、属性(Object)を含め、生成中or生成したデータであることを示す
**archivedAttributedText**・・・Data型としてアーカイブされたことを示す。

**selectedImage**・・・UIImagePickerで選択されたことを示す
**mutAttrMemoText**・・・NSMutableAttributedTextをmutAttrに略し、冗長にはせずに短くした
**resizedImage**・・・圧縮された画像なので、resizeを過去分詞の形にした
**width**・・・imagePickerControllerの中でしか使わず（スコープが小さい）、画像に使用すると理解できるので、他の情報は省いた
**padding**・・・widthと同様なので、他の情報は省いた
**scaleRate**・・・scale(拡大)Rate（割合）の意味を明確に表せる
**imageAttachment**・・・同じAttachmentでも画像なので、imageを頭につけた
**imageAttributedString**・・・画像を持つAttributedStringなので、頭にimageをつけた

### DisplayMemo

```swift
var selectedMemoObject: MemoModel = MemoModel()
var selectedIndexPathRow: Int!
var selectedMemo_attributedText = NSAttributedString()
```
**selectedMemoObject**・・・他画面から渡されたデータであること、単体のデータであることから、属性（Object）を追加
**selectedIndexPathRow**・・・ViewControllerで選択されたことを示し、属性（Row）を含めて、中身が数字であることを明示
**selectedMemo_attributedText**・・・選択されたメモのattributedTextであることを示す

### EditMemo

```swift
extension UIImage {
    func resizeImage() -> UIImage
}
@IBAction func attachImageGesture()
@IBAction func updateMemo()
```

**resizeImage**・・・圧縮された画像を返すので、Imageを末尾に付けることで返り値であること示す
**attachImageGesture**・・・画像を添付するジェスチャーであり、textAttachmentを使用してるのでattachを使用
**updateMemo**・・・Realm上の該当するデータを更新するのでupdateにした


## まとめ

本記事を執筆するまでは名前なんて直感で命名してましたが、**たかが名前でも、変えるだけで可読性が上がるんだ**ってようやく体感できました。

普通なら、とにかく開発を進めたくて、とりあえず扱うデータや処理に関連する単語をつなげるだけでは、わかりづらい名前になってしまいます。

しかし、
・**その状況に適した具体的な情報**
・**いつ、何に、何を、何する、などの情報**
が加わると、とてもわかりやすくなります。

また、下記の英語の文法を
・名詞
・動詞
・動詞の時期(現在進行形、過去形、未来形、過去分詞形など）
活用すれば、状態や時期などの細かい情報も含めることが可能です。

海外の記事やドキュメントを読んでいくうちに、英語は上達してくので、”英語やコードを読む”を実践し続ければ問題はないでしょう。

次回は、**コードの美しさ**を改善していきます。