-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Chapter 11 System
도입
클린 코딩은 낮은 추상화(abstraction) 단계에서의 모듈화와 관심분리(separation of concerns)에 도움을 준다. 그렇다면 높은 추상화 즉 시스템 단계에서의 모듈화와 관심분리는 어떻게 구현할 수 있을까?
시스템 실행(startup)과 시스템 사용(use)을 구분하라.
- 안티패턴 예시
시스템 실행은 그 자체로 하나의 관심(concern)이다. 관심분리의 원칙에 따라 시스템 실행은 당연히 어플리케이션의 다른 관심들로부터 분리되어야 한다. 다음 예를 보자.
class Controller {
service: Service | null = null;
getService(): Service {
if (this.service === null){
this.service = new ServiceImpl(...constructorArgs);
return this.service;
}
}
}장점
- getService 함수가 실제로 실행되기 전까지는 ServiceImpl을 생성하지 않으므로 불필요한 메모리 사용을 아낄 수 있고 어플리케이션 실행 속도도 빨라진다.
- null 체크를 통해 this.service가 null을 반환하는 것을 방지한다.
단점
- Controller가 ServiceImpl의 생성에 직접적으로 의존한다.
- 실제 ServiceImpl가 런타임에서 사용되지 않더라도 컴파일 단계에서 의존성을 갖는다.
- ServiceImpl의 생성이 런타임 로직과 결합되어 테스트가 어렵다.
위의 예시와 같은 lazy init은 어플리케이션의 모듈화를 저해하고 SRP에 위배된다
- main 함수를 통한 실행과 사용 분리
- 시스템 실행을 담당하는 main 함수 만들어라. main 함수는 런타임 시 필요한 인스턴스들을 생성하는 역할을 한다.
- 생성해야하는 인스턴스 타입이 런타임에 결정되는 경우 Abstract Factory 패턴으로 해결할 수 있다.
- 의존성 주입을 통한 실행과 사용 분리
- IoC(Inversion of Control)는 어떤 오브젝트가 갖고 있는 부차적인 기능을 해당 기능만을 전문적으로 담당하는 다른 오브젝트에게 전가시킴으로써 SRP를 달성하는 기법이다.
- Dependency Injection은 IoC를 의존성 관리에 적용시킨 것이다. 즉, 어떤 오브젝트의 의존성들을 인스턴스화하는 기능을 다른 오브젝트에게 맡기는 것을 DI라고 한다.
- DI를 가능케 하는 세 가지 핵심 요소
- 의존성 관계를 설정하기 위한 configuration
- 의존성을 넘겨 받을 수 있는 setter 혹은 생성자
- 의존성을 주입하는 컨테이너
확장 가능한 시스템을 만들어라
-
안티패턴 예시
- EJB(Enterprise JavaBeans)
EJB는 대형 어플리케이션을 위해 고안된 설계 스펙이다. 구성 요소는 아래와 같다.
EJB Local/Remote Interface
클라이언트가 EJB 어플리케이션를 사용하기 위해 필요한 API를 제공
public interface BankLocal extends java.ejb.EJBLocalObject { String getName() throws EJBException; void setName(String name) throws EJBException; Account getAccount() throws EJBException; void setAccount(Account account) throws EJBException; void addAccount(AccountDTO accountDTO) throws EJBException; }
EJB Entity Bean
관계형 데이터베이스의 레코드를 메모리 상에 로드하기 위한 클래스
public abstract class Bank implements javax.ejb.EntityBean { public abstract String getName(); public abstract void setName(String name); public Account getAccount(); public void setAccount(Account account); public void addAccount(AccountDTO accountDTO){ InitialContext context = new InitialContext(); AccountHomeLocal accountHome = context.lookup("AccountHomeLocal"); AccountLocal account = accountHome.create(accountDTO); this.setAccount(account); } // EJB container logic ... // The rest ... }
EJB Local/Remote Home Interface
클라이언트가 EJB Bean을 생성, 제거, 검색할 수 있는 API를 제공
XML 파일
데이터베이스 테이블과 Entity Bean 클래스의 프로퍼티를 매핑하고, 트랜스액션 정책, 보안 정책 등을 설정하기 위한 파일
EJB 디자인의 문제점
- 비즈니스 로직이 컨테이너와 얽혀있다. 비즈니스 도메인을 구성하는 클래스들이 컨테이너를 상속하고 컨테이너와 관련된 라이프사이클 함수들을 구현해야 한다. 결과적으로 테스트가 어렵고, 해당 클래스들을 EJB 외의 환경에서 전혀 사용할 수 없다.
- OOP에 적합하지 않다. bean 클래스간의 상속을 지원하지 않고, DTO 클래스들은 단순히 데이터를 담고 있을 뿐 어떠한 행동(함수)도 갖고 있지 않다.
- AOP
- Java Proxies
- Spring AOP / JBoss AOP
- AspectJ Aspects
확장 가능한 시스템의 장점 및 주의점
- 테스트 용이
: AOP 등으로 분리/확장 가능한 시스템을 만들면 새로운 기능을 추가하거나 테스트하기 쉽다. - 빠른 의사결정
: 시스템의 각 요소들이 독립적으로 모듈화 되어 있기 때문에 전문적인 의사결정을 빠르게 내릴 수 있다. - 증명가능 한 명확한 가치가 있는 시스템 표준을 사용하라
: 많은 팀들이 EJB가 업계 표준이라는 이유만으로 채택했다. 유행에 따라 시스템 표준을 정하지 말고 고객에게 최대한 많은 가치를 제공할 수있고, 어플리케이션 복잡도에 맞는 시스템을 도입해라. - 비즈니스 도메인 specific한 언어를 사용하라
: 해당 도메인 전문가의 요구사항을 제대로 이해할 수 있게 된다. 또한, 개발자들이 특정 코딩 방식이나 디자인 패턴에 종속되지 않는 시스템 레벨에서 통용가능한 코드를 작성할 수 있다.
- EJB(Enterprise JavaBeans)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels