클린 아키텍처

review, share · 2024-10-15

← 리스트로

클린 아키텍처

프로그램과 프로그램의 경계를 명확히 하여 프로젝트의 복잡도를 낮추는 방법

아키텍트란 결국 시스템을 쉽게 배포 운영 유지보수 되게 하는데 있다.

한마디로 쉽게 개발할수 있도록 만드는 것이다.

좋은 아키텍트란 개발자가 비지니스로직에만 집중할 수 있게한다.

프로그래밍 패러다임

프로그래밍에는 패러다임이 있는데 1. 구조적 프로그래밍, 2. 객체지향 프로그래밍, 3. 함수형 프로그래밍이 있다.

프로그래밍에서 특정 패턴으로 코딩하는 습관을 회피하면 훨씬 더 예측 가능하고 유지보수 가능한 코드가 된다. 패러다임은 코드를 더 쉽게 짜고 관리하기 위해서 프로그래머가 뭘 해서는 안되는지 알려준다.

프러그래밍은 과학이다. 수학은 옳음을 증명할수 있지만. 과학은 귀납적이라서 프로그래밍의 실패만 증명 가능하고. 항상 무결점으로 완벽한지는 증명할수 없다.

구조적 프로그래밍

구조적 프로그래밍은 goto와 같이 코드를 뛰어넘는 방식의 문법대신 if 와 else와 같은 구조의 문법을 쓰는것이다.

이러한 방식으로 코드를짜면 연관 되는 코드 끼리 뭉쳐지기 때문에 코드 예측이 쉬워진다.

객체지향 프로그래밍

객체지향은 프로그래밍에서 사용되는 메모리를 힙에서 관리하면 효율적으로 지역변수를 관리할 수 있다는 사실에서 발단이 되어, 우리가 현재 배우는 객체지향의 개념으로 발전하였다.

객체지향의 가장 획기적인 이점은 다형성과 의존성 주입을 손쉽게 만들어준다는 점이다. 코드를 의존성으루걱정없이 독립적으로 작업하고 배포할수 있게된다.

함수형 프로그래밍

함수형언어는 문제를 수학적 문제를 해결할때 함수의 불변성을 이용한 람다 계산법을 이용한다. 기초가 되는 개념은 불변성이다.

S.O.L.I.D 원칙

좋은 시스템은 깔끔한 코드로 부터 시작 된다. 좋은 벽돌집을 만들려면 좋은 벽돌이 필요한 것과 같다.

상태와 함수의 그룹을 갖는 모든 코드에는 solid 규칙을 적용할수 있으며, Solid 규칙을 준수하면 변경에 유연하고 이해하기 쉽고 재활용 가능한 코드를 만들 수 있게 된다.

단일책임 원칙

단일책임의 원칙은 모듈은 하나의 이해관계자 그룹만 책임져야 한다. 어떤 모듈을 사용하는 이해관계자가 여럿이라면 모듈을 분리해야 한다

개방 패쇄 원칙

코드는 변경에는 닫혀있고 확장에는 열려 있어야한다. 중요한 코드일수록 많은 사용처에서 재활용되므로 변경이 적도록 보호되어야 한다.

인터페이스 법칙

개발 패쇄의 원칙과 상통하게, 많은 사용처에서 사용되는 코드는 설명서와 같은 인터페이스가 확립되어야 하며, 한번 확립된 규칙은 변경되면 안된다. 그리하면 확장에는 열려있고 수정에는 닫힌 상태를 유지하게 된다.

인터페이스 치환의 법칙

하위 클래스에 의존성은 상위클래스로 교체했을때도 잘 작동해야 한다. 이 법칙을 잘 지키면 의존성을 마치 쉽게 교체 가능한 블럭처럼 가지고 놀수 있게 된다.

변동성이많고 많은코드에서 참조당하는 코드일수록 인터페이스 분리가 중요해진다.

다만 상속은 아주 신중히 해야하며 인터페이스 상속이 아닌 구체클래스 상속은 변동성이큰 클래스일경우 피해야한다. 여러 깊이에 상속은 오히려 코드를 파악하는데 방해가 될수 있다는것이 최근 실무자들에 의해 밝혀졌다.

의존성 역전의 원칙

dip를 사용하면 의존성 화살표의 방향을 역으로 만들수 있어서, 의존성 순환을 끊을 수 있다. 의존성 객체간의 관계도 느슨해진다.

백엔드 아키텍트에서 말하는 컴포넌트란?

컴포넌트란 배포 단위다. 자바에서는 jar가 컴포넌트다.

컨포넌트는 단독으로 빌드되어 다른 모듈에서 참조할수도 있는 링크 파일을 말한다.

아떤 클래스를 어떤컴포넌트에 속하게 해냐할까?

  1. Rep 재사용 릴리스 등가원칙

공통재사용 원칙은 rep를 구체적으로 설명하는 원칙이다. 어찌보면 암묵적으로 당연하게 여겨지는 모듈배포의 원칙을 누군가가 규칙으로 만들었다.

동일한 시점에 변경되어야 하는 클래스들은 같은 컴포넌트로 묶어라. 다른시점에 다른이유로 변경되어야 한다면 다른 컴포넌트로 묶어라. 함께 재사용되는 클래스를 하나의 컵포넌트에 묶어라.

컴포넌트 결합이란?

콤포넌트 의존관계에 순환이 있으면 안된다.

의존이 있는 컴포넌트는 결국 동일한 릴리즈 주기를 사용해야 하므로 유지보수가 힘들어진다.(유지 보수란 연속되는 코드의 개발과 배포다)

