いち早く図書館で新刊を借りたいので、入荷と同時にLINEで猫に通知させてみた

この記事は[身の回りの困りごとを楽しく解決！ by Works Human Intelligence Advent Calendar 2022](https://qiita.com/advent-calendar/2022/works-hi-1)の24日目の記事です。
（朝にカレンダーが空いていることに気づき、勢いで書いちゃいました）

# お詫び
タイトルに猫っていれたら、読む人増えるかなと思い入れちゃってますが、実態は、LINEのアカウント画像に著作権フリーの猫(イラスト)を使っているだけです。

# はじめに
みなさん、読みたい本は全て買っていますか？

僕は特に気になった、もしくは気になった本以外買ってません。でも、ちょっと読んでみたいなーと思う本はあります。そういうときはいつも図書館で本を借りるようにしています。

でも、図書館で新刊をいち早く読もうとすると、そもそも蔵書していなかったり、人気で他の人の予約で埋まってしまっていたり、なんかよくわからんけど検索にすら引っかからない、といろんな壁を乗り越えなければいけません。

その壁を **LINE × LIFF** で乗り越えてみました。

# 解決前と解決後
### Before
- 手間がかかる
    - 読みたい新刊あったら、逐一図書館ホームページにアクセスしてた
- 時間がかかる
    - いち早く読むためには毎日状況を逐一みなければいけなかった
    - なかなか引っかからないと、当然検索の優先順位は落ちて、次第に忘れてしまうことに。。
- 検索に引っかからない
    - 検索システムの問題かはわからないが、なんか読みたい本のタイトルを入力しても、そもそも検索に引っかからない

### After
- 待つだけ
    - 読みたい新刊あったら、自作のLIFFアプリに登録して、最寄りの図書館システムに入荷したかどうかを待つだけ
- それなりに確率高く新刊を早いタイミングで読める
    - 自分しかステータス変わったタイミングがわからないので、高確率で上の順位で予約ができる
- 検索に引っかかる
    - 世の中に公開されているAPIを使えば、なんでか検索に引っかからない、と言う事象自体は回避


# どうやって？

冒頭にある通り、 **LINEとLIFF** を使いました！！！

通知先はLINEにして、読みたい本や近くの図書館の登録は、LIFFを使ってアプリを作ることとしました。LINEには、毎日朝9時に読みたい本と図書館の登録状況をもとに、蔵書状況を問い合わせて、予約できる状態だったら通知するようにしました。
LINE、LIFF含むアプリの技術選定は以下のとおりです。（フレームワークや言語などごちゃごちゃに書きます :bow: ）

| 技術 | 用途 |
|:-:|:-:|
| React | フロントエンドのフレームワークとして利用 |
| TypeScript | React、Node.jsでアプリ作る際の言語として利用 |
| Node.js | バックエンド(API)の構築に利用 |
| LIFF | 主に認証用に利用 |
| LINE messaging API | 通知に利用 |
| LIFF Mock | ローカル開発に利用 |
| netlify | Hostingに利用 |
| Firestore | Databaseに利用 |
| Cloud Functions for Firebase | バックエンド(API, Pub/Sub)のデプロイ先に利用 |
| Cloud Tasks | 分散処理用のタスクキューとして利用 |
| Chakura UI | コンポーネントライブラリに利用 |
| Jest | テストに利用 |
| Storybook | UI作成時に利用 |
| GitHub Actions | CIに利用 |
| カーリルAPI | 図書館の蔵書状況を確認するために利用 |
| Google Books APIs | 書籍検索に利用 |

# アプリを作る前に考えたこと
## 無駄に時間かけて、まだ触れたことない技術を触ろう
実現方法を考えたときに、LINE messaging API、スプレッドシート、GASを使えば、すぐできそうでした。でもそれで作っちゃうと、なんだか自分が面白くありませんし、操作上のインターフェースが分離してなんだか気持ち悪いです。
LIFFちょっと流行ってるし、LIFFで管理画面作ってみよう！と言うことで本・図書館の管理アプリを開発しました。

## 一人だけに刺さるアプリを作ろう
大勢をターゲットにするより、一人をターゲットにして作った方がウケる、と聞いたことがあります。
なので、今回はもうとにかく自分のために自分のために、と考え機能や開発環境を作りました。 ~~自己中ですね。~~

# 完成イメージ
猫が通知してくれたり
![D77E6F15-FD46-4895-BFC7-FC3C7C5CAEAD.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/33405330-e750-f9c0-ab45-cab9052df64b.jpeg)



登録した借りたい本の一覧画面(ここから自分がよく使う図書館に問い合わせできたりもする)だったり
![AC309552-0CBA-4D88-896E-FBCA60F590CB.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/3f7d2ab3-8129-28ff-1f3b-e31a81a34c18.jpeg)

複数の条件で検索できたり
![7FE6370D-C4A8-4FE6-AB42-16A54AFAE7E8.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/1d64bf96-9a83-4d84-d0d9-0e734ddcafd8.jpeg)

と、ざっとこんな感じです。

機能はすごくシンプルで、

- よく使う図書館の追加、一覧取得、削除、検索
- 読みたい本の追加、一覧取得、削除、検索
- 蔵書状況の問い合わせ及び通知(定時実行/任意のタイミング)

のみです。

# 作る過程の中で思ったこと
## Clean Architectureの構成だと、色々便利

完全にできたわけではない、が以下のメリットを享受できました。

- テストが書きやすい
- Storybookが書きやすい

LIFFに依存してしまうと、アプリが作成しづらいです。ただ、LIFFに依存するかどうかは、構成によって回避できます。
この点に関しては別で記事を書きましたので、もしよろしければご覧ください↓

https://qiita.com/mball/items/5dc0a95ef691b17ff8bc

## 型の制約で表現できない部分をテストで担保すると、より堅牢なアプリが出来上がる
型定義ファイルを読んでいくと、ちょいちょい型で表現されていない制約があります。例えば以下のような箇所です。

```ts
export declare type TemplateCarousel = {
    type: "carousel";
    /**
     * Array of columns (Max: 10)
     */
    columns: TemplateColumn[];
```

これは、カルーセルメッセージを送るときは、一回の送信で10個まで、という意味です。（カルーセルメッセージについては [こちら](https://developers.line.biz/ja/docs/messaging-api/message-types/#carousel-template) ）
こういった型では表現できていない部分に対してテストを書くことで、結合テストを行わなくとも、LINE側で起きるエラーを回避することができました。

## 機能ごとに要件を最初に固めるのは、めちゃくちゃ大事
今回『はじめよう！ 要件定義～ビギナーからベテランまで』を読んで、要件定義からシステム開発を始めました。
企画書作ったり、システムの構成図を書いたり、UI遷移図を書いたり、と普段行わない工程もこなしました（全て手書きなので載せることを憚るレベルですが、、）。
また事前に上述したようなAPIの制約はカーリルAPIに関してもありました。そういった制約を開発着手前に潰しきる工程も挟みました。

そのおかげもあって、手戻りはほとんどなかったです。

https://gihyo.jp/book/2015/978-4-7741-7228-6

# アプリを活用した結果、、
自身が住む区で、一番乗りで『[APIデザイン・パターン](https://book.mynavi.jp/ec/products/detail/id=131252)』を読むことができました！！
読み終わるまでに6人くらい予約していました。僕は発売から3週間で僕の手元に届きましたが、6人目は、概算ですが3週間+2週間(自分)+2週間×5 = 15週間！！！3〜4ヶ月くらい待たなければいけません。アプリを使うことで最高の図書館体験を得ることができました。


# 終わりに
身近のちょっとした不自由を、アプリを開発して解決するって、個人的にものすごく楽しいです。