본문 바로가기

책/클린 아키텍쳐 (완)

3부 설계원칙

들어가며

  • 코드 수준부다는 조금 상위에서 적용되며 모듈과 컴포넌트 내부에서 사용되는 소프트웨어 구조를 정의하는 데 도움을 준다.
  • 3부에서는 각 원칙을 더 면밀하게 살펴본다. 아래는 이들 원칙의 개략적인 설명이다.
    • SRP: 단일 책임 원칙
    • OCP: 개방-폐쇄 원칙
    • LSP: 리스코프 치환 원칙
    • ISP: 인터페이스 분리 원칙
    • DIP: 의존성 역전 원칙

 

7장 SRP: 단일 책임 원칙

  • 이제 SRP의 최종 버전은 아래와 같다. "하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다."
  • '응집된'이라는 단어가 SRP를 암시한다. 단일 액터를 책임지는 코드를 함께 묶어주는 힘이 바로 응집성이다.

징후1: 우발적 중복

이러한 문제는 서로 다른 액터가 의존하는 코드를 너무 가까이 배치했기 때문에 발생한다. SRP는 서로 다른 액터가 의존하는 코드를 서로 분리하라고 말한다.

 

징후2: 병합

이들 징후는 모두 많은 사람이 서로 다른 목적으로 동일한 소스 파일을 변경하는 경우에 해당한다. 다시 한번 말하지만 이 문제를 벗어나는 방법은 서로 다른 액터를 뒷받침하는 코드를 서로 분리하는 것이다.

 

해결책

이러한 난관에서 빠져나올 때 흔히 쓰는 기법으로 파사드 패턴이 있다.

 

결론

단일 책임 원칙은 메서드와 클래스 수준의 원칙이다.

 

8장 OCP: 개방-폐쇄 원칙

소프트웨어 개체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.

 

사고 실험

  • 모든 컴포넌트 관계는 단방향으로 이루어진다는 뜻이다.
  • A 컴포넌트에서 발생한 변경으로부터 B 컴포넌트를 보호하려면 반드시 A 컴포넌트가 B 컴포넌트에 의존해야 한다.
  • 아키텍트는 기능이 어떻게, 왜, 언제 발생하는지에 따라서 기능을 분리하고, 분리한 기능을 컴포넌트의 계층구조로 조직화한다.

방향성 제어

추이 종속성을 가지게 되면, 소프트웨어 엔티티는 '자신이 직접 사용하지 않는 요소에는 절대로 의존해서는 안 된다.'는 소프트웨어 원칙을 위반하게 된다.

 

결론

  • OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는 데 있다.
  • 의존성 계층구조가 만들어지도록 해야한다.

 

9장 LSP: 치환원칙

여기에서 필요한 것은 다음과 같은 치환원칙이다. S 타입의 객체 o1 각각에 대응하는 T타입 객체 o2가 있고, T타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않느다면, s는 T의 하위 타입이다.

 

LSP와 아키텍처

이상의 모든 상황에 물론 더 많은 경우에 LSP를 적용할 수 있다. 잘 정의된 인터페이스와 그 인터페이스의 구현체끼리의 상호치환 가능성에 기대는 사용자들이 존재하기 때문이다.

 

결론

LSP는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 한다. 치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문이다.

 

10장 ISP: 인터페이스 분리 원칙

ISP와 언어

동적 타입 언어를 사용하면 정적 타입 언어를 사용할 때보다 유연하며 결합도가 낮은 시스템을 만들 수 있는 이유는 바로 이 때문이다.(선언문이 없는 대신 런타임에 추론을 한다.)

 

ISP와 아키텍처

일반적으로, 필요 이상으로 많은 걸 포함하는 모듈에 의존하는 것은 해로운 일이다. 소스 코드 의존성의 경우 이는 분명한 사실인데, 불필요한 재컴파일과 재배포를 강제하기 때문이다.

 

결론

여기에서 배울 수 있는 교훈은 불필요한 짐을 실은 무언가에 의존하면 예상치도 못한 문제에 빠진다는 사실이다.

 

11장 DIP: 의존성 역전 원칙

  • 의존성 역전 원칙에서 말하는 '유연성이 극대화된 시스템'이란 소스 코드 의존성이 추상에 의존하며 구체에는 의존하지 않는 시스템이다.
  • 자바와 같은 정적 타입 언어에서 이 말은 use, import, include 구문은 오직 인터페이스나 추상 클래스 같은 추상적인 선언만을 참조해야 한다는 뜻이다. 구체적인 대상에는 절대로 의존해서는 안된다.
  • 우리는 이들 환경(운영체제, 플랫폼)에 대한 의존성은 용납하는데, 변경되지 않는다면 의존할 수 있다는 사실을 이미 알고 있기 때문이다.

안정된 추상화

  • 즉, 안정된 소프트웨어 아키텍처란 변동성이 큰 구현체에 의존하는 일은 지양하고, 안정된 추상 인터페이스를 선호하는 아키텍처라는 뜻이다.
  • 변동성이 큰 구체 클래스를 참조하지 말라
  • 변동성이 큰 구체 클래스로부터 파생하지 말라
  • 구체 함수를 오버라이드 하지 말라
  • 구체적이며 변동성이 크다면 절대로 그 이름을 언급하지 말라

팩토리

자바 등 대다수의 객체 지향 언어에서 이처럼 바람직하지 못한 의존성을 처리할 때 추상 팩토리를 사용하고 한다.

 

구체 컴포넌트

DIP 위배를 모두 없앨 수는 없다. 하지만 DIP를 위배하는 클래스들은 적은 수의 구체 컴포넌트 내부로 모을 수 있고, 이를 통해 시스템의 나머지 부분과는 분리할 수 있다.

' > 클린 아키텍쳐 (완)' 카테고리의 다른 글

6부 세부사항  (0) 2024.05.31
5부 아키텍처  (0) 2024.05.02
4부 컴포넌트 원칙  (0) 2024.04.30
2부 벽돌부터 시작하기: 프로그래밍 패러다임  (0) 2024.04.01
1부 소개  (0) 2024.04.01