본문 바로가기

개발책

토비의 스프링 3.1 Vol. 1

1장. 오브젝트와 의존관계

  • 오브젝트
    • 스프링이 가장 관심을 많이 두는 대상
  • 애플리케이션에서 오브젝트가 생성되고 다른 오브젝트와 관계를 맺고, 사용되고, 소멸하기까지의 전 과정을 진지하게 생각해봐야 함.
  • 1장에서는 오브젝트의 설계와 구현, 동작원리에 더 집중할 것

1. 관심사의 분리

  • 객체를 설계할 때 가장 중요한 것은 미래의 변화를 어떻게 대비할 것인가이다.
  • 분리와 확장을 고려한 설계
    • 변경이 일어날 때 필요한 작업을 최소화
  • 관심이 같은 것끼리는 모으고, 관심이 다른 것은 따로 떨어져 있게 하는 것이다.
  • 스파게티 코드
    • 하나의 관심사가 방만하게 중복되어 있고, 여기저기 흩어져 있어서 다른 관심의 대상과 얽혀 있으면, 변경을 하기가 쉽지 않다.

2. 개방 폐쇄 원칙(OCP, Open-Closed Principle)

  • 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.
  • 인터페이스를 사용해 확장 기능을 정의한 대부분 API는 이 원칙을 따름
  • 높은 응집도와 낮은 결합도

3. 스프링의 IoC

1) 빈

  • 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 의미.
  • 스프링 컨테이너가 생성과 관계 설정, 사용 등을 제어해주는 제어의 역전(IoC)이 적용된 오브젝트
  • IoC방식으로 관리하는 오브젝트

2) bean factory

  • 빈의 생성과 관계 설정 같은 제어를 담당
  • 빈을 등록하고, 생성하고, 조회하고 돌려주고 등등 빈을 관리하는 기능을 담당

3) application context

  • 빈 팩토리에서 좀 더 확장된 개념
  • 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진
  • 싱글톤을 저장하고 관리하는 싱글톤 레지스트리(singleton registry)이기도 함.

4. 싱글톤 레지스트리

 

  • 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공
  • 장점
    • 스태틱 메서드와 private 생성자를 사용하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해 준다.
      • 즉, 각각의 클래스(entity)들이 싱글톤으로 사용할 수 있게 해 준다.
      • IoC 방식으로 오브젝트를 사용할 수 있다.
      • public 생성자를 가질 수 있다.
      • 테스트 환경에서 자유롭게 오브젝트를 만들 수 있다.
  • 스프링은 IoC 컨테이너이자 싱글톤 레지스트리이다.

 

1) 싱글톤

  • 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용한다.
  • 단점
    • private 생성자를 갖고 있기 때문에 상속할 수 없다.
    • 테스트하기 힘들다. 때론 테스트가 불가능하다.
    • 서버에서 클래스 로더를 어떻게 구성하고 있느냐에 따라 싱글톤 이어도 하나 이상의 오브젝트가 만들어질 수 있다.
    • 전역 상태(global state)로 사용되기 쉽다.

2) 싱글톤과 오브젝트의 상태

  • 싱글톤은 멀티스레드 환경에서 여러 스레드가 동시에 접근 가능
    • 상태 관리에 주의를 기울여야 한다.
  • 상태 정보를 내부에 갖고 있지 않은 무상태 방식으로 만들어져야 한다.
  • 기본적으로 인스턴스 필드의 값을 변경하고 유지하는 상태 유지 방식으로 만들지 않는다.
  • 읽기 전용의 값이라면 초기화 시점에서 인스턴스 변수에 저장해 두고 공유하는 것은 아무 문제가 없다.
  • stateless
    • 각 요청에 대한 정보나, DB나 서버의 리소스로부터 생성한 정보는 어떻게 다뤄야 함?
      • 파라미터와 로컬 변수, 리턴 값 등을 이용하면 된다.
        • 메서드 파라미터나 메소드 안에서 생성되는 로컬 변수는 매번 새로운 값을 저장할 독립적인 공간이 만들어지기 때문에 싱글톤 이어도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.

