Webの技術でTodoリストアプリを作って学んだこと
今回簡単なTodoリストのWebアプリを作りました.Webアプリ開発初心者が開発をしていく中で学んだことを記録を兼ねてまとめました.
作ったもの
Todoアイテムを追加し,アイテムの編集や削除ができるシンプルなアプリです.
Reactベースのフロントエンド部 (TypeScript),REST APIにのっとったバックエンド部 (Go),RDB (PostgreSQL) という構成で実装しました.またそれぞれをDockerコンテナで運用することで,各サービスを一括して管理できるようにしました.
これまでWeb系の技術はフロントエンド部のReactを1年弱ほど趣味で勉強した程度で,バックエンド部に関してはほぼ経験がない状態でした.そのため自分のスキルアップを狙い,事前にUdemyでバックエンドの開発入門講座を受講してから,1カ月半程かけてアプリの開発をしました.
Web3層アーキテクチャとDockerコンテナの相性の良さ
今回はフロントエンド部,バックエンド部,DB部をそれぞれ別のサーバで管理するWeb3層アーキテクチャを採用しました.Ruby on RailsやDjangoなどで開発する時のように,UIや機能処理,データベース管理を1つのプログラムで管理する方法 (MVCアーキテクチャ) もありますが,個人的になんでもかんでも1つのものが担当してしまうのは経験上管理が煩雑になる事が多いのでできるだけ担当を分けるようにしました.
開発の初めはGoやViteの機能を使ってローカルサーバを立てて各層を連携させていましたが,途中からDocker Composeを使ってDB,バックエンド,フロントエンドをコンテナで管理すると,コマンド一つで全てのサービスが起動できたりして便利でした.本番環境を想定したサーバ構成にするときはリバースプロキシを使ったりしましたが,このときもDockerコンテナの仕組みを使うと簡単に管理することができました.
今後Webアプリを開発するときはAWSやGCP,Firebaseのような外部サービスを利用していくことが多くなると思いますが,個人の開発環境でサーバを管理する場合はDockerが便利だと感じました.
シンプルなAPIを設計する重要性
バックエンドの処理のなかで,新しいTodoアイテムをPOSTしたあと,UIを更新するためDBに登録されている全てのTodoアイテムを取得する処理が必要でした.バックエンドAPIの設計において,当初はPOSTメソッドのレスポンスで全てのTodoアイテムを返そうとしましたが,テストケースの肥大化やエラー処理の複雑化,実装途中の仕様変更への対処が困難になりました.
そこで単一責任の原則に立ち返って,POSTメソッドでは新たなTodoアイテム作成のみを行い,Todoアイテムの取得はGETメソッドで行うようにしました.こうすると変更前に比べてリクエスト数は増えてしまいますが,それぞれの処理はシンプルな実装で済み,処理が明快でテストも単純化することができました.
またリクエストを組み合せることで,個々の処理の実装の単純さを維持しつつ複雑なDB操作もできるようになりました.このあたりの考え方はCPUのRISCだったり,昨今流行りのマイクロサービスみたいな所に通じていて,やはり理に適った設計方針なのだと感じました.
DDD(ドメイン駆動設計)の効果
バックエンドAPIを実装していく中でクリーンアーキテクチャの存在を知りました.様々なサイトをつまみ読みした程度ですが,DDDを意識してバックエンド処理をリポジトリ・サービス・コントローラに分けて設計しました.
それぞれで担当する役割を分担し処理をシンプルにすることで,API処理において「どこで何をしているか」を簡単に把握することができました.また途中でリポジトリをインメモリを扱うものからRDBを扱うものに実装を切り替えるときも,コンポーネント間の依存関係をできるだけ疎にしたおかげで,依存性の注入によってインターフェースが同じで実装の違うコンポーネントをサービスの外部からで渡すだけで対応することができました.
クリーンアーキテクチャについては一部の情報を拾った程度の理解なので,のちほどしっかりと解説を読んで適切な設計を理解したいです.
TDD(テスト駆動開発)の効果
自分はこれまであまりテストを書く習慣がありませんでした.しかしいろんな勉強会で「テストがないものは心配で使えない」という話もよく聞いていて,テストを書く必要性は感じていました.そこで今回はバックエンドの実装時にテストを先に記述し,テストが全て通るように実装を進めていくTDDを行いました.
TDDを実践していくなかで,ものを作るときには要件の定義を行いますが,ふるまいの要件定義がテストケースそのものだということに気がつきました.テストが成功するように処理を実装していくTDDのやり方は,要件を満たすように実装していくというモノづくりの進め方にとても合致していると感じました.
また今回はOpenAPIを使ってAPIの定義を書き,それに応じたテストケースを先に準備したうえでAIに実装を任せるといった開発も試しました.いくつか試したところでは,しっかりと要件や仕様を用意していればAIは十分な実装を生成してくれるように感じました.AIを使った開発を進めていくときにもTDDは有効だと感じました.
AIを使った開発プロセスの効果
実は自分は昨今流行りのAIを使ったソフトウェア開発をあまりやっておらず,ときどきコードについてCopilotやGeminiにチャットで質問する程度しか利用していませんでした.今回の開発ではGitHub CopilotやCursorを導入し,チャット以外にもコード補完やエージェント機能を利用して,アプリ開発プロセスにAIをどう活用するか探りながら開発を進めました.
AIを使ったアプリ開発で一番助かったのは,未経験者に対する相談相手になってくれたことでした.自分のような初心者は周りに経験者がいないため,書いたコードや考えている設計に関して相談できる人がおらず,実装が詰まることが多々あります.そんななか,AIは書いたコードに対してレビュワーになってより良い書き方の提案をしてきてくれたり,設計で迷っていることに対してそれぞれの手法のメリット・デメリットを挙げつつ,どちらが今回のケースではふさわしいかを説明してくれたりします.ある意味蒸留学習のようなことをやってくれるので,こちらとしても知識の習得効率が上がり,納得して開発を進めることができました.
良きパートナーとしてAIと接することができれば,これまでやりたいことがあっても自分の経験・スキル不足でなかなか手を付けられずにいた事が,AIを活用することで一気に実現する可能性を感じました.正直昨今のAIブームに関しては懐疑的な目で見ていましたが,ここまで世の中がAIに期待を寄せている理由がやっと理解できたように思いました.
ただいくらAIが高性能だったとしても,こちらが伝えていない情報を類推するのは難しいと感じました.たまに手を抜いていい加減な質問をすると,意図を組み切れずに的外れな回答が返ってきて,再度質問をし直す事が多々ありました.思えば最新のLLMで使われるDNNは人間の脳神経網を模したモデルであり,究極的にはAIは人と同じふるまいをするので,人に物事を伝えるように明確に分かりやすい質問をすることが重要なのだと再認識しました.
モチベーション維持の重要性
自分はこれまでの経歴でWeb方面の開発とは接点がありませんでした.そんな知識ゼロの状態でWebアプリを開発するため,まずはUdemyでフロントエンドとバックエンドの講座を受講してインプットを重点的に行いました.そのあと学習知識の定着を狙って,Todoアプリの開発というアウトプットを行いました.今回の開発はスキルの習得の側面が強く,実際アプリを開発することで以前に比べてスキルの向上を実感しましたが,学んだことを一つずつ確認しながら開発を進めていくと間延びしてしまい,途中でモチベーションの維持が難しくなってしまいました.
これまでの自分の開発は,「こういうものが作りたい」や「好きなことができるようになりたい」という自分の強い願望に基づいたものが主でした.そのため今回のようにスキルアップのためという理由付けだけでは開発をやり続けるだけの動機に成り得ず,途中で開発に飽きてしまいました.自分が「好きなこと駆動開発」に向いている人なのを再認識したので,これからのWebアプリ開発も自分が何を作りたいのかをベースに考えて,そのうえでスキルアップになるよう情報のインプット・アウトプットをするようにしたいです.
まとめ
Todoリストというシンプルなアプリの開発でしたが,実践的なWebアプリ開発経験がないこともあって色々悩むことがありました.そういった中でちゃんと完成品を仕上げられたのは良かったです.また完成したアプリを触っていると,自分がこれを作ったんだという達成感を感じられて素直に嬉しかったです.これからもWebの技術を使ってもっとたくさん使えるアプリを作っていきたいです.
Discussion