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 생성자를 가질 수 있다.
- 테스트 환경에서 자유롭게 오브젝트를 만들 수 있다.
- 스태틱 메서드와 private 생성자를 사용하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해 준다.
- 스프링은 IoC 컨테이너이자 싱글톤 레지스트리이다.
1) 싱글톤
- 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용한다.
- 단점
- private 생성자를 갖고 있기 때문에 상속할 수 없다.
- 테스트하기 힘들다. 때론 테스트가 불가능하다.
- 서버에서 클래스 로더를 어떻게 구성하고 있느냐에 따라 싱글톤 이어도 하나 이상의 오브젝트가 만들어질 수 있다.
- 전역 상태(global state)로 사용되기 쉽다.
2) 싱글톤과 오브젝트의 상태
- 싱글톤은 멀티스레드 환경에서 여러 스레드가 동시에 접근 가능
- 상태 관리에 주의를 기울여야 한다.
- 상태 정보를 내부에 갖고 있지 않은 무상태 방식으로 만들어져야 한다.
- 기본적으로 인스턴스 필드의 값을 변경하고 유지하는 상태 유지 방식으로 만들지 않는다.
- 읽기 전용의 값이라면 초기화 시점에서 인스턴스 변수에 저장해 두고 공유하는 것은 아무 문제가 없다.
- stateless
- 각 요청에 대한 정보나, DB나 서버의 리소스로부터 생성한 정보는 어떻게 다뤄야 함?
- 파라미터와 로컬 변수, 리턴 값 등을 이용하면 된다.
- 메서드 파라미터나 메소드 안에서 생성되는 로컬 변수는 매번 새로운 값을 저장할 독립적인 공간이 만들어지기 때문에 싱글톤 이어도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.
- 파라미터와 로컬 변수, 리턴 값 등을 이용하면 된다.
- 각 요청에 대한 정보나, 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) 오브젝트를 할당하지 않은 레퍼런스 변수 사용
- NullPointerException
- 꼭 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란 무엇인가?
- 특정 규약에 종속되지 않는다.
- 자바 언어와 꼭 필요한 API 외에는 종속되지 않아야 한다.
- 특정 환경에 종속되지 않는다.
- 객체지향적인 자바 언어의 기본에 충실하게 만들어져야 하기 때문
2) POJO 프레임워크
- 스프링이나 하이버네이트가 대표적
3) 스프링 기술
- IoC/DI, AOP, PSA(추상화)
9장 스프링 프로젝트 시작하기
1. 애플리케이션 아키텍처
- 3 계층 애플리케이션
- 프레젠테이션 계층
- 서비스 계층
- 데이터 액세스 계층
1) 거대한 서비스 계층 방식
- 비즈니스 로직의 대부분을 서비스 계층에 집중하는 접근 방법
2) 오브젝트 중심 아키텍처
- 오브젝트를 만들어두고 오브젝트 구조 안에 정보를 담아서 각 계층 사이에 전달하게 만드는 것
- 문제점
- 성능에서 손해
- DAO는 비즈니스 로직의 사용 방식을 알지 못하므로, 도메인 오브젝트의 모든 필드 값을 다 채워서 전달하는 경우가 대부분
- 오브젝트 관계에서도 문제
- 만약 단순히 Product 정보만 필요한데, Category 오브젝트도 함께 딸려갈 것이다.
- 성능에서 손해
- 해결책
- lazy loading 기법
- 최소한의 오브젝트 정보만 읽어두고 관계하고 있는 오브젝트가 필요한 경우에만 다이내믹하게 DB에서 다시 읽어온다.
- ORM 기술인 JPA 사용
- 도메인 오브젝트를 사용하는 오브젝트 중심 아키텍처에서는 ORM을 사용
- lazy loading 기법
'개발책' 카테고리의 다른 글
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 |