フォルダの構成や、命名規則のベストプラクティス

https://qiita.com/EasyCording/items/531ef712926b2419e494

# 昨日のハマり事

* 機械学習アプリをJupyterで開発していて、そろそろパッケージングを考えようとしている。
* しかしながら、フォルダの構成や、命名規則のベストプラクティスが見つからない。

# フォルダ構成
* 登場すべきメンバーは、だいたい分かってきた。
* 機能としてはForexが前処理で、Resultが後処理になっている。
* 機械学習のコアは除いている。

# 命名規則
元々のファイルは以下の状態であった。

```
├─crud.py
├─model.py
├─router.py
├─schema.py
```

* 今回、ソースが大きくなってきたこともあり、次のような命名規則にしている。
* フォルダ名を機能で分割し、ファイル名には```名前_機能.py```という規則にしている。

```
├─cruds
│  │  forex_crud.py
│  │  result_crud.py
├─models
│  │  forex_model.py
│  │  result_model.py
├─routers
│  │  forex_router.py
│  │  result_router.py
├─schemas
│  │  forex_schema.py
│  │  result_schema.py
```        
# 考え方
* 言うなれば、子供が成長して親になり、さらに家族ができたので名前を付けたイメージだ。
* ここで外国なら名→姓の順、日本の場合は姓→名の順

外国式） Michael Jackson  　　　ジャクソン家のマイケル君
日本式） 田中_一郎　　　　　　田中家の一郎君

* modelに属するforexの場合は、なんとなくではあるが、外国式の方がピンと来る

外国式）forex_model.py   　　　〇（modelに属するforex）
日本式）model_forex.py　　　        ×

* フォルダ名は単数形ではなくで、複数形とする
　Jackson　×　→　jacksons　〇
　model　×　→　models　〇

# アンチパターン
* 以下のようにも書けるが、これはやめた方がいい
→　ファイル名が被ると、エディタの置換機能で誤変換される可能性もあるし、人が見ても混乱する。
* 家族で呼び合うなら、それでも良いが、家の外に出た瞬間に、名前が同じ子供がいたら、どこの子やねん？てなるイメージ
```
├─cruds
│  │  forex.py
│  │  result.py
├─models
│  │  forex.py
│  │  result.py
├─routers
│  │  forex.py
│  │  result.py
├─schemas
│  │  forex.py
│  │  Result.py
```   

# ファイル内の命名規則
ここから先はファイル内の話であるが、先ほどとは少し事情が変わってくる。
* そもそも家族の中に、同じ名前を付けるバカはいない　→　親が呼ぶときに困る。呼ばれた子供もさあ大変！
* 家族が増えたら、だんだんと命名するのが面倒　→　一郎、二郎、三郎など、昔はそういう時代もあった。
* キラキラネームにしない　→　外に出たら馬鹿にされるし、その子が成長したときに、名前を受け継ぎたくなくなる。

上記と同じように、フォルダ内でもファイル名はちゃんと考えてあげる必要がある。
→　しかし、先ほどの例とは異なり、家族名は省略することができる。

C#では、`namespace`的なものがあるが、pythonではどうなんだろうか？

# ベストプラクティス

以下のように書くと、すっきりすることが分かった。

STEP1) インポートをフロムに変更　　               　import models　→　from　models 
STEP2) フォルダの中のファイル名をインポートにする　　→　import result_model
STEP3) 機能名のみになるようにリネームする　　　                    →　as models


```crud/result_crud.py
from models import result_model as models
from schemas import result_schema as schemas

def select_result_all(db: Session) -> List[schemas.Result]:
    return db.query(models.Result).all()
```
ここでは、あえて次の命名規則も追加する。
* クラス名は、先頭を大文字にする。
schemas.result　→　×　　　　schemas.Result →　〇　
→　なんとなくであるが、大文字にした方が、そちらの方に注目が集まるから


```models/result_model.py
class Result():
```
```schemas/result_schema.py
class Result():
```

# 考察
　特にFastApiを使っていると、スケマでバリデーションして、モデルでクエリを呼ぶとか、とにかく頭の中がこんがらがってくる。

　ひとまず、今回の命名規則は、下記の結論に落ち着いた。

* ファイル内の命名規則　　schemas.Result　→　jacksons.Michael
* ファイル名の命名規則　　result_schema　→　michael_jackson


# 別案
　さらに簡略化を考えると、次のような書き方も有効かもしれない。
* テンプレート的に使える
* コードの複製に便利

　コピペで使うには便利であるが、その理由も理解して使わないと、あとで大変なことになることが想像できる。
→　初級者の嫌がらせには便利かもしれない。　


```cruds/result_crud.py
from models.result_model import Result as model
from schemas.result_schema import Result as schema

def select_result_all(db: Session) -> List[schema]:
    return db.query(model).all()
```

# 最後に
* Pythonを長く触ってきたが、Fastapiを触りだして、こんなにも命名規則が大事だとは気づかなった。
→　そして最後に、コーディングのルールが書いてあるサイトを発見した。


https://pep8-ja.readthedocs.io/ja/latest/#section-20

* クラス名の頭を、大文字にする部分は、なんとなくやっていたのであるが、正式に推奨されていて妙に納得させられた。
（やはり、マニュアルと言うものは、ちゃんと読んだ方が良いなと思う）

### 抜粋

>パッケージとモジュールの名前
モジュールの名前は、全て小文字の短い名前にすべきです。読みやすくなるなら、アンダースコアをモジュール名に使っても構いません。Python のパッケージ名は、全て小文字の短い名前を使うべきですが、アンダースコアを使うのは推奨されません。

>C や C++ で書かれた Python の拡張モジュールに、高レベルの (例：オブジェクト指向的な) インターフェイスを提供する Python モジュールが付いている場合は C/C++ のモジュールはアンダースコアで始まります (例： _socket)

>クラスの名前
クラスの名前には通常 CapWords 方式を使うべきです。

>主に callable として使われる、ドキュメント化されたインターフェイスの場合は、クラスではなく関数向けの命名規約を使っても構いません。

>Python にビルドインされている名前には別の規約があることに注意してください： ビルトインされている名前のほとんどは、単一の単語(または、二つの単語が混ざったもの) ですが、例外的に CapWords 方式が使われている名前や定数も存在しています。