もっと日本語でSwiftプログラミングを

Swift に限った話ではありませんが、クラス名や変数名に Unicode が使えるようになってきました。🐶や🐱を変数にするのも結構ですが、もっと日本語を積極的に使っていけば、開発や保守が楽になるケースがあると考えていました。今回、日本語を積極的使って Swift でプログラミングする話をしたいと思います。


# そもそも何に日本語を使うの？

以下に何に日本語が使えそうかを示します。

* 変数名
* 定数名（不変変数名）
* クラス名、タイプ名、列挙子名
* コメント
* 関数名、メソッド名

# 名前に日本語を使うとどこがいいのか？

## 1. 専門用語が明確になる

例えば、以下のような用語の機能を実装する必要があったとします。みなさんならどんな風にコーディングしますか？ちゃんと英訳して、名前をつけますか？

* 確定申告
* 月末締め翌々月10日入金
* 瑕疵担保責任
* 無担保コール翌日物

そもそも、その英語の名前、英語圏の人が見て、その機能や特性を正確に理解してもらえますか？例えば、こんな具合にコーディングしてみてはどうでしょう。

```.swift
// 新会社法における会社の種類
enum 会社の種類 {
	case 株式会社
	case 合名会社
	case 合資会社
	case 合同会社
	case 有限責任事業組合
}
```

## 2. 日本語と英語で名称や呼び名が違う場合に便利

または、開発するゲームにこんなキャラクターのクラスのコーディングする事になったらどうでしょう。

<img width=80 src="http://cdn.bulbagarden.net/upload/5/53/054Psyduck.png">
<img width=80 src="http://cdn.bulbagarden.net/upload/3/39/007Squirtle.png">

おそらく大きく三つの名前の付け方があるかと思います。

### ①英語＋日本語コメント

```.swift
// ポケモン
class Pokemon {
}

// コダック
class Psyduck: Pokemon {
}

// ゼニガメ
class Squirtle: Pokemon {
}
```

日本語と英語では随分表記が異なりますね。よってちゃんとコメントをつけましょう。問題は開発の終盤にきて、英語の名前が間違っていた場合は、コンパイルエラーの及ぶ範囲が広くなる可能性があり、その場合は結構痛いです。


### ②ヘボン式表記

```.swift
// ポケモン
class Pokemon {
}

// コダック
class Kodakku: Pokemon {
}

// ゼニガメ
class Zenigame: Pokemon {
}
```

日本語をヘボン式またはそれに類する方法でアルファベット化する方法です。アプリ全体でなくても、局所的にこんなコーディングをする人もいるかと思います。欠点は、英語名がずらっと並んだ中に一つ二つヘボン式の名前が紛れていれも、一瞬で識別できず可読性が落ちる可能性がありますし、そもそもヘボン式は読みづらいです。

### ③日本語＋英語コメント

```.swift
// Pokémon
class ポケモン {
}

// Psyduck
class コダック: ポケモン {
}

// Squirtle
class ゼニガメ: ポケモン {
}
```

英語訳のコメントが間違っていても、修正によるコンパイルエラーの範囲は限定的です。ただ、日本語が読めないエンジニアがコードをメンテするような事態になると血の気がさっていくのを覚える事になります。

## 2. 英語でうまく表現できない名前の場合に便利

そもそも英語でうまく表現できない名前もあります。

### 「先手・後手」

こんな言葉、英語でも簡単にありそうですが、例えばチェスでは先手が白で、後手が黒です。ところが、囲碁やオセロはその逆で黒が先手で白が後手です。「Yu-Gi-Oh!」のルールブックでは、先手を「The player who goes first」と表現しています。では将棋の先手は英語でなんていうのでしょう。どんなゲームをプログラムを開発するのかによって、先手・後手という表現は不変ではなく、コーディングの可読性が落ちているかもしてません。

### 「トランプ」

トランプも不思議と英語では表現しづらい用語です。「trump」は和製英語で、英語では「Playing Card」ですが、これでは日本人の指すトランプを正確に英語で表現できていません。ちなみに 英次郎 によると花札は「Japanese Playing Card」ですが、これも正確に英語で表現できているとは言えません。なぜなら「花札」は「Japanese Playing Card」かもしれませんが、「Japanese Playing Card」は「花札」とは限らないからです。

http://eow.alc.co.jp/search?q=トランプ
http://eow.alc.co.jp/search?q=花札

## 3. へなちょこな英語名、変な英語名対策

概ね日本人の分法は悪くはないのですが、それでも、へなちょこな名前になってしまったり、不思議な名前になってしまったり、文法で意味が意図と違ってしまったりとか、になりがちです。もっと名前付けに時間をかけてもいいと思いますが、実際はそうなっていないのが現状だと思います。

