객체 지향 설계와 스프링

스프링의 컨셉

circle-info

스프링의 과거와 핵심 컨셉

자바 언어 기반의 프레임워크

스프링은 객체 지향 언어가 가진 강력한 특징을 살려내어 좋은 애플리케이션을 개발할 수 있도록 도와주는 프레임워크이다.

스프링으로 문제를 해결하고자 했던 부분은 EJB의 특징 중 하나였던 EJB 가 만들어 놓은 의존성에 의존 하여 코드를 개발 해야하는 점이다.

  • 이러한 문제점은 객체지향이 갖고 있는 좋은 스타일을 잃고 EJB 스타일에 맞춰 개발을 할 수 밖에 없었다.

그래서 1차적인 문제 해결 방법으로 POJO 라는 순수한 자바로 다시 돌아가는 프로젝트를 선택하기도 했다.

하지만, 스프링은 DI 컨테이너 방식을 활용하여 좋은 객체 지향 방식으로 애플리케이션을 만들어낼 수 있는 도구라는 것을 Rod Johnson이 책을 출간하며 많은 개발자가 주목하게 되었다.

"스프링의 컨셉인 좋은 객체지향 프로그래밍이란 뭘까?"

유연하고 변경이 용이한 다형성을 극대화 하여 사용할 수 있는 도구이다.

자동차를 타는 운전자는 변하지 않지만 자동차는 매번 새로운 모델을 출시한다. 하지만 그 타겟층은 언제나 같은 운전자를 타겟으로 삼고 출시한다.

"이 것은 운전자는 새로운 차가 나오더라도 새로운 차를 운전하는 데 지장이 없다." 라는 얘기다.

이 내용을 서비스의 시선으로 바라보면, 클라이언트에게 아무런 영향을 주지 않고 새로운 기능을 출시할 수 있다는 것이다.

circle-info

정리하기

역할과 구현을 명확히 분리하면 단순하게 설계할 수 있고 유연해지며 변경도 편리하다.

  • 클라이언트는 대상의 역할(인터페이스)만 알면 된다.

  • 클라이언트는 역할을 구현하고 있는 구현체를 변경해도 영향을 받지 않는다.

구현보다 역할이 먼저 탄생해야한다.

  • 즉, 서비스 클래스보다 인터페이스를 먼저 설계 하며 인터페이스를 안정적으로 설계 해야한다.

위 좋은 장점에 비해 분명한 한계점이 존재한다.

그 한계점은 "인터페이스" 자체가 변하는 경우 결국 내부 구현 코드와 인터페이스를 사용하는 클라이언트의 코드가 변경이 일어나기 때문이다.

그래서 인터페이스를 최대한 변경이 없는 선에서 안정적으로 설계하는 것이 대안이며 핵심이다.

circle-info

좋은 객체 지향 설계의 5가지 원칙

SRP - 단일 책임 원칙

하나의 클래스는 하나의 책임만 가져야한다. 하지만 책임의 크기가 굉장히 모호하다.

그래서 중요한 기준은 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따랐다고 볼 수 있다.

OCP - 개방 폐쇄 원칙 [중요!]

확장에는 열려있으면서 변경에는 닫혀있어야한다.

인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현 하는 다형성을 활용하더라도 구현 객체를 변경하기 위해서는 클라이언트 코드가 변경이 일어난다.

위 코드 처럼 새로운 구현 코드를 반영하기 위해서 기존 사용하던 구현체를 주석처리 하는 변경이 일어난다.

이 문제점을 해결하기 위해서 객체를 적재적소에 주입시킬 수 있는 별도의 설정자가 필요한데, 스프링 컨테이너가 이 역할을 대행 해주고 있다.

LSP - 리스코프 치환 원칙

다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야한다.

  • 즉, 인터페이스가 설계한 기능의 규약을 보장을 해줘야한다.

자동차가 엑셀을 밟는다는 기능이 있고, 이 기능은 앞으로 간다는 규약이 있다.

  • 만약 구현하는 구현체에서 엑셀이 뒤로 가는 기능을 구현했을 때 전혀 컴파일 단계에선 오류가 없지만 인터페이스가 설계한 규약에선 어긋난다.

이러한 예시 상황을 어긋나지 않도록 설계하는 원칙이다.

ISP - 인터페이스 분리 원칙

특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

  • 자동차 인터페이스

    • 운전 기능을 설계한 인터페이스

    • 정비 기능을 설계한 인터페이스

위 자동차 인터페이스가 만약, 한 개의 자동차 인터페이스로 관리되고 있다고 가정해보자.

정비 기능에 문제가 생겨서 코드를 수정할 때 자동차 인터페이스 전체가 영향을 받는다.

이런 거대한 인터페이스 하나를 수정하는 것 보다 작은 기능에 대한 인터페이스를 수정하는게 유지보수 측면에서 도움이 되며, 정비 인터페이스 자체가 변하더라도 클라이언트에게 영향을 주지 않는다.

DIP - 의존관계 역전 원칙 [중요!]

프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다."

클라이언트 코드가 구현된 코드를 바라보지 말고 인터페이스를 바라보도록 설계해야한다.

chevron-right요약hashtag

결론적으로 객체 지향의 핵심은 다형성인 것은 확실하다.

  • 하지만, 다형성만으로 코드를 갈아끼울 수 없다.

  • 다형성만으로 구현 객체를 변경할 때 클라이언트 코드도 함께 변경 된다.

  • 다형성만으로 OCP, DIP를 지킬 수 없다.

다시 스프링으로!

circle-info

스프링은 DI 컨테이너 기술로 다형성 + OCP, DIP 를 가능 하도록 지원한다.

"스프링이 없던 시절"

객체지향 설계를 하기 위해 OCP, DIP 원칙을 지키면서 개발을 해보니 너무 할 일이 많았다. 위에서 잠깐 언급했던 DI 컨테이너 기술이 순수 자바로 구현 되는 것 처럼 말이다.

Last updated