창발적 구조 Emergent Architecture
최근에 생각하고 있는 아키텍처가 있다.
4번의 (실패) 경험들을 통해서 점점 명확해진 생각이다.
szmc_data: 다섯번을 바닥부터 다시 짠 프로젝트
그리고 굉장히 훌륭한 반면 교사인 파이썬의 버전 관리도 한 몫...
아키텍처의 이름은 "창발적 구조 Emergent Architecture"다. 내 맘대로 지은 말이다.
핵심 철학
아키텍처는 창발적이어야 한다. 시스템은 작고 단순한 구성 요소들이 모여 복잡한 문제를 해결해야 한다.
시스템은 변하지 않는 구성 요소 의 재구성 과 추가 를 통해 만들어져야 한다.
시스템의 안정 버전이 릴리즈된 후에는, 한번 도입된 구성 요소의 인터페이스는 변경되어서는 안 된다.
새로운 요구 사항은 기존 구성 요소를 재구성하여 만족시켜라.
같은 이름의 구성요소가 다른 일을 하고 싶다면, 다른 이름의 구성요소를 추가해라. 기존의 구성요소를 변경하지 않는다.
구성 요소의 변경은 버그 수정, 혹은 리팩토링인 경우에만 허용한다. 그 외에는 엄격하게 금지한다.
시스템은 구성 요소들의 계층으로 이루어진다.
절대로 변하지 않는 가장 기본적인 요소의 집합으로 최하위 계층을 구성한다.
그보다 상위 계층은 보다 하위 계층 요소의 구성으로 만들어진다.
최하위 계층은 절대로 변해서는 안 된다.
상위 계층으로 올라갈수록 변화하기 쉬운 요소로 구성된다. 변화는 하위 계층의 요소를 재구성하여 대응한다.
하위 계층일수록 철저하게 유닛 테스트를 수행하고
상위 계층일 수록 통합 테스트와 E2E 테스트 등 더 큰 영역에 집중한다.
왜?
창발성 관련 과거 블로그 글
창발적 알고리즘과 창발적 시스템.
진화의 법칙(진화론)에 의해 살아남은 생물은 모두 창발성을 따른다.세상에서 가장 복잡한 기계인 생물은 보다 단순한 것들로 이루어진다.
분자가 모여 단백질을 이루고 이들이 모여 세포를 이루고 세포가 모여 기관이 되고 기관이 모여 생물이 된다.사실 SICP에서 이야기하는 계층 구조의 소프트웨어가
결국은 현실 세계의 창발성을 모방한 것 아닐까?언어라는 것이 결국
인간이 간신히 만들어낸 창발성은 아닌가?우주의 모든 것이 결국은 그러한 창발적 구조인 것은 아닌가?
인간이 만들 수 있는 시스템의 끝은 창발적 시스템이 아닐까?
망상해 본다.
어쩌면 진화적 알고리즘도 딥러닝처럼
너무 제한된 범위에서 하고 있었던 건 아닐까?지구의 생물은 그저 압도적인 시간과 다양성에 의해서 발전했다.
진화, 유전자 알고리즘도 충분히 많은 변수와 충분한 데이터와 충분한 양의 컴퓨팅 파워가 뒷받침한다면
딥러닝 이상으로 새로운 결과를 낼 수 있는 건 아닐까?다음 혁신은 진화 알고리즘일지도 모른다.
창발성은 우주의 법칙이다. 우주에 존재하는 모든 것들은 창발적이다.
우주라는 시스템의 가장 최하위 구성요소는 (알려진 바로는) 기본입자라고 한다.
(자세한 건 Kurzgesagt를 보도록 하자 https://www.youtube.com/watch?v=Da-2h2B4faU)
우리는 복잡한 시스템을 만들어야 한다.
그런데 현실에 존재하는 모든 복잡한 시스템들은 창발적이다.
그러니 우리 인간이 만드는 시스템도 창발적이어야 하지 않겠는가?
또한 잘만 한다면, 복잡한 시스템을 단순한 요소들로 만들어 낼 수 있을 것이다.
우주에 존재하는 수없이 많은 것들이 그러하니까!
또한 현실을 있는 그대로 표현하는 것(바텀-업)이
인간의 인식과 비슷하게 표현하는 것(탑-다운)보다 나은 경우가 많다.
가장 유명한 사례로는 천동설과 지동설이 있다.
인간이 인식하기에는 천동설이 맞는 것 같지만, 실제 현상을 설명하기 위해서는 수 많은 예외와 규칙이 필요했고,
다들 알다시피 현실을 그대로 묘사한 지동설이 받아들여졌다.
창발적 아키텍처는 우리가 만드는 시스템을 현실에 존재하는 시스템처럼 만들자는 생각이다.
우리가 인식하기에는 다양한 물질이 매우 많지만, 모든 물질은 결국 몇개 안 되는 원자들로 이루어진 것들이다.
우리가 만드는 시스템도 그런 기본적인 요소를 구성하여 다양한 문제를 해결해야 한다.
코드 쪼개기
여기까지는 추상적인 이야기이고, 실제 프로그래밍에서는 어떻게 할까?
코드를 utils, core, entity, (tasks), interface의 계층으로 나눈다.
interface: CLI, GUI, Web API, 기타 등등 외부와 소통하는 코드를 둔다.
--------
tasks: entity보다 상위의 비지니스 로직. 변경과 추가가 매우 자주 일어나는 코드들을 둔다.
entity를 구성하여 만드는 것이 좋다.
--------
entity: 비지니스 로직 중에서 변경이 덜 하면서 자주 재사용 되는 코드를 둔다.
가능하면 사이드 이펙트를 배제하지만, 필요한 경우에는 상태나 입출력을 할 수 있다.
--------
core: 이 프로젝트에서만 사용하는 변경되지 않는 구성요소.
가능하면 사이드 이펙트를 배제하라.
---------
utils: 프로젝트에 관계 없이 사용될 수 있는 기능이 절대 변경되지 않는 구성요소.
늘 사용하는 라이브러리도 여기에 속한다.
하위 계층에 가까울 수록
변화가 적고, 크기가 작고, 단순하고, 엄밀하게 검증하기 쉽고, 일반적이다
상위 계층으로 갈수록
변화가 크고, 크기가 크고, 복잡하고, 검증이 어렵고, 특수하다.
하위 계층의 요소는 Property Based Testing으로 빡세게 테스트하고 검증한다.
낮은 계층일수록 수학적으로 엄밀하게 정의하기 쉽기 때문에 가능하다.
상위 계층일 수록 통합 테스트를 적용하여 테스트한다. Stateful PBT를 적용할 수 있다.
잘 검증된 하위 요소로 구성된 비지니스 로직은 테스트가 거의 필요 없을 수 있다.
상위 계층을 얇게, 하위 계층을 두텁게 만드는 것이 좋다.
맺음말
이 아키텍처는 그냥 내 생각이다. 어디 다른 책에서 볼 수 있는 용어는 없다. 걍 내가 만든 말들이다.
이거... 지금 만드는 시스템도 이렇게 짜려고 노력은 하고 있지만, 쉽지는 않다.
지금은 이렇게 써 두고, 좀 더 경험을 많이 쌓고 나서 다시 돌아오겠다.