個人で小規模な書籍自炊システムを作った、振り返りながらシステム開発の勘どころをまとめる。#4実装編

# 概要
この度、自分だけで使う小規模な書籍自炊システムを作った。
振り返ってみると**業務でのシステム開発**に通じる要素がちらほらあった。
初心者や未経験者、大学生など、システム開発に関してまだそれほど明るくない方に向けて勘どころをまとめる。
また、顧客向けサービスや社内システム、受託開発、自社開発などを区別せず広い意味で**システム開発**を取り上げる。
IT関連の仕事に興味があるががなんとなく実態が掴めない、具体的な業務内容がピンとこない、という方が解像度を上げる助けになれば幸いである。

# 目次
[導入](https://qiita.com/kettle/items/056ab3728f9f4db51dc3)
[要件定義](https://qiita.com/kettle/items/dc4603795457cbe4dc12)
[設計](https://qiita.com/kettle/items/49a38558cf4a645f7659)
[実装](#)(この記事)

# 実装
前回の設計の記事でプロトタイピングを進めるうち、次の課題が見つかった。
> このプロトタイプで見つかった課題が次の3つである。
> 1. 画像ファイルの大容量化による処理速度の低下(トレードオフ)
> 2. スキャン作業中に端末が長時間拘束される
> 3. カメラで撮影された画像が横向きのため`vFlat scan`でも横向きにインポートされる
> 
> このうち1, 2はより性能の高いiPadを採用することで解決した(スキャン4)。
> また、3はiOS等に搭載されている`ショートカット`でスクリプトを組んで画像を自動回転することにした、これに関しては次の実装の記事で触れることにする。

課題3についてはカメラの設定や`vFlat scan`の機能で解消できないため、この実装工程で新しくプログラムを書いて解消するものとする。
このような**2つの要素を仲介するためのプログラム**というのは実際の現場でもよく発生する。
例えば**DBのレコードを取得して呼び出し元に返す**というのも同じことである。
多くの場合、DBのレコードを取得してもそのままでは次の処理に渡すことはできない。
次の処理で受け付けているのが`.csv`であればその形式に合わせる必要があるし、`.json`であっても同様である。
今回の実装では**横向きの画像を縦向きにして`vFlat scan`で処理できるようにする**というのが目的である。

:::note info
**プログラム**
世の中には「プログラム」という言葉の他に**アプリケーション**や**ソフトウェア**などなど似たような言葉がある、これらはどのような関係性があるのか。
誰かが厳密に決めているわけではないが、感覚的に以下のような大小関係がある。
`ソフトウェア > アプリケーション > プログラム`

また、より広くプログラムに関わる言葉を含めると以下のようになる。
`ソフトウェア > アプリケーション > フレームワーク > ライブラリ > モジュール > プログラム > コード`
プログラミングの最中によく見るのはフレームワークから下の部分だろう。
多くのプロジェクトでは、アプリケーションとフレームワークの間の領域でプログラムを書くことになる。
PGはプログラムを書いてアプリケーションを作る仕事、SEは設計をしてアプリケーションを作る仕事、PMはアプリケーションの制作進行をする仕事ということも出来る。
:::

## どのような設計か
前回の記事も設計について触れたが、ここではもう少し細かい設計に触れる。
前回はどちらかというと**基本設計**よりの内容だったが、より実装に近い設計を**詳細設計**と呼ぶ。
この記事で実装するプログラムは次のような設計になる。
- 次の処理をループする。
    1. 写真ライブラリの指定のアルバムから画像を1件取得する。
        - デジタル一眼カメラで転送された画像がiOSの写真ライブラリ > アルバムに保存される。
        - 転送された画像が保存されたアルバムをプログラム内で指定する。
    2. 角度を指定して写真を回転する。
        - 角度はプログラム呼び出し時に指定する、すべてのループで同じ角度を使用する。
    3. 回転した画像を写真ライブラリの別のアルバムに保存する。
        - 元の画像とは別のアルバムをプログラム内で指定する。
    4. 元の画像を削除する。

ここまでくると実装するプログラムの全体像が見えてくる。
あとはこの設計に沿って何らかのプログラミング言語で実装を進めればよい。
今回はiPad上ですべての処理を行いたいので`ショートカット`を使って実装していく。

# コーディング
先に出来上がったプログラムを載せることにする。
便宜上、iOSのアプリ名を`ショートカット`、1つひとつのショートカットを`プログラム`と呼称する。
`ショートカット`では無限ループが出来ないなどいくつかの制約があるため結果的に2つのプログラムを作成した。
![ショートカット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874887/e8a9292b-db06-5955-cf7e-54b84290a7f7.png)
**テザー撮影を自動回転**が呼び出し用プログラムで、ここで回転角度を指定する。
**自動回転ループ**がメイン処理であり、擬似的に無限ループを行って写真ライブラリの監視や画像の取得、回転などを行っている。

## python風にすると……
これらのプログラムを"python風"にすると次のようになる。
`ショートカット`とpythonはまったく違うもののため内容は大嘘だが、イメージとしてはこんな感じである。
```py
# テザー撮影を自動回転
def start_tether_auto_rotate():
    # クイックアクションから入力を受け取る
    input_str = ''
    while input_str not in ['left', 'right']:
        input_str =  input('左に回転 > left, 右に回転 > right: ')

    rotation_dict = {}
    if input_str == 'left':
        # 左に回転
        rotation_dict = {'rotation_angle': 270}
    elif input_str == 'right':
        # 右に回転
        rotation_dict = {'rotation_angle': 90}
    
    # 自動回転ループ を実行
    auto_rotate(rotation_dict)
```

```py
# 自動回転ループ
def auto_rotate(input_dict: dict):
    # 変数 回転角 を 値 に設定
    rotation_angle = input_dict.get('rotation_dict', None)
    if rotation_angle is None:
        return

    # 次に当てはまる すべての写真 を検索
    images = list(get_images({
        'album': 'CA_IMAGES',
        'sort_by': 'create_date',
        'sort': 'desc',
        'limit': 1
    }))

    if len(images) == 0:
        # 写真 値がない の場合
        # 60秒 待機
        sleep(60)
    else:
        # その他の場合
        original_image = images[0]
        # 写真 を 回転角 度回転
        rotated_image = rotate_image(original_image, rotation_angle)
        # 回転済みの画像/ビデオ を FOR_OCR に保存
        saved_image = save_image(rotated_image, 'FOR_OCR')
        # 写真 を削除
        deleted_image = delete_image(original_image)
        # 通知 保存済みの写真メディア を表示
        print(saved_image)

    # 自動回転ループ を実行
    auto_rotate(input_dict)
```
`ショートカット`はいわゆるノーコードツールなのに対して、pythonは一般的なプログラミング言語である。
当たり前だが、どんなノーコードツールも内部では何らかのプログラムが実行されている。
プログラミングの`雰囲気`が伝われば良いなと思って上記のコードを書いた。
このpythonコードは全く実務的でないが、次のようなプログラミング要素を盛り込んでいる。
- 変数定義
- データ型(文字列、数値、辞書型)
- ifによる分岐
- 繰り返し処理(今回はwhileループ)
- ログ出力
- ユーザー入力の取得
- ファイルの入出力
- 何もせずに処理を待機する
- 再帰関数

上から順に初心者向けの要素で、下に行くほど難しかったり利用頻度が少なかったりする。
変数定義～ログ出力まではどんな開発でも必ず使う要素で、それより下は場合によって使うことがある。
また、このpythonコードにはエラー処理がないため、そこも実務的なコードと異なる点である。

最後の**再帰関数**というのは「**その関数の中で自分自身を呼び出す関数**」を指す言葉で、使い方によってループと同等の処理ができる。
上記のコードでは`auto_rotate`関数の最後でもう1度`auto_rotate`関数を呼び出している。
`ショートカット`が無限ループできないという制約を回避するためにこのようにした。

## 初心者は何を勉強すればよいか
初心者は何を重点的に学ぶべきか？
個人的な意見だがデータ型を注意深く学ぶのが良いと考える。

if文やループはもちろん大切だが、これはもはやプログラミングの大前提といえる要素でわざわざ深堀りするほどでもない。
これを避けて通ることはできないため嫌でも覚えてしまう。
プログラミングを始めて数日から1週間程度でさらっと習得してしまうのがよい。

対してデータ型はどうか。
こちらはわざわざ意識して考えなくてもプログラムが書けてしまう、逆に言えばデータ型は**落とし穴になりやすい**のである。
仮に`'1' + 1`(文字列+数値)というコードを書いてもエラーが出ない言語さえある。
このような文字列と数値程度であれば簡単だが、他にも配列やオブジェクト(json、辞書)などプログラムには様々な型がある。
型というのは自分でも作れるので、ライブラリやプロジェクト固有の型も含めると数え切れないほどの型が存在する。

型は**そのオブジェクトに何が含まれているか**、**そのオブジェクトがどんな性質を持っているか**を示す役割もある。
慣れてくると始めて触れるライブラリでも型を見ながらコーディングが出来るためかなり作業効率が上がるだろう。

## 型を勉強すると何が嬉しいか
先にも書いたように型には次の役割がある。
- そのオブジェクトに何が含まれているかを示す
- そのオブジェクトがどんな性質を持っているかを示す

一見するとこれらにどんな嬉しい要素があるか分かりづらいが、具体的には次のようなことに繋がる。
例えばpythonにはHTTPリクエストを取り扱う`requests`というライブラリがある。
`VSCode`(コードエディタ)で作業していると、型情報がこの`requests`ライブラリについて次のことを教えてくれる。
![ポップアップ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874887/b63a17d9-2e10-83db-acc5-ea1d4617c6d5.png)
- `request`関数は引数として`method`や`url`を`str`または`bytes`型として受け取る。
- そのほか`header`や`auth`などの詳細なリクエスト制御に関わる引数を受け取る。
- `Response`型のオブジェクトを返却する。


また、返却された`Response`型は`res`変数に代入されて`res`から**何を取り出せるか**、**何が出来るか**を教えてくれる。
![ポップアップ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874887/c74da524-03cc-fdbf-0622-3a17cd0c77df.png)

ときには「`Response`型はそんな属性を持ってない」とも教えてくれる。
![ポップアップ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874887/c26de9b3-fbf2-a437-a71b-dbd7728111ed.png)

このような内容はすべて**型情報が開発者に教えてくれる**ものであり、それを理解できれば作業効率が劇的に向上する。
もしも型を勉強せずにこれらのポップアップの意味が分からなければ、新しいライブラリを触るたびにウェブなどで資料を探すことになるだろう。

## ライブラリとはどんなものか
ライブラリとは**よく使う処理をひとまとめにしたもの**である。
例えば先ほどの`requests`ライブラリはHTTPメソッドやURLを指定するほか、より細かい制御もできるように作られていた。
これらを自分で一から作るとなるとかなり大変である、GETリクエストを作るだけでも何行のコードになるか想像がつかない。
実際の業務ではいくつものライブラリを使って処理を書いていくことになる。

実をいうと世の中のプログラマはそれほど難しいコードを書いていない。
主要な処理はライブラリに任せて、自分の力で書くのはifやループなど初心者でも分かるコードがほとんどである。
（もちろん難しい処理を自分で書くプログラマもいる、彼らはいわゆるつよつよプログラマである）

## ライブラリを使うと何が嬉しいか
多くの場合、自分でコードを書くよりもライブラリを使うことが推奨される。なぜか。
自分が書いたコードは他の人も読むのである。
コードの読みやすさというのは書いた人によって非常にバラつきがある。
自分で難しい処理を書いてしまうと他の人が読めない可能性があるのだ。
実は簡単な処理でも読み手には（なんか変なことやってるな、何の処理だろう？）と意図が伝わらないことがある。
対面して説明できれば良いのだが**書いた人が既にいない**というのはよくある話だ。
また、先週の自分が書いた内容が理解できないことすらある、時間が経てば自分ですら他人なのだ。

それに対してライブラリはバージョンが同じであれば必ず同じ振る舞いをする、コードのバラつきも少なくできる。
先に出した`request`で言えば`request('GET', url)`は誰が書いても`request('GET', url)`なのだ。

# まとめ
今回の記事では実装工程をまとめた。
書籍自炊システムとしてコーディングをしたわけではないが、似た要素としてiosの`ショートカット`でプログラムを作成した。
また、pythonで書いたら……という例を挙げてプログラミング的な要素を解説した。
この記事を一旦の終わりとして、気が向いたら運用に関する内容や書籍自炊システムのアップデートなど続きの記事を書こうと思う。