コーディング規約
Bazbiiプロジェクトのコーディング規約とスタイルガイドを説明します。
コーディング規約の概要
言語別の規約
- Go: Go標準のコーディング規約(gofmt、go vet)
- TypeScript: ESLint + TypeScript標準規約
- Protocol Buffers: buf lintによるチェック
自動フォーマット
すべてのコードは自動フォーマットツールで統一します。
Goコーディング規約
基本方針
- gofmt: コードフォーマットは自動化
- go vet: 静的解析を実行
- 命名規則: Go標準の命名規則に従う
命名規則
パッケージ名
// ✅ 良い例
package post
package postgres
package logmsg
// ❌ 避けるべき例
package postService // 冗長
package PostService // 大文字で始まらない
型名
// ✅ 良い例
type Post struct { ... }
type PostService struct { ... }
type PostID uuid.UUID
// ❌ 避けるべき例
type post struct { ... } // 公開型は大文字で始める
関数名
// ✅ 良い例
func CreatePost(ctx context.Context, input CreateInput) (PostID, error)
func (s *Service) CreateUserPost(ctx context.Context, input CreateInput) (PostID, error)
// ❌ 避けるべき例
func create_post(...) // スネークケースは使わない
エラーハンドリング
// ✅ 良い例
id, err := service.CreatePost(ctx, input)
if err != nil {
return nil, err
}
// ❌ 避けるべき例
id, _ := service.CreatePost(ctx, input) // エラーを無視しない
Context使用
// ✅ 良い例
func (r *Repo) FindByID(ctx context.Context, id PostID) (*Post, error) {
// ctxを下位レイヤーに渡す
return r.db.QueryContext(ctx, query, id)
}
// ❌ 避けるべき例
func (r *Repo) FindByID(id PostID) (*Post, error) {
// contextを省略しない
}
インターフェース設計
// ✅ 良い例: 小さいインターフェース
type PostRepository interface {
FindByID(ctx context.Context, id PostID) (*Post, error)
Insert(ctx context.Context, post Post) (PostID, error)
}
// ❌ 避けるべき例: 大きなインターフェース
type Repository interface {
FindPostByID(...)
FindUserByID(...)
FindAllPosts(...)
// 多くのメソッド
}
コメント
// ✅ 良い例
// CreateUserPost creates a new post by a user.
// It validates the input and emits a domain event on success.
func (s *Service) CreateUserPost(ctx context.Context, input CreateUserPostInput) (PostID, error) {
...
}
// ❌ 避けるべき例
// create post // 簡潔すぎる、英語でない
func CreatePost(...) { ... } // コメントなし
コードフォーマット
# 自動フォーマット
make go/fmt
# 静的解析
make go/vet
TypeScriptコーディング規約
基本方針
- ESLint: コード品質チェック
- Prettier: コードフォーマット(検討中)
- TypeScript: 型安全性を重視
命名規則
変数・関数
// ✅ 良い例(camelCase)
const postId = "123";
function createPost(input: CreatePostInput): Promise<Post> { ... }
// ❌ 避けるべき例
const post_id = "123"; // スネークケース
const PostId = "123"; // パスカルケース(型名以外)
型・インターフェース
// ✅ 良い例(PascalCase)
interface CreatePostInput {
h3Hex: string;
text: string;
}
type PostID = string;
// ❌ 避けるべき例
interface createPostInput { ... } // 小文字で始まらない
コンポーネント
// ✅ 良い例(PascalCase)
export function PostCard({ post }: { post: Post }) {
return <div>...</div>;
}
// ❌ 避けるべき例
export function postCard(...) { ... } // 小文字で始まらない
型定義
// ✅ 良い例: 明示的な型定義
function createPost(input: CreatePostInput): Promise<Post> {
...
}
// ❌ 避けるべき例: anyの使用
function createPost(input: any): any {
...
}
非同期処理
// ✅ 良い例: async/await
async function fetchPost(id: PostID): Promise<Post> {
const response = await fetch(`/api/posts/${id}`);
return response.json();
}
// ❌ 避けるべき例: Promiseチェーン
function fetchPost(id: PostID): Promise<Post> {
return fetch(`/api/posts/${id}`).then(res => res.json());
}
エラーハンドリング
// ✅ 良い例
try {
const post = await createPost(input);
return post;
} catch (error) {
console.error("Failed to create post:", error);
throw error;
}
// ❌ 避けるべき例
const post = await createPost(input); // エラーハンドリングなし
コードフォーマット
# ESLintチェック
pnpm lint
# 自動修正
pnpm lint --fix
Protocol Buffers規約
ファイル構造
// ✅ 良い例
syntax = "proto3";
package bazbii.post.v1;
option go_package = "go.bazbii.app/packages/proto-gen-go/bazbii/post/v1";
message CreateRequest {
string h3_hex = 1;
string text = 2;
}
命名規則
- メッセージ: PascalCase
- フィールド: snake_case
- サービス: PascalCase
- メソッド: PascalCase
バージョニング
// パッケージ名でバージョン管理
package bazbii.post.v1;
package bazbii.post.v2;
リントチェック
# Protocol Buffersリント
make proto/lint
# 破壊的変更チェック
make proto/breaking
コーディング規約のチェック
自動チェック
# Goコード品質チェック
make go/fmt # フォーマットチェック
make go/vet # 静的解析
# TypeScriptコード品質チェック
pnpm lint
# Protocol Buffersチェック
make proto/lint
コミット前チェック
開発ワークフローで以下のチェックを実行:
- フォーマットチェック:
make go/fmt - 静的解析:
make go/vet - テスト実行:
make go/test - リントチェック:
pnpm lint,make proto/lint
コードレビュー方針
レビューチェックリスト
- コーディング規約に準拠しているか
- 適切なエラーハンドリングがされているか
- テストが追加されているか
- ドキュメントが更新されているか
- セキュリティ上の問題がないか
レビューの優先事項
- 機能性: 要件を満たしているか
- テスト: 適切にテストされているか
- 保守性: 将来の変更に対応できるか
- パフォーマンス: パフォーマンスに問題がないか
ベストプラクティス
1. 一貫性の維持
- 同じパターンを使い回す
- 既存のコードスタイルに合わせる
2. 可読性の重視
- 明確な変数名・関数名
- 適切なコメント(なぜそうするか)
3. 型安全性
- 型を明示的に定義
- anyの使用を避ける
4. エラーハンドリング
- エラーを無視しない
- 適切なエラーメッセージ