2 분 소요

스프링

스프링이란 문맥에 따라 아래와 같이 다르게 사용된다.

  • 스프링 DI 컨테이너 기술

  • 스프링 프레임워크

  • 스프링 부트, 프레임워크 등 모두 포함한 생태계

이런 스프링을 편리하게 사용하기 위해서 주로 스프링 부트와 함께 사용한다. 여기서 스프링 부트는 스프링을 편리하게 사용할 수 있도록 지원하는 것이지 단독으로 사용할 수 없다. 스프링 부트를 사용함으로 얻을 수 있는 장점은 다음과 같다.

  • 스프링 부트를 이용하면 Tomcat과 같은 웹 서버를 내장하기 때문에 별도의 웹 서버를 설치하지 않아도 되고 이런 내장서버를 통해 단독으로 실행 할 수 있는 애플리케이션을 쉽게 생성 할 수 있다.
  • 기본적으로 필요한 dependency 들을 포함하는 starter 종속성을 제공하여 이 starter 종속성만으로 한번에 설정가능하다
  • 라이브러리 사이에 버전이 안 맞으면 안 돌아가는 dependency conflict를 해결할 수 있게 잘 호환이 되는 버전을 알아서 구성해준다.

스프링의 핵심 개념

스프링은 다양한 기능을 제공하지만 스프링이 만들어진 이유, 즉 핵심 개념은 좋은 객체 지향 애플리케이션 개발을 돕기 위함이다. 스프링은 자바 언어 기반의 프레임워크이고 자바 언어의 가장 큰 특징은 객체 지향언어라는 것이다. 즉, 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크이다.

좋은 객체 지향에 대해서는 SOLID 를 참고하자

https://ahrang777.github.io/etc/solid/

이 SOLID 중 스프링의 필요성과 연관하여 간단하게 OCP, DIP 그리고 객체 재향의 특징 중 하나인 다형성에 대해 알아보자

다형성

다형성은 프로그램을 유연하고 변경이 용이하게 만들어 준다. 예를 들면 내가 평소 쓰던 마우스를 바꿔도 문제없이 평소처럼 사용할 수 있다. 이처럼 다형성은 컴포넌트를 유연하게 변경하면서 개발할 수 있게 해준다.

다형성을 고려하여 개발을 한다는 것은 역할(인터페이스), 구현(인터페이스 구현 클래스, 구현 객체)을 구분하는 것이다.

spring1

다음 사진을 보면 운전자는 자동차라는 역할만 알면 되고 K3, 아반떼, 테슬라 모델3 에 대해서는 잘 몰라도 운전이 가능하다. 때문에 K3 에서 아반떼로 차를 바꾸어도 아무 문제없이 운전할 수 있다.

이처럼 역할과 구현을 분리를 하면 클라이언트 입장(예시의 운전자)에서 여러 장점이 있다.

  • 클라이언트는 인터페이스만 알면 된다.
  • 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
  • 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
  • 클라이언트는 구현 대상을 변경해도 영향을 받지 않는다.

여기서 클라이언트가 영향을 받지 않는다는 것은 클라이언트의 코드 변경이 없다는 것이다. 이처럼 역할, 구현을 분리하면 유연하고 변경이 용이하며 어떠한 구현체를 만들어도 클라이언트는 상관이 없다. 즉, 계속해서 확장이 가능하다. 때문에 이 역할(인터페이스)이 중요하여 가급적 역할의 변화를 적게 안정적으로 설계하는 것이 중요하다.

클라이언트: 요청하는 객체

서버: 응답하는 객체

OCP(개방-폐쇄 원칙, Open/closed principle)

OCP는 소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 한다 라는 의미다. 앞서 설명한 다형성에서의 역할과 구현을 분리했던 예시를 생각해보자. 자동차라는 역할을 구현한 K3, 아반떼, 테슬라 모델3 가 있다. K3에서 테슬라로 변경한다 하더라도 클라이언트는 변경이 없다. (변경에 닫혀있다) 그리고 기름 자동차뿐 아닌 전기 자동차가 추가되어도 클라이언트 입장에서 사용할때 자동차라는 역할만 알면 되니 확장에 열려 있다.

이런 OCP의 경우 얼핏 문제 없어 보이지만 다음과 같은 문제가 있다.

구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다.

예를 들면 클라이언트 쪽에서 Car car = new K3(); 의 형태로 사용하다가 구현 객체를 변경아려면 Car car = new Tesla(); 처럼 코드를 변경해야 한다. 이는 OCP를 위반한 것이다. 이를 해결하기 위해선 객체를 생성하고 연관 관계를 맺어주는 별도의 설정자가 필요하다.

DIP(의존관계 역전 원칙, Dependency inversion principle)

프로그래머는 추상화에 의존해야지, 구체화에 의존해선 안된다 라는 것이다. 즉, 구현 클래스가 아닌 인터페이스에 의존하라는 것이다. 하지만 OCP처럼 DIP 또한 문제가 있다.

인터페이스 뿐 아니라 구현 클래스도 의존한다.

OCP 예시에서 Car car = new K3(); 를 보면 클라이언트는 Car 이라는 인터페이스에 의존하지만 K3 라는 구현 클래스에도 의존한다. 이는 DIP를 위반한 것이다.

위에서 보았듯이 단순 다형성만으로는 OCP, DIP를 지킬 수 없다. 순수하게 자바로 OCP, DIP를 지키면서 개발을 해보면 결국 스프링 프레임워크가 나오게 된다. 스프링의 경우 객체를 생성하고 의존관계를 주입해 줘서 다형성+ OCP, DIP가 가능해진다.

요약

  • 스프링의 핵심은 좋은 객체 지향 애플리케이션 개발을 돕는데 있다.

  • 좋은 객체 지향을 위해 역할(인터페이스) 과 구현(인터페이스 구현 클래스, 구현 객체) 을 분리하여 유연하고 변경 용이하게 설계하자.
  • 단순 다형성 만으론 OCP, DIP 를 지킬 수 없었고 이를 해결하며 개발하다 보면 결국 스프링 프레임워크가 나오게 된다.
참고: [스프링 핵심 원리 - 기본편 - 인프런 강의 (inflearn.com)](https://www.inflearn.com/course/스프링-핵심-원리-기본편)

태그:

카테고리:

업데이트:

댓글남기기