앞서 SOLID원칙에서도 말한 내용을 이 책에서는 계속 연관되는 이슈로 재 설명하고 있다.

의존상 역전은 순환참조를 깨뜨릴 수 있다. 인터페이스를 참조하게 하면 직접 참조를 깨뜨리고 약속에 의한 인터페이스 로서 안전한 코드 사용을 보장할 수 있게된다.

계층 아키텍트

이 책에서는 명확한 명칭 없이 설명했지만, 이것이 다른 책에서도 많이 인용되는 어니언 아키텍트다. 안정된 코드일수록 더 자차원에 머물며 많은 곳에 의존되어야 하며 그 반대로 변동성이 많은 코드는 많은곳에 참조되서는 안된다.

어니언 아키텍트로 설계하게 되면 화살표를 많이 받는 코드가 안정적인 코드이며 많이 나갈수록 불안정한 코드가 된다.

운영 개발 배포

이 책에서 말하는 유스케이스란 서비스 사용빈도와 사용량 같은것을 말한다.

물론 유스케이스도도 중요하지만, 유스케이스와 운영은 하드웨어 투입으로도 비교적 쉽게 해결 가능하지만 진정 신경써야 하는 부분은 개발과 배포 용이성이다.

좋은 설계의 원칙

각 컴포넌트 계층을 독립적으로 쉽게 배포할수 있어야 한다.

진짜 중복과 가짜 중복을 구분해야 한다. 현재는 증복처럼 보여도 다른 목적으로 발전해나가야하는 2개의 코드는 분리되어야 한다

아키텍트는 코드의 경계를 적절한 시점에 잘 그리는 것이다.

각각의 코드를 플러그인처럼 다룰 수 있어야 한다.

코드와 코드외의 관계를 마치 플러그인 처럼 만들어 각각의 코드가 서로 안전하게 공존하도록 해야한다.

그 구조를 누구나 보면 어떤 시스템인지 금방 알 수 있어야 좋은 아키텍트다.

좋은 아키텍트에서 프레임웍의 선택은 부가사항일 뿐이다. 소프트웨어를 프레임웍에 너무무 의존 시키지 말고 거리를 둬라 프레임워크는 세부사항일 뿐이다.

험블객체의 개념을 알고 잘 활용해야한다.

험블객체란 테스트 하기 어려운 코드들을 따로 때내어 분리한 객체이다. 변동성이 많은 것에는 테스트를 하지마라. 시간낭비다.

섯부른 최적화나 오버엔지니어링을 해서는 안된다

추상화가 필요하리라고 미리 예측해서는 안된다. 오버엔지니어링은 언더엔지니어링 보다 더 나쁘다.

메인모듈은 어플리케이션에 속한 모듈들의 플러그인이다

메인 모듈은 아키텍트에 관점에는 가장 저수준이고 코드 추상화 계층으로는 가장 고수준이다.

서비스가 분리되어 있다고 해도, 꼭 반드시 커플링이 없는 서비스란 없다. 메인 모듈처럼 어떠한 한 부분에서는 커플링이 생기는 포인트가 있다 하지만 그런 어쩔수 없는 객체를 잘 알고 다루는 것이 좋은 아키텍트다.

마이크로 서비스라고 완벽한 건 아니다

물리적으로 마이크로 서비스가 분리되어 있어도 각각의 서비스가 동시에 배포해야 한다면 서로의 변경이 서로에게 영양을 주므로 ㅁ 아키텍트로서는 실패이다.

되도록 퍼블릭 변수의 사용을 제한해야 한다

퍼블릭 으로 변수를 관리하면 코드 종속성의 분산되어 코드간의 경계가 흐려지고 배포하기 힘들어지게 된다.

소프트웨어와 하드웨어의 경계는 분리되어야 한다.

자기디스크 방식의 저장소가 없어지면 ram 으로 대체될 것이고 프로그래밍에서는 자료구조에 그대로 데이터를 저장할 것이다.

데이터베이스는 하나에 메커니즘에 불과하다.

계층기반 설계(어니언 아키텍트)를 항상 적용하라.

의존성은 한 방향으로 흐르고 최대한 순환되지 않아야 한다.

패키징의 단위

패키징의 단위에는 계층기반 패키지, 기능기반 패키지, 컴포넌트 기반 패키지가 있다고 한다.

  1. 계층 기반은 코드의 추상화 계층 기반으로 배포단위를 나누는 것이다.
  2. 기능기반은 도메인 규칙의 성격별로 배포단위를 나누는 것이다.(코드가 어떤 비지니스 규칙에 속한 것인지에 따라)
  3. 컴포넌트 기반은 같은 버전으로 묶을 수있는 배포 독립성 기준으로 패키징 하는 것이다.

계층기반은 좋은 설계지만 패키징의 관점에서는 기능기반으로 패키징 하는게 더 좋은 선택이다. 여러 패키지를 돌아다니지 않아도 패키지 응집력이 생기기 때문이다. 하지만 그것보다 더 좋은 패키징 설계는 컴포넌트 단위로 패키징을 설계하는 것이다.

이미 책의 앞에서 이 책의 저자는 컴포넌트가 패키징의 단위로고 단정지어 설명하였다. 여기서 새로운 패키징의 관점을 설명하므로서 더 헷갈리긴 했지만 이 책의 저자가 말하는 가장 이상적인 패키징의 단위는 컴포넌트 단위다.

배포 독립성이 유지되는 컴포넌트 단위로 패키징 하는게 가장 효율적이다.