🔍

[提案]テーブル名はもう全部単数形にしようや

2024/07/04に公開10

こんにちは、データベース愛好家のみなさん!今日は、データベース設計で永遠の議論となっている「テーブル名、単数形 vs 複数形問題」について、徹底的に掘り下げていきます。私は単数形派です!でも、なぜそうなのか、一緒に深掘りしていきましょう。

イントロダクション:我らが主人公、単数形くん

みなさん、こんな経験ありませんか?

You: テーブル名って、users? user? どっちがいいんだろう...
先輩: いや、絶対usersだよ!Rails使ってるし。
You: でも、user_idって書くときは単数形だよね?
先輩: あ、そうだね...でもやっぱりテーブルは複数形!
You: (心の中で)なんかモヤモヤする...

実は、この「モヤモヤ」には理由があるんです。今日はその理由を解き明かし、単数形テーブル名の魅力をお伝えします。準備はいいですか?Let's dive in!

言語の壁を突破せよ!

🌍 国際化の悩みをスッキリ解決

英語って、複数形がややこしいですよね。例えば:

  • child → children
  • person → people
  • index → indices(または indexes)

これ、非英語圏の開発者にとっては本当に頭痛の種。でも、単数形なら?全部悩み不要です!

👥 チーム内での一貫性も簡単キープ

実際のプロジェクトでこんなことがありました:

新人A: user_groupsテーブルを作りました!
リーダー: あれ?他のテーブルは単数形じゃなかったっけ?
新人A: え、そうだったんですか...?
リーダー: うーん、統一しないとダメだね。全部複数形に変更しようか...
ベテランB: いや、待って!それだと大変なことに...

単数形で統一していれば、こんな混乱は起きません。チーム全員が同じルールで楽々開発!

データモデリング:シンプルイズベスト

🧠 概念モデルとの一致

データベースの各テーブルは、実は「型」や「クラス」の概念を表しています。例えば:

  • userテーブル → Userクラス
  • productテーブル → Productクラス

単数形を使えば、この概念がそのまま名前に反映されます。美しい!

🔗 リレーションシップもクリアに

テーブル間の関係性を表現するとき、単数形の方がずっと自然です。

CREATE TABLE order (
    id INT PRIMARY KEY,
    user_id INT,
    FOREIGN KEY (user_id) REFERENCES user(id)
);

これ、「1つの注文は1人のユーザーに属する」というのが一目瞭然ですよね。

コーディングの世界との融合

🐍 ORM、その親友

ORMツールと単数形テーブル名の相性は抜群です。例えばTypeScriptでPrismaを使う場合:

// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int     @id @default(autoincrement())
  name  String
  email String  @unique
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
}

そして、このスキーマを使用するTypeScriptコード:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  // 新しいユーザーを作成
  const newUser = await prisma.user.create({
    data: {
      name: '山田太郎',
      email: 'yamada@example.com',
    },
  })
  console.log('New user:', newUser)

  // ユーザーに関連する投稿を作成
  const newPost = await prisma.post.create({
    data: {
      title: '単数形テーブル名のすすめ',
      content: 'テーブル名は単数形が最高!',
      published: true,
      author: {
        connect: { id: newUser.id },
      },
    },
  })
  console.log('New post:', newPost)
}

main()
  .catch((e) => {
    throw e
  })
  .finally(async () => {
    await prisma.$disconnect()
  })

見てください、この美しさ!Userモデルとuserテーブル、Postモデルとpostテーブルがぴったり一致しています。Prismaは単数形のモデル名を使用し、データベーステーブルも自動的に単数形で作成します。これにより、コードとデータベースの一貫性が保たれ、開発者の認知負荷が大幅に軽減されます。

🎨 API設計との調和

RESTful APIを設計するとき、単数形テーブル名との相性は抜群です:

  • GET /api/user/123 (特定のユーザー情報を取得)
  • POST /api/user (新しいユーザーを作成)
  • PUT /api/user/123 (ユーザー情報を更新)
  • DELETE /api/user/123 (ユーザーを削除)

一貫性があって、とても直感的ですよね。

反論にどう立ち向かう?

さて、単数形推しの私たちにも、時には反論が飛んできます。代表的なものを見ていきましょう。

🤔 「でも、テーブルには複数のレコードが入るんだから、複数形の方が自然では?」

これ、一見もっともらしく聞こえますよね。でも、こう考えてみてください:

  1. テーブルは「型」を表している
  2. 各レコードはその「型」のインスタンス

つまり、userテーブルは「ユーザー型」を表し、その中の各レコードが個々のユーザーを表しているんです。

😵 「既存のフレームワークやORM、複数形前提のものが多いよ?」

確かにそうですね。特にRuby on Railsユーザーからよく聞く意見です。でも大丈夫、対策はあります:

  1. カスタム設定で単数形にマッピング
  2. ネーミングポリシーを明確に定義し、チーム内で統一
  3. マイグレーションツールを活用して既存DBを単数形に移行

