01 스프링의 역사
자바 진영은 오래전 아주 길고 긴 암흑기를 겪었다. 그 암흑기를 시작한 것은 서버 어플리케이션 EJB였다. EJB는 자바에서 정식 인증한 표준으로서 영업에 성공해서 많은 개발자들이 이용했지만, 객채지향 프로그래밍에 맞지 않는 표준으로 설계난이도가 너무 어렵고 난해해서 선배 개발자들은 지옥불에 빠진듯하게 코딩을 했어야 했다. SOLID 표준에 맞는 코딩이 너무나 어려웠고 심지어는 플레인 자바로 돌아가자는 운동까지 이어졌다. 프레임 워크를 사용하는 것보다 그냥 쌩으로 코딩하는것이 편하다는 이야기였다. 개발자의 편의를 위해 개발된 툴이 오히려 개발자의 발목을 잡는 암흑기가 있었다는 것이다. 난세에 영웅이 나오듯이 자바 진영에는 로드 존슨이라는 영웅이 나타나 세상을 평정하게 된다. 로드 존슨은 J2EE Design and Development라는 책을 출간하게 되고 이 책을 읽은 개발자들은 EJB대신 책에 나온 코드를 프레임 워크로 사용해서 개발하기 시작했다. 이 책에는 스프링의 핵심코드들이 수록 되어있었다. 책을 출간한 후에 유겐 휠러, 카로프가 오픈소스 프로젝트를 제안하게되고 EJB라는 겨울에서 벗어나 자바진영의 봄이 왔다는 뜻으로 Spring이라는 이름으로 오픈소스 프로젝트를 시작한다. 이것이 스프링의 시작이다. 하이버네이트도 이것과 같은 이유로 개발되었고 새로운 ORM의 표준(JPA)이된다.
02 스프링 생태계
스프링은 스프링 프레임워크나 스프링 부트 외에도 다양한 어플리케이션들이 존재한다. 이러한 스프링 생태계를 전부 이해하는 것은 불가능하지만 어떠한 어플리케이션들이 있는지 정도는 알고 있는게 중요하다. 이러한 어플리케이션들이 유기적으로 움직이는 것이 스프링의 생태계이다.
•
핵심 기술: 스프링 DI 컨테이너, AOP, 이벤트, 기타
•
웹 기술: 스프링 MVC, 스프링 WebFlux
•
데이터 접근 기술: 트랜잭션, JDBC, ORM 지원, XML 지원
•
기술 통합: 캐시, 이메일, 원격접근, 스케줄링
•
테스트: 스프링 기반 테스트 지원
•
언어: 코틀린, 그루비
스프링 부트는 이러한 기술들을 편리하게 관리해주고 이어주는 역할을 한다. 버전끼리의 호환성을 알아서 관리해주고 설정해준다.
03 왜 스프링?
스프링이 개발된 이유는 단 하나다. 자바의 객채지향의 이점을 완벽하게 활용하기 위해서이다. 나머지 편리한 기능들, 웹 어플리케이션 만들기, DB접근 관리, 전자정부 프레임워크 등등은 객채지향의 산물이라고 생각한다. 그럼 그냥 자바를 사용하지 왜? 스프링을 사용하는 것인가? 그리고 객채지향이 왜 좋은것인가? 라는 의문이 생긴다.
01) 플레인 자바의 한계점
객채지향에서 플레인 자바의 한계점은 없다. 다만, 위에서 말한 로드 존슨의 핵심코드(약 3만 줄)의 코드를 SOLID에 맞는 어플리케이션 개발할 때 마다 계속쳐야 한다는 것이다. 그 3만 줄의 코드 중에 가장 중요한것은 무엇인가?
02) 스프링의 핵심
DI(dependency injection)이다. DI보다 중요한 개념은 스프링에서 없다. DI를 함으로써 우리는 추상화에만 의존하여서 구현 할 수 있고, 또, 추상화 개념들만 맞춰주면 런타임에서 객채를 끼웠다 뺐다 할 수 있는것이다. 이것은 엄청난 이점이다. 결국, SOLID의 이점을 전부 챙길 수 있는것이다.
03) 객채지향의 이점, SOLID의 이점
객채지향을 잘 구현하려면 객채의 책임을 기준으로 객채간의 관계를 우선으로 지정하고 구현과 책임을 분리하여 코딩하면 유연하고 변경이 용이하며 확장 가능한 설계를 할 수 있다. 따라서, 인터페이스를 안정적으로 설계하는게 중요하고 그럴려면 SOLID를 잘 이해하고 있어야한다.
결국, SOLID는 객채의 책임과 인터페이스 설계에 대한 이야기다. 하나씩 들여다보자.
•
SRP: 하나의 객체에 하나의 책임이 들어가야한다. 즉, 어떠한 메시지가 들어가면 어떠한 메시지를 출력할지 정할때 적당한 책임을 부여해야 한다는것이다. 여러가지 책임을 부여하는 객채가 있으면 대채가 어렵고 유지보수 또한 복잡해진다. 하나의 객채에 하나의 책임이다. 하지만, 이 부분에는 상당히 오묘한 점이 존재한다. 책임의 크기를 정하는 것이다. 어느것이 적당한 책임의 크기인지는 유스케이스를 잘 생각해서 나눠야하며 그럴려면 도메인에 대한 이해가 필수적이다.
•
OCP: 확장에는 열려있어야하며 변경에는 닫혀있어야 한다. 이게 무슨 소리인가 하면, 확장을 할때 최소한의 코드만 건드려야 하는것이다. 하나의 기능을 달려고 모든 코드를 손보는 일이 있어서는 안된다. 딱, 원하는 부분만 고치면 확장이 가능해야 한다는 말이다. 즉, 객채끼리 연결성이 희미해야 한다는 것이다. 서로 메시지는 주고 받지만 내부를 들여다보는 코드가 있어서는 안된다.
•
LSP: 인터페이스 설계가 정해지면 그 설계에 따라서 객채를 구현해야한다. 컴파일이 되고 안되고의 문제가 아니라 명세를 정확하게 따라서 설계하여서 다형성을 가질수 있도록 코딩해야한다는 것이다. 예를들면 악셀를 밟으면 앞으로 가는 자동차라고 명세에 써있으면 뒤로 가는 자동차를 개발해서 인터페이스에 꽂으면 자동차이기 때문에 컴파일에는 문제는 없지만 기능에는 상당한 문제가 생긴다. 인터페이스의 명세에 따라서 실제 객체를 구현해야한다.
•
ISP: 인터페이스를 쪼개야한다. 여러가지를 기능을 가지고 있는 범용인터페이스 한개보다는 책임소지가 분명한 여러개의 인터페이스가 객채지향의 방향과 맞는 코드이다. 대채 가능성이 높아지고 인터페이스의 방향이 명확해진다.
•
DIP: 코드는 추상화에 의존해야한다. 구체화에 의존해서는 안된다. 구체화에 의존하게되면 객채들은 서로 내부를 들여다 볼 수있고 대채가능성이 상당히 떨어지고 코드끼리 얽혀있게되어 유기적인 관계를 맺는게 상당히 힘들어진다. 쉽게 이야기해서 인터페이스를 의존해야지 클래스에 의존해서는 안된다는 것이다.
여기서 스프링이 해결해준 문제는 OCP와 DIP를 획기적으로 해결해주었다.
class MemberService{
MemberRepository m = new MemoryMemberRepository();
}
Java
복사
이 코드는 DIP와 OCP를 위반한 코드이다. 왜냐하면 멤버서비스 클래스가 직접 레포지토리 객채를 들여다보고 있기 때문이다. 이러한 코드는 연극으로 치면 배우가 상대역을 캐스팅하는 것이다. 스프링의 역할은 감독이 되어서 배우들을 캐스팅해서 적당한 자리에 넣어주는데에 있다. 그렇게 함으로써 배우들은 자기가 맡은 연기에만 집중할 수 있도록 도와주는 것이다.
스프링은 객채지향을 올바르게 구현할 수 있도록 도와주고 있다. 이제 직접 스프링을 사용하면서 그 이점을 느껴보면 체감 할 수 있을것이다. 객채지향의 이점은 코드의 확장성이 획기적으로 증가하고 코드들을 부품처럼 갈아끼울 수 있어서 유지보수가 편해진다. 어플리케이션이 커지면 커질수록 객채지향의 중요성은 강조된다. 따라서, 스타트업에서 대기업으로 가는 과정에서 대부분의 회사들에서 빠른 개발보다는 유지보수가 용이한 Java Spring으로 개발을 대채하는 것이다.