All
설계가 잘못되는 이유
•
정원을 관리하지 않으면 잡초로 무성해지며 야생의 상태가 됨
•
소프트웨어 시스템도 마찬가지로 관리하지 않으면 혼돈상태로 향하게 된다
•
깔끔하게 세웠던 계획과는 반대로 잘못 구현한 부분이나 에지 케이스를 처리하기 위한 코드가 점점 늘어나 결국 온갖 코드가 섞인 잡탕이 된다. > 큰 진흙 공 안티패턴
캡슐화와 추상화
캡슐화 - 행동의 단순화 데이터 은닉. 코드에서 수행할 작업을 식별하고 이 작업에 잘 정의된 객체나 함수를 부여해 행동을 캡슐화한다
추상화 - 이렇게 행동을 캡슐화 해주는 객체나 함수를 추상화라고 한다
아래 두 코드는 urllib와 request 를 사용해 검색하는 코드이다.
import json
from urllib.request import urlopen
from urllib.parse import urlencode
params = dict(q= 'Sausages' , format= 'json')
handle = urlopen('http://api.duckduckgo.com' + '?' + urlencode(params))
raw_text = handle.read().decode('utf8')
parsed = json.loads(raw_text)
results = parsed['RelatedTopics’]
for r in results:
if 'Text' in r:
print(r['FirstURL'] + '-' + r['Text'])
Python
복사
import requests
params = dict(q= 'Sausages' , format= 'json')
parsed = requests.get('http://api.duckduckgo.com/', params=params).json()
results = parsed['RelatedTopics'] for r in results:
for r in results:
if 'Text' in r:
print(r['FirstURL'] + '-' + r['Text'])
Python
복사
두 코드는 같은 일을 하지만 두번째 코드가 더 높은 수준의 추상화 아래서 동작하기 때문에 더 잘 읽히고 이해하기 쉽다.
import duckduckgo
for r in duckduckgo.query('Sausages').results:
print(r['FirstURL'] + '-' + r['Text'])
Python
복사
행동을 추상화로 캡슐화하는 것은 코드 표현력을 높이고 테스트와 유지보수를 쉽게 만듦.
계층화
어떤 함수나 모듈, 객체인 A가 다른 함수나 모듈, 객체인 B를 사용할때 A가 B에 의존한다(A depends on B) 라고 한다.
큰 진흙공에서는 의존싱이 제어 할 수 없을 정도로 복잡하기 때문에 어느 한 노드를 변경하기 어려움.
계층화한 아키텍쳐는 이 문제를 해결하는 방법 중 하나. 계층화한 아키텍처에서는 코드를 서로 구분하는 범주나 역할로 분할하고, 어떤 코드 범주가 어떤 코드 범주를 호출할 수 있는지 규칙을 도입.
의존성 역전 원칙
의존성은 임포트나 호출만 아니라 한 모듈이 다른 모듈을 필요로 하거나 안다는 것도 의존성이 된다.
DIP(dependency inversion principle)
1. 고수준 모듈은 저수준 모듈에 의존해서는 안되며 두 모듈 모두 추상화에 의존해야 한다.
•
고수준 모듈 - 조직에서 중요하게 여기는 코드. 실세계의 개념을 처리하는 함수, 클래스, 패키지
•
저수준 모듈 - 조직에서 신경쓰지 않는 코드. 예를 들면 급여 시스템에 정시에 정상적 실행되면 사업부서는 급여 시스템이 크론잡인지 쿠버네티스에서 실행되는 일시적인 함수인지 신경쓰지 않는다.
•
서로를 독립적으로 변경하기 위해. 고수준 모듈은 비즈니스 필요에 따라 쉽게 변경이 가능해야 하며 저수준 모듈은 실제로 변경이 어려움.
2. 추상화는 세부 사항에 의존해서는 안된다. 반대로 세부사항은 추상화에 의존해야 한다.
•
세부 사항 변경할 필요가 있을때 비즈니스 계층을 변경하지 않고도 세부 사항을 바꿀 수 있어야 한다.
•
둘 사이의 추상화를 사용하면 두 계층이 더 많이 독립적으로 변경 될 수 있다.