pythonモジュールの完成度を高める

役に立つ（と思っている）自作Pythonモジュールがある。
それが、業務で必ず使うモジュールだったり、再利用する頻度が高いなら、モジュールの完成度を高めていこう。

# 目的は１つだけにする。
業務の中で、一連のタスクを解決するために、リポジトリを作りながらタスクを解決していく。
そういう状況で、タスクを解決していくなかでツールをたくさん作ることになる。
### 生じがちな状況
- 一連のタスクを解決するために、開発したツールが複数そのリポジトリに含まれてしまう。
- そのため、そのリポジトリが何のためのツールであって、どういう場合に再利用ができるのかが、極めてわかりにくくなる。
- そのため、再利用されなくなってしまう。
- 再利用しようとしても、余分なものがあるので、理解が困難になってしまう。
- リポジトリの仕様が確定しないので、再利用する範囲とは関係ない部分でバグを含めてしまう。
- それだけで、そのリポジトリの実装が枯れたもの（＝安定したもの）にならなくなってしまう。

### だから主張すること
- リポジトリの目的はひとつだけにする。

### 書く必要があるコードを書こう
- [ ] 再利用する価値があるか。
    - [ ] 他の人も使いたいと思うか。
- [ ] 既存のOSSで代替できないか。
    - [ ] 独自ライブラリとするよりは、既存のOSSに追加したほうがよくないか。
    既存のOSSの実装の方は有効であるならば、自分の努力は、いいものをよりよくする方向に向けたほうがいい。
    独自実装は、自分の勉強と割り切る。
- [ ] 使う目的は明確に、単一の役割を上手にこなすだけのことを考える。
    - [ ] 別の目的がでてきたら、それは別モジュールにしよう。
    余計な機能をつけると、無駄な作業が発生して、手離れが悪くなる。
- [ ] サポートする環境は明確になっているか
    - OS,　CPUの種類
    - 言語のバージョン
    - ライブラリのバージョン    
実行したい内容が明確であれば、手離れも楽になる。

### README.md
- [ ] README.md は簡潔に    
１行での要約を書く。
何ができるのかのデモを書く
必要に応じて図やグラフ・画像を加える。
実行環境の条件を書く
インストール手順を書く
    pythonモジュールのインストールが必要なものはpyproject.toml に書く。


- [ ] 世界に向けて発信するコードならば、ASCIIの文字コードにする。日本語を含めない。

```
grep -P '[\p{Hiragana}\p{Katakana}\p{Han}]' -r path_to_your_repository
```

  最初は日本語でいいから、わかりやすく書く。
  有用なソフトウェアのgithubをまねて章立てを書く。
  それを英語に直すには、機械翻訳で簡単だ。
- [ ] 次の依存性が、READMEなどでわかること
    - 特定のデバイスが必要である場合
    　例：特定のカメラ（3Dカメラ）
    - 商品として購入する必要のあるライブラリを利用している場合　
- [ ] 何の目的のソフトウェアかわかるような画像をREADME.md の表示に追加する。
- [ ] スクリプト、コマンドの使い方は`-h` オプションで表示されるか。 
- [ ] 最低限の実行をするために必要なサンプルデータを用意しておく。

### pyproject.toml
- [ ] pyproject.toml を書いてあるか
　　従来のrequirement.txt や、Dockerfile中のpip install の記述は減らせる。
   開発時にだけinstallすれば十分なものはproject.toml ファイル中に記述してあるか
   pyproject.tom: [project.optional-dependencies]に記載しているか。
- [ ] 整形ツールをpyroject.toml に記載したか
    - [ ] 1行の文字数を記載しよう。
    例:
