자바 기반 백엔드 개발을 시작하는 많은 사람들은 처음에 스프링(Spring)을 어렵다고 느낀다. 그러나 실제로 스프링이 탄생한 배경과 목적을 이해하면, 스프링이 왜 이렇게 강력한 프레임워크인지 자연스럽게 깨닫게 된다. 이 글에서는 스프링이 어떤 문제를 해결하기 위해 등장했는지, 그리고 왜 객체 지향 설계(OOP)와 밀접한 관련이 있는지 쉽게 설명해본다.
1. 스프링은 왜 등장했는가? 불편했던 과거의 자바 개발 환경
스프링 이전의 자바 진영은 개발하기 매우 까다로운 환경이었다. EJB(Enterprise Java Beans)가 널리 사용되던 시절, 개발자들은 다음과 같은 문제들로 고통을 겪었다.
- 객체 지향스럽지 않은 구조
- 불필요하게 복잡한 코드
- 테스트하기 어려운 구조
- 변경에 취약한 설계
- 새로운 기능을 추가할 때마다 많은 부분을 수정해야 하는 문제
예를 들어, 할인 기능을 담당하는 코드가 있다고 해보자. 정책이 “VIP는 1000원 할인”에서 “VIP는 결제 금액의 10% 할인”으로 바뀌었다고 가정하면, EJB 기반 설계에서는 서비스 코드 자체를 수정해야 했다. 즉, 기능 변경이 곧 전체 코드 변경으로 이어지는 구조였다.
이처럼 변화에 취약하고 복잡한 구조를 개선하기 위해 스프링이 등장했다. 스프링은 “객체 지향의 장점을 100% 활용할 수 있도록” 돕는 프레임워크로 시작되었다.
2. 스프링의 핵심 목적: 객체를 효율적으로 관리하고 유연한 구조 만들기
스프링을 DI(Dependency Injection) 프레임워크라고 부르는 이유가 있다. 스프링이 하는 주요 역할은 다음과 같다.
- 객체(빈)를 대신 생성하고 관리한다.
- 객체 간 연결 관계를 자동으로 설정해준다.
- 정책이 변경되어도 코드를 최소한으로 수정할 수 있도록 구조를 제공한다.
- 결합도를 낮추고 확장에 유리한 구조를 만든다.
즉, 스프링의 핵심은 애플리케이션 내의 “객체 관리 자동화”라고 볼 수 있다.
스프링의 본질은 매우 간단하다.
스프링 = 객체 생성 + 의존관계 관리 + 애플리케이션 구조 유지 도구
이 덕분에 개발자는 비즈니스 로직에만 집중할 수 있고, 반복적이고 복잡한 객체 관리 작업은 스프링이 대신 처리해준다.
3. 좋은 객체 지향 프로그래밍(OOP)은 무엇인가?
스프링을 이해하려면 먼저 객체 지향 설계의 본질을 알아야 한다. 좋은 객체 지향 프로그래밍은 다음 원칙을 지켜야 한다.
3-1. 역할과 구현의 분리
역할(Role) = 인터페이스
구현(Implementation) = 실제 클래스
예를 들어, “할인 서비스”라는 역할이 있다면, 다양한 구현을 만들 수 있다.
- 고정 금액 할인
- 정률(%) 할인
- 프로모션 할인
- 쿠폰 할인
좋은 객체 지향은 실제 구현이 바뀌어도 외부 코드가 영향을 받지 않는 구조를 말한다.
3-2. 다형성을 활용할 수 있어야 한다
클라이언트 입장에서는 “할인 정책이 어떤 방식으로 동작하는지” 몰라도 된다. 단지 할인 결과만 잘 나오면 된다. 구현을 바꿔 끼워도 문제가 없도록 만들어주는 것이 다형성이다.
4. SOLID 원칙: 좋은 객체 지향 설계를 위한 5가지 가이드라인
스프링 교안에서 가장 강조하는 부분이 바로 선배 개발자가 만든 객체 지향 설계 5대 원칙, SOLID이다. 스프링은 이 SOLID 원칙이 자연스럽게 적용되는 구조를 제공한다.
4-1. SRP — 단일 책임 원칙
한 클래스는 하나의 책임(변경 이유)만 가져야 한다.
예를 들어, “회원 가입” 기능을 가진 서비스가 “DB 선택”까지 맡고 있다면 책임이 너무 많다.
4-2. OCP — 개방-폐쇄 원칙
확장에는 열려 있고, 변경에는 닫혀 있어야 한다.
할인 정책을 변경하기 위해 서비스 코드를 뜯어 고친다면 OCP를 위반한 것이다.
4-3. LSP — 리스코프 치환 원칙
부모 타입을 자식 타입으로 바꿔도 프로그램이 정상적으로 동작해야 한다.
4-4. ISP — 인터페이스 분리 원칙
하나의 거대한 인터페이스보다, 작은 인터페이스 여러 개가 낫다.
4-5. DIP — 의존관계 역전 원칙
구체 클래스가 아닌, 인터페이스(추상)에 의존해야 한다.
구현체를 직접 new로 생성하면 DIP를 위반하는 것이다.
5. 스프링과 객체 지향 설계의 관계: 왜 스프링이 SOLID와 맞닿아 있는가?
스프링이 하는 일은 OOP 원칙을 어기지 않도록 구조를 잡아주는 것이다.
예를 들어, 할인 정책이 FixDiscountPolicy에서 RateDiscountPolicy로 바뀌었다고 하자.
순수 자바 코드만 사용할 때는 보통 다음과 같이 바꾼다.
new FixDiscountPolicy()
→ new RateDiscountPolicy()
이렇게 하면 OCP, DIP를 모두 위반한다.
하지만 스프링에서는 이런 변경을 AppConfig나 DI 설정 부분에서만 바꾸면 된다.
서비스는 여전히 DiscountPolicy 인터페이스만 바라본다.
즉, 클라이언트는 구현체 변경의 영향을 받지 않는다.
스프링이 지향하는 핵심 철학은 다음과 같다.
객체 지향 설계 원칙을 지키기 쉽게 만드는 프레임워크
스프링이 왜 유명해졌는지, 왜 개발자들이 스프링을 사용하는지 바로 이 이유 때문이다.
6. 정리: 1장을 통해 배운 핵심 메시지
- 과거 자바 환경은 복잡하고 확장성이 떨어졌다.
- 스프링은 이러한 문제를 해결하기 위해 등장했고, 객체 지향 설계를 돕는 것을 목적에 둔다.
- 스프링은 DI를 통해 객체 생성과 의존관계를 자동으로 관리한다.
- 객체 지향 설계(SOLID)를 지키기 위해 스프링이 중요한 역할을 한다.
- 스프링을 이해한 개발자는 더 유연하고 확장성 있는 프로그램을 만들 수 있다.