대체로 아키텍쳐라고 하면 보통 언어(java), 프레임워크(스프링), DB(Mysql), sql mapper(jpa hibernate) 등을 의미하며, 개발 이전의 설계나 기획이라고 생각하는 경향이 크다.
오히려 좋은 아키텍쳐는 위에 나열한 툴과 기획에 의존하지 않는 상태에서 만들어진다. tool에 한정되는 순간 툴에 종속적인 유연하지 않은 어플리케이션이 된다.
tool로부터 decouple하고 최대한 그 선택을 늦춰야(Deferring decisions) 한다.
현대적 의미에서 아키텍쳐는 use case로 설명한다. 어플리케이션의 actor를 상정하고, 사용자가 어플리케이션을 사용하고 상호작용하는 것에 초점을 맞춘다.
Deferring Decisions 툴에 대한 결정을 최대한 미룬다
좋은 아키텍쳐는 툴에 대한 결정을 최대한 연기한다.
우리는 충분한 정보를 가지고 있지 않다. 우리가 가진 정보는 언제든 변경될 수 있다. 우리에게 요구한 사람들은 자신이 무엇을 요구하는지도 명확하게 모른다.
“known unknowns” 혹은 “known knowns” 보다 “unknown unknowns” 인 경우가 많다. 그러니까 우리는 기획, 설계 때 상황에 따라 무엇이 적절한 도구 혹은 디자인 패턴인지 알지 못하는 경우가 많다.
개발은 그러므로 툴에 대한 선택을 최대한 늦추는 방향을 선택해야 한다. DB를 예를 들면 아래와 같다.
DB is core abstraction?
보통 개발은 DB 중심으로 수행하기 십상이다. 그럼 시스템은 DB에 종속적인 형태로 개발된다. sql 중심으로 개발하면 절차지향적인 개발이 될 가능성이 매우 높다.
undo의 비용은 생각보다 크다. Mysql에서 postgreSQL로 변경하는 것은 쉽지 않다. db를 선택하는 것을 최대한 늦추는 것이 장기적으로 낫다.
DB를 대신하는, 결정을 최대한 늦추는 개발은 다양하며, 그 방식은 좋은 아키텍쳐를 만드는데 도움을 준다.
대역(double) repository를 사용한다. 일단 가짜 클래스에 save() 메서드를 구현한다.
데이터를 불가피하게 넣어야 한다면 Map을 사용한다.
데이터가 휘발되어선 안된다면, 메모리를 직렬화하여 파일로 저장한다.
sql의 사용을 회피할 수 없다면 인메모리 DB를 사용한다.
개발이 거진 완료되고 데이터를 영속화해야 하는 상황이 도래할 때, DB를 선택한다.
빠른 구현과 리팩터링(혹은 재개발)은 현대적인 개발에서 필수이다.
유사한 어플리케이션이 나오는 상태에서 빠른 개발은 필수이다.
경쟁사보다 먼저 시장을 선점하기 위해서는 좋은 기획에 초점을 맞출 수 없다. 급박하고 급변하는 상태에서 완벽한 기획과 설계를 하고 개발하는 것은 어렵다. 일단 동작하되 더럽게 만든다.
사족으로, 만약 어플리케이션이 시장에서 호응이 좋고 동작도 잘 할 경우, 우리에게는 두 가지의 선택지가 남겨진다.
1) 고객의 요구사항에 따라 새로운 기능을 추가한다. 하지만 급하게 만든 코드는 더러워지고 문제가 방치된다. 역겨운 코드가 된다.
2) 어플리케이션이 동작하면 이를 리팩토링한다. 혹은 이전의 경험을 기반으로 새롭게 만드는 것이 더 나은 선택일 수 있다. 무엇이 되었든 이때 좋은 디자인의 코드를 구현하기 위해 노력한다. 유연하고 좋은 코드가 작성되면, 이때부터 새로운 기능을 추가한다. 이때 TDD 기반으로 개발하고 회귀 테스트가 완비될 경우 리팩터링에 자신감을 가지고 수행 가능하다.
빠르게 배포를 하기 위하여 만들었던 코드는 재사용해야 하는가? 그것을 다시 구현하고 테스트코드를 작성하는 일은 새로 만드는 일보다 오래 걸린다. 어플리케이션은 빠르게 출시하고 그 이후에 그것을 더 단단한 형태로 새로 개발하는 것이 맞다.
MVC의 오용
MVC란 model, view, controller 가 각각의 레이어로서 독립적으로 존재하는 디자인 패턴이다. 그러니까 model 시스템을 보면, 그것이 web인지 모바일 앱인지 알 수 없어야 한다.
하지만 대체로 MVC 패턴은, model이 view나 controller에 강하게 의존하는 경향이 있다. 그러니까 model에서 view에서 사용하는 html 관련한 데이터가, controller의 session이나 request/response 객체가 침투한다. model이 pojo하지 못한다. model이 pojo하면, controller와 model 사이에 pojo하지 않은 레이어가 하나 더 있는 경우도 있다.
architecture 변경 없이 delivery 메커니즘을 변경할 수 있어야 한다.
boundary object, partitioning
각 영역을 분리한다. 각 영역은 interface로 적절하게 연결한다. 연결을 할 때 Data structure로서 dto를 사용한다.
web에서 request은 일종의 Data structure이다.
use case
Use Case는 입력 데이터를 해석하여 출력 데이터를 생성하는 필수 알고리즘. 시스템의 상호작용과 시스템의 의도를 보여준다.
“사용자가 무엇을 한다 -> 시스테임이 어떻게 대응한다”의 핑퐁 스타일이다.
이를 문서로 정리할 때, “사용자가 무엇을 한다” 수준으로 간략하게 정리할 수도 있다. 에러 상황에 대한 복잡한 내용까지 정리할 수도 있다. 형식이 정해져 있는 것은 아니다.
architect?
회사는 아키텍트을 시니어 개발자가 되기를 바란다. 기획, 설계, 디자인, 리뷰 등을 하기 바란다. 코딩은 저급한 것으로 보곤 한다.
하지만 코드를 작성하지 않으면 개발자는 무능해진다.
기획, 설계는 계속 변경된다. 소스코드가 기획, 설계도가 된다. 소스코드를 잘 작성하는 것이 아키텍트의 역할이다.