[토비의 스프링] - 오브젝트와 의존관계

Ader(아더)·2022년 3월 10일
0

Spring

목록 보기
1/6
post-thumbnail

✔ 오브젝트와 의존관계


이 포스팅은 토비의 스프링을 읽고 개인적으로 정리하는 글입니다.

스프링의 관심사는 뭘까?

  • 스프링은 당연히도 자바를 기반으로 한 기술이고 자바에서 가장 중요하게 가치를 두는 것은 객체지향 프로그래밍이라고 한다.
  • 자바 엔터프라이즈에서 잃었던 객체지향 기술을 회복하고 그 폭넓은 혜택을 누리기 위해 기본으로 돌아가자! 이것이 바로 스프링의 핵심 철학이다.
  • 그래서 스프링이 가장 관심을 많이 두는 대상은 오브젝트이다.

관심사의 분리

  • 개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항은 미래의 변화를 어떻게 대비할 것인가이다.
  • 객체지향 프로그래밍은 이런 변화에 상대적으로 유연하게 대응할 수 있다. 좋은 대책은 변화의 폭을 최소한으로 줄여주는 것!
  • 분리와 확장
    • 분리
      • 모든 변경과 발전은 한 번에 한 가지 관심사항에 집중해서 일어난다는 뜻(단일 책임 원칙을 지켜서 코딩하자!)
      • 관심사의 분리(Seperation of Concerns)를 객체지향에 적용해보면, 관심이 다른 것은 가능한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것
      • 중복 코드의 메소드 추출
      • 변경이 일어나면 이에 대해 검증이 필요하며 이것을 편리하게 하기 위해 우리는 테스트 코드를 작성해두는 편이 좋다!
    • 확장
      • 상속을 통한 확장
      • 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법을 디자인패턴에서 템플릿 메소드 패턴이라고 한다.
      • 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴이라고 한다.

확장

  • 클래스의 분리
    • 완전히 독립적인 클래스로 분리해보자
      • ex) SimpleConnectionMaker
    • 자유로운 확장이 가능하려면 아래 두 가지 문제를 해결해야함
      • SimpleConnectionMaker의 메소드명들
      • 사용할 클래스를 구체적으로 알고있어야함
    • 위의 문제를 해결할 수 있는 방법은?
      • 두 개의 클래스가 서로 긴밀하게 연결되어 있지 않도록 중간에 추상적인 느슨한 연결고리를 만들어주자!
      • 추상화란 어떤 것들의 공통적인 성격을 뽑아내어 이를 따로 분리해내는 작업
      • 최선의 선택은 인터페이스이다
  • 관계설정 책임의 분리
    • 공통 관심사를 인터페이스로 잘 분리해냈지만 아직 어느 구현체를 사용할지 코드에 남아있다. 이를 분리해내야한다.
    • 다형성을 잘 활용하려면 사용하는 곳에서 구현체로 객체를 생성하지 않고 인터페이스로 생성해 코드를 작성한 후 사용하려는 구현체를 잘 주입해주면 된다!
  • 원칙과 패턴
    • 개방 폐쇄 원칙(Open Closed Principle)
      • 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.
      • 책의 예제에서는 DB 연결 방법을 여러 개의 방법으로 확장하는 데 열려있다.
      • 또한 핵심 기능 구현 코드는 변화에 영향을 받지 않으니 변경에는 닫혀있다고 표현한다.
    • 높은 응집도와 낮은 결합도
      • 응집도가 높다는 것은 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있다는 뜻
      • 높은 응집도
        • 응집도가 높다는 것은 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 것
        • 즉, 변경이 일어날 때 모듈의 많은 부분이 함께 바뀐다면 응집도가 높다고 말할 수 있다.
      • 낮은 결합도
        • 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직
        • 느슨한 연결은 관계를 유지하는데 꼭 필요한 최소한의 방법만 간접적인 형태로 제공하고, 나머지는 서로 독립적이고 알 필요도 없게 만들어주는 것
        • 결합도'하나의 오브젝트가 변경이 일어날 때에 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도'
        • 책의 예제에서는 DB 연결 기능 구현 클래스가 변경되어도 DAO가 변경되지 않으니 낮은 결합도이다
        • 보통 낮은 결합도를 위해 인터페이스를 많이 사용하는 듯하다.
    • 전략 패턴
      • 전략 패턴은 개방 폐쇄 원칙에 가장 잘 들어 맞는 패턴이다.
      • 자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴
      • 책에서는 UserDao가 컨텍스트이며, DB연결 방식이라는 알고리즘을 인터페이스로 정의하고, 이를 구현한 클래스들을 바꿔가며 사용한다.

