データベースレス で サーバーレス な 社内図書システムをGoogle App Script (GAS) で作ってみる


この記事は Retty Inc. アドベントカレンダー  10日目の記事になります。
昨日は @noripi さんによる [ Kotlin/Nativeを使ってiOSアプリを作ってみる](https://qiita.com/noripi/items/4ee969c48b3da5ca6fbd) でした。

Retty Inc. で Software Engineerしている @tkngue です。
本日は社内アプリケーションのお話をさせていただきます！

# 背景

Retty では 技術書や専門書、そのほか気になる本があれあば 気軽に買え、
社内の蔵書として貸し借りが行えるようになっています。

これまでは 本の貸し借りは、「Slackのチャンネルで各自宣言して借りて返す」といった
運用だったのですが、最近では 社員数も増え蔵書数も1000を超えるようになり
この貸し借り管理だけでも なかなか大きな手間となります

- 蔵書で何があるかよく分からない (新しく注文するべき？)
- 誰に何が借りられているかが探しづらい

という問題点にぶつかってしまいました。

# 要件整理・技術選定

ということで社内用の図書システムをそろそろ用意しないとね、ということになったのですが
一番の懸念は「運用どうするの？」というところでした。

できることなら **「運用したくない」**  というのが本音です。

可能ならばシステムを作らない、で行きたかったので
要件に合うものが見つからず、結局開発することにしました。

運用のことも考えると
「社内でしか利用しないのに, DBやAppサーバを立ち上げるのも高コストだよな...」

と考えて色々模索した結果として
運用コストが低い、DBレスでサーバレスに図書管理システムを作ってみました。

構成としては以下のようになります

- DB  ⇨ **スプレッドシート**
- App ⇨ **Google App Script(GAS)**
- UI ⇨ **Slack の Slash Comand**

GAS は楽でいいですね。

スプレッドシートは （良くも悪くも）万人にとって親やすいインタフェースであるため
DBの代わりにこいつを持ってくることで、Excelが触れる人ならば 
誰でも本の整理できる(=運用が誰でもできる)ということになります。
 
Slackで検索・貸し借りの管理できると便利

# つくってみた

作る手間もそんなにかからず、簡単に作れました

### スラックから操作: 

Slackの Slash Command を GASで実装した形です

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/1454d4f4-721e-d61a-8dc1-c1aa8701ed05.png)

### 使い方:

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/923ede10-da2d-a83e-1282-1703207247e2.png)


### 蔵書検索:

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/4c470e15-5de4-fa19-a4a4-79bdfc0eb592.png)



### 貸し借り:

特定のチャンネル(\#book-rent) で履歴が見れます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62929/0b856e09-75f0-7a93-11e9-950d96efba15.png)


### 蔵書管理用のスプレッドシート

こんな感じで管理しています

<img width="1361" alt="スクリーンショット 2017-12-10 9.06.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/62929/b4ea338c-d822-4630-95f5-a24294907be6.png">



# 開発について

https://github.com/TKNGUE/gas-book-library

GASによる初めてのアプリケーションでしたが、
ただサーバーレスで面倒な手続きは一切無しにできたので、これはちょっとした感動です。

Google Apps Scriptの開発環境が使いこなせていないのか、いまいちだったので
デバッグ作業の方がに時間がかかってしまいました...
あとES5のため、非同期処理なんていうリッチな機能は使えません。

開発の罠も色々あったので、簡単にですが共有しておきます

- 新しい版を発行しないと、APIは更新されない
- Logger.logなどのLoggerAPI と シート書き込みによるログ機能を活用する
- 小まめに機能開発
- Slackからのパラメータは, e.parameter, e.parametersだけでなく e.postDataも確認すること
- シートとのIOは重い。読み込みや書き込みはまとめて、そしてキャッシュを利用する

ぐらいになります。

特に **スプレッドシートのIO** は**とても遅く**、
検索の実装のためにキャッシュをうまく使う必要がありました。

そのため以下のクラスを使います：
[Google App Script - CacheService](https://developers.google.com/apps-script/reference/cache/cache-service)

雑な作りですが、以下のようなユーティリティを作って活用しています


```javascript
function cacheWrapper(key, f){
   var cache = CacheService.getScriptCache();
   var cached = cache.get(key)
   if ( cached != null) {
     Logger.log("CACHE HIT:" + cached)
     return JSON.parse(cached)
   }
   
   content = f()
   Logger.log(content)
   cache.put(key, JSON.stringify(content), 21600)
   return content
}
```

使うときは下のような感じです。

```javascript
cacheWrapper('members', function { 
// some heavy IO process
return 1});
```

検索用のインデックスとして、Google App Scriptのトリガを使って
バッチ処理を走らせてキャッシュを更新しています。

これによってIOが非常に遅いスプレッドシートの検索も
比較的高速に返るようになりました。

# 終わりに

ということで図書システムつくってみました。
貸し借りだけであるならば、紙とペンだけで良いと思うのですが
検索機能が欲しかったあまりにこのようなシステムを作ってみました。

現状の運用としては、コードベースの管理ぐらいなもので楽に運用しています。

他の会社さんの蔵書管理はどういう風にやられているのでしょう。
気になります :eyes: