이야기 - 자바 진영의 추운 겨울과 스프링의 탄생
EJB
- 2000년대 초반, 자바 진형에서 EJB가 많이 사용되었다. 기능은 많았지만 사용하기 복잡하다는 단점이 있었다. 이후 하이버네이트가 등장하였고, 이를 기반으로 JPA를 만들어 표준 인터페이스가 되었다.
스프링의 역사
- 2002년 로드 존슨이 EJB의 문제점을 지적하며 30000라인 이상의 기반 기술을 예제 코드로 선보이며 스프링이 탄생했다. 이 때 현재 스프링의 핵심 기술이 확립되었다.
- 유겐 휠러, 얀 카로프가 로드 존슨에게 오픈소스 프로젝트를 제안하였다.
- 스프링의 이름은 J2EE(EJB)라는 겨울을 넘어 새로운 봄이라는 뜻으로 지어졌다.
스프링이란?
- 스프링에는 많은 관련 기술들이 있지만 스프링 프레임워크, 이러한 기술을 편리하게 사용할 수 있도록 도와주는 스프링 부트 두 가지가 핵심 기술이다.
- 스프링
- DI 컨테이너, MVC, JDBC, ORM, 캐시, 스키줄링 등..
- 스프링 부트
- 스프링을 편리하게 사용할 수 있도록 지원하며, 최근에는 기본으로 사용한다.
- Tomcat과 같은 웹 서버를 내장하므로 별도의 웹 서버를 설치하지 않아도 된다.
- 관례에 의한 간결한 설정이 가능하다.
스프링의 핵심
- 스프링은 객체 지향 언어인 자바 언어 기반의 프레임워크이다.
- 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크이기 때문에 좋은 객체 지향 애플리케이션을 개발하는데 도움이 된다.
좋은 객체 지향 프로그래밍이란?
- 다형성이 가장 중요하다.
- 역할과 구현으로 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해진다.
- 클라이언트는 대상의 역할(인터페이스)만 알면 된다. 구현 대상의 내부 구조를 몰라도 되며 내부 구조가 변경되더라도, 구현 대상 자체를 변경하더라도 영향을 받지 않는다.
역할과 구현을 분리
- 객체를 설계할 때 역할(인터페이스)와 구현(인터페이스를 구현한 클래스, 구현 객체)를 명확히 분리해야 한다.
다형성의 본질
- 인터페이스를 구현한 객체 인스턴트를 실행 시점에 유연하게 변경할 수 있다.
- 자바 언어의 특징인 오버로딩과 오버라이딩을 사용한다.
- 오버로딩 : 매개변수의 개수나 타입에 따라 메소드를 여러개로 정의
- 오버라이딩 : 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의
- 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
- 스프링을 통해 다형성을 극대화할 수 있다.
좋은 객체 지향 설계의 5가지 원칙(SOLID)
SRP
- 단일 책임 원칙 (Single responsibility principle)
- 한 클래스는 하나의 책임만 가져야 한다.
- 변경이 있을 때 한 부분의 수정만으로 해결이 가능하다면 달인 책임 원칙을 잘 따른 것이다.
OCP
- 개방-폐쇄 원칙 (Open/closed principle)
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
OCP의 문제점
- 구현 객체를 변경하려면 클라이언트 코드를 변경해야 하기 때문에 OCP 원칙을 지킬 수 없다.
- ex) 기존의 코드
MemberRepositoy m = new MemoryMemberRepository();
를 MemberRepository m = new JdbcMemberRepository();
로 변경하려면 코드를 바꿔야 한다.
- 스프링의 컨테이너와 같은 객체를 생성하고 연결관계를 맺어주는 별도의 조립, 설정자가 필요하다.
LSP
- 리스코프 치환 원칙 (Liskov substitution principle)
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
- ex) 자동차 인터페이스의 엑셀은 앞으로 가는 기능이기에 뒤로 가게 구현하면 LSP 위반이다. 느리더라도 앞으로 가야 한다.
ISP
- 인터페이스 분리 원칙 (Interface segregation principle)
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
- ex) 자동차 인터페이스는 운전 인터페이스와 정비 인터페이스로 분리하는게 낫다.
- ex) 사용자 클라이언트는 운전자 클라이언트와 정비사 클라이언트로 분리하는게 낫다.
DIP
- 의존관계 역전 원칙 (Dependency inversion principle)
- 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.
- 구현 클래스가 아닌 인터페이스에 의존하라는 뜻이다.
- 역할(Role)에 의존하게 해야 한다.
정리
- 객체 지향의 핵심은 다형성이다.
- 다형성만으로는 OCP, DIP를 지킬 수 없다.
- 스프링 필요
객체 지향 설계와 스프링
- 스프링은 다형성 + OCP, DIP를 가능하게 지원함으로서 클라이언트 코드의 변경 없이 기능 확장을 가능하게 한다.
- 좋은 개발을 위해 모든 설계에 역할과 구현을 분리해야 한다.
- 이상적으로는 모든 설계에 인터페이스를 부여해야 한다.
- 하지만 인터페이스를 도입하면 추상화라는 비용이 발생한다.
- 기능 확장의 가능성이 없다면 구체 클래스를 직접 사용하고, 향후 필요할 때 리팩터링해서 인터페이스를 도입하는 것도 방법이다.
본 포스팅은 김영한 강사의 스프링 핵심 원리 강의를 수강하고 요약한 것으로, 해당 강의의 영상 및 강의자료를 참고하였습니다.