💡 Intro

  • 스프링에서 어느날 등장한 개념은 아니고 어떠한 이름으로든 사용이 되고 있던 기술인데 스프링에서 더 잘 사용되도록 특정 형태를 부여했다.
  • 이 3가지 기술들이 그 자체로 스프링이기보다 POJO 기반 엔터프라이즈 개발을 편하게 해줄 수 있는 일종의 도구이다. 즉, 객체지향적인 구현에 충실하면서 자연스럽게 등장하게 된 결과라고 할 수 있다.
  • 스프링에서 제공하는 PSA, AOP만 사용하는 것이 아니라 그 개념을 차출하여 객체지향적 구현을 하는 것이 중요하다.

🌩 IoC/DI

  • AOP, PSA도 IoC/DI에 바탕을 두고 있는 기술이다.
  • 느슨한 결합을 위해 인터페이스를 두고 실제 구현체를 DI를 통해 외부에서 주입하는 것이다.

왜 강한 결합보다 느슨한 결합이 나은가?

  • 유연한 확장이 가능하게 하기 위해서 → OCP
  • 변경에 닫혀있다는 것은 재사용이 가능하다 라는 뜻이다.
    • A → B 의존관계일 때 B가 변경이 되어도 A가 아무 영향을 받지 않으면 A 입장에서는 폐쇄이며 B 관점에서는 유연한 확장이다.
    • B가 B1, B2, B3로 바뀔수도 있고, A는 그대로 재사용이 가능하기 때문이다.

DI의 활용 방법 및 장점

  1. 핵심기능의 변경
    • 구현체를 바꿀 수 있다.
    • 예를 들어 DAO를 사용하고 그 구현을 JDBC, JPA 하이버네이트, JDO 등으로 바꿀 수 있다.
  2. 핵심기능의 동적인 변겅
    • 애플리케이션 동작 중간에 의존 대상을 다이나믹하게 변경할 수 있다.
    • 예를들어 사용자의 입력에 따라서 다른 DataSource를 사용하게 만들 수 있다.
    • 기술적으로 프록시를 활용한 것인데 이것은 DI 없이는 불가능한 기술이다.
  3. 부가기능의 추가
    • 핵심 기능은 그대로 둔 채 부가기능을 추가하는 데코레이터 패턴과 같은 것이다.
    • DI를 사용해서 데코레이터 패턴을 쉽게 적용할 수 있다.
    • 클라이언트 코드에는 영향을 주지 않으면서 부가기능 추가가 가능하다.
    • 부가 작업을 특정 오브젝트를 대상으로 하는 것이 아니라 많은 대상으로 일반화 한다면 AOP가 되는 것이다.
  4. 인터페이스의 변경
    • 클라이언트에서 사용하는 인터페이스와 오브젝트의 인터페이스가 일치하지 않을 때 DI를 활용하여 어댑터 패턴을 응용할 수 있다.
    • 예를 들어 A가 B인터페이스에 의존하지만 C 오브젝트를 사용하고자 할 때, B 인터페이스를 상속하고 C기능을 제공하는 어댑터를 구현하여 해결할 수 있다.
    • 일반화하여 인터페이스가 다양한 구현을 같은 방식으로 사용하도록 할 수도 있다. → PSA
      • 구현체는 다양하지만 클라이언트 입장에서는 같은 방식으로 늘 사용하는 것이다.
  5. 프록시
    • 필요한 시점에서 실제로 사용할 오브젝트를 초기화해고 지연된 로딩을 적용할 때 사용할 수 있다.
  6. 템플릿과 콜백
    • 작업의 흐름 사이에 자주 바뀌는 부분을 템플릿과 콜백으로 만들고 DI 원리를 사용하면 코드를 간결하게 구현할 수 있다.
  7. 싱글톤과 오브젝트 스코프
    • DI하는 오브젝트의 생명주기를 제어할 수 있다. DI를 컨테이너가 한다면 오브젝트의 생명주기를 마음대로 관리하고 제어할 수 있다.
    • 기본 스코프는 싱글톤이다. 웹 엔터프라이즈는 수많은 클라이언트를 대상으로 서비스를 제공해야하기 때문에 여러 스레드의 요청을 동시에 처리할 수 있도록 하기 위해서다.
    • 전통적인 싱글톤은 오브젝트에 많은 제약을 가했지만 IoC 방식의 싱글톤은 자유로운 설계가 가능하다.
  8. 테스트
    • 오브젝트를 효과적으로 테스트하기 위해서는 오브젝트가 고립되어야 한다.
    • 다른 오브젝트와 협력하는 부분을 테스트하기 위해서는 환경 전체를 테스트해야한다는 부담감이 있다.
    • DI를 한다면 의존 오브젝트를 대신하여 스텁 혹은 목 오브젝트 같이 테스트 대역을 할 수 있다.
      • 번외) stub과 mock의 차이

        stub은 더미 객체를 사용하여 실제로 동작하는 것 처럼 보이도록 하는 것이다. 상태검증을 한다.

        mock은 기대값을 명세하고 특정 결과를 반환하도록 하는 것이다. 행위검증을 한다.


🌩 AOP

  • 관점 지향 프로그래밍이라고도 많이 알려져 있다.
  • 관심사가 같은 코드를 분리해 객체지향의 원칙에 따라서 분리하고 응집된 것들을 한 곳에 모으는 것이 좋다.
  • 트랜잭션의 경우
    • 트랜잭션은 한 곳에 모을 수 없고 여기저기에 흩어져있다. 따라서 모듈화가 힘들다.
    • 부가기능이기 때문에 스스로 독립적인 방식으로 존재하는 것이 어렵다.
    • 흩어져있는 부가로직을 분리하여 중복되지 않고, 변경이 필요한 경우 한 곳만 변경할 수 있도록 하는 것이 AOP의 역할이다.
  • Aspect는 부가 기능을 정의한 advice와 해당 advice를 적용할 포인트컷을 가지고 있다.
  • 부가기능이 핵심기능 모듈에 침투하면서 핵심기능을 파악하고 수정하고 테스트하기 어렵다.
  • AOP와 OOP
    • AOP와 OOP가 대체관계라고 생각할 수 있지만 사실 보조하는 기술이다.
    • 부가기능이 핵심기능 안으로 침투하면 핵심기능에 객체지향 기술을 부여하기 힘들고 테스트하기 어려움으로 AOP로 해당 로직을 분리하여 객체지향적인 가치를 지킬 수 있도록 해주는 것이다.

🌩 PSA

  • 환경과 세부 기술의 변화와 관계없이 일관된 방식으로 기술에 접근할 수 있다.
  • POJO 코드가 JavaEE에 직접 노출되지 않도록 해준다.
    • 예를 들어서 트랜잭션이라는 엔터프라이즈 기술을 직접 POJO에 노출하는 것이 아니라 일관적인 서비스 추상화 기술의 형태로 제공해준다.
  • 대신 설정을 통해 추상화 된 부분에 어떤 기술을 할 것인지 지정해주어야한다.

🛋 느낀 점

  • 스프링 프레임워크의 목적은 “엔터프라이즈 기술을 사용하되 비즈니스 로직을 객체지향적으로 구현하고자 하는 것”이다.
  • 이해하기 어려운 스프링 프레임워크의 기술도 이 관점으로 보면 나름 이해할 수 있다.
  • 그리고 그 모든 기술의 기반은 바로 DI 다 !! 추상적으로 구현하여 확장성을 보장하고 변경에 자유로운 객체지향적 코드를 구현할 수 있도록 해준다.