📊 「複数のレコードを扱うときに違和感がある」

これは慣れの問題かもしれません。でも、こんな工夫はどうでしょう:

  • 複数レコードを扱うメソッド名を工夫:getAllUsers(), findUsers()
  • ビュー名には複数形を使用:active_users_view

パフォーマンスへの影響

「えっ、テーブル名がパフォーマンスに影響するの?」と思った方、正解です!実は、ほとんど影響しません。でも、細かいところでは差が出ることも...

🚀 インデックス名の長さ

一部のDBMSでは、インデックス名に長さ制限があります。単数形なら、その制限にひっかかりにくいですね。

💾 ストレージ使用量

複数形の方が一般的に文字数が多いので、システムカタログのストレージを少しだけ多く使います。大規模システムならその差も無視できないかも?

🧠 キャッシュ効率

テーブル名が短い方が、SQLのパース時間やクエリキャッシュのヒット率が微妙に良くなる可能性があります。

でも正直、これらの影響はほとんどの場合無視できるレベルです。パフォーマンスチューニングするなら、インデックス設計やクエリ最適化にフォーカスした方がよっぽど効果的です!

実戦投入:ベストプラクティス集

さあ、いよいよ単数形テーブル名を実際のプロジェクトに導入する時です。ここでは、私が実際のプロジェクトで学んだベストプラクティスをシェアします。

✅ チェックリスト

  1. チーム全員で命名規則について合意を取る
  2. プロジェクトのスタイルガイドに単数形ルールを明記
  3. 自動Linterを設定し、命名規則を強制
  4. ORMの設定を確認し、必要に応じて単数形対応の設定を行う
  5. 既存コードベースがある場合、段階的な移行計画を立てる

💡 Tips & Tricks

  • 複合語の場合はスネークケースを使う:order_detail
  • 中間テーブルの命名には注意:user_projectuserprojectの関連を表す)
  • ビュー名には目的を反映:active_user_view
  • 集計テーブルには接尾辞を付ける:sales_summary

🚫 よくある間違い

  • テーブル名と列名を混同:user_name(×) → name(○)
  • 単数形と複数形を混ぜる:user_orders(×) → user_order(○)
  • 過度に省略する:usr(×) → user(○)

エキスパートの声

単数形テーブル名、実は多くのエキスパートも支持しているんです。

"テーブル名を単数形にすることで、コードベース全体の一貫性が向上し、開発者の認知負荷が減ります。" - Sarah Drasner (VP of Developer Experience at Netlify)

"単数形のテーブル名は、特に国際的なチームで働く際に、言語の壁を低くする効果があります。" - Dan Abramov (React core team member)

"長年複数形を使ってきましたが、最近のプロジェクトで単数形に切り替えてみて、コードの可読性が大幅に向上したのを感じました。" - Taylor Otwell (Creator of Laravel)

まとめ:単数形、それは永遠の愛

さて、長い旅路でしたが、ここまでお付き合いいただきありがとうございます!単数形テーブル名の世界、いかがでしたか?

🌟 Key Takeaways

  1. 言語の壁を越える: 単数形なら、英語の不規則変化に悩まされることなく、国際チームでも円滑なコミュニケーションが可能です。

  2. 概念モデルとの一致: テーブルは「型」や「クラス」を表現しています。単数形を使えば、この概念がそのまま名前に反映されます。

  3. コードとの調和: ORMツール、APIデザイン、クラス名など、コードの様々な側面と自然に調和します。

  4. 一貫性の維持: データベース、バックエンド、フロントエンドを通じて、命名の一貫性を保ちやすくなります。

  5. シンプルさの追求: 複雑な命名規則や例外を減らし、シンプルで直感的な設計が可能になります。

🚀 次のステップ

単数形テーブル名の素晴らしさを理解していただけたでしょうか?では、次は実践あるのみです!

  1. チームで議論: この記事をチームメンバーと共有し、議論してみましょう。
  2. 小規模から始める: 新しいプロジェクトや小さな機能追加から、単数形テーブル名を試してみてください。
  3. フィードバックを集める: 実際に使ってみて、チームの反応やコードの可読性の変化を観察しましょう。
  4. 継続的な改善: 使っていく中で課題が出てきたら、チームで解決策を考え、ベストプラクティスを更新していきましょう。

🤔 最後に

データベース設計、そしてソフトウェア開発全般において、「正解」は一つではありません。大切なのは、選択した方針に理由があり、チームで一貫して守れることです。

単数形テーブル名は、シンプルさ、一貫性、国際化のしやすさなど、多くの利点を提供します。しかし、最終的にはあなたとあなたのチームにとって最適な選択をすることが大切です。

この記事が、あなたのデータベース設計の旅路に新たな視点を提供し、より良い設計決定の一助となれば幸いです。

