第4部:実務スキル / 第2章:実装作業

Step3: 実装する

実装計画ができたら、いよいよコードを書いていきます。初心者が陥りがちな失敗を避け、確実に動くコードを書くための方法を解説します。

📖 読了目安 約13分 対象:実装作業に入る方

なぜ「実装の進め方」が重要なのか

初心者あるある

「とりあえず全部書いてから動かそう」→ エラーが大量に出て、どこが間違っているか分からない

実装の進め方を間違えると、以下のような問題が起こります:

  • エラーの原因特定が困難:100行書いてから動かすと、どの行が原因か分からない
  • 手戻りが大きい:根本的な設計ミスに最後に気づくと、全部書き直し
  • デバッグ時間の増大:複雑に絡み合ったバグは解決が難しい

正しい進め方を身につけると

  • エラーが出ても原因がすぐ分かる
  • 小さな成功を積み重ねてモチベーションを保てる
  • 確実に動くコードが書ける

原則1: 小さく作って、小さく確認

なぜ小さく作るのか

  • ❌ 悪い例:一気に全部書く
    100行のコードを書く → 実行してみる → エラーが10個出る → どこが原因か分からない...
  • ⭕ 良い例:小さく書いて確認を繰り返す
    10行書く → 動作確認 → OK! → 次の10行書く → 動作確認 → OK! → さらに10行書く → エラー! → 直前の10行が原因と分かる → すぐ修正

具体的な進め方

1. 骨格を先に作る

まず、処理の流れ(骨格)だけを作ります。

// 悪い例:いきなり詳細を書き始める
public void processOrder(Order order) {
    // 在庫チェックのロジックをいきなり100行...
}

// 良い例:まず骨格を作る
public void processOrder(Order order) {
    // Step1: 入力値チェック
    validateOrder(order);

    // Step2: 在庫確認
    checkStock(order);

    // Step3: 注文登録
    registerOrder(order);

    // Step4: 通知送信
    sendNotification(order);
}

// 各メソッドは最初は空でOK
private void validateOrder(Order order) {
    // TODO: あとで実装
}

2. 一つずつ肉付けしていく

骨格ができたら、一つずつ中身を実装します。

// Step1から順番に実装
private void validateOrder(Order order) {
    if (order == null) {
        throw new IllegalArgumentException("注文がnullです");
    }
    if (order.getItems().isEmpty()) {
        throw new IllegalArgumentException("注文商品がありません");
    }
    // ここで一度動作確認!
}

3. 一つ実装したら必ず動作確認

実装 → 保存 → 実行 → 確認 → 次へ

このサイクルを短く回すことが大切です。


原則2: 動くコードを維持する

なぜ「常に動く状態」を保つのか

初心者あるある

「あとでまとめて直すから、今はコンパイルエラーがあってもいいや」

これは危険な考え方です:

  • エラーが雪だるま式に増える:1つのエラーを放置すると、それに依存する部分もエラーになる
  • 何が正しい状態か分からなくなる:エラーだらけだと、どこまでが動いていたか不明
  • 心理的負担が増大:エラーの山を見るとやる気がなくなる

実践方法

1. コンパイルエラーは即座に直す

コンパイルエラーが出たら、次の行を書く前に直しましょう。

// コンパイルエラーを放置して次に進む ❌
public void method1() {
    unknownMethod();  // エラー!でも後で直そう...
}

public void method2() {
    // method1のエラーを直さないまま次を書く
    // → エラーが増えていく
}

2. TODOコメントで仮実装

まだ実装しない部分は、TODOコメントと仮の実装で動く状態を保ちます。

private int calculateDiscount(Order order) {
    // TODO: 割引計算ロジックを実装
    return 0;  // 仮の値を返して動く状態を維持
}

3. 定期的にコミット

動く状態になったら、こまめにコミットしましょう。

$ git add .
$ git commit -m "注文バリデーション機能を追加"

これにより、いつでも「動いていた状態」に戻れます。


原則3: 既存コードに合わせる

なぜ既存コードに合わせるのか

初心者あるある

「自分の好きな書き方のほうが読みやすいから」

チーム開発では、個人の好みより一貫性が重要です:

  • 読みやすさ:統一されたコードは誰が見ても理解しやすい
  • 保守性:スタイルが混在すると、どれが正しいか分からなくなる
  • レビュー効率:「なぜこの書き方?」という指摘を避けられる

確認すべきポイント

1. 命名規則

// 既存コードがキャメルケースなら
private int orderCount;      // ✅ 既存に合わせる
private int order_count;     // ❌ スネークケースは使わない

// 既存コードがget/setを使っているなら
public int getOrderCount()   // ✅ 既存に合わせる
public int orderCount()      // ❌ 独自スタイルは避ける

2. インデントとフォーマット

// 既存コードがスペース4つなら
if (condition) {
    doSomething();    // ✅ スペース4つ
}

// タブや2スペースは使わない
if (condition) {
  doSomething();      // ❌ スペース2つ
}

3. エラーハンドリング

// 既存コードが例外をスローしているなら
if (order == null) {
    throw new IllegalArgumentException("...");  // ✅
}