例えば英語の「S+V+O」文型の場合、メソッドになると「S」が抜けて、「V+O」のケースで「O+V」になったり、または、現在分詞形や過去分詞形の使い方が曖昧で、「影響を与えるのか、影響が与えられるのか」／「これから起きる事なのか」「既に起きてしまった事なのか」／「単数なのか」「複数なのか」がはっきりしないメソッド名になったり、わかればいいと言っても、間違えると意味の変わってしまうネーミングにはやはり注意した方がいいと思います。

```.swift
  func cutHair()  // ヘアカットする
  func gotHairCut()  // ヘアカットを受けた
```

```.swift
  func loginFailed()  // 意味はわかるけどなんか変
  func didFailedLogin() // did の後は原型!!
  func accountValidate() // validateAccount() じゃない？
  func accountValidateSuccess() // 意味はわかるけどやっぱり変
  func startDownload() { // start, finish 直後の動詞は動名詞(-ing)
```

```.swift
  func updateItems() // アップデートする
  func itemsUpdated() // アップデートした
  var hasItemUpdated: Bool // アップデート済み
  var haveItemsUpdated: Bool // 今度は複数形
  func itemsAreBeingUpdated() // アップデート現在進行中
  func itemsHaveFinishedBeingUpdated() // ん〜やりすぎ？
  func didFinishUpdatingItems() // アップデート完了
```

<font color="silver">2016.9.14に加筆</font>

# 日本語化が有効な例、疑問な例

さて、いつも日本語化が有効であるとは言えないようです。

### 日本語化が有効な例

* 日本固有の法令に基づく
* 日本固有の商慣行に基づく
* 日本固有の固有名詞に基づく
* 日本固有の文化に基づく
* 数年以内の海外ビジネス展開の見込みが低い

### 日本語化が疑問な例

* 日本固有の法令とは無関係
* 日本固有の商慣行とは無関係
* 日本固有の固有名詞とは無関係
* 日本固有の文化とも無関係
* そもそもビジネスの海外展開を見込んでいる

# 積極的に日本語化に取り組んだケーススタディ

という事で、先の日本語化が有効な例で、実際に日本語を積極的に使って Swift のライブラリを書いてみました。そのお題は「将棋」です。日本の文化に基づき、日本語が読めないエンジニアがメンテをする確率は限りなく小さいと思うので、実験には丁度良いと思いました。たとえば、駒の裏表を意識した表現を以下のように表現できます。「駒面」という正式な用語はなく、実装上の都合による造語です。

```.swift
enum 駒面型 {
  case 歩, 香, 桂, 銀, 金, 角, 飛, 玉
  case と, 杏, 圭, 全, 馬, 竜
}
```

先ほど問題にしていた先手後手問題も、以下のように表現できます。

```.swift
enum 先手後手型 {
  case 先手   case 後手 
}
```

盤上のひとマスの状態は「空」、「先手の駒」、「後手の駒」の可能性があり、以下のように表現できます。

```.swift
enum 升型: Int8 {
  case 空

  case 先歩, 先香, 先桂, 先銀, 先金, 先角, 先飛, 先玉
  case 先と, 先杏, 先圭, 先全, 先馬, 先竜

  case 後歩, 後香, 後桂, 後銀, 後金, 後角, 後飛, 後玉
  case 後と, 後杏, 後圭, 後全, 後馬, 後竜
}
```

対局中の将棋盤の一場面を表現します。（一部簡略化して表現しています）

```.swift
class 局面型 {
  var 前の局面: 局面型?
  var 直前の指手: 指手型?
  var 手合: 手合割型
  var 全升: [升型]
  var 持駒表: [先手後手型: 持駒型]
  var 手番: 先手後手型
  var 終局理由: 終局理由型?
  var 勝者: 先手後手型?
  var 手数: Int?
}
```

<img width=300 src="https://qiita-image-store.s3.amazonaws.com/0/65634/6835038b-1a14-58b6-d90b-0c4cc4c78f6d.png">

### 単発移動

積極的なメソッドの日本語化にも挑戦してみました。以下のメソッドはある駒が単発（連続ではない）で移動できるオフセット（`x`,`y`）の Array を戻します。例えば先手の「金」を例に出せば、下図の赤丸へのオフセット(`x`, `y`)が Array で得られます。

