python clean code chapter10
Python Clean Code
10. 클린 아키텍처
10-1 .관심사 분리
대형 시스템을 하나의 컴포넌트로 구현하는 것은 바람직하지 않다.
모노리식(monolithic) 단일 어플리케이션은 단일 진실의 근원(single source of truth)처럼 동작하여 시스템의 모든 것을 책임지고 의도하지 않은 결과를 유발할 수 있다.
이는 분리하기 어렵고 변경된 부분을 식별하기 어렵고 효과적으로 테스트하기 어렵다.
코드의 모든 것을 한 곳에 두면 관리하기 어렵게 되는 것처럼, 컴포넌트도 모든 것을 한 곳에 두면 마찬가지의 문제가 생기게 된다.
한 가지 방법은 여러 번 재사용될 만한 공통 로직을 파이썬 패키지에 두는 것이다.
또 다른 대안은 마이크로 서비스 아키텍처(MSA)를 사용하여 애플리케이션을 여러 개의 작은 서비스로 나누는 것이다.
그렇게 하려면 단일하고 명확한 책임을 가진 서비스를 만들고 각 서비스가 협력하여 모노리식 시스템에 한 것과 같은 기능을 구현하면 된다.
추상화
코드 수준에서도 그러했듯이 시스템 도메인 문제에 관해서도 추상화란 세부 구현 사항을 최대한 숨기는 것이다.
코드는 그 자체로 문서화가 되는 정도의 표현력을 가져야 하며, 문제의 본질에 대한 해결책을 제시하는 올바른 추상화를 해야 한다.
중요한 것은 시스템이 무엇을 하는가이다.
스크림(SCREAM) 아키텍처에 이러한 개념이 반영되어 있다.
추상화를 하고 의존성을 역전시키는 것은 좋은 습관이지만 충분하지 않다. 객체를 추상화하는 것 이상의 것으로 추상화의 계층이 필요하다.
이것은 세부적인 디자인과 관련하여 미묘하지만 중요한 차이다.
DIP원칙을 지키려면 abc 모듈을 사용하여 인터페이스를 만드는 것이 좋다. 파이썬은 덕타이핑을 지원하기 때문에 추상 클래스를 사용하지 않아도 동일한 효과를 쉽게 얻을 수 있으므로 반드시 사용해야 하는 것은 아니다.
어떤사람들은 ‘ORM은 데이터베이스에 대한 좋은 추상화이다.’라고 주장할 수도 있다. 그러나 ORM자체가 의존성이며 통제할 수 없는 부분이기도 하다.
즉,ORM만으로 데이터 베이스를 추상화 했다고 볼 수는 없다.
그 위에 추상화 계층을 사용하여 도메인에 속한 자신만의 객체를 정의해야한다.
그 다음 이러한 컴포넌트를 애플리케이션에 임포트하고, 해당 계층에서 제공하는 엔터티만 사용해야한다.
새로운 계층은 API를 제공하여 연결하려는 모든 저장소의 컴포넌트는 해당 API를 준수해야한다.
이것은 육각형(HEX)아키텍처의 개념이다.
10-2 소프트웨어 컴포넌트
대규모 시스템을 확장해야 한다고 해보자.
그러면서 유지보수가 가능한 상태를 유지해야 한다. 이 시점에서 우려되는 것은 기술적인 것뿐만 아니라 조직적인 문제이기도 하다.
대규모 시스템이 어떠한 컴포넌트로 구성되어 있는지를 명심해야 하며, 상호작용 또한 잘 해야한다. 대규모에서 잘 동작하기 위한 유일한 방법은 모든 부분이 인터페이스, 즉 계약에 동의하는 것이다.
패키지
예를 들어 애플리케이션에서 특정 관용구를 반복적으로 사용하거나 함수 또는 매커니즘에 크게 의존할 수도 있다. 그리고 팀에서 이러한 특수한 요구사항에 맞는 더 나은 기능을 고안했을 수도 있다. 이러한 작업을 보다 효율화하려면 이러한 추상화를 라이브러리 형태로 구현하고, 팀원들이 해당 라이브러리에서 제공하는 관용구를 사용하도록 독려해야한다. 그렇게 하면 버그를 줄이고 실수를 피할 수 있다.
파이썬 프로젝트 패키징의 핵심은 다음과 같다.
-
플랫폼에 독립적이며, 로컬 설치에 의존하는 지 않는지 테스트하고 검증을 해야 한다.
-
단위 테스트를 패키지에 같이 배포하지 않음.
-
의존성 분리 - 프로젝트가 필요로 하는 것과 개발자가 필요로 하는 것은 다르다.
-
가장 많이 요구되는 명령에 대해서는 진입점을 만드는 것이 좋다.
컨테이너
여기서 컨테이너는 파이썬 컨테이너 객체가 아니다.
컨테이너는 특정한 제약사항을 가지고 격리된 상대로 실행되는 프로세스이다.
구체적으로 말하자면 도커(Docker)컨테이너를 말한다.
컨테이너의 경우 라이브러리가 아닌 애플리케이션을 생성할 때 사용한다. 그러나 애플리케이션이나 플랫폼이 반드시 전체 서비스를 의미하는 것은 아니다.
컨테이너를 만드는 이유는 작고 명확한 서비스를 나타내는 작은 컴포넌트를 만들기 위함이다.
컨테이너는 애플리케이션이 표준적인 실행방법을 갖도록 도와줄뿐만 아니라 개발 프로세스를 수월하게 만든다.(환경에 따른 시나리오를 재현, 테스트 복제, 새로운 멤버의 개발환경 구축 등.)
도커가 애플리케이션을 컨테이너화하는 유일한 기술은 아니며 파이썬과 완전히 독립적이라는 것을 명심하자.
패키지가 코드를 재사용하고 조건을 통일하는 수단인데 반해, 컨테이너는 애플리케이션의 다양한 서비스를 만드는 수단.
이들은 아키텍처에 대한 관심사의 분리(SoC)를 도와준다.
10-3. 분석
어떠한 아키텍처나 구현도 완벽하지 않다. 같은 솔루션이 모든 경우에 유용할 수는 없다. 팀, 조직 등 여러 환경에 상당 부분 의존하게 되어 있다.
추상화의 한계
모든 것을 추상화 할 수는 없다. 어떤 경우에는 단순히 불가능해서 일수도 있고 어떤 경우에는 불편해서 일수도 있다.
깔끔한 API를 제공하기 위한 웹 프레임워크 어댑터가 있다고 해보자.
그러나 보다 복잡한 상황에서는 이러한 변경이 불가능할 수도 있다. 이렇게 추상화를 하더라도 라이브러리의 일부는 여전히 애플리케이션에 결합된다. 전체 프레임워크를 추상화 하는 것은 어려울 뿐만 아니라 어떤 경우에는 불가능할 수 있다.
중요한 것은 어댑터가 아니다. 중요한 것은 최대한 기술적인 세부사항을 숨기는 것이다.
즉, 가장 좋은 코드는 우리 코드와 웹프레임워크 사이에 어댑터가 있다는 사실이 아니라 웹프레임워크 자체가 보이지 않는 코드이다.
의도 표현
작은 함수를 만들고, 관심사를 분리하고, 의존성을 격리하고, 코드의 모든 부분에서 올바른 의미가 부여된 추상화를 해야 한다는 의도가 깔려있다.
의도표현의 원칙은 매우 중요한 것으로, 코드에서 사용되는 모든 이름이 현명하게 선택되어야하며, 해야할 일을 명확하게 전달해야 한다는 원칙. 모든 함수는 이름만으로 그 의도를 말할 수 있어야 한다.
훌륭한 아키텍처 역시 시스템의 의도를 밝혀야 한다. 아키텍처는 사용하고 있는 도구를 언급해서는 안된다.