제어의 역전(Inversion Of Control)

  • 팩토리
    • 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 역할을 하는 오브젝트들을 흔히 팩토리라고 부른다.
    • 사용하는 목적은 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 깔끔하게 분리하려는 목적
    • 이렇게 팩토리 클래스로 분리해냈을 때 우리는 DAO의 내부 코드를 수정할 필요없이 구현 클래스 변경이 필요하면 팩토리에서 수정을 통해 변경이 이루어진다.
  • 오브젝트 팩토리
    • 이렇게 분리해냈지만 DAO가 추가되면 중복코드가 다시 오브젝트 팩토리 내부에 생긴다.
    • 이를 해결하기 위해 어떤 구현체를 의존할지 메소드로 분리해놓고 사용하면 중복코드가 최소한으로 줄어든다.
  • 제어권의 이전을 통한 제어관계 역전
    • 제어의 역전이란 프로그램의 제어 흐름 구조가 뒤바뀌는 것
    • 제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않는다.
    • 서블릿의 경우에는 서블릿에 대한 제어 권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출한다.
    • 가장 대표적으로는 프레임워크가 제어의 역전 개념이 적용된 대표적인 기술이다.

스프링에서의 IoC

  • 오브젝트 팩토리를 이용한 스프링 IoC
    • 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 빈(Bean)이라고 부른다.
    • 동시에 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말이다.
    • 스프링에서 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리라고 부른다.
    • 보통 빈 팩토리보다는 기능을 좀 더 확장한 애플리케이션 컨텍스트를 주로 사용한다.
    • 스프링이 빈 팩토리를 위한 오브젝트 설정을 담당하는 클래스라고 인식할 수 있도록 @Configuration 어노테이션을 클래스에 추가한다.
    • 오브젝트를 만들어주는 메소드에는 @Bean이라는 어노테이션을 부여준다.
  • 애플리케이션 컨텍스트의 동작방식
    • 스프링에서는 애플리케이션 컨텍스트를 IoC 컨테이너라고 하기도 하고, 간단히 스프링 컨테이너라고 부르기도 한다.
    • 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다
    • 어플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다
    • 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다
  • 스프링 IoC의 용어 정리
    • 빈(Bean)
      • 스프링이 IoC 방식으로 관리하는 오브젝트
      • 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만을 빈이라고 부른다
    • 빈 팩토리(Bean Factory)
      • 스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다.
      • 빈을 등록하고, 생성하고, 조회하고 돌려주고, 관리하는 기능을 담당한다.
    • 어플리케이션 컨텍스트(Application Context)
      • 빈 팩토리를 확장한 IoC 컨테이너다.
      • 빈 팩토리라고 부를 때는 주로 빈의 생성과 제어의 관점에서 이야기 하는 것이고, 애플리케이션 컨텍스트라고 할 때는 스프링이 제공하는 애플맄이션 지원 기능을 모두 포함해서 이야기하는 것이라고 보면 된다.
    • 컨테이너 또는 IoC 컨테이너
      • IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고도 한다.
    • 스프링 프레임워크
      • 스프링 프레임워크는 IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용한다.

싱글톤 레지스트리와 오브젝트 스코프

  • 싱글톤 레지스트리로서의 애플리케이션 컨텍스트
    • 스프링은 기본적으로 별다른 설정을 하지 않으면 내부에서 생성하는 빈 오브젝트를 모두 싱글톤으로 만든다.
    • 서버 어플리케이션과 싱글톤
      • 스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경이기 때문에 싱글톤으로 빈을 만든다.
      • 서버 환경에서 매번 클라이언트의 요청이 올때마다 오브젝트를 만들어서 사용하면 엄청난 부하가 일어난다.
    • 싱글톤 패턴의 한계
      • private 생성자를 갖고 있기 때문에 상속할 수 없다
        • 이는 객체지향의 상속과 다형성을 적용할 수 없다는 뜻이다.
      • 싱글톤은 테스트하기가 힘들다
        • 싱글톤은 만들어지는 방식이 제한적이기 때문에 테스트에서 사용될 대 목 오브젝트 등으로 대체하기가 힘들다.
      • 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다
        • 서버의 클래스 로더 구성 방식에 따라서 싱글톤임에도 하나 이상의 오브젝트가 만들어질 수 있다.
      • 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다
        • 싱글톤의 스태틱 메소드를 이용해 언제든지 싱글톤에 쉽게 접근할 수 있기 때문에 애플리케이션 어디서든지 사용될 수 있고, 그러다 보면 자연스럽게 전역 상태로 사용되기 쉽다.
    • 싱글톤 레지스트리
      • 스프링은 자바의 싱글톤 구현 패턴의 단점을 보완하기 위해 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공하는데 이를 싱글톤 레지스트리라고 한다.
    • 싱글톤과 오브젝트 상태
      • 싱글톤은 멀티스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있기 때문에 상태관리에 주의를 기울여야 한다.
      • 여러 스레드가 접근할 수 있기 때문에 내부에 상태를 갖고 있지 않은 무상태방식으로 만들어져야 한다.
    • 스프링 빈의 스코프
      • 스프링 빈의 기본 스코프는 싱글톤이다. 이는 컨테이너 내에 한 개의 오브젝트만 만들어져서, 강제로 제거하지 않는 한 스프링 컨테이너가 존재하는 동안 계속 유지된다.
      • 경우에 따라서는 프로토타입 스코프를 가질수 있는데 이는 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.

