shimgo
5/4/2019 - 2:31 AM

教訓

要件定義

  • たいていのことは世の中に製品があるのでそれを使うことを検討する
  • たいていのことは世の中にライブラリがあるのでそれを使うことを検討する(Awsomeなんちゃらとか)
  • まずはアクターの洗い出しとフローの定義から

モバイルアプリ

  • 強制アップデート機能の考慮
  • メンテモードの考慮
  • 再送処理の考慮
  • お知らせの考慮
  • 審査用の抜け道作成
  • 機能のリアルタイム開放
  • 狙ったユーザにだけ機能開放

DB設計

  • 基本NULLは許容しない
    • SQLが複雑になる(IS NOT NULL AND ...とかが必要になりがち)
    • PUTでnullで更新することと空文字で更新することの差がないなら
  • ユーザが何種類かいるのではなくロールが何種類かあるだけではないか?
    • PCで管理画面を見る人とアプリから見る人は両方の役割を兼任するかもしれない。ユーザテーブルを種類で分けていると苦労するかも。アプリ内でPCの役割もやりたいときとか。
  • 同じテーブル内に二者択一のカラムを作らない
    • NULLのカラムが増えるし、テストデータを作るときのロジック 複雑になる
  • 論理削除は状態遷移 or 削除時刻 or 退避を検討
    • 削除フラグじゃなくて業務フロー上のひとつの状態ではないか?を検討
    • 削除ステータスにする前のステータス元に戻す必要があるなら別途状態遷移の履歴を保存するテーブルを用意すれば良い
    • 参照頻度が少ないなら本当に消すとか、どこかに退避するとか
    • まだ事故ったことはないが、一意制約を設けたいテーブルでは論理削除にすると一意性の確認を自分でやらないといけない
    • 削除=退会ならある期間のうちの退会数をカウントする方法を考えておく
    • 削除時刻やフラグのようにして状態遷移と分離すると、特定のステータスのものを取得する、という場合にすべて削除フラグの判定をしなければならない。
    • 外部参照制約で物理削除が難しいなら削除済みデータ専用レコードを作ってそれを割り当てるのもいいかもしれない。 ユーザが組織単位で、その配下に組織内ユーザを作る形式なら退職後にデータ参照をできるべきなのでそのケースには適さないが、アカウントが個人単位でサインアップするものなら無効なユーザとして差し替えるのはできそう。
  • そのテーブルの亜種がないか考える
    • 料金表テーブルがあったとき、従量課金プランや固定プランなどが出てくる可能性が考えられる。 料金表テーブルを基底テーブルとしたクラステーブル継承などを検討する。
  • そのデータには有効期限がないか考える
    • ユーザに適用するプランには有効期限があるかもしれない
  • 対象の動きを記録するテーブルあるいはカラムが必要かもしれない。例えばフリマの商品ならpublished_at、sold_at、delivered_atのように。
  • エンティティルートのIDをそれに所属するすべてのテーブルに持たせることを考える(参照をショートカットするために)。 しかしその場合、エンティティルート間を移動するときに全参照を整合性あるように更新しないといけない手間が増える。

APIサーバ

  • 料金見積もりのロジックは、同じパラメータなら指定時刻から同じ料金が出せるようにする。あとから 計算できるように計算時刻も保存しておく
  • 外部に公開するAPIにはモックを差し込めるように
  • 認証トークンを無効化することができるようにする。トークンそのものの有効期限だけでなく、DBのトークンと一致しているか を調べる。
  • ユーザは階層構造の組織になっていないか。上位組織から下位組織のリソースにアクセスできるようにするなら 権限やAWSのassume role的な動きを目指すといいかもしれない。
  • リクエストパラメータのidは連番にしない
    • 予測されてしまうので
  • テストデータはルートエンティティを作り込んでテストコードからはルートエンティティを
    基本にアクセスした方が、データ構造の変更があったときに修正箇所が散らばらない
  • レスポンス中でネストしたオブジェクトでnullになるものは中のキーまでは表現しない方がいいかも
    • レスポンス中のどれが本当に存在していなければならない値なのかわかりにくい
  • 何回も呼ばれたら困るAPIはガードする。特にお金関連は。
  • 更新APIは各項目をパラメータが存在している場合だけ更新する方式にするべきか考える
  • ブラックリスト方式でユーザに選択させると、今後その項目が増えたときにユーザは暗黙的にOKの要素を 増やしていることになる。それは問題ないかよく考える
  • マスタをAPIサーバに寄せても結局フロントの出し分け条件で区分値がXだったら〜というXの部分で固定値が必要になるし、区分値変更のメンテナンス影響も受けるのでフロントで固定持ちも割と選択肢かも

Rails固有

  • after_initializeで初期値をセットしない
    • selectでafter_initialize処理が走ってしまってパフォーマンスに関わる可能性

モデリング

  • 今メインで扱おうとしているリソースの前後のライフサイクルを考えること(発生から終了まで)。 今考えているそのリソースの姿は、そのリソースのライフサイクルの中では中間の姿かもしれない。 注文を管理するシステムを作っていて"注文"というリソースを設計したが、プロジェクトが 進んで、実は"注文"リソースは"依頼"リソースが"受注済み"状態になったものであったと いうことになるかもしれない。

インフラ

  • 外部公開APIはAPI Gatewayを作って裏側は自由にする
  • 本番DBのマスキングされたレプリカを使用可能にする
  • graceful shutdownされるか確認する

オペレーション

  • ドキュメントは自由にさせると散乱するので制限する