「脳に収まるコードの書き方」のバーティカルスライスを試す
はじめに
最近、『脳に収まるコードの書き方(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(内側)を実装していきます。
- まずはハッピーパス(正常系)を狙う
- ハイレベルのテストはアサーションを緩くしておく(仕様が固まるにつれ厳しくする)
- 最初は実装が空でもいい
① コントローラーのテスト(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