의존관계 주입(DI)

  • 제어의 역전(Ioc=C)과 의존관계 주입
    • 스프링이 제공하는 IoC 방식을 의존관계 주입이라는 이름으로 사용한다.
    • 초기에는 주로 IoC컨테이너라고 불리던 스프링이 직므은 DI컨테이너라고 더 많이 불리고 있다.
  • 런타임 의존관계 설정
    • 의존관계
      • 의존한다는 것의 의미는 한 쪽이 변하면 다른 한쪽에 영향을 미친다는 뜻이다.
      • 의존관계에는 방향성이 있다.
    • 의존관계에 의한 변경을 최소한으로 줄일 수 있는 방법은 역시 인터페이스를 사용하는 방법인 것 같다!
    • 의존관계 주입은 다음 세 가지 조건을 충족하는 작업을 말한다.
      1. 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.
      2. 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.
      3. 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공해줌으로써 만들어진다.
    • 즉, 의존관계 주입의 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제 3의 존재가 있다는 것이다.
  • 의존관계 검색과 주입
    • 의존관계를 맺는 방법이 외부로부터의 주입이 아니라 스스로 검색을 하는 방식을 의존관계 검색이라고 부른다.
    • 이 방법은 내부에서 스스로 컨테이너에게 필요한 빈을 요청한다.
    • 기존 의존관계 주입의 모든 장점을 갖고 있지만 오브젝트 팩토리 클래스와 스프링 API를 내부에 갖고있어 다른 오브젝트에 의존하게 되어 그다지 바람직하지 않다.
  • 의존관계 주입의 응용
    • DI의 기술의 장점은?
      코드에는 런타임 클래스에 대한 의존관계가 나타나지 않고, 인터페이스를 통해 결합도가 낮은 코드를 만들어서 다른 책임을 가진 사용 의존관계에 있는 대상이 바뀌거나 변경되더라도 자신은 영향을 받지 않으며, 변경을 통한 다양한 확장 방법에는 자유롭다!
    • 기능구현의 교환
      • 예를 들면 실제 운영에 사용할 데이터베이스는 매우 중요한 자원이므로 테스트용으로는 localDB를 활용하려고 한다.
      • 이때 connectionMaker() 내부에 있는 구현체 한 줄만 변경하게 되면 코드의 변경을 최소화하며 목적을 달성할 수 있다.
    • 부가기능 추가
      • 또한 테스트용도로 기능을 추가하고 싶을 때 단순히 구현체를 하나 더 만들어 그 구현체로 갈아끼우면 간단하게 목적을 달성한다.
  • 메소드를 이용한 의존관계 주입
    • 요즘 스프링에서는 롬복과 final 키워드를 활용해 생성자 주입을 사용하라는 것이 대세이지만 책에서는 다른 방법도 제시하고 있다.(물론 이렇게 쓰면 인텔리제이가 고치라고 한다!)
    • setter 메소드 사용
      • setter 메소드를 통해 인스턴스를 변경하는 방법이다.
      • 이 방법은 어디서든 사용할 수 있기 때문에 변경 포인트를 관리하기 어려워 권장되지 않는 방법이다.
    • 일반 메소드 사용
      • 이 방법은 굳이 생성자의 모든 파라미터를 갖고 싶지 않을 때 활용할 수 있는 방법이지만 실수하기 쉽고 다른 개발자와의 협업이 어려울 수 있어 개인적으로는 고려되지 않는 방법이다!

XML을 이용한 설정

  • 요즘은 거의 사용하지 않는 XML을 통한 설정 방법이다.
  • 가볍게 읽고 지나가자!

정리

  • 스프링이란 어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임워크라는 사실을 꼭 기억하자!
  • 스프링의 관심사는 오브젝트와 그 관계다. 하지만 오브젝트를 어떻게 설계하고, 분리하고, 개선하고, 어떤 의존관계를 가질지 결정하는 일은 스프링이 아닌 개발자의 역할이며 책임이다!
  • 스프링은 단지 번거로운 작업을 편하게 도와주는 도구일 뿐이다!
profile
하루하루 성장하는 개발자

0개의 댓글