```pyproject.toml:
[tool.black]
line-length = 120
```
- [ ] lintツールのpyroject.toml に記載したか
    - [ ] lint系ツールで確認できる内容    
    - [ ] 無駄なimport削除したか。
    - [ ] PEP8 [命名規則](https://pep8-ja.readthedocs.io/ja/latest/#id25)に従った命名になっているか
    - [ ] 非公開にすべきデータ、メソッドは、"_"で始めてあるか
    - [ ] type hintを書いてあるか

- [ ] 主旨の違いに応じてモジュールファイルを別にする。
- [ ] 開発時にだけ必要なものは、分離しやすいフォルダ構成に。
### Makefile
- [ ] `make test` でpytestが実行するようにMakefileなどを書いてあるか
- [ ] `make reformat` で自作部分のpython ファイルの書式をblack などで記述をそろえられるように書いてあるか

- [ ] whl ファイルを作る手順 を追加する。

```
apt install -y python3.8-venv
python3 -m venv venv
. venv/bin/activate
python3 -m pip install build
python3 -m build
```	
	
### python モジュール
- [ ] どのディレクトリで実行しても、必要なデータファイルにアクセスできる。

- [ ] 標準出力へのprintを減らす（なくす）
    表示を見やすくしたい
    - [ ] 進行状況を示すにはtqdmを使うといいね
     [グレートなtqdmの使い方](https://qiita.com/SeeLog/items/73c054a37722890b17a2)

    - [ ] loggingを使う。
    どうしても必要なものはloggingを使って、モジュールからのログ、もしくは、プログラムからのログとして出力させる。
logger.error()
logger.warning()
logger.info()
などを使い分けよう。
不具合や、不具合の予兆がライブラリのどこで生じているのかがわかるようになるのがいい。
    [logging --- Python 用のログ記録手段](https://docs.python.org/ja/3/library/logging.html)


    - [ ] journalctlでログを見れるようになっていることを確認する。
`journalctl -u [サービス名]`
で実行すると[サービス名]　分だけのlogが表示される。
これを使うと、目的のサービスが、どういう具合に推移したのかが、logに吐き出された内容を元に確認できる。他の出力と混在しないし、コンソールの彼方に消え去ることもない
- [ ] 出力ファイルを一般的なデータ形式にする。
　例：独自テキストファイルよりはJsonファイル。
 　例：独自バイナリデータよりは、npyファイル。
- 例外処理
    - [ ] 発生した例外の種類を区別するように必要な例外処理を書く。
    - [ ] ^C(コントロール＋C)以外での終了方法を用意する。
    - [ ] file のopenにwith 文を使う。
    スコープの外にきた時に終了処理が実行されるようになります。
    例：次のように書いても自動でclose()されます。
```
with open("outfile.txt", "wt") as f:
    f.write("message\n")
```
- [ ] 公開するインタフェースを最小限にできているか
    - [ ] 使ってほしくない部分はprivate化してあるか
    - C++だったら、private変数, private メソッド化しておく。
    - Pythonなら、pythonなりのprivate化をしておく(="_"アンダースコアで始まる識別子にする）。
    - 公開するインタフェースでの仕様の破壊的な変更は避けること。


### test
- 自動化テストに成功しているかぎり、実装が壊れていないことがわかるようにする。
- テストされる関数のコードを示して、それをテストするコードをChatGPTなどに生成させることができる。
[PythonのテストをChatGPTに書いてもらう](https://zenn.dev/karaage0703/articles/d52b4cdca3b896)


### バージョン番号
- [ ] モジュールのバージョン番号を定義する。
- [ ] importしたモジュールでバージョン番号がわかるようにする。
- [ ] whl　などのパッケージのファイル名にバージョン番号が含まれていることを確認する。

### LICENSE
- 利用者が困らないLICENSEを選択するのがいい。
- public のリポジトリになっているのに、LICENSEの記述がないと利用に困る。


### 利用者がやりがちな失敗の可能性があったら、対策をとっておこう。
##### 例：3 channelの画像を想定しているのに、4 channel の画像が入ってきたとき
選択肢 1: assertで終了させる。
`asssert image.shape[2] == 3`
選択肢 2: error ログを記録する.
```
if image.shape[2] != 3:
    logger.error('invalid image.shape[2]: expected = 3 ')
```
選択肢 3:Exceptionを発生させる。
```
if image.shape[2] != 3:
    raise ValueError("image channel must be 3.")
```
選択肢 4: 何もしない
ほんとうにトラブルが発生する場所まで、先送りする。

### データのダウンロード
選択肢１：
	データをダウンロードする手順を、README.md に明確に書く。
選択肢２：
	データをダウンロードする必要を生じたら、自動で取得させる。
- 学習済みのモデルのように大きすぎるものをgithub におかない。
- Google Driveでも、自分のアカウントがなくなったら、削除されてしまうような場所を避ける。
- 十分に有用なものは、huggingfaceに登録する。

### 別環境でのダウンロード・実行を確認する。
- 自分の環境では動作するのに、他の人の環境では動作しないということが起きるかもしれない。
- 例：必要なデータファイルがパッケージに含まれてなく、しかもネットワークからダウンロードする方法が記されていない。
- 例: apt install　しなくちゃならないパッケージの情報が不足している。

## whl ファイルをpypiに登録しよう
- [はじめてPyPIにPythonライブラリを登録した話](https://zenn.dev/sikkim/articles/490f4043230b5a)
- [作ったパッケージを公開してみた](https://qiita.com/nonbiri15/items/4689a03438c40342ac2e)
- [PyPiのテスト環境へのアップロードするまでの作業の備忘録](https://qiita.com/nonbiri15/items/a6e4e5e43a3230566a32)
- [PyPIに登録した内容を検証する　pip install ${自作パッケージ} の確認](https://qiita.com/nonbiri15/items/5352f65e8f99a72ecab9)


## コミュニティーにアナウンスする
- このモジュールを使いたいと思う人がいそうなところで、そのモジュールを作ったことをアナウンスする。

## ドキュメントーションの作成

- [Sphinxの使い方．docstringを読み込んで仕様書を生成](https://qiita.com/futakuchi0117/items/4d3997c1ca1323259844)
- [Sphinx の使い方](https://zenn.dev/y_mrok/books/sphinx-no-tsukaikata)
- [【Ubuntu 22.04】Sphinxの文書生成を1からめちゃくちゃ丁寧にやる](https://qiita.com/Nenshu_agetai/items/3dc7b2d7717e7bb07c47)

------------------
- [【2023年1月版】 journalctl 覚えておきたい使い方メモ](https://qiita.com/nouernet/items/c60ff2621385f4d8f7b6)
- [pprint --- データの整形表示](https://docs.python.org/ja/3/library/pprint.html)
- [journalctl 最低限覚えておくコマンド](https://qiita.com/aosho235/items/9fbff75e9cccf351345c)
- [PyPIパッケージ公開手順](https://qiita.com/shinichi-takii/items/e90dcf7550ef13b047b5)
 setup.py setup.cfg 時代の書き方での説明です。pyproject.toml 時代にあわせて、適宜読み替えるのが必要でしょう。 
- [git tag と GitHub の Release 機能でプロっぽさを出してみよう](https://qiita.com/tommy_aka_jps/items/5b39e4b27364c759aa53)
- [リーダブルコード - 良いコードを書くためのシンプルで実践的なテクニック」](https://www.oreilly.co.jp/books/9784873115658/)

- Python Packaging User Guide [How to modernize a setup.py based project?](https://packaging.python.org/en/latest/guides/modernize-setup-py-project/)

- [手離れの良い「放ったらかしシステム」を作るエンジニアリングについての話](https://blog.myntinc.com/2021/12/blog-post_13.html)