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?

Web系開発で知るべき10の"分離"パターン:現場で使える優先順3ヶ月ガイド

Posted at

目次

  1. なぜ「分離」が重要なのか
  2. 現場で遭遇する順番で学ぶ10の分離
    • レベル1:最初に出会う基本の分離(Day1から)
    • レベル2:チーム開発で必須の分離(1ヶ月目)
    • レベル3:サービス成長で必要になる分離(3ヶ月目以降)
  3. 実践チェックリスト
  4. まとめ

1. なぜ「分離」が重要なのか

スタートアップで開発していると、こんな場面に遭遇します:

  • 「ボタンの色変えたいだけなのに、なんでバックエンドも触らないといけないの?」
  • 「本番のパスワードがコードに書いてあって、GitHub に上がってる...」
  • 「エンジニア2人追加したいけど、みんな同じファイル触るから競合しまくる」

これ、全部「分離不足」が原因です。

分離とは**「変更の影響範囲を限定すること」**。適切に分離されていると:

  • 開発スピードが上がる(担当を分けて並行作業できる)
  • バグが減る(変更箇所が明確で影響範囲が予測できる)
  • 新メンバーが理解しやすい(どこを見ればいいかわかる)

逆に分離できていないと、ちょっとした修正で全体が壊れ、レビューに時間がかかり、デプロイが怖くなります。


2. 現場で遭遇する順番で学ぶ10の分離

レベル1:最初に出会う基本の分離(Day1から)

1-1. 設定値とコードの分離

優先度:★★★★★(最優先)

何が問題?

// ❌ ダメな例
function connectDB() {
  return mysql.connect('localhost', 'root', 'password123');
}

パスワードがコードに直書き。これをGitHubに上げたら情報漏洩です。

どう分離する?

// ✅ 良い例
// .env ファイル(Gitには上げない)
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password123

// コード
function connectDB() {
  return mysql.connect(
    process.env.DB_HOST,
    process.env.DB_USER,
    process.env.DB_PASSWORD
  );
}

現場での使い方:

  • .env ファイルに環境ごとの設定を書く
  • .gitignore.env を追加(絶対にコミットしない)
  • .env.example を作って必要な項目だけ共有

いつ使う? プロジェクト開始の初日から必須。


1-2. 表示とデータの分離

優先度:★★★★★(最優先)

何が問題?

// ❌ ダメな例
function showUserList() {
  const users = [
    { id: 1, name: 'Alice', age: 25 },
    { id: 2, name: 'Bob', age: 30 }
  ];
  
  return '<ul><li>Alice (25)</li><li>Bob (30)</li></ul>';
}

データ取得と表示が混ざってる。デザイン変更でロジックを触ることになります。

どう分離する?

// ✅ 良い例
// データ取得
function getUsers() {
  return [
    { id: 1, name: 'Alice', age: 25 },
    { id: 2, name: 'Bob', age: 30 }
  ];
}

// 表示(React の例)
function UserList() {
  const users = getUsers();
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name} ({user.age})</li>
      ))}
    </ul>
  );
}

現場での使い方:

  • データ取得関数とコンポーネントを分ける
  • デザイナーが触るのは表示部分だけ

いつ使う? 画面を作る最初から。


1-3. フロントエンド・バックエンド分離

優先度:★★★★★(最優先)

何が問題?

昔はPHPやRailsで全部やってました:

<!-- ❌ 古い方法 -->
<h1>ユーザー一覧</h1>
<?php foreach($users as $user): ?>
  <div><?= $user['name'] ?></div>
<?php endforeach; ?>

これだと:

  • フロントエンド担当が PHP を理解する必要がある
  • スマホアプリを作るときに全部作り直し
  • 画面の変更でサーバー再起動が必要

どう分離する?

フロントエンド(React/Vue)    バックエンド(Rails/Node)
        ↓                            ↓
   ブラウザで動く                サーバーで動く
        ↓                            ↓
    見た目担当                   データ担当
        ←────── API ──────→

具体例:

