이정우
1. 📌 핵심 개념 정리
✅ 요약하기
각자 해당 챕터에서 중요하다고 느낀 개념이나 아이디어를 간략하게 정리하고 개선 전, 후에 대한 예시 코드를 비교하며 개념을 설명합니다.
- 시스템 제작과 시스템 사용을 분리하라
-
제작(constructio)
과사용(use)
은 다르다. -
소프트웨어 시스템은
준비과정
과런타임 로직
을 분리해야 한다.1️⃣ 관심사
관심사 분리
는 가장 오래되고 가장 중요한 설계 기법 중 하나이다.
public Service getService() { if (service == null) service = new MyServiceImpl(...); return service; }
- 초기화 지연 (= 계산 지연) 기법
- 장점
- 실제 필요시 까지 객체생성x -> 불필요한 과부하x
- 어떤 경우에도 null 포인터 반환x
- 단점
- getService 메서드는 MyServiceImpl과 생성자 인수에 명시적 의존
- MyServiceImpl이 무거운 객체라면 단위 테스트에서 getService 메서드 호출 전 적절한
테스트 전용 객체
를 service 필드에 할당해야 한다. - 일반 런타임 로직에 객체 생성 로직이 섞여 모든 실행 경로를 테스트 해야 한다. -> 작게나마
SRP
를 깬다. - MyServiceImpl이 모든 상황에 적합한 객체인지 모른다.
- 한 번 정도는 문제x
- 체계적이고 탄타한 시스템을 만들기 위해서는 흔히 사용하는
손쉬운 기법
으로 모듈성을 깨선 안된다. - 객체 생성, 의존성 연결 시에도 마찬가지이다.
- 설정 논리는 일반 실행 논리와 분리해야 모듈성이 높아진다.
- 주요 의존성 해서를 위한 방식, 즉 전반적이고 일관적인 방식도 필요하다.
- 장점
2️⃣ Main 분리
- 시스템 생성, 사용을 분리하는 방법으로, 생성과 관련된 코드는 모두 main이나 main이 호출하는 모듈로 옮기고, 나머지 시스템은 모든 객체가 생성되어고 모든 의존성이 연결되었다고 가정한다.
3️⃣ 팩토리
- 떄로는 객체 생성
시점
을 애플리케이션이 결정할 필요도 생긴다.
4️⃣ 의존성 주입
- 사용과 제작을 분리하는 강력한 메커니즘
- 제어 역전 기법을 의존성관리에 적용한 메커니즘
- 제어역전에서는 한 객체가 맡은 보조 책임을 새로운 객체에게 전적으로 떠넘긴다.
- 새로운 객체는 넘겨받은 책임만 맡으므로 SRP를 지키게 된다.
- 의존성 관리 맥락에서는 객체는 의존성 자체를 인스턴스로 만드는 책임은 지지 않는다.
- 대신 이런 책임을 다른 전담 메커니즘에 넘겨야만 한다.
- 그렇게 함으로써 제어를 역전한다.
- 초기 설정은 시스템 전체에서 필요하므로 대개 책임질 매커니즘으로 main 루틴이나 트굿 컨테이너를 사용한다.
- 진정한 의존성 주입은 한 걸음 더 나간다.
- 클래스가 의존성을 해결하려 시도하지 않고, 의존성을 주입하는 방법으로 설정자 메서드나 생성자 인수를 제공한다.
- 확장
- 우리는 오늘 중진 사용자 스토리에 맞춰 시스템을 구현해야 한다.
- 내일은 새로운 스토리에 맞춰 시스템을 조정하고 확장한다.
- 이것이 반복적이고 점진적인 애자일 방식의 핵심이다.
- TDD, 리팩터링, 깨끗한 코드는 코드 수준에서 시스템을 조정하고 확장하기 쉽게 마든다.
- 시스템 수준에서는 단순한 아키텍처를 복잡한 아키텍처로 조금씩 키울 수 없다는 현실은 정확하다.
소프트웨어 시스템은 물리적인 시스템과 다르다. 관심사를 적절히 분리해 관리한다면 소프트웨어 아키텍처는 점진적으로 발전할 수 있다.
- 횡단(cross-cutting) 관심사
- 영속성과 같은 관심사는 애플리케이션의 자연스러운 객체 경계를 넘나드는 경향이 있다.
- 모든 객체가 전반적으로 동일한 방식을 이용하게 만들어야 한다.
- 원론적으로는 모듈화되고 캡슐화된 방식으로 영속성 방식을 구상할 수 있다.
- 현실적으로는 영속성 방식을 구현한 코드가 온갖 객체로 흩어진다.
- 자바 프록시
- 자바 프록시는
단순한 상황
에 적합- ex) 개별 객체나 클래스에서 메서드 호출을 감싸는 경우
- JDK에서 제공하는 동적 프록시는
인터페이스
만 지원한다. - 클래스 프록시를 사용하려면 CGLIB,ASM,Javassit 등과 같은 바이트 코드 처리 라이브러리 필요
- 코드의
양
과크기
는 프록시의 두 가지 단점이다. - 시스템 단위로
실행 지점
을 명시하는 메커니즘 제공x
- 자바 프록시는
- 순수 자바 AOP 프레임워크
- 순수 자바 관점을 구현하는
스프링 AOP
,JBoss AOP
등과 같은 여러 자바 프레임워크는 내부적으로 프록시를 사용한다. - 스프링 : 비즈니스 논리를
POJO
로 구현한다. - POJO (Plain Old Java Object)
- 순수하게 도메인에 초점을 맞춘다.
- 엔터프라이즈 프레임워크에 의존 x
- 테스트가 개념적으로 쉽고 간단하다.
- 순수 자바 관점을 구현하는
- AspectJ 관점
- AspectJ
- 관심사를 관점으로 분리하는 가장 강력한 도구
- 언어 차원에서 관점을 모듈화 구성으로 지원하는 자바 언어 확장
- 새 도구를 사용하고 새 언어 문법과 사용법을 익혀야 한다.
- AspectJ 애너테이션 폼
- 새로운 도구, 새로운 언어의 부담을 완화
- 순수한 자바 코드에 자바5 애너테이션을 사용해 관점을 정의
- 스프링 프레임워크는 AspectJ에 미숙한 팀들이 애너테이션 기반 관점을 쉽게 사용하도록 다양한 기능을 제공
- AspectJ
- 테스트 주도 시스템 아키텍처 구축
- 애플리케이션 도메인 논리를 POJO로 작성할 수 있다면, 즉 코드 수준에서 아키텍처 관심사를 분리할 수 있다면, 진정한 테스트 주도 아키텍처 구축이 가능하다.
- BDUF(Big Design Up Front)를 추구할 필요 없이 매번 새 기술을 채택해 단순한 아키텍처를 복잡한 아키텍처로 키워갈 수 있다.
- 프로젝트 시작 시에는 일반적인 범위, 목표, 일정과 결과로 내놓을 시스템의 일반적 구조도 생각해야 한다.
- 하지만 변하는 환경에 대처해 진로를 변경할 능력도 반드시 유지해야 한다.
최선의 시스템 구조는 각기 POJO 객체로 구현되는 모듈화된 관심사 영역으로 구성된다. 이렇게 서로 다른 영역은 해당 영역 코드에 최소한의 영향을 미치는 관점이나 유사한 도구를 사용해 통합한다. 이런 구조 역시 코드와 마찬가지로 테스트 주도 기법을 적용할 수 있다.
- 의사 결정을 최적화하라
- 모듈을 나누고 관심사를 분리하면 지엽적인 관리와 결정이 가능하다.
- 때떄로 가능한 마지막 순간까지 결정을 미루는 방법이 최선일 수도 있다.
- 성급한 결정은 불충분한 지식으로 내린 결정이다.
- 너무 일찍 결정하면 고객 피드백을 더 모으고, 프로젝트를 더 고민하고, 구현 방안을 더 탐험할 기회가 사라진다.
관심사를 모듈로 분리한 POJO 시스템은 기민함을 제공한다. 이런 기민함 덕택에 최신 정보에 기반해 최선의 시점에 최적의 결정을 내리기가 쉬워진다. 또한 결정의 복잡성도 줄어든다.
- 명백한 가치가 있을 때 표준을 현명하게 사용하라
- 단지 표준이라는 이유만으로 채택하거나 결정하지 마라
표준을 사용하면 아이디어와 컴포넌트를 재사용하기 쉽고, 적절한 경험을 가진 사람을 구하기 쉬우며, 좋은 아이디어를 캐슐화하기 쉽고, 컴포넌트를 엮기 쉽다. 하지만 때로는 표준을 만드는 시간이 너무 오래 걸려 업계가 기다리지 못한다. 어떤 표준은 원래 표준을 제정한 목적을 잊어버리기도 한다.
- 결론
- 시스템 역시 깨끗해야 한다.
- 깨끗하지 못한 아키텍처는 도메인 논리를 흐리며 기민성을 떨어뜨린다.
- 도메인 논리가 흐려지면 제품 품질이 떨어진다.
- 기민성이 떨어지면 생산성이 낮아져 TDD가 제공하는 장점이 사라진다.
- 모든 추상화 단계에서 의도는 명확히 표현해야 한다.
- POJO를 작성하고 관점 혹은 관점과 유사한 메커니즘을 사용해 각 구현 관심사를 분리해야 한다.
- 시스템, 개별 모듈등 설계 시에 실제로 돌아가는
가장 단순한 수단
을 사용해야 한다는 사실을 명심하자.
2. 🤔 이해가 어려운 부분
🔍 질문하기
책을 읽으며 이해하기 어려웠던 개념이나 명확하지 않았던 내용을 정리합니다.
- 개념 또는 원칙의 이름
- 어려웠던 부분
횡단(cross-cutting) 관심사에 관한 설명이 모호한 것 같습니다. - 이해한 내용
-
크로스-커팅(Cross-Cutting) 객체지향 소프트웨어 개발에서 크로스-커팅라는 것은 하나의 변경으로 인한 다른 영역에 영향을 미친다고 하는 프로그램 관점 중 하나이다.
-
이러한 것들은 디자인, 구현면에서 시스템의 나머지 부분으로부터 깨끗이 분해되지 못하는 경우 있을 수 있다. 이 때문에 분산(코드중복)이 되거나 얽히는(시스템 간의 상당한 의존성) 일이 일어날 수 있다.
-
이를테면, 의무기록을 관리하기 위한 애플리케이션을 작성한다고 했을 때 이러한 기록 색인화가 핵심이라면 변경 이력을 기록 데이터베이스, 사용자 데이터베이스에 로깅 및 인증 시스템은 크로스-커팅이다.
-
이들은 프로그램의 더 많은 부분과 상호작용한다.
-
- 어려웠던 부분
- 개념 또는 원칙의 이름
-
POJO
-
이해한 내용
-
POJO란 Plain Old Java Object의 약자로, 이를 직역하면 순수한 오래된 자바 객체이다. 즉, Java로 생성하는 순수한 객체를 뜻한다.
이를 해석하면 POJO는 객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고, 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 의미한다. 이러한 POJO에 애플리케이션의 핵심 로직과 기능을 담아 설계하고 개발하는 방법을 POJO 프로그래밍이라고 한다.
-
POJO 프로그래밍 POJO 프로그래밍은 POJO를 이용하여 프로그래밍 코드를 작성하는 것이다. 그러나 순수 자바 객체만을 사용한다고 해서 POJO 프로그래밍이라고 볼 수는 없다. POJO 프로그래밍으로 작성한 코드가 되기 위해서는 기본적인 규칙들을 지켜야 한다.
-
1️⃣ Java나 Java의 스펙에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 한다. 다음 코드는 getter와 setter만 가지고 있는 코드의 예제이다.
해당 코드는 자바에서 제공하는 기능만 사용하기 때문에 해당 클래스는 Java 언어 이외의 특정한 기술에 종속되어 있지 않은 순수한 객체이기 때문에 POJO라고 부를 수 있다.
-
public class User { private String userName; private String id; private String password; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
-
2️⃣ 특정 환경에 종속적이지 않아야 한다. 이는 특정한 프레임워크에서만 동작이 가능하면 안된다는 의미를 가진다. POJO는 환경에 독립적이어야 한다. 특히, 비즈니스 로직을 담고 있는 POJO 클래스는 웹 기반의 환경 정보나 웹 기술을 담고 있는 클래스 또는 인터페이스를 사용하면 안된다.
웹 컨트롤러와 연결하여 사용하더라도, 직접적으로 사용 환경을 웹으로 제한하거나 웹에서만 동작하는 API를 직접 사용하지 말아야 한다. 이러한 이유는 웹 이외의 클라이언트는 해당 기능을 요청할 수 없기 때문이다.
따라서 비즈니스 로직을 담는 코드에 HTTPServletRequest, HttpSession, 캐시 등에 관련된 API를 사용하게 된다면 POJO라 할 수 없다.
-
POJO 프로그래밍이 필요한 이유
- 특정 환경이나 기술에 종속적이지 않으면 재사용이 가능하고, 확장 가능한 유연한 코드를 작성할 수 있다.
- 저수준 레벨의 기술과 환경에 종속적인 코드를 제거하여 코드를 간결해지며 디버깅하기에도 상대적으로 쉬워진다.
- 특정 기술이나 환경에 종속적이지 않기 때문에 테스트가 단순해진다.
- 객체지향적인 설계를 제한 없이 적용할 수 있다. (가장 중요한 이유)
-
-
3. 📚 참고 사항
📢 논의하기
관련된 자료가 있다면 공유하고, 더 깊이 논의하고 싶은 아이디어나 의견을 정리합니다.
- 논의하고 싶은 주제
- 주제
논의하고 싶은 내용을 간략히 정리합니다. - 설명
논의하고 싶은 이유를 작성합니다.
- 주제