3) 스프링 빈의 스코프

  • 빈이 적용되는 범위
  • 빈의 기본 스코프는 싱글톤
  • 싱글톤 스코프는 컨테이너 내에 한 개의 오브젝트만 만들어져서, 강제로 제거하지 않는 한 스프링 컨테이너가 존재하는 동안 계속 유지된다.

5. DI(의존관계 주입)

  • 오브젝트의 레퍼런스가 전달된다.
  • DI는 오브젝트 레퍼런스를 외부로부터 제공(주입) 받고 이를 통해 여타 오브젝트와 다이내믹하게 의존관계가 만들어지는 것이 핵심
  • 런타임 시 의존관계를 결정
  • 스프링을 공부하는 건 DI를 어떻게 활용해야 할지를 공부하는 것
  • 장점
    • 관심사의 분리를 통해 얻어지는 높은 응집도

6. 정리

  • 스프링이란 어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임워크
  • 스프링의 관심은 오브젝트와 그 관계다.
  • 하지만 오브젝트를 어떻게 설계하고 분리하고 개선하고 어떤 의존관계를 가질지 결정하는 일은 스프링이 아니라 개발자의 역할이며 책임이다.

 

2장 테스트

  • 자신이 만든 코드를 테스트로 검증하는 방법을 알고 있어야 하며, 테스트를 개발에 적극적으로 활용해야 한다.
  • 네거티브 테스트 케이스부터 만들어야 한다.
  • 테스트는 어떤 경우에도 서로 의존해선 안된다.

1. 단위 테스트(unit test)

  • 테스트는 가능하면 작은 단위로 쪼개서 해야 한다.
  • 확인의 대상과 조건이 간단하고 명확할수록 좋다.
  • 항상 일관성 있는 결과가 보장되어야 한다.

3장 템플릿

  • 템플릿이란 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 모아놓아 활용하는 방법

1. 템플릿

  • 어떤 목적을 위해 미리 만들어둔 모양이 있는 툴
  • 고정된 작업 흐름을 가진 코드를 재사용한다는 의미

2. 콜백

  • 실행되는 것을 목적으로 다른 오브젝트의 메서드에 전달되는 오브젝트를 말함.
  • 템플릿 안에서 호출되는 것을 목적으로 만들어진 오브젝트

 

4장 예외

1. 잘못된 예외처리

  • catch() 블록에 아무것도 하지 않는 것.
  • 예외를 단순히 println()로 찍는 것.
  • 그냥 log에 남기는 것.
  • 예외를 무시하거나 잡아먹어버리는 코드

2. 올바른 예외처리

  • 모든 예외는 적절하게 복구되어야 한다.
  • 작업을 중단시키고 운영자 또는 개발자에게 분명하게 통보돼야 한다.

3. 무의미하고 무책임한 throws

  • catch를 통해 예외 처리하는 것이 귀찮다고 throws로 던지면 안 된다.
  • 어디서 에러가 났는지 명확하게 찾기 힘들다.

4. throw를 통해 발생시킬 수 있는 예외 세 가지(꼭 throw를 쓰라는 말이 아님)

1) Error

  • java.lang.Error class의 서브 클래스들
  • 애플리케이션에서는 이런 에러에 대한 처리는 신경 쓰지 않아도 된다.

2) Exception과 체크 예외

  • java.lang.Exception class의 서브 클래스들
  • 개발자들이 만든 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용된다.
  • Exception class
    • 체크 예외
      • Exception 클래스의 서브클래스
      • RuntimeException 클래스를 상속하지 않음
    • 언체크 예외(unchecked exception)
      • RuntimeException을 상속한 클래스
  • 체크 예외는 catch문이나 throws를 정의해서 메서드 밖으로 던져야 함.