// フロントエンド(React)
function UserPage() {
  const [users, setUsers] = useState([]);
  
  useEffect(() => {
    fetch('/api/users')  // APIでデータ取得
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []);
  
  return <div>{users.map(u => <p>{u.name}</p>)}</div>;
}
# バックエンド(Rails)
class Api::UsersController < ApplicationController
  def index
    users = User.all
    render json: users  # JSON形式で返す
  end
end

現場での使い方:

  • フロントとバックを別々のリポジトリで管理
  • デザイナーはフロントだけ見ればいい
  • スマホアプリが必要になっても同じAPIを使える

いつ使う? 今どき標準。最初から分ける。


レベル2:チーム開発で必須の分離(1ヶ月目)

2-1. 責務分離(関心の分離)

優先度:★★★★☆

何が問題?

// ❌ ダメな例:1つの関数が何でもやる
function registerUser(email, password) {
  // バリデーション
  if (!email.includes('@')) return 'Invalid email';
  if (password.length < 8) return 'Password too short';
  
  // パスワード暗号化
  const hash = bcrypt.hash(password);
  
  // DB保存
  db.query('INSERT INTO users VALUES (?, ?)', [email, hash]);
  
  // メール送信
  sendEmail(email, 'Welcome!');
  
  // ログ記録
  logger.info('User registered');
}

この関数は「バリデーション」「暗号化」「DB操作」「メール送信」「ログ」を全部やってます。どこかバグがあっても探しにくい。

どう分離する?

// ✅ 良い例:責務ごとに分割
function validateUser(email, password) {
  if (!email.includes('@')) throw new Error('Invalid email');
  if (password.length < 8) throw new Error('Password too short');
}

function hashPassword(password) {
  return bcrypt.hash(password);
}

function saveUser(email, hashedPassword) {
  return db.query('INSERT INTO users VALUES (?, ?)', [email, hashedPassword]);
}

function sendWelcomeEmail(email) {
  sendEmail(email, 'Welcome!');
}

// メイン処理
function registerUser(email, password) {
  validateUser(email, password);
  const hash = hashPassword(password);
  saveUser(email, hash);
  sendWelcomeEmail(email);
  logger.info('User registered');
}

現場での使い方:

  • 1つの関数は1つの仕事だけ
  • 関数名で何をするか分かるように
  • テストもしやすくなる

いつ使う? 関数を書くたびに意識。


2-2. レイヤー分離(階層分離)

優先度:★★★★☆

何が問題?

コードがごちゃまぜだと、どこに何があるか分からない。

どう分離する?

プレゼンテーション層(見た目)
    ↓
ビジネスロジック層(ルール)
    ↓
データアクセス層(DB操作)

具体例:

// プレゼンテーション層(Controller)
app.post('/users', async (req, res) => {
  const user = await userService.create(req.body);
  res.json(user);
});

// ビジネスロジック層(Service)
class UserService {
  async create(data) {
    // ビジネスルール:メールアドレスは小文字化
    data.email = data.email.toLowerCase();
    
    // 既存ユーザーチェック
    const exists = await userRepository.findByEmail(data.email);
    if (exists) throw new Error('Email already exists');
    
    return await userRepository.save(data);
  }
}

// データアクセス層(Repository)
class UserRepository {
  async findByEmail(email) {
    return db.query('SELECT * FROM users WHERE email = ?', [email]);
  }
  
  async save(data) {
    return db.query('INSERT INTO users SET ?', data);
  }
}

現場での使い方:

  • Controller:HTTPの入出力だけ
  • Service:ビジネスロジック(値段計算、在庫チェックなど)
  • Repository:DBの読み書きだけ

いつ使う? ファイルが10個超えたら導入。


2-3. API分離(エンドポイント分離)

優先度:★★★★☆

何が問題?

// ❌ ダメな例:1つのエンドポイントで何でもやる
app.post('/api', (req, res) => {
  if (req.body.action === 'getUser') {
    // ユーザー取得
  } else if (req.body.action === 'updateUser') {
    // ユーザー更新
  } else if (req.body.action === 'deleteUser') {
    // ユーザー削除
  }
});

どう分離する?

// ✅ 良い例:REST APIで分離
app.get('/api/users/:id', getUser);      // 取得
app.put('/api/users/:id', updateUser);   // 更新
app.delete('/api/users/:id', deleteUser); // 削除

現場での使い方:

  • URLで何をするか分かるように
  • HTTPメソッド(GET, POST, PUT, DELETE)を使い分け
  • バージョニング:/api/v1/users, /api/v2/users

いつ使う? API設計の最初から。


2-4. 認証と業務ロジックの分離

優先度:★★★★☆

何が問題?

// ❌ ダメな例
app.post('/orders', (req, res) => {
  // 認証チェック
  const token = req.headers.authorization;
  if (!token) return res.status(401).send('Unauthorized');
  const user = verifyToken(token);
  
  // 注文処理
  const order = createOrder(user, req.body);
  res.json(order);
});

全てのエンドポイントで同じ認証コードを書くのは無駄。

どう分離する?

// ✅ 良い例:ミドルウェアで分離
function authMiddleware(req, res, next) {
  const token = req.headers.authorization;
  if (!token) return res.status(401).send('Unauthorized');
  req.user = verifyToken(token);
  next();
}

// 使う側
app.post('/orders', authMiddleware, (req, res) => {
  // 認証済みなので業務ロジックだけ
  const order = createOrder(req.user, req.body);
  res.json(order);
});

現場での使い方:

  • 認証はミドルウェアで一元管理
  • 権限チェックも同様に分離
  • 業務ロジックに認証コードを書かない

いつ使う? ログイン機能を作る時。


レベル3:サービス成長で必要になる分離(3ヶ月目以降)

3-1. データとロジックの分離

優先度:★★★☆☆

何が問題?

// ❌ ダメな例
const user = {
  name: 'Alice',
  birthYear: 1995
};

// 年齢計算がバラバラ
const age1 = 2024 - user.birthYear;
const age2 = new Date().getFullYear() - user.birthYear;

どう分離する?

// ✅ 良い例:クラスで分離
class User {
  constructor(name, birthYear) {
    this.name = name;
    this.birthYear = birthYear;
  }
  
  getAge() {
    return new Date().getFullYear() - this.birthYear;
  }
  
  isAdult() {
    return this.getAge() >= 18;
  }
}

const user = new User('Alice', 1995);
console.log(user.getAge());  // 常に同じロジック

現場での使い方:

  • データに関連するロジックはクラスに入れる
  • 計算ロジックが統一される
  • テストしやすい

いつ使う? 同じ計算を複数箇所でやってる時。


3-2. データベース分離

優先度:★★★☆☆

何が問題?

全てのデータを1つのDBに入れると:

  • アクセス集中でパフォーマンス低下
  • 障害時に全サービス停止

どう分離する?

ユーザーDB(認証用)
  - users テーブル
  - sessions テーブル

商品DB(EC機能)
  - products テーブル
  - orders テーブル

分析DB(レポート用)
  - access_logs テーブル
  - sales_summary テーブル

現場での使い方:

  • 読み取り専用DBを分ける(レプリケーション)
  • 機能ごとにDBを分ける
  • 重いレポート処理は分析DBで

いつ使う? ユーザー数が1万人超えたら検討。


3-3. マイクロサービス分離

優先度:★★☆☆☆(初期は不要)

何が問題?

1つの巨大アプリ(モノリス)だと:

  • デプロイに時間がかかる
  • 一部の変更で全体テストが必要
  • チームが増えると競合しまくる

どう分離する?

ユーザーサービス(認証担当)
  ↓ API
注文サービス(注文処理担当)
  ↓ API
決済サービス(決済担当)
  ↓ API
通知サービス(メール送信担当)

現場での使い方:

  • 各サービスは独立してデプロイ
  • チームごとにサービスを担当
  • APIで連携

いつ使う? エンジニアが10人超えたら検討。それまでは早すぎる。


3. 実践チェックリスト

今日からやること

  • .env ファイルで設定値を分離
  • .gitignore.env を追加
  • データ取得と表示を別の関数に

1週間以内にやること

  • フロントとバックでリポジトリを分ける
  • REST API設計(GET/POST/PUT/DELETE)
  • 1つの関数は1つの仕事に

1ヶ月以内にやること

  • Controller/Service/Repository に分割
  • 認証ミドルウェアを作成
  • APIエンドポイントを整理

3ヶ月後に検討すること

  • データベースのレプリケーション
  • 読み取り専用DBの分離
  • (チームが大きければ)マイクロサービス化

4. まとめ

分離の本質は「変更の影響範囲を限定すること」

スタートアップでは「最初から完璧」を目指す必要はありません。ただし:

  1. 設定値の分離は初日から必須(セキュリティ)
  2. フロント・バック分離は初日から必須(チーム開発)
  3. 責務・レイヤー分離は1ヶ月以内に導入(コード品質)
  4. マイクロサービスは焦らない(チームが大きくなってから)

「今どの分離が必要か?」を見極めて、一歩ずつ改善していきましょう。

完璧な設計よりも、動くものを素早くリリースして改善するのがスタートアップのエンジニアリングです。

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?