0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【失敗3例】開発現場で今すぐ実践できる!ディレクトリ構造改善の教科書【完全保存版】

Posted at

目次

  1. なぜディレクトリ構造が重要なのか
  2. よくある3つの失敗パターン
  3. 現状分析の具体的な進め方
  4. 段階的改善の5ステップ実践法
  5. チーム全体で成功させる秘訣
  6. 明日から使える実例とテンプレート
  7. まとめ:継続的な改善サイクルを回そう

1. なぜディレクトリ構造が重要なのか

プログラミングを始めたばかりの頃、「とりあえず動けばいい」と思ってファイルを適当な場所に置いていませんか?最初は問題なくても、プロジェクトが大きくなると必ず壁にぶつかります。

ディレクトリ構造が崩れると起こる3大問題

問題1:探索時間の爆発的増加
「あのファイルどこだっけ?」と探す時間が1日30分だとすると、年間で約120時間も無駄にしています。これは3週間分の労働時間に相当します。

問題2:バグの温床化
似たような機能が5箇所に散らばっていると、修正漏れが発生します。1箇所直しても他の4箇所は古いままというケースが頻発します。

問題3:新メンバーの学習コスト増大
新しいメンバーがコードベースを理解するのに通常1〜2週間かかるところ、構造が悪いと1〜2ヶ月かかることも。これは組織の成長速度に直結します。

きれいなディレクトリ構造がもたらすメリット

  • 開発速度が30%向上:必要なファイルがすぐ見つかる
  • バグ発生率が40%減少:関連コードが集約されている
  • チーム拡大がスムーズ:誰が見ても理解できる

これらは実際の開発現場で報告されている数値です。構造を整えることは、単なる「見た目の問題」ではなく、ビジネス価値に直結する投資なのです。


2. よくある3つの失敗パターン

実際の現場で頻繁に見られる失敗例を見ていきましょう。あなたのプロジェクトに当てはまるものはありませんか?

失敗パターン1:「とりあえずutilsフォルダ」症候群

project/
├── utils/
│   ├── helper.js (1500行)
│   ├── common.js (2000行)
│   ├── functions.js (800行)
│   └── misc.js (1200行)

何が問題か
utilsやcommonという名前は「何でも入れていい魔法の箱」になりがちです。結果、5000行を超える巨大ファイルが生まれ、誰も触りたがらないレガシーコードになります。

実際の被害例

  • 「このバリデーション関数、どのutilファイルだっけ?」で毎回10分探す
  • 同じような関数が3箇所に重複していることに後で気づく
  • 1つのファイルを修正すると全く関係ない機能が壊れる

失敗パターン2:「階層の迷宮」化

project/
├── src/
│   ├── components/
│   │   ├── common/
│   │   │   ├── shared/
│   │   │   │   ├── base/
│   │   │   │   │   ├── core/
│   │   │   │   │   │   └── Button.jsx

何が問題か
6階層も潜らないとButtonコンポーネントにたどり着けません。これでは import文が ../../../../../ だらけになり、可読性が著しく低下します。

ベストプラクティス
一般的に、階層は3〜4層までに抑えるのが理想です。それ以上深くなったら、構造を見直すサインです。

失敗パターン3:「技術的分類」の罠

project/
├── controllers/
│   ├── userController.js
│   ├── productController.js
│   └── orderController.js
├── models/
│   ├── userModel.js
│   ├── productModel.js
│   └── orderModel.js
├── views/
│   ├── userView.js
│   ├── productView.js
│   └── orderView.js

何が問題か
技術的な層(MVC)で分けると、1つの機能を実装するのに3つのディレクトリを行き来する必要があります。ユーザー機能を修正するのに、controllers、models、viewsの3箇所を開かなければなりません。

より良いアプローチ
機能(ドメイン)ごとに分ける方が、実際の開発では効率的です:

project/
├── user/
│   ├── userController.js
│   ├── userModel.js
│   └── userView.js
├── product/
│   ├── productController.js
│   ├── productModel.js
│   └── productView.js

3. 現状分析の具体的な進め方

改善の第一歩は「現状を正確に把握すること」です。具体的な分析方法を見ていきましょう。

ステップ1:問題の可視化(30分でできる)

やること
チームメンバー3〜5人に以下の質問をします:

  1. 「先週、ファイルを探すのに困った経験は?」
  2. 「どのディレクトリが一番分かりにくい?」
  3. 「新しいファイルをどこに置くか迷うことは?」

記録方法
GoogleフォームやNotionで回答を集め、頻出する問題をリストアップします。

