重要
- シンプルさ、は何よりも力になるので、出来うる限りシンプルにシステムを構築していく覚悟を持つ!!
売上
- IOSとAndroidアプリで開発すると、売り上げの3割を持っていかれたり、Apple・Googleのポリシーに振り回されたり、ブラウザよりはデバッグしづらいので、Webで行けるなら普通にWebアプリを作ったほうが良い(3割持ってかれてもトータル上回る確信があるならアプリでも可)
- システムはスケール出来る構成にする必要がある。しかし、パフォーマンスの低い言語を使うとサーバ台数がかなり必要になるので、開発速度とパフォーマンスを両立できる開発言語を選定したほうが良い(2018-07-01現在だと、Go言語が1番近いと思う)
- スタンドアローンでWebサーバを起動できる
- Javaとかと違って、Go言語をサーバにインストールしなくて良い(バイナリを配置すれば動く容易性)
- 課金処理に関しては、コストを払ってでもしっかりとした自動テストを作成する(きれいに処理が分けられれば、テストコストも増大しないはず)
設計
- 下記には目を通しておくこと
- UNIXという考え方 The UNIX philosophy
- The Twelve-Factor App (日本語訳)
- JPCERT セキュアコーディング
- ブルーグリーンデプロイメントを念頭に置いて開発すること!!
- フルスタックフレームワークは絶対使わないこと
- 自分でライブラリを組み合わせて必要な機能のみのシンプルなフレームワークを自作すること!!
- レイヤードアーキテクチャを意識する(コントローラ層がバッチ実行層に代わっても動作できるように!!)
- Controller層(ここにLogicは書かない。あくまでin outと、従属しているServiceを呼び出すだけにする)
- Service層(Controllerに従属するもので、Logicを組み合わせて使うだけの処理)
- Logic層(ピュア言語)(コネクション保持オブジェクト以外は単なる関数で構成したい)(上下の層が変更されても、こちらの層は影響を受けないように書くこと!!)
- Repository層(インフラストラクチャを使う層、使う側(Logic層など)にSQLなどDBを意識させないように書くこと)
- Infrastructure層(DB操作用ライブラリ)(ドライバーをラップしただけの簡単なもので良い)
- テスト実行時間の削減を意識する
- ファイル単位でテストが独立しているようにして、パラレルでテスト出来るようにする。
- DBもパラレル分用意して最初の初期データ投入後は、各テストが実行後に元に戻すように書くこと
- バッチ処理書くときにフルスタックフレームワークのせいで簡単に書けないとかにならないこと(Logic層をピュア言語で書いておけば使えるはず)
- アプリケーションコード、管理画面コード、バッチコード。全部ワンプロジェクトに収めて相互連携出来ること。
- 統合開発環境無しで、コマンドでビルドとか起動できること
- テスト駆動開発できること(テスト1ファイルの実行時間は2秒以下で終わること)
- コードの静的チェックをコマンドでかけられること
- コードのフォーマットをコマンドで実行できること
- テストをコマンドで実行できること
- テストのカバレッジを測定できること
- CIサーバ(Jenkinsなど)で、ビルドとかデプロイとかテストを実行出来ること
- 環境変数を使って、同じコードで違う環境動作に変えられること(local, dev, staging, production)
- 機能を削除するときに、削除しやすい設計になっているとよい(独立性の担保とか)(1フォルダ削除するだけで機能を消せるとか?)
- Controller、Batch、Infrastructures以外(外部インターフェース部分以外?)は、フォルダでまとまっているとわかりやすいとおもう(serviceとかLogicとかRepositoryとか)
- パラメータのチェックはしっかりと行うこと。常に悪意のあるリクエストが来ると想定すること。
- クライアントサイドで判定ロジックなどは書かないこと(サーバーサイド以外では不正リクエストかどうか?区別できなくなるため。)
- ロジック上で最終的にどんなSQLとかクエリが発行されているか?わかるようなライブラリを使うこと(または自作すること)
- ORMとかは出来る限り使わないこと(シンプルなものを自作するとか)
- DBデータの総容量に注意する。無尽蔵にデータが増えないように仕様的に予め上限を設けて置くこと(サービスの要のデータであればそこだけ仕方なくやるくらいがちょうど良いかと)
- マスタ情報はDBから都度取得せずにアプリケーションサーバにキャッシュすること
- キャッシュの際に使いやすいように加工してからキャッシュしたくなるが、DB値とかけ離れると分からなくなるので加工は都度やるで良いと思う(パフォーマンス改善が必要であれば、そのときに必要な分だけ加工してキャッシュしておく)
- マスタキャッシュの更新タイミングは、管理画面などで管理する。キャッシュの更新を管理画面からやるまでは保持した情報で動作するようにしたい。
- ↑ブルーグリーンデプロイメントで必要になる(待機系で確認する際に最新キャッシュで待機系確認したいなど)
- データ量削減と不要データ保持によるリスク低減のため、物理削除できるなら一気にすること(削除したら自動でバックアップ&復元できる的な機能はつけておくこと)
- 2度押し防止
- 1つ目の処理が終わっていないのに次の処理を実行するのを防ぐなど
- 各リクエスト単位だと実装が面倒なので、一律そうなるようにして、このリクエストは例外的に実行できるとかのほうがわかりやすい
- 1つ目の処理が終わっていないのに次の処理を実行するのを防ぐなど
- ブルートフォースアタックの防止
- すごく短い時間に大量のコマンドが来た場合はブロックするなど
- マスタキャッシュする場合は、素のままキャッシュしたほうがよいかも
- あまりに色々と手を加えた後のオブジェクトをキャッシュしてしまうと、DBの値がオブジェクトのどこと対応しているか?判別しづらいし、処理を追う必要が出るため。
- 素のマスタオブジェクトと、手を加えまくったオブジェクト。分けて保存するのもあり?
- データベースのテーブル情報とかが一覧で見れるyamlファイルなり何かを用意する
- Deletability(機能削除容易性)や使用用途の把握に使えるので必要
- typeとかカテゴリを用意しておけば、ユーザ関連テーブルを設定ファイルから取得して、ユーザデータを削除するということにも使える
- MongoDBなどはスキーマ情報を持たないので、作成しておかないとあとで大変
- jsonスキーマを設定ファイルに書いておいて、そちらのスキーマ情報を元にアプリケーションロジックで更新するとか連動させると尚良さそう。
- jsoneditor的なのとも連携できるはず。
- データベースのバージョンアップについて
- DBサーバを2つ用意して、メンテ後同じDBに対して更新すればわかる?
- DB側でマネージャー的なものを介して、うまいこと両バージョンで動作するように作る?
- 裏でバージョンアップ後のDBが問題なく動くことを確認できれば良いので、何か最初から手を打っておくのはどうか?
- ライブラリを直接使わない。必ずwrapクラスを作成して使用する(ライブラリを変更したい場合、生で使用していると広範囲に修正が必要になるため)
- マスタデータなどの番号は、0番から始めない。intの初期値(null的なもの)なのか?実際の値か?わからんくなる。
- 管理画面などは、操作ログを自動で出るようにしておくこと。
- 管理画面で、権限による操作制限もほしい(Mustではないが。。)
開発
- 各種環境はローカルも含め、出来る限り本番に似せて作れるとよい。
- 付与処理などを共通化したいため、保持しているアイテムとかアイテム数を1つのテーブルで表現したい(違う情報を保持したいアイテムは、その部分だけ別で分けるとか)
- 期限付きアイテムや、手に入れてから1週間使えるというアイテムがある場合、↑の部分で表現が難しくなる?
- 常にシーケンス付きで保持するとレコード数が膨大になるので、まとめられるものはまとめたい。
- 起動時間の短縮
- ビルド言語ならビルド時間を短く出来るように最初から考える(テスト駆動開発とかで部分的に機能を実行できれば、フルビルドはある程度掛かってもよい?)
- DB側で出力したクエリログを確認しながら開発できるようにすること(アプリサーバのログだけだと見誤ることもあるため)
- DBドライバのパラメータなどはしっかりとマニュアルを読んで理解して設定すること
- これがあるので、出来る限り素のドライバを使ったほうが複数のマニュアルを読まなくてよくなる。シンプルになる。
- 実装するときは、DBのクエリログなどを眺めながらやること(変なクエリを発行していないか?確認すること)
- 動作確認をユニットテストだけで行えるようにすること
- ORM的なものを使うなら、最後に実行されるSQLやMongoクエリなどが分かるようものを使うとよい(実際にDBに発行するときと寸分違わないのが理想)(無いならシンプルなものを自作すること)
- SQLインジェクション、クロスサイトスクリプティング、クロスサイトリクエストフォージェリなど、基本的な攻撃は防げるように作ること。
- MongoDBは、型があったりするが、jsonで表現できなくなるような型は使わないほうが良い。例)Date型は使わずにtimestampを数値で保存しておくなど。
- jsonにすると型が失われるので、それを意識して変更するとか面倒になるため
- 管理画面は最終的にCSVとかスプレッドシートのアップロードしたくなるので、あまり作りこまないようにする。
- マスタデータは、RDBMSで作成し、スプレッドシートなどと連携するとシンプルに作成できると思う(用途にもよるが、ユーザデータはMongoDBというのもありかと)
- マスタデータとユーザデータでDBを分けておく?(負荷削減には効きそうだが、面倒なことになる可能性がある?)
測定、デバッグ、トラブルシュート
- メモリの状態や、オブジェクトの状態を見るために、デバッグ用の情報を出せるような仕組みを用意する(モニタリングAPIとか、モニタリング用のポート開くとか、デバッグユーザだとアクセスできるAPIとか)
- リクエストなどの数や実行時間を測定できるようにログを出力すること
- 各リクエストやコマンドにどれくらいの時間が掛かっているか?計測できること
- システムで何が起こっているのか?把握できるようにログは出すこと(とりあえずログ出すとかはしない。最低限のみにすること。)
- リクエスト、レスポンスはログで確認できるとよい(本番はエラー時のみ出力できるようにする)