🥃

Go+Next.jsの構成で設計を考えてボイラープレートを組んだよ

2022/11/28に公開

木瓜丸です。
最近こんなツイートを見かけました。

木瓜丸「ただしい😐」

そこで、最近Go+Next.js(+PostgreSQLとかS3とか)みたいな構成でWebアプリの個人開発をやっているので、その構成で良く使う部分をまるごとボイラープレート化して公開してみることにしました。

https://github.com/boke0ya/boke0ya-monorepo-boilerplate

この記事では取り急ぎ、実装上の思想や意識している点をまとめておきたいと思います。よかったらアドバイスとか下さい。Forkして使って頂くのも大歓迎です!
※本記事ではデプロイの話はしません。

概要

本ボイラープレートでは、ユーザーのメール認証、ユーザー登録、ログイン、セッション管理、設定変更といった、ユーザー管理を伴うアプリケーションでは頻繁に実装する必要がある機能をあらかじめ実装しています。APIの設計はDDDに従い、フロントエンドでのコンポーネント管理にはAtomic Designを採用しています。

構成

API

  • Go
  • DB: PostgreSQL
  • Object Storage: AWS S3 (ローカル環境ではminioを採用)
  • SMTP: Gmail

画像などの保存にはS3を使用します。アップロードにはAWS S3互換のストレージで提供されているPresigned URLを使用します。
また、メール認証に用いるメールサーバーはGmailを利用します。

フロントエンド

  • Next.js(TypeScript)
  • sass-loader

スタイリングにはSCSS moduleを使用します。スタイリングがめんどくさい時にはフレームワークなどを採用して適宜導入して下さい。

全体のディレクトリ構成

.
├── Makefile
├── docker-compose.yml
├── README.md
├── api/
│   ├── cmd/
│   ├── internal/
│   ├── migrations/
│   ├── Dockerfile
│   ├── README.md
│   ├── go.mod
│   └── go.sum
├── data/
│   └── minio/
└── front/
    ├── components/
    ├── hooks/
    ├── libs/
    ├── pages/
    ├── public/
    ├── styles/
    ├── types/
    ├── README.md
    ├── next.config.js
    ├── package-lock.json
    ├── package.json
    ├── tsconfig.json
    └── yarn.lock

フロントエンドとDockerを起動するコマンドをMakeで作ってあります。DBのマイグレーションもMakeに書いてあります。

API

ディレクトリ構成はStandard Go Project Layoutを参考にしています。
DBのORMにはgormを採用し、マイグレーションは別途golang-migrateを採用しました。
全体的な設計思想としてはDDDを意識しており、api/cmd/main.goにて依存の注入を手動で行っています。

.
├── Dockerfile
├── README.md
├── cmd
│   └── main.go
├── go.mod
├── go.sum
├── internal
│   ├── adapters
│   ├── controllers
│   ├── entities
│   ├── errors
│   ├── infrastructures
│   ├── middlewares
│   └── usecases
└── migrations
    ├── 20221123153221_create_users_table.down.sql
    ├── 20221123153221_create_users_table.up.sql
    ├── 20221123153312_create_email_verifications_table.down.sql
    └── 20221123153312_create_email_verifications_table.up.sql

リクエストの流れとしては以下の通りです。
Controller (internal/controllersパッケージ)

Usecase (internal/usecasesパッケージ)

Entities (internal/entitiesパッケージ)

また、internal/adaptersパッケージでは外部サービス(GmailとS3)を扱うためのインターフェースが定義されています。internal/entitiesやinternal/adaptersで定義されたインターフェースはinternal/infrastructuresで実装され、cmd/main.goで注入されます。

フロントエンド

コンポーネント管理

コンポーネントの管理はAtomic Designに従いました。コンポーネント粒度の目安は以下の通りです。

Pages

APIとの通信やページ全体の状態を保持し、Template以下の粒度のコンポーネントに注入する役割を担います。

Template

Orgzanizations以下の粒度のコンポーネントを子に持ち、全体のデザインを定めます。
この時、表示にあたり必要なデータを状態として保持しません。(表示/非表示くらいはギリおkかなーと思うけど、それが全体のロジックに関係するならPagesから注入するべき)

Organizations

AtomsとMoleculesを組み合わせてレイアウトしたものです。
Organizationsより細かいコンポーネントではビジネスロジックにかかわる機能を持ってはいけません。

Molecules

AtomsやAtomsレベルの要素を組み合わせたものです。Molecules以下の粒度では使い回しを大前提として作成します。よって汎用性の高さが一つの切り出しの基準になります。

Atoms

ボタンや単一のテキスト、単体のフォームなどです。デザインツールで一つの箱で表現するくらいがAtomsにあたるかなと思います。

状態管理

以前記事にした状態管理手法を採用しています。よかったら見ていってください。
https://zenn.dev/boke0/articles/12e81125813b18

おわりに

ざっくり構成や設計思想をまとめてみました。詳細はコードを参照して頂けると嬉しいです。
コメント等もお待ちしています!

Discussion