ステップ2:メトリクス測定

以下の数値を測定すると、問題の深刻度が見えてきます:

測定項目

  • 平均ファイル数(ディレクトリごと):理想は10〜15ファイル以下
  • 最大階層深度:理想は4階層以下
  • 1000行超えファイル数:理想は全体の5%以下
  • 命名パターンの一貫性:utils/helpers/common等の汎用名が全体の何%か

簡単な測定方法

# ファイル数をカウント
find src -type f | wc -l

# 階層の深さを確認
find src -type d | awk -F/ '{print NF}' | sort -n | tail -1

# 大きいファイルを探す
find src -type f -exec wc -l {} + | sort -rn | head -10

ステップ3:ゴール設定の具体例

問題が見えたら、測定可能な目標を設定します。

良いゴールの例

  • 「どのファイルも5秒以内に見つけられる」
  • 「新機能追加時に迷わずディレクトリを選べる」
  • 「ディレクトリ名から中身が80%推測できる」
  • 「1つのディレクトリに20ファイル以上置かない」

悪いゴールの例

  • 「きれいにする」(抽象的すぎる)
  • 「ベストプラクティスに従う」(何がベストか不明瞭)

4. 段階的改善の5ステップ実践法

ここからが本題です。実際にどう改善していくか、具体的な手順を解説します。

ステップ1:新規追加から始める(リスク:低)

なぜこれから始めるか
既存コードに手を入れず、新しく作るものだけルールを適用するため、リスクがほぼゼロです。

実践例:ユーザー認証機能を追加する場合

従来の配置

src/
├── utils/
│   └── auth.js (ここに追加してしまう)

新ルールでの配置

src/
├── features/
│   └── authentication/
│       ├── login.js
│       ├── logout.js
│       ├── validateToken.js
│       └── README.md (この機能の説明)

ポイント

  • 機能ごとに独立したディレクトリを作る
  • README.mdで責務を明確にする
  • 既存のauth.jsはそのまま残す(移行は後で)

ステップ2:独立モジュールの移行(リスク:中)

選定基準
以下の条件を満たすモジュールを選びます:

  1. 他のコードからの依存が少ない(3ファイル以下)
  2. 最近1ヶ月で変更がない(安定している)
  3. テストコードが存在する

実践例:日付処理ユーティリティの移行

移行前

src/
├── utils/
│   └── helper.js (この中に日付関数が10個)

移行後

src/
├── utils/
│   ├── helper.js (日付関数を削除)
│   └── dateUtils/
│       ├── formatDate.js
│       ├── parseDate.js
│       ├── calculateDuration.js
│       └── index.js (エクスポートをまとめる)

移行手順(所要時間:1時間)

  1. 新ディレクトリ作成(5分)

    mkdir -p src/utils/dateUtils
    
  2. 関数を個別ファイルに分割(30分)

    • helper.jsから日付関連関数をコピー
    • 各関数を独立ファイルに配置
    • index.jsで再エクスポート
  3. import文の更新(15分)

    // 変更前
    import { formatDate } from './utils/helper'
    
    // 変更後
    import { formatDate } from './utils/dateUtils'
    
  4. テスト実行(5分)

    npm test
    
  5. 古いコードを削除(5分)

    • helper.jsから日付関数を削除

ステップ3:テストで安全網を張る

なぜテストが重要か
ディレクトリ移動は、import文のパスが変わるため、予期しないエラーが発生しやすい作業です。テストがあれば、移動前後で動作が変わっていないことを確認できます。

最低限必要なテスト

// formatDate.test.js
import { formatDate } from './dateUtils'

test('日付を正しくフォーマットする', () => {
  const date = new Date('2025-01-15')
  expect(formatDate(date, 'YYYY-MM-DD')).toBe('2025-01-15')
})

test('nullを渡すとエラーを投げる', () => {
  expect(() => formatDate(null)).toThrow()
})

テストがない場合の対処法

  • 移動前に最低限のテストを追加する(1機能あたり10分程度)
  • E2Eテストで主要な画面が動くことを確認する

ステップ4:ドキュメント化して共有

作成すべきドキュメント(所要時間:30分)

1. ディレクトリ規約ガイド

# ディレクトリ構造ガイド

## 基本方針
- 機能ごとにディレクトリを分ける
- 1ディレクトリは15ファイル以下
- 階層は最大4層まで

## 配置ルール
### features/ - ビジネス機能
例:authentication, user-profile, payment

### components/ - UI部品
例:Button, Modal, FormInput

### utils/ - 汎用関数
例:dateUtils, stringUtils
※helper.js, common.jsは禁止