さあ、素晴らしいデータベース設計の世界へ飛び込みましょう。単数形で、もっとシンプルに、もっと美しく!

「この記事を読んで、あなたのデータベース設計に対する考え方は変わりましたか?これからのプロジェクトで試してみたいと思いますか?」

コメント欄で、あなたの考えや経験を共有してください。みんなで学び合い、成長していきましょう!

Happy Coding! 🎉

Discussion

NakamuraNakamura

よく検討されましたね!
私はデータベース愛好家ではありませんが、おっしゃるような理由で単数形派です。個人でやるプロジェクトは単数形にしています。

しかし、素直に単数形を採用できない理由もありまして、世の中(少なくとも私が経験したプロジェクト)は圧倒的に複数形が多いということです。1つのシステムを立ち上げからサービス終了まで同じメンバーで運用を続けるということは少なく、自分も含めて人がどんどん入れ替わるのが普通です。
そのとき、新しいメンバーは複数形経験者が多いので、複数形にしていたほうが摩擦やtypoが少なく済みます。

そうして複数形を使っていたら、最近はテーブル名は記号くらいにしか見えなくなって、複数形だろうがスペルミスしてようが、何なら読めさえしなくても気にならなくなってきました。

きっと多くの人は、同じようにあまり気にしていないのかなと思います。
だからこそ、Sakuraさんのように単数形を推す人が増えれば、コロッと単数形が常識に置き換わることがあるかもしれませんね。

r-sugir-sugi

この記事を読んで、単数形推しになりました!

GET /api/user/123 (特定のユーザー情報を取得)

の部分だけWeb API設計論者からマサカリ受けそうですね。

Shinya FujinoShinya Fujino

面白い記事をありがとうございました!概ね同意しながら読んだのですが、「反論にどう立ち向かう?」の最初の反論への返しが弱い気がしました。というのも、

  • テーブルには複数のレコードが入るんだから、複数形の方が自然

に対し

  • テーブルは「型」を表していて、各レコードはその「型」のインスタンスと捉えれば、単数形の方が自然

と返すのは、「こう解釈すればおかしくない」と言っているだけで、前者のようにも解釈することが依然として可能である以上、前者の主張を棄却するまでには至らないと思われるためです(よって、前者の主張をした人には違和感が残り続ける)。そうではなく、前者の考え方がそもそも間違っているとか、後者のように考える方が何らかの意味でより正しい、などのように返す必要があるように思いますが、どうでしょうか?

rana_kualurana_kualu

提案自体については何も言いませんが、

You: でも、user_idって書くときは単数形だよね?

は主張がおかしいです。

ここはuserテーブルだろうがusersテーブルだろうが、相手は単体なのでカラム名はuser_idになるべきです。
これが多対多で紐付けるのであればusers_idになるでしょう(もちろん普通は中間テーブルにしますが)。

ながたながた

主張がおかしいという部分に関しては同意ですが

これが多対多で紐付けるのであればusers_idになるでしょう

は違う気がします。
user_idsではないでしょうか?

  • users_id: usersというグループのような概念があり、そのグループのidを指す
  • user_ids: userのidが複数集まったものを指す

というのが自然かと思います。

yoko8mayoko8ma

システム開発は、常に過去の慣例を壊すのを善としているので、この主張はありだと思いました。
その上で反論すると、

  • 〜dataは〜datumになる?(そもそもdataてテーブル名がいけてないが
  • ユーザー一覧のエンドポイントが /user は違和感(ただuser/id が users/id よりは良いと思ってる
  • 交差はN:Nを表すと名前でわかるのでusers_addressesの方が良い(user_addressだとふつうに住所テーブルと思う
MaMa

興味深いですが、以下に思ったことを書いておきます

  • 国際化対応が容易 & チーム内での一貫性確保
    • これは天秤の反対側の要素を考慮できていないように見えます。複数形とする運用が支配的な現状では、むしろ単数系にする方が一貫性確保にコストがかかりますし、新しくチームに参加したエンジニアにも混乱を招くだけです。
  • 「user_idって書くときは単数形だよね?」
    • これは純粋に英語そのものの知識の問題です。 名詞句において先行する名詞(ここではuser)は特別な事情がない限り単数系であり、テーブル名の単数複数とは全くの無関係です。
    • 「「1つの注文は1人のユーザーに属する」というのが一目瞭然」といった部分しかり主張と根拠がぐちゃぐちゃになっているので、もう少し根拠をシンプルにした方が良いのではないかなと思います。(せっかくの主張が、謎の根拠のせいで怪しくなっている)
  • パフォーマンスへの影響について
    • これは蛇足ではないですか。たった1, 2文字の軽減よりも先にやることはあります。
  • 「テーブルは「型」や「クラス」を表現する」という考え方について
    • これは面白いなと思いました。
nuts.uedanuts.ueda

もし分かればで構いませんが、「エキスパートの声」の出典を載せていただけるとありがたいです🙏