はじめに
Imairuというサービスを友人と5人で開発しています。私はサーバーサイドを担当しています。
開発の際に生じた課題とそれをどう解決したか、話します。
課題
バグが生まれやすかった
Socket.IOを使って、クライアント<->サーバで通信を行います。
クライアント側の動作に不具合がありました。エラー的にクライアントに問題がありそうでした。しかし、クライアントでどれだけデバッグをしても直りません。
結局、問題はサーバー側にありました。私が担当した機能の実装漏れが原因です。背筋が凍りました。
仕様書や進捗が把握しにくかった
問題は3つありました。
API仕様書が見にくかった
API仕様書をマークダウンで書いていました。時間がなかったですし、それ以外の方法を使った経験がなかったためです。
文字だらけですし、型も書いてませんでした。ですので、とても見にくいです。
進捗管理を口頭でしていた
進捗管理はもっと酷いです。チームで仕様を決めた時に、必要な機能仕様はドキュメントに書いてあります。
しかし、その実装の進捗管理は、ミーティングで口頭で管理していました。
DBのER図を書く手間が大きかった
DBのER図にも問題がありました。draw.ioで書いたER図を画像化し、ドキュメントに貼っていました。 書くのに時間がかかりますし、変更の手間も大きいです。
コードがいじりにくかった
問題は3つありました。
型がついていなかった
サーバーサイドの実装に動的型付け言語であるNode.jsを使いました。
型がついていないと以下の問題があります。
- コードが読みにくい
- 機能追加・変更がしにくい
- バグを生みやすい
モデル層はSQLを直書きしていた
また、データベースを抽象化するモデル層はORMを使わず、SQLを直書きしました。
機能追加の度にSQLを書く必要があり、手間です。書き間違いも起こり得ます。
Controller層の責務が大きすぎた
私たちのアーキテクチャは、Controller, Modelのみです。Controllerに通信周りの実装、ビジネスロジックが混在しています。
読みにくく、変更がしにくいです。
解決
バグを生まれにくくする
テスト駆動開発する
プロトタイプの開発ではテストを書いてませんでした。
テスト駆動開発(TDD)をすることにしました。
流れは以下です。
- 実装前にイシューでテストケースを書き出す
- テストの実装を行う
- テストを通せるように機能の実装を行う
実装前にテストケースを書き出すことで、実装漏れを防ぎやすくなります。また、テストによりコードが正しく動作することも保証されます。
コードレビューを入れる
プロトタイプの開発では、レビューをしてませんでした。
コードレビューをすることにしました。
コードレビューにより、以下のメリットがあります。
- バグや実装漏れを防ぐ
- 書き方を揃える
- コードの理解が深まる
自動テストとレビューによってブランチを保護する
GitHub Actionsを使って、自動テストを行うようにしました。
また、GitHubの機能を使って、自動テストとレビューを通過した場合のみ、マージができるように設定しました。
仕様書や進捗を把握しやすくする
API仕様書をStoplightを使ってOpenAPIで書く
StoplightはGUI的にOpenAPIのAPI仕様書を書けるツールです。
API仕様書通りのレスポンスを返すモックサーバーも自動で立ててくれます。
また、APIはRESTに従うREST APIに設計し直しました。
GtiHubのProjectsを使って、kanbanでタスク管理する
issueやPRと紐づけることができるので便利です。
dbdiagram.ioを使う
dbdiagram.ioを使うと、SQLチックなコードからER図を作ることができます。
リンクをドキュメントに埋め込むだけで、ER図を表示することができるため、非常に便利です。
コードの保守性を高くする
TypeScriptでNode.jsに型をつける
TypeScriptを導入することで、Node.jsに型をつけるようにしました。
TypeScriptに慣れるまで少し時間がかかりました。
型をつけるメリットは以下です。
- 型がドキュメントがわりになる
- 型によるエラーチェックができる
- 型による入力補完が効く
ORMを使う
TypeScriptと相性の良いORMであるTypeORMを導入しました。
ORMにより、SQLを書く必要がなくなり、実装の手間が減ります。
責務を分ける
ビジネスロジックを書く、Service層を導入しました。
また、Controller層、Service層において、コードを複数ファイルに分割するようにしました。
Controller層であれば以下のような感じです。
- Group.ts
- GroupUser.ts
- GroupUserSetting.ts
- User.ts
API仕様書からコードを自動生成する
swagger-typescript-apiを使って、OpenAPIのAPI仕様書から型を自動生成するようにしました。
また、oas3-toolsを使って、OpenAPIのAPI仕様書からルーティングもするようにしました。