### services/ - 外部API連携
例:apiClient, authService

2. 移行チェックリスト

- [ ] 新ディレクトリ作成
- [ ] ファイル移動
- [ ] import文更新
- [ ] テスト実行(全て緑)
- [ ] レビュー依頼
- [ ] 古いファイル削除
- [ ] ドキュメント更新

ステップ5:レビューで徹底する

コードレビューのチェックポイント

## ディレクトリ構造チェック
- [ ] 新ファイルは適切なディレクトリに配置されているか
- [ ] ディレクトリ名は内容を表しているか(utils/helper禁止)
- [ ] 同じ責務のファイルが散らばっていないか
- [ ] 1ディレクトリが15ファイルを超えていないか

GitHubのPRテンプレートに追加

## ディレクトリ構造への影響
- [ ] 新しいディレクトリを追加した → なぜそのディレクトリが必要か説明
- [ ] 既存ファイルを移動した → 移行チェックリストを完了
- [ ] 影響なし

5. チーム全体で成功させる秘訣

個人の努力だけでは改善は続きません。チーム全体で取り組む仕組みを作りましょう。

秘訣1:定例ミーティングで進捗共有(週15分)

アジェンダ例

  1. 今週移行したモジュール報告(5分)
  2. 困っていること共有(5分)
  3. 来週の移行対象決定(5分)

成果の可視化
Notionやスプレッドシートで進捗を記録:

日付 移行対象 担当 ステータス 削減行数
1/15 dateUtils 田中 完了 300行
1/22 stringUtils 佐藤 進行中 -

秘訣2:「塩漬け」という選択肢

塩漬けとは
古くて安定しているコードは、あえて移行せずそのまま残す戦略です。

塩漬けにすべきコードの基準

  • 3ヶ月以上変更がない
  • 依存が複雑すぎる(10ファイル以上から参照されている)
  • ビジネス価値が低い(将来削除予定の機能)

実践例

src/
├── legacy/  (塩漬けゾーン)
│   └── oldHelper.js (触らない)
├── features/  (新規ルール適用)
│   └── authentication/

ポイント
完璧を目指さず、20%の改善で80%の効果を得る姿勢が大切です。

秘訣3:ツールによる自動化

1. ESLintでルールを強制

// .eslintrc.js
module.exports = {
  rules: {
    'no-restricted-imports': [
      'error',
      {
        patterns: [
          '**/utils/helper',  // helper.jsからのimportを禁止
          '**/utils/common',  // common.jsからのimportを禁止
        ]
      }
    ]
  }
}

2. 命名規則チェック

// lint-directory-names.js
const fs = require('fs')
const bannedNames = ['helper', 'common', 'misc', 'temp']

const dirs = fs.readdirSync('src', { withFileTypes: true })
  .filter(dirent => dirent.isDirectory())
  .map(dirent => dirent.name)

const violations = dirs.filter(name => 
  bannedNames.includes(name.toLowerCase())
)

if (violations.length > 0) {
  console.error('禁止されたディレクトリ名:', violations)
  process.exit(1)
}

package.jsonに追加:

{
  "scripts": {
    "lint:dirs": "node scripts/lint-directory-names.js",
    "precommit": "npm run lint:dirs"
  }
}

秘訣4:定期的な見直し(3ヶ月に1回)

チェックポイント

  1. 新ルールは守られているか?
  2. 不便な点は出てきていないか?
  3. 新たな問題は発生していないか?

見直しの会議(1時間)

  • 現状のメトリクスを再測定
  • チームメンバーからフィードバック収集
  • ルールの修正や追加を検討

6. 明日から使える実例とテンプレート

実際のプロジェクトタイプ別に、具体的なディレクトリ構造を紹介します。

パターン1:小規模Webアプリ(1〜3人、3ヶ月程度)

project/
├── public/           # 静的ファイル
├── src/
│   ├── components/   # UIコンポーネント
│   │   ├── Button.jsx
│   │   ├── Modal.jsx
│   │   └── Form.jsx
│   ├── pages/        # ページコンポーネント
│   │   ├── Home.jsx
│   │   ├── About.jsx
│   │   └── Contact.jsx
│   ├── utils/        # 汎用関数(最大3ファイル)
│   │   ├── format.js
│   │   └── validate.js
│   ├── api.js        # API通信
│   └── App.jsx       # ルートコンポーネント
└── package.json

特徴

  • シンプルで迷わない
  • 階層は最大3層
  • ファイル数が増えたら次のパターンへ移行

