本書について
ハンズオンの特徴を大きく二つあげてみますと、
- アーキテクチャを重視している
- フレームワークを使用しない
という2点が挙げられるかなと思います。
アーキテクチャを重視している
クリーンアーキテクチャ・ドメイン駆動設計の考えをアーキテクチャに適用させています。保守性・拡張性のために前者を、ビジネスルールをコードに落とし込むために後者をという役割で考えています。
2章にてクリーンアーキテクチャを、3・4章にてドメイン駆動設計を扱っていきます。それぞれの概念の詳細は書籍や他の有識者の方の記事を読んだ方がわかりやすくまとまっていると思いますが、説明をした後で実装していくという流れとなっていますので、つまづくことなく取り組んでいただけると思っています。
フレームワークを使用しない
golangでフレームワークを使用しない開発 = webサーバーにnet/httpパッケージを用いた開発と捉えています。フレームワークを使用せずに開発する理由はこの後に述べています。標準パッケージのみで開発するわけではなく、あくまでそれはwebサーバー周りの実装の話であって、ormや各種サードパーティパッケージは多用していきます。その方が便利・安全だからです。
コードはなるべく載せるつもりでいるのですが、必要に応じて以下のGithubのソースコードをご覧ください。
そしてかなりボリュームが多くなってしまいました。章も多いですね...ご了承ください。必要な部分だけを読んでもらっても構いません!
また、記事を書くにあたって参照した記事・書籍・公式ドキュメントはなるべく載せていますので、気になる方はそちらもみてみることをオススメいたします。
本書を執筆した経緯
この本は、Goを用いてTodoアプリを開発していくハンズオン形式のものとなっています。本書の特徴の一つは、先述した通りフレームワークなしの開発を進めていく点にあります。この本を書こうと思った理由は以下の2点となっています。
- 「初学者こそ
net/http(標準パッケージ)で開発」のすゝめ - 自己学習のアウトプット
「初学者こそnet/http(標準パッケージ)で開発」のすゝめ
筆者まだgolangを学び始めて3ヶ月強くらいです(執筆時点:2024/12/29)。それまで、バックエンドには主にrubyをよく書いていました。rubyといえば、開発の際にwebフレームワークであるruby on railsが必ずといっていいほどに使用されます。プレーンなrubyのみで開発することもそうそうないでしょう。そこで、筆者はgolangの文法をある程度知ってから何か開発しようと考え、フレームワークを調べ始めました。すると、「開発するなら絶対これ!」といったフレームワークは、golangにはあまりないということを知ります。つまりruby on rails的立場のフレームワークがなかったんですね。有名どころでいえば、
- gin(⭐️79.2k)
- echo(⭐️30k)
- beego(⭐️31.7k)
- Fiber(⭐️34.1k)
が挙げられるでしょうか。⭐️はgithubスター数です。 ginが頭一つ抜けているようですが、どれも人気で支持があることがわかります。
そこで、golang初心者の筆者が思ったのが「フレームワーク多すぎてどれを使えばいいかわからん...」 ということでした。それぞれの特徴があり、企業は要件によってフレームワークを選定することでしょう。それに、どのフレームワークもお作法はそう変わらないでしょうから、何から学んでもいいです。
それでも、まず最初にどのフレームワークを学ぶかは迷いますよね....。迷いませんか?笑。そこで、最初に学ぶgolangを用いた開発手法として選択肢を提示したいのがフレームワークを使わない開発です。 golangはbattery includedな言語です。サードパーティライブラリを使用せずともある程度の開発はできてしまいます。
battery includedとは、開発に必要なツール・環境など、標準で多くの機能を備えていることを指します。追加のライブラリや外部ツールをインストールしなくても、必要な機能がすぐに使える状態だということです。
先ほどあげたgolangのwebフレームワークたちは、どれも主に充実したwebサーバーの機能を提供するものが多いです。それはおそらく、標準パッケージであるnet/httpだけでは機能として不十分であったからでしょう。フレームワークという位置付けではなさそうですが、chiやgorilla/muxなどのルーティングライブラリも開発されているぐらいです。標準パッケージでは主にHTTPメソッドの制御、パスパラメータなどがネックでしたが、1.22のバージョンアップデートでそこはクリアしています。他のフレームワークのようにミドルウェアは提供されていませんが。
そこで筆者は、学習として最初にgolangで開発する選択肢として、
net/httpを用いたwebフレームワークを使わない開発
はアリなのではないかと思うのです。
ginやechoなどのフレームワークはnet/httpをラップしているようです。
つまり、net/http標準パッケージを使って開発し、仕様をある程度理解することは、他のフレームワークへの理解にも繋げられるのではないかということです。
実際に個人開発をしたりするなら、効率性や安全性からフレームワークから提供されるミドルウェアを使用するのがいいと思いますが、学習としてロギング、認可制御ミドルウェアを本ハンズオンでは実装します。
net/httpを用いたフレームワークを使わない開発をテーマとしたZennの書籍は今の所見受けられなかったので、この本を執筆してみようと思った次第です。
間違っている、または改善点などありましたらどうぞご指摘ください。
自身の学習としてのアウトプット
執筆に至った理由としてもう一つは、自身のアウトプットのためとなります。 golangを勉強し始めてから、クリーンアーキテクチャやドメイン駆動設計などを知り、書籍を読んだりハンズオンをやってみたりしました。
「自分なり」ではありますが、todoアプリでありながらも設計をしっかり考えた開発を行ないました。公式ドキュメントを読んだり、自身で調べながら様々なサードパーティパッケージの使い方を学んだり、時にはコードリーディングもたくさん行いました(特にnet/httpパッケージ)。
そんなこんなで、「基本的な開発に必要な技術を体系的に網羅した」API開発だったので、この開発を振り返って、ハンズオン形式でまとめれば需要が多少あるのではないかと考えました。
ドキュメントや記事を読んだり、コードリーディングによって得られた理解・知見を文章として、また図解として示せば、「誰かの役に立つかもしれない」と思ったのです。さらに、こうしてアウトプットすることは自身の理解を定着させるのにも効果的だと考えました。
また、筆者がこのtodoアプリを開発していくにあたって、すぐには理解できなかった概念や、使用技術などの説明も(めちゃくちゃ詳細に書いているわけではありませんが)逐一述べています。そしてgolang初学者の方がgolangを用いた基本的なAPI開発を、この一冊で大体理解できるように構成・執筆しています。(筆者もまだまだ初学者の範疇です、まだまだ未熟です...)
アウトプットのためというのは少々利己的ではありますが、どうぞ最後までお付き合いいただけると幸いです。
作るもの
本のタイトルにもあるとおり、todoアプリです。複数のユーザーがシステムに登録でき、他人のtodoタスクも閲覧できたりする、若干SNSじみたものにしていきます。また、認証の機能も実装します。
エンドポイントは以下の通りです。
エンドポイント
| HTTPメソッド | エンドポイント | 説明 |
|---|---|---|
| POST | /users | 新しいユーザーを作成する |
| DELETE | /users/me | カレントユーザーを削除する |
| GET | /users | 全てのユーザーを取得する |
| PATCH | /users/me | カレントユーザーのプロフィールを更新する |
| POST | /tasks | 新しいタスクを作成する |
| DELETE | /tasks/{id} | 指定したIDのタスクを削除する |
| PATCH | /tasks/{id}/state | 指定したIDのタスクの状態を更新する |
| GET | /tasks/{id} | 指定したIDのタスクを取得する |
| GET | /tasks | 全てのタスクを取得する |
| GET | /users/me/tasks | カレントユーザーに紐づくタスクを取得する |
| POST | /login | ログインを行う |
| DELETE | /logout | ログアウトを行う |
本書の構成
第1章 開発環境を整える
docker、docker-composeで環境構築を行います。また、airというホットリロードツールを使用します。加えて、Makefileでタスクの自動化を図ります。 GithubActionsでCIの自動化も行います。
第2章 プロジェクト構成とアーキテクチャ
ハンズオンで作成するtodoアプリのプロジェクト構成を示すとともに、そこに落とし込まれている概念であるクリーンアーキテクチャについて触れます。
第3章 ドメイン駆動設計
ドメイン駆動設計の概要を知り、アプリケーションを設計してみます。
第4章 ドメイン層の実装
3章にて行ったドメイン駆動設計にそってドメイン層の実装を行います。ドメインオブジェクトとしてuser、taskを定義します。また、ドメインサービスを実装します。
第5章 アプリケーション層 ー ユースケースの実装
ユーザー、タスクそれぞれのCRUD処理のユースケースを記述していきます。リポジトリ・クエリサービスのインターフェースを用意し、それに依存する形でアプリケーションロジックを組んでいきます。
第6章 環境変数を管理する
7章以降で必要なため、github.com/kelseyhightower/envconfigパッケージを用いて環境変数を管理する実装を行います。
第7章 インフラストラクチャ層 ー データベース・キーバリューストア
リポジトリ・クエリサービスの実装を行う前に、リレーショナルデータベースとしてMySQLに接続するための処理を実装します。また、golang-migrateというマイグレーションツールを用いてテーブルを作成します。また、キーバリューストアであり、インメモリデータベースとして動作するRedisへの接続処理の実装も行います。
第8章 アダプター層 ー リポジトリの実装
5章で実装したリポジトリのインターフェースに基づいて実装していきます。また、ORMとしてsqlcを用いた諸々のセットアップも行います(インフラストラクチャ層に記述していきます)。また、dockertestを用いたテスト用DB環境を使ってリポジトリのテストを行います。
第9章 アダプター層 ー クエリサービスの実装
5章で実装したクエリサービスのインターフェースに基づいて実装していきます。また、「クエリサービスとは何か」を説明するとともに、リポジトリとは別にクエリサービスを実装する必要性を述べます。
第10章 認証・認可機能の実装
認証系の実装をどのようにすべきか・コードを配置する層を考え、実装していきます。
第11章 アダプター層 ー プレゼンテーション(プレゼンター・ハンドラー)の実装
5章で実装したユースケースを利用してハンドラを実装します。プレゼンテーションをプレゼンター/ハンドラーというように責務分けしており、JSONとしてレスポンスを形作る処理をプレゼンターに担わせ、ユースケースを呼び出す処理をハンドラーに担わせます。また、swaggoというツールを用いたAPIドキュメントの作成も行なっていきます。
第12章 アダプター層 ー ミドルウェア(ロギング・認可制御)の実装
エンドポイントへのリクエスト-レスポンスをログに残すためのロガーミドルウェアと、認可制御ミドルウェアを実装します。
第13章 インフラストラクチャ層 ー HTTPサーバー・ルーティングの実装
HTTPサーバー周りの処理(サーバーの起動、グレースフルシャットダウン等)と、ルーティング処理を実装します。また、実際にエンドポイントを叩いてハンドラーを呼び出し、レスポンスを確認することでエンドポイントがしっかり通っているかも確認します。
第14章 エンドポイントの統合テスト
エンドポイントへのリクエスト-レスポンスを確かめるテストを、ゴールデンテストという手法を用いたリグレッションテスト(回帰テスト)として行います。
ソースコード
ソースコードは以下です。適宜ご参照ください。