클린 아키텍처 - 기초 이론 및 실습

Seok-Hyun Lee·2022년 4월 28일
0

클린아키텍처

목록 보기
1/1

Clean Architecture

1 기초 이론

  • 저수준 정책이 고수준 정책에 의존하도록 관심사를 4계층으로 분리하여 개발하는 방식
  • 고수준 정책은 저수준 정책을 추상화한 것이기에 수정의 여지가 적다
    • 저수준 정책은 고수준 정책에 디테일을 더한 것으로 이해하면 좋다
    • 즉, 디테일을 변해도 핵심은 변하지 않을 경우가 많다는 것으로 이해하자
  • 관심사는 4 계층으로 분류
    • 1층 : 핵심 업무 규칙(Entity Layer)
    • 2층 : 애플리케이션 업무 규칙(Usecase Layer)
    • 3층 : 인터페이스 어댑터(Interface Adapter Layer)
    • 4층 : 프레임워크(Framework Layer)
  • 각 계층은 아래 계층에 의존하도록 만든다.
    - 즉, 높은 층일수록 저수준인 것을 의미
    • 계층 사이의 의존 관계가 반대로 되는 경우 의존 역전 원칙(Dependency Inversion Principle) 에 맞추어 관계를 재설정해야 한다.

2 실습

  • Java 코드로 프레임워크 레이어를 제외한 간단한 실습
    • Entity, Usecase, Interface Adapter 계층만 구현

2.1 Entity Layer

  • 핵심 업무 규칙
  • 가장 고수준
  • 애플리케이션 업무 규칙에 구애받지 않음

class Entity {
    private int age;
    private String name;
    
    public Entity setAge(int age) { System.out.println("[Entity] Entity-setAge"); this.age = age; return this; }
    public Entity setName(String name) { System.out.println("[Entity] Entity-setName"); this.name = name; return this; };
    public int getAge() { return this.age; }
    public String getName() { return this.name; }
}

2.2 Usecase Layer

  • 애플리케이션 업무 규칙
  • 핵심 업무 규칙보다 저수준
  • 핵심 업무 규칙에 의존


class Usecase implements InputPort{
    private Entity entity;
    private OutputPort op;
    
    public Usecase(Entity e, OutputPort op){this.entity = e; this.op = op;}
    
    public void setEntity(int age, String name){
        System.out.println("[Port] InputPort-setEntity");
        publishEntity(age, name);
    }
    
    public void publishEntity(int age, String name){
        System.out.println("[Usecase] Usecase-publishEntity");
        entity.setAge(age)
              .setName(name);
        op.setDTO("Result: " + entity.getAge() + "," + entity.getName());
    }
}

2.2.1 Port

  • Interface Adapter Layer 와 Usecase Layer 의 의존 관계를 설정해주는 계층
  • Interface Adapter Layer 가 Usecase Layer 에 의존하게 하는 용도

interface OutputPort {
    public void setDTO(String data);
}

interface InputPort {
    public void setEntity(int age, String name);
}

2.2.2 Data Transfer Object

  • Framework Layer 와 Usecase Layer 사이에서 주고 받는 데이터 전송 객체
  • 상대적으로 고수준인 Usecase Layer 에서 사용하기 편하도록 만드는 것이 좋다

class DTO {
    private String data;
    public DTO(){}
    public void setData(String data) { this.data = data;}
    public String getData(){ return this.data; }
}

2.3 Interface Adapter Layer

  • Usecase Layer 의 업무 규칙과 Framework Layer 의 외부 프로그램들의 연결을 도움
  • MVC 패턴을 기준으로 Controller 와 View 를 담당하는 Presenter 는 내부 계층에 의존하도록 만듦
class Presenter implements OutputPort {
    private DTO dto;
    public Presenter(DTO dto){ this.dto = dto; }
    
    public void setDTO(String data) { 
        System.out.println("[Port] OutputPort-setDTO");
        dto.setData(data); 
        printData(dto.getData());
    }
    
    public void printData(String data) {
        System.out.println("[Adapter] Presenter-printData");
        System.out.println(data);
    }
}

class Controller {
    private InputPort ip;
    public Controller(InputPort ip) { this.ip = ip; }
    
    public void printData(int age, String name){ 
        System.out.println("[Adapter] Controller-printData");
        ip.setEntity(age, name); 
    }
}

주의할 점!
만약 Presenter 에서 OutputPort 를 구현해서 Usecase Layer 에 접근하는 것이 아니였다면, 1번처럼 계층간 의존 관계 원칙을 위반한 셈이다.

이렇게 Usecase 계층의 InputPort 와 OutputPort 는 DIP 에 의거하여 의존 관계 재설정 및 결합력 감소의 효과를 제공

2.3.1 DI 및 실행

  • 간단한 실습용 코드이기에 main 메소드에서 각 객체 생성 및 실행
public class Main
{
	public static void main(String[] args) {
        Entity entity = new Entity();
        DTO dto = new DTO();
        OutputPort presenter = new Presenter(dto);
        Usecase usecase = new Usecase(entity, presenter);
	    Controller controller = new Controller(usecase);
	    
	    controller.printData(12, "Henry");
	}
}

결과는 아래와 같이 나오는 것을 확인할 수 있음

[Adapter] Controller-printData
[Port] InputPort-setEntity
[Usecase] Usecase-publishEntity
[Entity] Entity-setAge
[Entity] Entity-setName
[Port] OutputPort-setDTO
[Adapter] Presenter-printData
Result: 12,Henry

제어의 흐름 : Adapter -> Port -> Usecase -> Port -> Adapter

profile
Arch-ITech

0개의 댓글