パターン2:中規模SPA(3〜10人、6ヶ月以上)

project/
├── src/
│   ├── features/              # 機能別(ドメイン別)
│   │   ├── authentication/
│   │   │   ├── components/
│   │   │   │   ├── LoginForm.jsx
│   │   │   │   └── RegisterForm.jsx
│   │   │   ├── hooks/
│   │   │   │   └── useAuth.js
│   │   │   ├── api.js
│   │   │   └── index.js
│   │   ├── user-profile/
│   │   │   ├── components/
│   │   │   ├── hooks/
│   │   │   └── api.js
│   │   └── dashboard/
│   ├── components/           # 共通UIコンポーネント
│   │   ├── Button/
│   │   │   ├── Button.jsx
│   │   │   ├── Button.test.js
│   │   │   └── Button.module.css
│   │   └── Modal/
│   ├── hooks/                # 共通カスタムフック
│   │   ├── useFetch.js
│   │   └── useLocalStorage.js
│   ├── utils/                # 純粋関数のみ
│   │   ├── date/
│   │   │   ├── format.js
│   │   │   └── parse.js
│   │   └── string/
│   ├── services/             # 外部サービス連携
│   │   ├── apiClient.js
│   │   └── analytics.js
│   └── App.jsx

特徴

  • 機能(features)を中心に構成
  • 機能内部で完結する設計
  • 共通部品は厳選

パターン3:大規模アプリ(10人以上、1年以上)

project/
├── packages/                  # モノレポ構成
│   ├── web/                  # Webアプリ
│   │   └── src/
│   │       └── features/
│   ├── mobile/               # モバイルアプリ
│   │   └── src/
│   ├── shared/               # 共通ロジック
│   │   ├── domain/           # ドメインロジック
│   │   │   ├── user/
│   │   │   └── product/
│   │   └── utils/
│   └── design-system/        # デザインシステム
│       └── components/
├── docs/                     # ドキュメント
│   ├── architecture.md
│   └── directory-guide.md
└── package.json

特徴

  • 複数アプリで共通コードを再利用
  • ドメインロジックを独立パッケージ化
  • チーム間の依存を明確化

実践的なファイル命名規則

良い命名例

✅ userAuthentication.js  (具体的)
✅ formatCurrency.js      (何をするか明確)
✅ validateEmail.js       (責務が単一)

悪い命名例

❌ helper.js              (何でも入る)
❌ utils.js               (抽象的すぎる)
❌ functions.js           (意味がない)
❌ misc.js                (miscellaneous = 雑多)

移行の優先順位マトリクス

どこから手をつけるべきか迷ったら、この表を参考にしてください:

優先度 条件 推奨アクション
最優先 毎日触る + 問題多い 今週中に移行
週1回触る + 問題あり 来月中に移行
月1回触る + 問題あり 四半期内に移行
ほぼ触らない 塩漬け検討

7. まとめ:継続的な改善サイクルを回そう

ディレクトリ構造の改善は、1回やって終わりではありません。継続的なサイクルとして回すことが成功の鍵です。

改善の3原則

1. 完璧を目指さない
80%の改善で十分です。残り20%に時間をかけるより、新機能開発に集中しましょう。

2. 小さく始める
全体をいきなり変えるのではなく、1週間に1モジュールのペースで進めます。

3. チームで決める
個人の好みではなく、チーム全体が納得したルールで運用します。

今日から始める3つのアクション

アクション1:現状を測定する(30分)

# プロジェクトルートで実行
find src -type f | wc -l
find src -name "*helper*" -o -name "*utils*" -o -name "*common*"

アクション2:チームに提案する(15分)
「来週のミーティングで、ディレクトリ構造について15分話し合いませんか?」とSlackで提案。

アクション3:次の新機能で新ルールを試す(実装時に適用)
新しく作る機能から、features/ディレクトリに配置してみる。

成功のための最終チェックリスト

✅ 現状の問題を3つリストアップした
✅ 測定可能なゴールを設定した
✅ チームメンバー3人以上と話した
✅ ドキュメントを作成した(簡単なもので可)
✅ 最初の移行対象を決めた(小さく始める)
✅ レビューでチェックする項目を決めた
✅ 3ヶ月後の見直し日をカレンダーに入れた

最後に

ディレクトリ構造の改善は、地味ですが確実に開発体験を向上させます。1年後には「あの時頑張ってよかった」と必ず思えるはずです。

大切なのは、完璧な構造を作ることではなく、チームが迷わず開発できる状態を維持することです。

あなたのプロジェクトが、より快適な開発環境になることを願っています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?