Czy Korea Południowa to „republika Springa”?
Jeśli chcesz znaleźć pracę jako backend developer w Korei, jest jedno pytanie, którego prawie nie da się uniknąć: „Umiesz Springa?”
Wystarczy wejść na portal z ofertami pracy, a dziewięć na dziesięć ogłoszeń ma wpisane „doświadczenie ze Spring Boot” w wymaganiach. Nie bez powodu mówi się nawet o „republice Springa”. Kiedy byłem na studiach, myślałem, że to tylko chwilowa moda.
„Przecież można to po prostu napisać w Javie, po co od razu używać ciężkiego Springa?” „Czy Node.js albo Python (Django) nie są po prostu łatwiejsze?”
Ale kiedy wszedłem do praktyki i zobaczyłem duże projekty od środka, zrozumiałem, o co chodzi. Spring nie był zwykłym trendem, tylko standardowym stołem roboczym, dopracowywanym przez wielu doświadczonych programistów po to, by ogromne i złożone systemy enterprise dało się budować bezpiecznie i szybko.
Ta seria jest właśnie o tym, jak na takim standardowym stole roboczym buduje się zamek, który się nie zawali, czyli Monolith.
Framework: dlaczego nie możesz robić wszystkiego po swojemu
Zanim przejdziemy do właściwej części technicznej, trzeba uporządkować jedną rzecz. Czym właściwie jest framework? I czym różni się od biblioteki?
W poprzedniej serii Re: Booting wspomniałem o tym krótko, ale najważniejsza różnica sprowadza się do jednego pytania: kto trzyma ster?
Spring jest frameworkiem. Korzystanie ze Springa przypomina więc trochę złożenie przysięgi: „na chwilę odłożę na bok własny styl kodowania i będę robił to tak, jak chce Spring”. Sednem tego „tak, jak chce Spring” jest właśnie temat dzisiejszego wpisu: Inversion of Control (IoC).
„Proszę, przestańcie wszędzie używać new”
Pierwsza zasada tej przysięgi była dla mnie szokiem. W gruncie rzeczy mówiła: nie używaj new, jednego z najbardziej podstawowych elementów Javy.
Na studiach to było oczywiste: jeśli potrzebowałem obiektu, pisałem MemberService service = new MemberService();. Jeśli czegoś potrzebuję, to sam to tworzę i używam. Co może być w tym dziwnego?
Ale gdy po zatrudnieniu otworzyłem projekt Spring Boot, nigdzie nie widziałem słowa kluczowego new. Zamiast tego kod był pełen dziwnych adnotacji takich jak @Autowired czy @RequiredArgsConstructor.
„Zaraz, jeśli nikt nie tworzy tego obiektu, to jak w ogóle wywoływana jest metoda? To naprawdę działa?”
Kiedy zapytałem o to starszego programistę, odpowiedź zabrzmiała frustrująco niejasno: „Spring Container sam to wstrzyknie, więc nie musimy tworzyć tego ręcznie. Co więcej, jeśli będziesz używać new bezpośrednio, później utrzymanie kodu stanie się dużo trudniejsze.”
Nie mogłem się z tym pogodzić. To ja byłem właścicielem kodu, który pisałem, więc dlaczego nie mogłem nawet swobodnie stworzyć obiektu? Czułem to niemal jak dyktaturę Springa.

Kucharz i menedżer składników (IoC & DI)
Żeby zrozumieć, dlaczego ta pozornie autorytarna zasada jest potrzebna, zmieńmy metaforę i przenieśmy się do kuchni w restauracji.
1. Tradycyjny sposób (to ja rządzę)
Jestem kucharzem, czyli Class. Żeby gotować, potrzebuję noża, czyli Dependency.
2. Sposób Springa (rządzi Spring)
Nadal jestem kucharzem. Ale tym razem jest jeszcze menedżer odpowiedzialny za składniki i narzędzia: Spring Container.
Innymi słowy, zamiast samodzielnie zarządzać potrzebnymi zasobami, pozwalam, by zarządzało nimi coś zewnętrznego i przekazywało mi je wtedy, gdy ich potrzebuję. To właśnie jest Inversion of Control (IoC: Inversion of Control), a konkretną techniką, która to realizuje, jest Dependency Injection (DI).