// 独自の方法を使わない
if (order == null) {
    return null;  // ❌ 既存と異なる方法
}

4. ログ出力

// 既存コードのログレベルに合わせる
logger.info("注文処理開始: orderId={}", orderId);  // ✅

// 独自のフォーマットを使わない
System.out.println("注文処理開始: " + orderId);    // ❌

既存コードの調べ方

  1. 同じような機能を探す:「注文処理」を実装するなら、既存の「商品処理」を参考に
  2. コーディング規約を確認:プロジェクトにあれば必ず読む
  3. 先輩に聞く:「この書き方で合っていますか?」と確認

原則4: YAGNIの原則を守る

YAGNIとは

YAGNI = "You Aren't Gonna Need It"(それは必要にならない)

初心者あるある

「将来こういう機能が必要になるかも」→ 今は使わない機能を作り込む

なぜYAGNIが重要か

  • ❌ 過剰な実装の問題
    今必要な機能: 1つ → 「将来のため」に作った機能: 5つ → 開発時間が5倍 → 将来の仕様変更で作り直し → 使われないコードが負債になる
  • ⭕ 必要な分だけ作る
    今必要な機能だけを実装 → 必要になったらそのときに追加 → シンプルで保守性が高い

現実

  • 「将来必要になる」と思った機能の多くは、結局使われない
  • 使われるとしても、想像と違う形で必要になる
  • 今作っても、その時には仕様が変わっている

具体例

// ❌ 過剰な実装
public class OrderProcessor {
    // 今は日本円だけだが、将来のために多通貨対応...
    private Map converters;

    // 今は1店舗だが、将来のためにマルチテナント対応...
    private TenantManager tenantManager;

    // 今は同期処理だが、将来のために非同期対応...
    private AsyncExecutor asyncExecutor;

    // 実際に必要な処理はこれだけ
    public void process(Order order) {
        save(order);
    }
}

// ✅ 必要最小限の実装
public class OrderProcessor {
    public void process(Order order) {
        save(order);
    }
}

YAGNIの実践

  1. 仕様書に書かれていることだけ実装する
  2. 「あると便利」は作らない
  3. 迷ったら作らない
  4. 本当に必要になったら、その時に作る

原則5: 読みやすさを優先する

なぜ読みやすさが重要か

事実:コードは書く時間より読む時間のほうが圧倒的に長い

  • 自分で書いたコードも、1週間後には「他人のコード」
  • チームメンバーがあなたのコードを読む
  • 将来の保守担当者が読む

読みやすいコードの書き方

1. 意味のある名前をつける

// ❌ 分かりにくい名前
int d;  // 何の日数?
String s;  // 何の文字列?
List list;  // 何のリスト?

// ✅ 意味が分かる名前
int daysSinceLastOrder;
String customerName;
List pendingOrders;

2. 1つのメソッドは1つのことだけ

// ❌ 1つのメソッドで複数のことをやる
public void processOrder(Order order) {
    // バリデーション(30行)
    // 在庫チェック(20行)
    // 注文登録(25行)
    // メール送信(15行)
    // ログ出力(10行)
    // 合計100行...
}

// ✅ 役割ごとにメソッドを分ける
public void processOrder(Order order) {
    validateOrder(order);
    checkStock(order);
    registerOrder(order);
    sendConfirmationEmail(order);
}

3. ネストを浅くする

// ❌ 深いネスト
public void process(Order order) {
    if (order != null) {
        if (order.getItems() != null) {
            if (!order.getItems().isEmpty()) {
                for (Item item : order.getItems()) {
                    if (item.getStock() > 0) {
                        // 処理...
                    }
                }
            }
        }
    }
}

// ✅ 早期リターンでネストを減らす
public void process(Order order) {
    if (order == null) return;
    if (order.getItems() == null) return;
    if (order.getItems().isEmpty()) return;

    for (Item item : order.getItems()) {
        if (item.getStock() <= 0) continue;
        // 処理...
    }
}

4. マジックナンバーを避ける

// ❌ 意味不明な数値
if (status == 3) {
    discount = price * 0.1;
}

// ✅ 定数で意味を明確に
private static final int STATUS_PREMIUM = 3;
private static final double PREMIUM_DISCOUNT_RATE = 0.1;

if (status == STATUS_PREMIUM) {
    discount = price * PREMIUM_DISCOUNT_RATE;
}

実践チェックリスト

実装中は、以下を意識しましょう:

進め方

  • ☐ 10〜20行書いたら動作確認している
  • ☐ コンパイルエラーを放置していない
  • ☐ 動く状態を常に維持している

コードの品質

  • ☐ 既存コードのスタイルに合わせている
  • ☐ 仕様書にないことは実装していない(YAGNI)
  • ☐ 意味のある名前をつけている
  • ☐ 1メソッドが長すぎない(目安: 30行以内)

確認

  • ☐ 定期的にコミットしている
  • ☐ 動作確認してから次に進んでいる

次のステップ

実装が一段落したら、次は動作確認です。

Step4: 動作確認する


関連ページ