個人開発の際に生じた課題とその解決

はじめに

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)をすることにしました。

流れは以下です。

  1. 実装前にイシューでテストケースを書き出す
  2. テストの実装を行う
  3. テストを通せるように機能の実装を行う

実装前にテストケースを書き出すことで、実装漏れを防ぎやすくなります。また、テストによりコードが正しく動作することも保証されます。

コードレビューを入れる

プロトタイプの開発では、レビューをしてませんでした。

コードレビューをすることにしました。

コードレビューにより、以下のメリットがあります。

  • バグや実装漏れを防ぐ
  • 書き方を揃える
  • コードの理解が深まる

自動テストとレビューによってブランチを保護する

GitHub Actionsを使って、自動テストを行うようにしました。

また、GitHubの機能を使って、自動テストとレビューを通過した場合のみ、マージができるように設定しました。

仕様書や進捗を把握しやすくする

API仕様書をStoplightを使ってOpenAPIで書く

StoplightGUI的にOpenAPIのAPI仕様書を書けるツールです。

f:id:wada0421514:20220321120915p:plain

API仕様書通りのレスポンスを返すモックサーバーも自動で立ててくれます。

また、APIはRESTに従うREST APIに設計し直しました。

GtiHubのProjectsを使って、kanbanでタスク管理する

issueやPRと紐づけることができるので便利です。

f:id:wada0421514:20220321115236p:plain

dbdiagram.ioを使う

dbdiagram.ioを使うと、SQLチックなコードからER図を作ることができます。

リンクをドキュメントに埋め込むだけで、ER図を表示することができるため、非常に便利です。

f:id:wada0421514:20220321115446p:plain

コードの保守性を高くする

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仕様書からルーティングもするようにしました。

まとめ

  • バグを生まれにくくする
    • テスト駆動開発する
    • コードレビューを入れる
    • 自動テストとレビューによってブランチを保護する
  • 仕様書や進捗を把握しやすくする
    • API仕様書をStoplightを使ってOpenAPIで書く
    • GtiHubのProjectsを使って、kanbanでタスク管理する
    • dbdiagram.ioを使う
  • コードの保守性を高くする
    • TypeScriptでNode.jsに型をつける
    • ORMを使う
    • 責務を分ける
    • API仕様書からコードを自動生成する