```.swift
enum 駒面型 {
	public func 移動可能なオフセット列(駒面 駒面: 駒面型, 先後: 先手後手型) -> [(Int, Int)] {
		let y = 先後.direction
		switch 駒面 {
		case 歩: return [(0, y)]
		case 香: return []
		case 桂: return [(-1, y * 2), (1, y * 2)]
		case 銀: return [(-1, y), (0, y), (1, y),  (-1, -y), (1, -y)]
		case 角: return []
		case 飛: return []
		case 玉, 馬, 竜: return [(-1, -1), (0, -1), (1, -1),  (-1, 0), (1, 0),  (-1, 1), (0, 1), (1, 1)]
		case 金, と, 杏, 圭, 全: return [(-1, y), (0, y), (1, y),  (-1, 0), (1, 0),  (0, -y)]
		}
	}
}
```

<img width=160 src="https://qiita-image-store.s3.amazonaws.com/0/65634/ef6f3e8c-20f2-0871-053a-eec2df01ab0e.jpeg">

### 連続移動

同様に、連続移動できる駒がありますので、連続移動できるベクトル(`vx`, `vy`)を Array で返すメソッドを考えてみます。`vx`, `vy` のベクトルを味方の駒に当たる直前まで、あるいは相手の駒に当たるまで、もしくは盤の外に出るまで、連続して移動できる事を表現できます。

```.swift
enum 駒面型 {
	public func 移動可能なベクトル列(駒面 駒面: 駒面型, 先後: 先手後手型) -> [(Int, Int)] {
		let y = 先後.direction
		switch 駒面 {
		case 香: return [(0, y)]
		case 角, 馬: return [(y, y), (-y, y), (y, -y), (-y, -y)]
		case 飛, 竜: return [(0, y), (0, -y), (y, 0), (-y, 0)]
		default: return []
		}
	}
}
```

<img width=200 src="https://qiita-image-store.s3.amazonaws.com/0/65634/0058fc76-0db7-bcac-3998-21af84a11790.jpeg">

### 盤上の駒の移動可能な位置の Array

先の二つを組み合わせれば、盤上の特定の駒がどこに移動できるか調べるために、移動可能な場所を全て Array で返す、何のもい可能ように実装可能です。

```.swift
class 局面型 { 
	public func 指定位置の駒の移動可能位置列(指定位置: 位置型) -> [位置型] {
		let 指定筋 = 指定位置.筋
		let 指定段 = 指定位置.段
	
		var 位置列 = [位置型]()
		
		let 升 = self[指定筋, 指定段]
		if let 先後 = 升.先後, 駒面 = 升.駒面 {
			let 敵方 = 先後.敵方

			// find movable positions for single step like 歩, 桂, 金, ...
			for (dx, dy) in 駒面.移動可能なオフセット列(駒面: 駒面, 先後: 先後) {
				let (x, y) = (指定筋 + dx, 指定段 + dy)
				if let 筋 = 指定筋 + dx, let 段 = 指定段 + dy {
					let 位置 = 位置型(筋: 筋, 段: 段)
					let 対象升 = self[位置]
					if let どちらの駒 = 対象升.先後 where どちらの駒 == 先後 {
					}
					else if let 筋 = x, let 段 = y {
						let 位置 = 位置型(筋: 筋, 段: 段)
						位置列.append(位置)
					}
				}
			}

			// find movable positions for distant move like 香, 飛, 角
			for (vx, vy) in 駒面.移動可能なベクトル列(駒面: 駒面, 先後: 先後) {

				// 盤を外れるまで繰り返す
				var (x, y) = (指定筋 + vx, 指定段 + vy)
				
				while let 筋 = x, let 段 = y {
					let 対象升 = self[筋, 段]
					if 対象升.先後 == 先後 {
						break // 自駒に当たった場合
					}
					else if 対象升.先後 == 敵方 {
						let 位置 = 位置型(筋: 筋, 段: 段)
						位置列.append(位置)
						break
					}
					else {
						let 位置 = 位置型(筋: 筋, 段: 段)
						位置列.append(位置)
					}
				
					(x, y) = (筋 + vx, 段 + vy)
				}
			}
		}
		return 位置列
	}
}
```

### 挑戦的な日本語メソッド名

そのほか挑戦的な名前の日本語メソッドを用意してみました。

```.swift
class 局面型: Equatable, SequenceType {
  //... 
  func 指定位置の駒の移動可能指手列(位置: 位置型) -> [指手型]
  func 指定駒を打つことが可能な指手列(先後: 先手後手型, _ 駒種: 駒種型) -> [指手型]
  func 駒の位置列(駒: 駒種型, 先後: 先手後手型) -> [位置型]
  func 指手を実行(指手: 指手型) throws -> 局面型
  func 全可能指手列() -> [指手型]
  func 成って移動可能か(先後 先後: 先手後手型, 移動前の位置: 位置型, 移動後の位置: 位置型, 移動前の駒面: 駒面型) -> Bool
  func 不成で移動可能か(先後 先後: 先手後手型, 移動前の位置: 位置型, 移動後の位置: 位置型, 移動前の駒面: 駒面型) -> Bool
  func 王手列(手番: 先手後手型) -> [指手型]
  var 詰みか: Bool
  //... 
}
```

