Spring Boot: 韓国の開発者標準、そして制御の反転

📖 8min read

韓国は「Spring共和国」なのか?

韓国でバックエンド開発者として就職したいなら、ほぼ避けて通れない質問がある。”Springできますか?” だ。

求人サイトを見れば、10社中9社は応募条件に「Spring Boot経験者」と明記している。冗談ではなく「Spring共和国」とまで言われるほどだ。大学生の頃の私は、これをただの流行だと思っていた。

“普通にJavaで書けばいいのに、どうしてわざわざ重いSpringを使うの?” “Node.jsやPython(Django)のほうが簡単じゃない?”

だが実務に入り、大規模プロジェクトを経験して初めてわかった。Springは単なる流行ではなかった。巨大で複雑なエンタープライズシステムを「安全に、しかも速く」作るために、多くの先輩開発者たちが磨き上げてきた標準作業台だったのだ。

このシリーズは、その標準作業台の上で崩れない城、つまりMonolithを積み上げる方法についての話だ。

フレームワーク: なぜ好き勝手にできないのか

本格的な技術の話に入る前に、一つ整理しておきたい。そもそもフレームワークとは何なのか。ライブラリとは何が違うのか。

前の Re: Booting シリーズでも少し触れたが、この二つの決定的な違いは「主導権を握っているのは誰か」にある。

Springはフレームワークだ。つまりSpringを使うというのは、”自分のコーディングスタイルを少し脇に置いて、Springの流儀に従います” と誓うようなものだ。その「従う」の核心こそ、今日のテーマである制御の反転(IoC)だ。

new をそんなに使わないでください」

その誓約の最初のルールは衝撃的だった。Javaの基本中の基本である new 演算子を使うな、というのだ。

大学の頃は、オブジェクトが必要なら MemberService service = new MemberService(); と書くのが当たり前だった。必要なものは自分で作って使う。それのどこが不自然なのか、私にはわからなかった。

ところが入社後にSpring Bootプロジェクトを開いてみると、コードのどこを探しても new が見当たらない。その代わりに @Autowired@RequiredArgsConstructor のような見慣れないアノテーションが並んでいた。

“いや、オブジェクトを作っていないのに、どうやってメソッドを呼ぶの? 本当にこれで動くの?”

先輩開発者に聞いたとき、返ってきた答えは妙に煙に巻くようだった。”Spring Container が自動で Inject してくれるから、自分で作る必要はないよ。むしろ new を直接使うと、あとで保守がつらくなる。”

私は納得できなかった。自分が書いたコードなのに、どうしてオブジェクト一つ自由に作れないのか。まるでSpringの独裁のように感じられた。

自分で作るのか、誰かが用意したものを使うのか。

料理人と材料担当マネージャー(IoC & DI)

この独裁のように見えるルールがなぜ必要なのかを理解するために、世界観を「レストランの厨房」に変えてみよう。

1. 従来のやり方(自分が主導)

私は料理人、つまり Class だ。料理をするには包丁、つまり Dependency が必要になる。

2. Springのやり方(Springが主導)

私は相変わらず料理人だ。だが今回は「材料担当マネージャー(Spring Container)」がいる。

つまり、自分に必要な資源を自分で管理せず、外部の管理者が管理して自分に渡してくれる。これが制御の反転(IoC: Inversion of Control)であり、その具体的な実装方法が依存性注入(DI)なのだ。

Injectionを受けるというのは、道具選びの悩みを他人に預けることだ。

[Code Verification] なぜ new は危険なのか

言葉だけでは実感しづらい。コードで直接比べてみよう。ここでは「カード決済システム」を作ると仮定する。

1. 悪い例: 直接生成(密結合)

public class PaymentService {
    // 私が直接「サムスンカード」を選んで生成した(newを使用)
    private final SamsungCard card = new SamsungCard();

    public void pay() {
        card.payment(); // サムスンカードでのみ決済可能
    }
}

問題点: ある日、社長が “手数料の安い 現代カード に変えよう” と言ったとする。そうなると私は PaymentService のコードを開いて、SamsungCardHyundaiCard に全部書き換えなければならない。もしそのコードが100か所にあったら? 残業確定だ。

2. 良い例: 依存性注入(疎結合)

public class PaymentService {
    private final Card card; // 具体的なカード会社を指定しない(インターフェースを使用)

    // コンストラクタ注入:「誰かが外からカードを渡してくれるはず」と信じる
    public PaymentService(Card card) {
        this.card = card;
    }

    public void pay() {
        card.payment();
    }
}

これで PaymentService は、どのカード実装が渡ってきても気にしなくてよくなる。

    これこそが実務で言う「保守しやすいコード(OCP原則)」の核心だ。Spring Bootを使う理由は、まさにこの柔軟さにある。

    Spring Container: オブジェクトたちのホテル

    では、こうしたオブジェクトを生成して渡してくれる「マネージャー」とは誰なのか。まさにそれがSpring Containerだ。

    Spring Bootサーバーを run した瞬間、内部ではかなり多くのことが起きている。

    私たちがやることは、クラスの上に「これを管理してください」というシール、たとえば @Service を貼るだけだ。あとの面倒は、巨大なホテル支配人のようなSpringが引き受けてくれる。

    実務アドバイス: コンストラクタ注入を使え

    Springで依存性を注入する方法はいくつかある。@Autowired によるフィールド注入、Setter注入、そしてコンストラクタ注入だ。だが実務では、基本的にコンストラクタ注入一択と考えていい。(Lombokの @RequiredArgsConstructor を使う、あのやり方だ。)

    @Service
    @RequiredArgsConstructor // これがコンストラクタ注入を自動的に作ってくれる
    public class OrderService {
        // finalを付けられるので安全
        private final PaymentService paymentService;
    }
    
    

    理由:

    締めくくり: 魔法使いではなく、指揮者

    最初は、Springが私のコードを勝手に振り回しているように感じて拒否感があった。だが今は違う。Springは私を苦しめる独裁者ではなく、複雑なオブジェクト関係を整理してくれる有能な指揮者なのだ。

    おかげで私は「どのオブジェクトを作るか」を悩む時間を減らし、「このオブジェクトでどうビジネスロジックを組むか」に集中できるようになった。韓国の開発者たちがSpringに熱狂する理由は、きっとそこにある。

    さて、これでオブジェクト管理の権限はSpringに渡した。サーバーを起動する準備はできた。だがWebアプリケーションは単独では動かない。画面、つまりFrontendと会話しなければならない。PHP時代はHTMLとコードが1つのファイルに混ざっていて楽だったのに、なぜ今はFrontend(Vue, React)とBackendを分けて開発するのか。そして両者をつなごうとすると、なぜ赤い CORS エラーが出るのか。

    次回は、Webアーキテクチャの変化、SSR vs CSR、そしてその間に立ちはだかる CORS の正体を掘り下げてみよう。

    コメントする