3) RuntimeException과 언체크/런타임 예외

  • java.lang.RuntimeException을 상속한 예외들은 명시적인 예외처리를 강제하지 않음
  • 런타임 예외라고도 부름
  • 주로 프로그램의 오류가 있을 때 발생하도록 의도된 것들.
    • NullPointerException
      • ex) 오브젝트를 할당하지 않은 레퍼런스 변수 사용
  • 꼭 catch, throws를 사용 안 해도 됨.

 

5. 예외처리 방법

  • 어떤 방법이던지 의도가 분명해야 함.

1) 예외 복구

  • 예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 것

2) 예외처리 회피

  • 예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것이다.
    • throws 문으로 선언해서 예외가 발생하면 알아서 던짐.
    • catch 문으로 로그를 남긴 후 예외를 던짐(throw)

3) 예외 전환

  • 예외를 메서드 밖으로 던짐.
  • 이때 예외 회피와 다른 점은 적절한 예외로 전환해서 던진다.
  • 의미를 분명하게 해 주기 위해

4) 정리

  • 대부분 서버 환경에서는 애플리케이션 코드에서 처리하지 않고 전달된 예외들을 일괄적으로 다룰 수 있는 기능을 제공한다.
  • 어차피 복구하지 못할 예외라면,
    • 애플리케이션 코드에서는 런타임 예외로 포장해서 던진다.
    • 예외처리 서비스 등을 이용해 자세한 로그를 남긴다.
    • 관리자에게는 메일 등으로 통보한다.
    • 사용자에게는 친절한 안내 메시지를 보여준다.

6. 예외처리 전략

1) 런타임 예외의 보편화

  • 체크 예외가 일반적인 예외를 다룸
  • 언체크 예외는 시스템 장애나 프로그램상의 오류에 사용
  • 자바의 환경이 서버로 이동하면서 체크 예외의 활용도와 가치는 점점 떨어지고 있다.
  • 대응이 불가능한 체크 예외라면 빨리 런타임 예외로 전환해서 던지는 게 낫다.
  • 복구 불가능한 상황이 많고 RuntimeException 등으로 포장해서 던져야 하는 경우가 많으니 아예 API 차원에서 런타임 예외를 던지도록 만드는 것이 좋음
  • 런타임 예외를 사용하는 경우
    • API 문서나 레퍼런스 문서에서 예외의 종류와 원인, 활용 방법을 자세히 확인.
  • 낙관적인 예외처리 기법
    • 복구할 수 있는 예외는 없다고 가정
    • 런타임 예외이므로 시스템 레벨에서 알아서 처리해줄 것으로 기대

2) 애플리케이션 예외

  • 시스템 또는 외부의 예외상황이 원인이 아니다
  • 애플리케이션 자체의 로직에 의해 의도적으로 발생시키는 예외

7. 예외 전환

  • 런타임 예외로 포장해서 catch/throws를 줄여줌
  • 의미가 분명히 드러나는 예외로 전환

5장 서비스 추상화

1. enum

  • 비즈니스 로직과 데이터 액세스 로직의 분리

2. 트랜잭션

  • 중간에 예외가 발생해서 작업을 완료할 수 없다면 아예 작업이 시작되지 않은 것처럼 초기 상태로 돌려놔야 한다.

3. 추상화 특징

  • 추상화란 하위 시스템의 공통점 뽑아내서 분리시키는 것을 의미.

4. 단일 책임 원칙

  • 하나의 모듈은 한 가지 책임
  • 장점
    • 어떤 변경이 필요할 때 수정 대상이 명확
  • 책임과 관심이 다른 코드를 분리하는데 핵심적인 도구가 DI

6장 AOP(Aspect Oriented Programming)

  • AOP의 적용 대상은 선언적 트랜잭션 기능이다.
  • 부가기능 모듈
  • OOP를 돕는 부조적인 기술

1. 스프링 AOP

  • 비즈니스 로직에 반복적으로 존재했던 트랜잭션 코드를 분리
  • 분리된 트랜잭션 코드는 기존 코드에 영향을 주면 안 된다.
  • 프록시를 이용한 AOP라고 할 수 있음

7장 스프링 핵심 기술의 응용