[Code Verification] Dlaczego new jest niebezpieczne?
Słowa nie wystarczą, żeby to naprawdę poczuć. Porównajmy to bezpośrednio w kodzie. Załóżmy, że budujemy system płatności kartą.
1. Zły przykład: tworzenie bezpośrednie (silne sprzężenie)
public class PaymentService {
// Sam wybralem i stworzylem Samsung Card (uzywajac new)
private final SamsungCard card = new SamsungCard();
public void pay() {
card.payment(); // Platnosc tylko Samsung Card
}
}
Problem: któregoś dnia szef mówi: „Przejdźmy na Hyundai Card, bo ma niższe prowizje!” Wtedy muszę otworzyć kod PaymentService i wszędzie zamienić SamsungCard na HyundaiCard. A jeśli taki kod występuje w stu miejscach? Nadgodziny murowane.
2. Dobry przykład: dependency injection (luźne sprzężenie)
public class PaymentService {
private final Card card; // Nie okreslaj konkretnego wystawcy karty (uzyj interfejsu)
// Wstrzykiwanie przez konstruktor: ufasz, ze ktos z zewnatrz poda karte
public PaymentService(Card card) {
this.card = card;
}
public void pay() {
card.payment();
}
}
Teraz PaymentService nie obchodzi już, jaka konkretna implementacja karty zostanie do niego przekazana.
To właśnie jest sedno tego, co w praktyce nazywa się „kodem łatwym w utrzymaniu”, czyli zasadą OCP. I to właśnie ta elastyczność jest prawdziwym powodem, dla którego używa się Spring Boota.
Spring Container: hotel dla obiektów
Kim więc jest ten „menedżer”, który tworzy obiekty i je rozdaje? Właśnie tym jest Spring Container.
W chwili, gdy uruchamiamy serwer Spring Boot poleceniem run, wewnątrz dzieje się naprawdę mnóstwo rzeczy.
Naszym zadaniem jest tylko przykleić do klasy karteczkę z napisem „proszę tym zarządzać”, na przykład przez @Service. Resztą zajmuje się Spring, niczym wielki kierownik hotelu porządkujący wszystkich gości.
Praktyczna rada: używaj wstrzykiwania przez konstruktor
Spring oferuje kilka sposobów wstrzykiwania zależności: field injection z @Autowired, setter injection i constructor injection. Ale w prawdziwych projektach niemal zawsze zaleca się constructor injection. To właśnie wzorzec często używany razem z @RequiredArgsConstructor z Lomboka.
@Service
@RequiredArgsConstructor // To automatycznie tworzy wstrzykiwanie przez konstruktor.
public class OrderService {
// mozna uzyc final, wiec jest bezpiecznie
private final PaymentService paymentService;
}
Dlaczego?
Na koniec: nie magik, lecz dyrygent
Na początku Spring mnie odpychał, bo miałem wrażenie, że dowolnie rozporządza moim kodem. Dziś patrzę na to inaczej. Spring nie jest dyktatorem, który uprzykrza mi życie, ale sprawnym dyrygentem, który porządkuje złożone relacje między obiektami.
Dzięki temu spędzam mniej czasu na zastanawianiu się „jaki obiekt mam stworzyć?”, a więcej na myśleniu „jak zbudować logikę biznesową przy użyciu tego obiektu?”. To pewnie właśnie dlatego tak wielu programistów w Korei nadal tak mocno trzyma się Springa.
Teraz przekazaliśmy Springowi zarządzanie obiektami. Serwer jest gotowy do startu. Ale aplikacja webowa nie działa sama: musi rozmawiać z frontendem. W czasach PHP było wygodnie, bo HTML i kod znajdowały się w jednym pliku. Dlaczego więc dziś rozdziela się frontend, z Vue albo Reactem, od backendu? I dlaczego od razu pojawia się czerwony błąd CORS, gdy tylko spróbujesz połączyć te dwie strony?
Następnym razem przyjrzymy się zmianie architektury webowej, SSR vs CSR, oraz prawdziwej naturze CORS, ściany stojącej między nimi.
1