### 感想

どうでしょう。違和感はあるものの、思ったほど悪くはないような気もします。

## 将棋盤Kit

という事で 将棋盤Kit というライブラリを公開してみました。[ShogibanKit](https://github.com/codelynx/ShogibanKit) 今回は将棋盤Kitそのものの紹介よりも、日本語プログラミングの記事ですので、より詳細な将棋盤Kitの説明は割愛させていただきます。将棋盤Kit自体に関しては [Qiita の記事](http://qiita.com/codelynx/items/03769792994f11025343)を参考にしてください。


## 将棋盤Kitを実際に日本語で書いてみて…

### 大文字小文字問題

英語ベースでコーディングしている時は無意識（意識的？）に class 名は大文字で始まり、変数等は小文字で始まる名前を使っているかと思いますが、日本語には、ひらがなカタカナはあっても、大文字小文字がないので、タイプ名と変数名を同じ名前で書くとコンパイルエラーとなってしまいます。

```.swift
// OK
class Object {}
var object: Object
```

```.swift
// Error: 型と変数は同じ名前を使えない
class オブジェクト {}
var オブジェクト: オブジェクト
```

そこで、これを回避するために２つの方法を考えました。一つは、タイプ名の後に「型」をつける方法です。これで、タイプ名と変数名の名前空間（？）を分離することがきます。

```.swift
// OK: タイプの名前に「型」をつける
class オブジェクト型 {}
var オブジェクト: オブジェクト型
```

もう一つは、旧来の方法のように、型の頭に「プレフィックス」をつける方法です。これで同様に、タイプ名と変数名の名前空間を分離できます。

```.swift
// OK: 固有のプレフィックスをつける
class MYオブジェクト {}
var オブジェクト: MYオブジェクト
```

### 単数形・複数形問題

日本語には単数形・複数形を区別しない言葉が多いです。例えば英語の「item」の複数形は「items」でも「項目」の複数形を表現するのは難しいし、用語毎に悩むのは精神衛生上好ましくないので、以下のような回避法を考えてみた。

```.swift
   for item in items {
      // ...
   }
```

```.swift
   for 項目 in 項目 { // 項目の複数形って何？
      // ...
   }
```

### 多少の不自然さは残っても、単数・複数を区別できる接尾辞を導入

* `Array` は、「列」を接尾辞に付加する（例：`駒列`）
* `Set` には「群」「集合」を接尾辞に付加する（例：`駒群`）
* `Dictionary` には「表」を接尾辞に付加する（例：`位置駒表`）

### そもそもやっぱり関数名は日本語にそぐわないかもしれない問題

とはいえやっぱり、関数名やメソッドに日本語を使うのは、かなり行き過ぎている間もあります。現状では、全力ではオススメできないかもしれませんが、良い名前の付け方のノウハウが蓄積すれば、積極的に使う日もくるやもしれません。

# その他技術的な問題

## CoreData の制限

CoreData  では entity の名前に日本語は使えません。

<img width="652" alt="Screen Shot 2016-08-30 at 1.31.49 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/65634/79c4941e-0587-066f-27f6-a9341335129c.png">

## Xcodeで日本語名クラスの自動生成する場合

同様に、attribute にも日本語の名前は付けられません。

<img width="677" alt="Screen Shot 2016-08-30 at 1.37.27 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/65634/8e90a1a8-f93b-22d0-3714-7aef8780a2d7.png">

Xcode の `File` > `New` > `File...` から 例えば、`日本語ViewController` のサブクラスを作ろうと思うと、実際のクラス名は文字化けを起こします。しかし、文字化けした所を手動でちゃんと修正すれば問題ありません。

## Storyboard に日本語名を付ける場合

<img width="588" alt="Screen Shot 2016-08-30 at 1.41.19 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/65634/db6e6f56-3463-e63f-741d-6930836d94b7.png">

storyboard では日本語名のストーリボードをそもそも、ロードしてくれません。

<img width="1138" alt="Screen Shot 2016-08-30 at 3.15.54 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/65634/b58724c2-a248-1d93-c314-3ce59e8751cb.png">


# 補足

この記事は、16年8月30日に開催された [iOSDC Reject Conference](http://iosdc-reject-conference.connpass.com/event/37017/) でお話しした内容をベースにしています。

その時のスライドは以下のURLから確認することができます。
https://speakerdeck.com/codelynx/programming-swift-in-japanese

［環境］

```.log
Xcode 7.3.1
Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
```