이 내용은 “파이썬으로 살펴보는 아키텍처 패턴” 을 읽고 작성한 내용입니다. 블로그 게시글과, 작성한 코드를 함께 보시면 더욱 좋습니다.
3장은 해당 코드를 살펴봐주세요. 코드 링크
어떤 컴포넌트가 깨지는 것을 두려워해서 다른 컴포넌트롤 못건들이면, 두 컴포넌트가 결합되어 있다고 말한다. 결합은 엮여있음을 의미한다.
그런데 지역적 결합은 ‘응집’이라고 표현한다.
전역적 결합은 코드를 ‘진흙 공’ 처럼 서로 뭉치게 만든다. 앱이 커지면 커질 수록 결합을 훨씬 빠르게 하기 때문에 시스템은 사실상 고착화된다.
따라서 추상화를 통해 세부사항을 감출 필요가 있다.
따라가보자…
두 파일 디렉토리를 동기화하는 코드를 작성하고자 한다. 각 디렉토리를 원본, 사본이라고 하자.
import hashlib
BLOCK_SIZE = 65_536
def hash_file(path):
hasher = hashlib.sha1()
with path.open("rb") as file:
buf = file.read(BLOCK_SIZE)
with buf:
hasher.update(buf)
buf = file.read(BLOCK_SIZE)
return hasher.hexdigest()
처음부터 문제를 풀 때는 보통 간단한 구현을 짜고, 이걸 가지고 리팩토링 한다.
가장 작은 부분부터 일단 만들면서 더 풍부하고, 더 좋은 해법의 설계를 가져가는 것을 반복한다.
바꿔말하면 처음 코드는 보통 구지단 말이다. 처음부터 못해도 좋다. 빠르게 이터레이션을 가져가면서 좋은 코드로 바꾸는 연습을 하자.
pathlib
, shutil
, hashlib
을 다 써야함shutil.move()
가 잘못 사용중이다(!)
--dry-run
같은 기능을 추가하려면?테스트하기 쉽게 짜려면 생각을 다시 해보자.
→ 파일 시스템의 어떤 기능을 코드에서 쓸지 생각해본다
2. 코드 내에는 3가지 뚜렷한 서로 다른 일이 일어남을 캐치한다. 즉, 코드의 책임을 찾는다
1. os.walk
을 사용해 시스템 정보 및 파일해시를 구한다 (원본, 사본 모두에서 처리)
2. 파일이 새 파일인지, 이름이 변경된 파일인지, 중복된 파일인지 정한다
3. 원본과 사본을 일치시키기 위해 파일 복사하거나, 옮기거나, 삭제한다.
세 가지 책임에 대해 단순화한 추상화(simplifying abstraction) 을 찾으려는 과정이다. 마치 인터페이스를 만드는 것 처럼… 개선해보자!
→ “무엇” 을 원하는가와 원하는 바를 “어떻게” 달성할 지를 분리하자. 1. 프로그램이 아래와 비슷한 명령 목록을 출력하도록 하자
```python
("COPY", "sourcepath", "destpath"),
("MOVE", "old", "new"),
```
2. 여기서 파일 시스템을 표현하는 두 딕셔너리를 입력받는 테스트 작성 가능
어려운 개발 도서들은 말은 좋지. 실제로 코드를 어떻게 짤까? 일단 목표를 다시 생각해보자.
외부 상태에 대해 의존성이 없는 코드의 ‘코어’를 만들고, 외부 세계를 표현하는 입력에 대해 이 코어가 어떻게 반응하는지 생각해보자1
step 1) 코드에서 로직과 상태가 있는 부분을 분리한다.
이러면 큰 로직과 저수준 I/O의 의존성을 함수단위로 풀었다. 쉽게 코드의 코어를 테스트할 수 있다(determine_actions
)!
전체를 테스트하려는 통합/인수테스트도 유지할 수도 있다만, 더 나아가 sync()
를 다듬어서 단위테스트를 겸해서 동시에 e2e 테스트까지 할 수도 있다. 이걸 책의 공동저자는 edge-to-edge
테스트라고 부른다.
새 시스템을 짤 때는 위에서 언급한 추상화를 통한 구현을 하자. 어느 시점이 되면 시스템의 더 큰 덩어리를 한번에 테스트하고자 할 것이다.
저자는 이 때 한번에 테스트하되 가짜 I/O를 사용하는 류의 edge-to-edge 테스트를 추천한다.
요컨대, 어느 파일 시스템에서(filesystem
) 액션을 취할지를 테스트하는 방법을 DI를 통한 테스트 더블로 처리할 수 있다.
mock.patch
를 쓰지 않는 이유mock을 통한 monkey patching을 별로라고 하면서, 테스트 더블을 소개한다. 왜 안쓰는지를 설명하는 지에 대한 이유는 다음과 같다:
여기 내용은 유닛 테스팅 책을 좀 보고 다시 이해해야겠다… 여전히 모르겠다.
비즈니스 로직과 I/O 사이의 인터페이스를 단순화하는게 중요하다는 것을 배웠다. 올바른 추상화를 찾는 것은 어렵다. 아래는 올바른 추상화를 하기 위한 방법이다.
계속 연습하자… 계속…