mong - Dockerのコンテナ名をランダム生成するコードをPythonに移植してみた -

`goofy_grothendieck`, `ecstatic_lederberg`, `quizzical_wu`, ...
Dockerのコンテナのように，ランダムなんだけど読みやすい名前を付けたいことってありますよね？[moby/moby](https://github.com/moby/moby)に[Go言語のコード](https://github.com/moby/moby/blob/master/pkg/namesgenerator/names-generator.go)を見つけたのでPythonに移植して[mong](https://github.com/toshihikoyanase/mong)というライブラリにしてみました．

2019/12/22追記： [続報](https://qiita.com/toshihikoyanase/items/f386f7b81d3cf8c98317)書きました

# 使い方

Python 3.6と3.8で動作確認しています．Python3.5以降なら動くと思いますが，Python2はType Hintingなどが原因で動きません．

標準ライブラリだけしか使っていないので，インストールはすぐ終わるはずです．

```
$ pip install git+https://github.com/toshihikoyanase/mong.git
```

さっそく，ランダムに名前を生成してみましょう．

(2019/12/22修正： インスタンス化する方法から関数呼び出しに変更しました)

```python
import mong
mong.get_random_name()  # 'goofy_robinson'
mong.get_random_name()  # 'stoic_feynman'
```

Google ColabにJupyter Notebookを用意しました．以下からすぐに試せます：
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/16iw3njq06R32-0dHiRn2efUvvZmYHeRL)

# 実装方針

[オリジナルのコード](https://github.com/moby/moby/blob/master/pkg/namesgenerator/names-generator.go)を見ると名前の元となる単語の辞書がその大半をしめていました．移植先のコードに辞書をべた書きすると，メンテナンスが大変そうなので，オリジナルのコードから抽出する方法を選びました．

具体的には下記のとおりです．
- `mong/create_dict.py` でオリジナルのコードから名前のもととなる単語の辞書を抽出しています．
- `mong/moby_dict.json` に抽出した辞書を保存しています．
- `mong/name_generator.py` の `NameGenerator` に名前生成ロジックを移植しています．


# オリジナル(moby)の実装

[Dockerの名前生成コード](https://github.com/moby/moby/blob/master/pkg/namesgenerator/names-generator.go
)は [moby/moby](https://github.com/moby/moby) にあって，Go言語で書かれています．なお，mobyはコンテナシステムのためのツール集のようです．[こちらのスライド](https://www.slideshare.net/zembutsu/5-minuts-docker-2017/31-31MobyDockerMoby_Project)に簡潔にまとめられています．

名前は２つの語からなっていて，形容詞と有名な科学者とハッカーの人名です．それらが `_` でつながれています．

例

```python
# 怒った（形容詞）_チューリング（人名）
angry_turing
```

形容詞は`left`，人名は`right`というリストで管理されています．


```go
	left = [...]string{
		"admiring",
		"adoring",
		"affectionate",
		"agitated",
```

```go
	right = [...]string{
		// Muhammad ibn Jābir al-Ḥarrānī al-Battānī was a founding father of astronomy. https://en.wikipedia.org/wiki/Mu%E1%B8%A5ammad_ibn_J%C4%81bir_al-%E1%B8%A4arr%C4%81n%C4%AB_al-Batt%C4%81n%C4%AB
		"albattani",

		// Frances E. Allen, became the first female IBM Fellow in 1989. In 2006, she became the first female recipient of the ACM's Turing Award. https://en.wikipedia.org/wiki/Frances_E._Allen
		"allen",

```

名前の生成処理は，基本的にランダムに選択して，つなぐだけです．

```go
// GetRandomName generates a random name from the list of adjectives and surnames in this package
// formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random
// integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3`
func GetRandomName(retry int) string {
begin:
	name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
	if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
		goto begin
	}

	if retry > 0 {
		name = fmt.Sprintf("%s%d", name, rand.Intn(10))
	}
	return name
}
```

[このQiita記事](https://qiita.com/takuyakawaguchi/items/11dfac46f626b4d399f7)にもあるように， `boring_wozniak` は生成されないようになっています．（出たらもう一度作り直しています．）

2019年12月21日時点で， `left`は108語， `right`は235語あったので合わせて25,379種類の名前が生成できます．意外と少ないような気がしますね．

なお，`retry` 引数についてはよくわかっていなくて，処理を見ても`retry`しているように見えません．`retry>0`だと `0`　以上 `9` 以下の整数をランダムに選んで名前の末尾につけています．これは使う側のコードを読まないとわからないかもしれません．単純に１桁種類数を増やすためかな？

# まとめと今後の課題

PythonでDockerコンテナ風のランダム名を生成できる [mong](https://github.com/toshihikoyanase/mong) というライブラリを作ってみました．

一応，動くところまでは書いたのですが，テストカバレッジが低かったり，エラー処理を省いていたり，CIをしていないなどいろいろ改善の余地はあります．また，pypiに登録していないので，インストールがやや面倒です．

（自分も含めて）ニーズがあればもう少し整えようかなと思っています．


# 参考文献

- [moby/moby](https://github.com/moby/moby)
- [Dockerをnameオプション無しで起動してもウォズニアックは決して退屈にならなかった](https://qiita.com/takuyakawaguchi/items/11dfac46f626b4d399f7)
- [Docker / Go言語 — docker コンテナに自動付与されるデフォルト名を直接生成してみる](https://qiita.com/YumaInaura/items/74ca6f0896bd073dc026)