こんにちは。AWS事業本部モダンアプリケーションコンサルティング部に所属している今泉(@bun76235104)です。
設計書は作った。だが更新されているとは言っていない。
そんな体験ありませんか?私はあります。
人間が手動でやる必要がない作業はあると思いますので、PrismaというORMを利用して、ER図をMermaid.jsの仕組みで生成するライブラリを試してみました。
ついでにER図のコミット漏れを防ぐためのGitHub Actionsの設定を書いてみましたので共有します。
先に結論!!
こちら長いので折り畳みますが、以下のようにPrismaのスキーマファイルを記述しています。
schema.prisma
schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
// ER図生成用途で追加
generator erd {
provider = "prisma-erd-generator"
theme = "forest"
output = "ERD.md"
includeRelationFromFields = true
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
userId String @id @default(uuid())
userProfile UserProfile?
userActive UserActive?
userDeleted UserDeleted?
posts Post[]
}
model UserActive {
userId String @id
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model UserProfile {
userId String @id
name String
firstName String
lastName String
middleName String
age Int
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model UserDeleted {
userId String @id @default(uuid())
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model Post {
title String @id
userId String
user User @relation(fields: [userId], references: [userId])
}
以下のコマンドでマイグレーションを行うとER図が生成されます。
prisma migrate dev #prisma generate でもOKです
出力されるmermaid.jsのER図
erDiagram
"User" {
String userId "?️"
}
"UserActive" {
String userId "?️"
DateTime createdAt
}
"UserProfile" {
String userId "?️"
String name
String firstName
String lastName
String middleName
Int age
DateTime createdAt
}
"UserDeleted" {
String userId "?️"
DateTime createdAt
}
"Post" {
String title "?️"
String userId
}
"User" o{--}o "UserProfile" : "userProfile"
"User" o{--}o "UserActive" : "userActive"
"User" o{--}o "UserDeleted" : "userDeleted"
"User" o{--}o "Post" : "posts"
"UserActive" o|--|| "User" : "user"
"UserProfile" o|--|| "User" : "user"
"UserDeleted" o|--|| "User" : "user"
"Post" o|--|| "User" : "user"
何が嬉しいのか
- 実際のスキーマファイルに従って自動でER図が生成される
- ブランチがマージされる度にER図を書き直す必要がありません
- mermaid.jsの形式で出力可能であるため、GitHubでもER図を表示できます
- 開発者の近くにドキュメントがあるというのは非常に重要なことだと考えています
- いつでもER図で思考を整理できます
- mermaid.jsの形式で出力可能であるため、次の設計の検討時にも利用できます(個人的に重要)
- 出力されたマークダウンに記載されている
mermaid.js
のerDiagram
の部分をコピーして追加したい列やテーブルを追記できます - GitHubのIssueで仕様のやりとりをするのにもピッタリだと思いました
- 出力されたマークダウンに記載されている
参考にした記事
今回prisma-erd-generator
というライブラリを利用させていただいたのですが、存在を知ったのはこちらのZennの記事のおかげです。
@terrierscript さんありがとうございます。
手順
以下に手順を記載します。
設定ファイルやその他ファイルの全容を確認したい方は、以下のリポジトリをご覧ください。
前提条件
私のローカルPCはMacを利用しています。
Windows環境などでは未検証ですが、ご了承ください。
その他 node
や npm
コマンドも利用可能な状態という前提で記事を執筆しています。
Key | Value |
---|---|
OS | macOS Monterey |
npm | 9.7.1 |
prismaの導入
Quickstart with TypeScript & SQLiteを参考に、Prismaの初期設定をします。
npm init -y
npm i -D prisma
また、今回SqLiteではなくMySQLを利用したかったため、docker-compose.yml
を以下のように用意します。
version: '3'
services:
database:
image: mysql:8
container_name: db
command: --default-authentication-plugin=mysql_native_password
ports:
- '3306:3306'
volumes:
- db-volume-sample:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 'password' #本番でこのようにパスワードを利用・直書きはやめましょう
MYSQL_DATABASE: sample
volumes:
db-volume-sample:
以下コマンドでコンテナを立ち上げます。
docker compose up
次に以下のようにPrismaの設定ファイルを用意しておきます。
prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
userId String @id @default(uuid())
userProfile UserProfile?
userActive UserActive?
userDeleted UserDeleted?
posts Post[]
}
model UserActive {
userId String @id
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model UserProfile {
userId String @id
name String
firstName String
lastName String
middleName String
age Int
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model UserDeleted {
userId String @id @default(uuid())
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [userId])
}
model Post {
title String @id
userId String
user User @relation(fields: [userId], references: [userId])
}
.env
ファイルには以下のようにDBの情報を記載しておきます。
DATABASE_URL="mysql://root:password@localhost:3306/sample"
ここまでの状態で、npx prisma migrate dev
を実行することで、DBに User
テーブルなどが作成されれば準備OKです。
prisma-erd-generatorの設定
次にprisma-erd-generatorのインストールをします。
GitHubのReadmeに記載のとおり、以下コマンドを実行します。
npm i -D prisma-erd-generator @mermaid-js/mermaid-cli
ただし、後ほどER図の生成時に以下のライブラリが足りないとエラーが出たため追加で以下のインストールも行いました。
# エラーの内容
Error: Cannot find module '@prisma/generator-helper'
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
# 追加でインストールしました
npm i -D @prisma/generator-helper
次に prisma/schema.prisma
に以下を追記します。
prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
// これを追記しました
generator erd {
provider = "prisma-erd-generator"
theme = "forest"
output = "ERD.md"
includeRelationFromFields = true
}
これで準備OKです。
以下コマンドを実行することで prisma/ERD.md
が生成されました。
npx prisma generate
出力されるmermaid.jsのER図
erDiagram
"User" {
String userId "?️"
}
"UserActive" {
String userId "?️"
DateTime createdAt
}
"UserProfile" {
String userId "?️"
String name
String firstName
String lastName
String middleName
Int age
DateTime createdAt
}
"UserDeleted" {
String userId "?️"
DateTime createdAt
}
"Post" {
String title "?️"
String userId
}
"User" o{--}o "UserProfile" : "userProfile"
"User" o{--}o "UserActive" : "userActive"
"User" o{--}o "UserDeleted" : "userDeleted"
"User" o{--}o "Post" : "posts"
"UserActive" o|--|| "User" : "user"
"UserProfile" o|--|| "User" : "user"
"UserDeleted" o|--|| "User" : "user"
"Post" o|--|| "User" : "user"
テーブル規模が大きくなると、もっとごちゃついてくると思いますが、スキーマから自動で生成してくれるのは非常にありがたいですね。
おまけ ER図のコミット漏れに気づく仕組み
prisma/ERD.md
は prisma migrate dev
コマンドでも生成・更新されます。
Prisma Migrate in development and productionにもあるとおり、通常開発環境でマイグレーションを実行したい場合 prisma migrate dev
を実行されると思います。
そのたびprisma/ERD.md
も更新されると思うのですが、うっかりコミットを漏らしてしまうとスキーマファイルとER図に乖離が生じる可能性があります。
そこで、GitHub Actionsの設定ファイルを追加して、ER図のコミット漏れを検知する仕組みを考えてみました。
まず package.json
にER図を生成するためのscripts
を定義しています。
package.json
{
"name": "prisma-cicd",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@mermaid-js/mermaid-cli": "^10.2.2",
"@prisma/generator-helper": "^4.16.1",
"@types/node": "^20.3.2",
"prisma-erd-generator": "^1.6.2",
"ts-node": "^10.9.1",
"typescript": "^5.1.3"
},
"scripts": {
// ER図生成のためのコマンドをscriptsに定義
"erd": "prisma generate"
},
"dependencies": {
"@prisma/client": "4.16.1",
"prisma": "^4.16.1"
}
}
そして、以下のように .github/workflows/check_er.yml
を準備します。
.github/workflows/check_er.yml
name: Pull Request Check
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 20
- run: npm install
- name: makeERD
run: |
npm run erd
- id: checkErdDiff
run: echo "changed=$(git diff --name-only prisma/ERD.md)" >> $GITHUB_OUTPUT
- run: echo ${{ steps.checkErdDiff.outputs.changed}}
- if: ${{ steps.checkErdDiff.outputs.changed != '' }}
run: |
echo "ERD.md has changed.Please update ERD.md and commit it."
exit 1
これによりPullリクエスト作成時に実際にスキーマファイルからER図を生成してdiffをチェックしています。
私が実際に「スキーマでテーブルに列を追加したけどERD.mdをコミットせずにPull Requestを作成した」際には以下のように、更新漏れを検知してくれました。
また、きちんとERD.mdの変更をコミットして再度プッシュすることで、このCIが通ることを確認しました。
さいごに
ER図が自動で生成される仕組みを試してみました。
大規模なプロジェクトだとER図はかなりごちゃつくとは思いますが、だからこそ人間が手動で更新し続けるのは難しいと思うので、試してみたい課題だなと感じました。
昨今ではSwagger-UIなどを利用して、OpenAPI仕様を自動で生成するなど、人間が手で更新してきていた仕組みを自動化する仕組みがありますよね。
今後もこれらを活用して、開発者が本当に価値あることに集中できるような仕組みづくりを試していきたいと思います。
以上、今泉でした。最後まで見ていただきまして、本当にありがとうございました。