✏️

「脳に収まるコードの書き方」のバーティカルスライスを試す

に公開

はじめに

最近、『脳に収まるコードの書き方(Code That Fits in Your Head)』という本を読みました。

今回はこの本を参考に、Java(Spring Boot)で新しいプロジェクトを立ち上げる際の「初手」を実際に試しながらまとめました。

1. 空のディレクトリに git を作成する

まずは履歴管理から。
ポイントは、最初のコミットを「空(Empty)」にすることです。こうすると、後でリベース等の操作をする際にルートコミットを扱いやすくなります。

git init
git commit --allow-empty -m "Initial Commit"

2. 「Hello World」レベルのアプリケーションを用意する

いきなり複雑な設計はしません。まずは「動く」状態を作ります。
Spring Initializr ( https://spring.io/quickstart ) を使い、必要最低限の依存関係(Spring Webなど)だけでプロジェクトを作成します。

目標:
GET /hello にアクセスしたら 200 OK が返ってくること。

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}

3. デプロイパイプラインを構築する

機能を作り込む前に、本番(または検証環境)へのデプロイを自動化します。
いわゆる**「ウォーキング・スケルトン(歩く骸骨)」**の状態です。

Dockerfileの作成(マルチステージビルド)

Java 17を使用した軽量なコンテナイメージを作成します。

# ビルドステージ
FROM eclipse-temurin:17-jdk-jammy AS builder
WORKDIR /app
COPY . .
# テストはCIで回す想定で、ここではスキップしてビルド
RUN ./mvnw clean package -DskipTests

# 実行ステージ
FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
# ビルド成果物をコピー(ファイル名はプロジェクトに合わせて調整)
COPY --from=builder /app/target/*.jar app.jar
# ポートの明示(必須ではないが親切)
EXPOSE 8080
# 実行コマンド
ENTRYPOINT ["java", "-jar", "app.jar"]

これをRenderなどのPaaSにデプロイし、インターネット経由で「Hello World」が見れる状態にします。

4. 品質の「閾値」を上げる

コードが汚れてから掃除するのではなく、最初から汚さない設定にします。

  • コンパイラ警告: IDEやビルドツール(Maven/Gradle)の設定で、警告(Warning)をすべて表示するようにします。
  • 特性評価テスト: テンプレートで作った「Hello World」が動くことを保証するテストを実行します。
    • ユニットテストで不要な警告が出る場合は、アノテーション等で抑制しても構いませんが、プロダクトコードでは警告ゼロを目指します。

5. バーティカルスライスで実装する

ここから機能実装に入りますが、レイヤーごと(DBだけ、Controllerだけ)には作りません。
「一番シンプルな機能で、入力から永続化までを一気通貫(Vertical Slice)で作る」ことを目指します。

おすすめは「データ登録」のテストから始めることです。

アプローチ:Outside-In(外側から内側へ)

APIのエンドポイント(外側)からテストを書き、そのテストを通すために必要なドメインやDB(内側)を実装していきます。

  1. まずはハッピーパス(正常系)を狙う
  2. ハイレベルのテストはアサーションを緩くしておく(仕様が固まるにつれ厳しくする)
  3. 最初は実装が空でもいい

① コントローラーのテスト(MockMvc)

実装はまだ空っぽの状態で、テストコードから書き始めます。

@Test
void postValidReservation() throws Exception {
    // フォームデータ等の準備
    MultiValueMap<String, String> postData = new LinkedMultiValueMap<>();
    postData.add("date", "2023-03-10 19:00");
    postData.add("email", "katinka@example.com");
    postData.add("name", "Katinka Ingabogovinanana");
    postData.add("quantity", "2");

    // リクエストの検証
    this.mvc.perform(
            MockMvcRequestBuilders.post("/reservations")
                    .params(postData)
                    .accept(MediaType.APPLICATION_JSON)
                    .header("Content-Type", "application/json"))
            .andExpect(MockMvcResultMatchers.status().is2xxSuccessful());
}

この時点では 404 Not Found やコンパイルエラーになるはずです。これを「Red」の状態としてスタートします。

② 実装(最小限)

テストを通すための最低限の実装を行います。

@PostMapping("/reservations")
public void post() {
    // まだ中身は空でよい、あるいはモックを呼ぶだけ
}

③ DB層までの貫通

  • Repository層はいったんモックでも構いませんが、最終的には実DBへ保存できることを確認します。
  • DDLもコミットする: schema.sql やFlywayなどのマイグレーションファイルも、コードと同じタイミングでコミットします。

まとめ

「早く機能を作りたい」という焦りを抑え、最初にこれらの土台(ビルド・デプロイ・テストの仕組み)を整えることが重要です。

「脳に収まる」サイズで問題を切り出し、一つずつ確実に倒していく。これが、結果として一番速く、かつ安全に開発を進める方法なのだと実感しました。

Discussion