ゼロ機能リリースで始めるサービス開発

こんにちは、すライムです。
N予備校で、学んだり忘れたりしています。

# ゼロ機能リリース is 何？
ゼロ機能リリース(Zero feature release 以降 **ZFR**)とは、
まだ何の機能もない「ひな型」の時点でデプロイして、
アクセスできる URL を作ってから機能を追加していく開発手法のようです。

N予備校の教材って、
テストやデータベースとの接続など
インフラから整えていく流れなので、
なんというか...ちょうど良さそうですね！（むりやり感）

さっそく express のひな型を作って、Render にデプロイしてみました。
見えちゃダメなアレも確認できました。

データモデルの実装まで進めてみたので、メモの一部を公開してみます。

# run.sh の変更
開発環境に入ると、もうポートが使われちゃってることに気づきます。
`run.sh` でサーバが起動してるからです。

もうひとつポートを用意しても良いけど...ムダなサーバを動かしておく必要ないですよね。
環境変数を使って、本番環境でのみ `yarn start` してみようと思いました。

Render 側の環境変数に `NODE_ENV` を追加。値は "production" にしました。
![スクリーンショット 2022-12-17 13.13.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219243/e6452fc1-c1e4-e0c6-1fe2-ae65898b9f0c.png)

`run.sh` は環境変数で分岐するように変更しました。

```sh:run.sh
yarn install
if [ "$NODE_ENV" = "production" ]; then
  yarn start
else
  /bin/bash
fi
```

`/bin/bash` があるのは、開発環境で Docker コンテナが止まってしまうため。

Dockerfile 側に `CMD /bin/bash` を追記しても良いかもしれません。

# express-session でメモリリーク

教材を認証のあたりまで進めると、
本番環境で `/login` にアクセスしても `404` を返されるようになります。

開発環境ではちゃんと動くし、認証もできてるのに...

どうやら express-session 単体では、
セッションを期限切れにする適切な方法が無いらしいのです。

遠からず大流行する予定のサービスなので
これではメモリがいくらあっても足りなくなってしまいます。

そこで、セッションに期限をもうける [memorystore](https://www.npmjs.com/package/memorystore) モジュールを使わせていただきました。
私は yarn を使っているので、いつものコマンドでモジュールを追加します。

```sh
yarn add memorystore
```
`app.js` は

```js:app.js の一部
// 追加
const MemoryStore = require('memorystore')(session);
const SESSION_MAX_AGE = 24 * 60 * 60 * 1000 // セッション情報の期限

// 変更
app.use(session({
	cookie: { maxAge : SESSION_MAX_AGE },
	store: new MemoryStore({
		checkPeriod : SESSION_MAX_AGE
	}),
	secret: 'xxxxxxxxxxxxxxxx',
	resave: false,
	saveUninitialized: false }));
```
こんな感じで、コードを追加・変更しました。

[互換性のあるストア用モジュール](https://github.com/expressjs/session#compatible-session-stores)の中には
sequielize を使ったものもありますが、
まずはシンプルな方法で解決してみました。
# そうだ .env ファイルを作ろう
うっかり GitHub に大切なパスワードなどをプッシュしてしまわないよう、
開発環境側の各種定数にも環境変数を使ってみようと思い始めました。

なので `.env` ファイルを作るのです。
```sh:.env
export PORT=8000
export NODE_ENV="development"
export DATABASE_URL="postgres://postgres:postgres@db/schedule_arranger"
export GITHUB_CLIENT_ID="xxxxxxxxxxxxxxxxxxxx"
export GITHUB_CLIENT_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export GITHUB_CALLBACK_URL="http://localhost:8000/auth/github/callback"
export DATABASE_URL="postgres://postgres:postgres@db/schedule_arranger"
```
できました。

あとは `source` コマンドで読み込みます。
```sh
source .env
```
これで、環境変数にセットされ、node.js からも `process.env.ホニャララ` で使えます。
`.env` は Git 管理から外したので、パスワードが漏れる心配も軽減されました。

環境変数については、らべねこ先生の
[環境変数の渡し方にはどんな種類があるのかというお話](https://qiita.com/rabeneko/items/40e9871ae65c2911b22d)で詳しく解説してくださっています。

# ORM の設定
環境変数を使ったことで、`sequelize-loader.js` の設定もこのようにシンプルに。
```js:sequelize-loader.js
'use strict';
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize(
  process.env.DATABASE_URL, {
    define: {
      freezeTableName: true,
      timestamps: false
    }
  });

module.exports = {
  sequelize,
  DataTypes
};
```
教材では Heroku で必要だった SSL 接続の設定が残ってますが、Render では不要みたいですね。
Internal Database URL を使っているからかもしれません。
Render では Access Control を設定しないかぎり、外部アクセスがすべて無効になるようです。

どのモデルにも共通で指定するオプションなら
ここへ define の名前で指定しておくと
各モデルを定義するときに省略できるみたいです。

設定が複数のファイルに分かれるので
後で見返したときにイライラしたいときとか便利ですね。

# 開発はまだまだ続きます

毎年、N予備校で開催されている「動く Web ページコンテスト」
応募作品を作りはじめる生徒さんもいらっしゃることと思います。

アイデアがなかなか思い浮かばないなら、ZFR という方法もありますよ。