1. 인터페이스 상속을 통한 안전한 기능 확장

1) DI를 의식하는 설계

  • DI는 런타임 시에 의존 오브젝트를 다이내믹하게 연결해줘서 유연한 확장을 꾀하는 게 목적이기 때문에 항상 확장을 염두에 두고 오브젝트 사이의 관계를 생각해야 한다.
  • 확장은 항상 미래에 일어나는 일
  • DI란 결국 미래를 프로그래밍하는 것

2) DI와 인터페이스 프로그래밍

  • DI를 DI 답게 만들려면 두 개의 오브젝트가 인터페이스를 통해 느슨하게 연결돼야 한다.
  • 인터페이스를 사용하는 이유
    • 다형성을 얻기 위해
      • 인터페이스 타입으로 여러 클래스의 객체를 만들 수 있음.
    • 인터페이스 분리 원칙을 통해 클라이언트와 의존 오브젝트 사이의 관계를 명확하게 해 줄 수 있기 때문
      • 즉 인터페이스는 하나의 오브젝트가 여러 개를 구현할 수 있으므로, 하나의 오브젝트를 바라보는 창이 여러 가지일 수 있다는 뜻.
      • 각기 다른 관심과 목적을 가지고 어떤 오브젝트에 의존하고 있을 수 있다는 의미
  • 인터페이스 분리 원칙
    • 목적과 관심이 각기 다른 클라이언트가 있다면 인터페이스를 통해 이를 적절하게 분리해줄 필요가 있다.

3) 인터페이스 상속

  • 때론 인터페이스를 여러 개 만드는 대신 기존 인터페이스를 상속을 통해 확장할 수 있다.

 

8장 스프링이란 무엇인가?

  • 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
    • 원래 엔터프라이즈 개발은 편하지가 않음
    • 경량급은 생산성과 품질면에서 우수

1) POJO란 무엇인가?

  1. 특정 규약에 종속되지 않는다.
    1. 자바 언어와 꼭 필요한 API 외에는 종속되지 않아야 한다.
  2. 특정 환경에 종속되지 않는다.
  3. 객체지향적인 자바 언어의 기본에 충실하게 만들어져야 하기 때문

2) POJO 프레임워크

  • 스프링이나 하이버네이트가 대표적

3) 스프링 기술

  • IoC/DI, AOP, PSA(추상화)

 

9장 스프링 프로젝트 시작하기

1. 애플리케이션 아키텍처

  • 3 계층 애플리케이션
    • 프레젠테이션 계층
    • 서비스 계층
    • 데이터 액세스 계층

1) 거대한 서비스 계층 방식

  • 비즈니스 로직의 대부분을 서비스 계층에 집중하는 접근 방법

2) 오브젝트 중심 아키텍처

  • 오브젝트를 만들어두고 오브젝트 구조 안에 정보를 담아서 각 계층 사이에 전달하게 만드는 것
  • 문제점
    • 성능에서 손해
      • DAO는 비즈니스 로직의 사용 방식을 알지 못하므로, 도메인 오브젝트의 모든 필드 값을 다 채워서 전달하는 경우가 대부분
    • 오브젝트 관계에서도 문제
      • 만약 단순히 Product 정보만 필요한데, Category 오브젝트도 함께 딸려갈 것이다.
  • 해결책
    • lazy loading 기법
      • 최소한의 오브젝트 정보만 읽어두고 관계하고 있는 오브젝트가 필요한 경우에만 다이내믹하게 DB에서 다시 읽어온다.
    • ORM 기술인 JPA 사용
      • 도메인 오브젝트를 사용하는 오브젝트 중심 아키텍처에서는 ORM을 사용

'개발책' 카테고리의 다른 글

Kotlin In Action  (0) 2022.06.05
토비의 스프링 3.1 Vol. 2  (0) 2021.11.11
코딩을 지탱하는 기술  (0) 2021.10.30
Effective Java  (0) 2021.10.30
윤성우의 자료구조  (0) 2021.10.30