우리가 만드는 아키텍처는 우리가 무엇인지 소리쳐야 한다. 소리쳐야 하는 부분은 디렉터리 구조, 패키지에 담긴 소스파일이다. 그것이 무엇이라고 소리치는지 보자. 나는 헬스 케어 시스템이야 또는 재고 관리 시스템이야 라고 소리친다면 올바른 아키텍처지만, 만약 나는 스프링이야, 나는 ASP야 라고 소리친다면 이를 수정하는게 좋다. 아키텍처의 테마 애플리케이션 아키텍처는 유스케이스에 대해 소리쳐야 한다. 프레임워크에 대해 소리치고 있다면 유스케이스에 대해 소리치도록 바꿔보자. 프레임워크는 우리를 돕는 주체이지 우리가 맞춰야 하는 주체가 아니다. 아키텍처의 목적 좋은 아키텍처는 유스케이스를 그 중심에 두기 때문에, 프레임워크나 도구, 환경에 전혀 구애받지 않고 유스케이스를 지원하는 구조를 아무런 문제 없이 기술할..
전체 글
업무 규칙은 수익을 얻거나 비용을 줄일 수 있는 규칙이다. 이는 컴퓨터로 구현됐을 수도 있고, 사람이 수동으로 하는 작업들이 될 수도 있다. 예를 들어 은행에서 대출에 N%의 이자를 붙인다는 것은 사람이 하던, 컴퓨터가 하던 업무 규칙이다. 대출에 이자를 붙인다는 것을 핵심 업무 규칙이라고 하고, 이러한 핵심 업무 규칙에는 대출 잔액, 이자율, 지급 일정과 같은 핵심 업무 데이터가 필요하다. 핵심 업무 규칙과 핵심 업무 데이터를 객체로 만든 것이 엔티티다. 엔티티 엔티티는 컴퓨터 시스템 내부 객체로 핵심 업무 데이터를 기반으로 동작하는 핵심 업무 규칙을 구체화한다. 엔티티의 인터페이스는 핵심 업무 데이터를 기반으로 동작하는 핵심 업무 규칙을 구현한 함수로 구성된다. 엔티티는 입출력 장치 등과 같은 외부 ..
좋은 시스템일수록 저수준 컴포넌트가 고수준 컴포넌트에 의존하도록 설계되어 있다. 수준 수준은 입력과 출력까지의 거리이다. 시스템의 입력과 출력과의 거리가 멀어질수록 정책의 수준은 높아진다. 입력과 출력을 다루는 정책은 시스템의 최하위 수준에 위치해야 한다. 따라서 고수준의 정책(비즈니스 로직)이 입출력 시스템에 영향을 받게 되어 있다면 잘못 설계된 경우일 가능성이 크다. 아래의 코드가 그렇다. function encrypt() { while (true) { writeChar(translate(readChar())); } } 고수준의 encrypt 함수가 저수준(입력과 출력을 담당하는)의 writeChar 와 readChar 에 의존성을 가지고 있다. 이러한 경우 입출력 시스템의 정책에 변화가 생긴다면 e..
시스템 아키텍처는 일련의 소프트웨어 컴포넌트와 그 컴포넌트들을 분리하는 경계에 의해 정의된다. 경계 횡단하기 '런타임에 경계를 횡단한다' 는 뜻은 경계 한쪽에 있는 기능이 반대편의 기능을 호출하는 것이다. 적절하게 경계를 횡단하는 방법은 소스코드 의존성 관리이다. 두꺼운 단일체 모놀리틱 구조에서는 대부분 다형성에 의존해 내부 의존성을 관리한다. 따라서 특히 객체 지향 패러다임이 중요해진다. 가장 단순한 형태의 경계 횡단은 저수준 클라이언트에서 고수준 서비스로 향하는 함수 호출이다. 이 경우 런타임 의존성과 컴파일 의존성 모두 저수준 컴포넌트에서 고수준 컴포넌트로 향한다. 배포형 컴포넌트 아키텍처의 경계가 물리적으로 드러나는 경우 배포형 컴포넌트다. 배포형 컴포넌트는 별도의 실행 파일이 존재해 배포 과정에..
소프트웨어 아키텍처는 선을 긋는 기술이다. 이 선은 소프트웨어를 분리하고 이 선을 사이에 두고 한 쪽은 다른 쪽을 알지 못한다(반대는 알 수 있다). 결합을 줄이고 일찍 결정하지 않아도 되는 요소들을 나중으로 미루는 것이 선 긋기의 목표다. 어떻게 선을 그을까? 그리고 언제 그을까? 관련이 있는 것과 없는 것 사이에 선을 긋는다. GUI 와 비즈니스 로직은 관련이 없기 때문에 GUI 와 비즈니스 로직 사이에는 선이 그어져야 한다. 그리고 비즈니스 로직과 DB 사이에도 선이 그어져야 한다. 어떤 DB 를 사용하더라도 비즈니스 규칙이 그에 따라 변화되어서는 안된다. 이렇게 정하고 보면 인터페이스가 어떤 계층에 있어야 하는지 알게 된다. 기본적으로 스프링 컨트롤러 - 서비스 - 레포지토리 구조에서 DB 인터페..
좋은 아키텍처가 지원하는 것들 유스케이스 운영 개발 배포 유스케이스 시스템 아키텍처는 반드시 시스템의 요구사항을 지원해야 한다. 명확한 이름을 짓는 것, 유스케이스 단위로 분리하는 것이 유스케이스를 지원하는 좋은 방법이 될 수 있다. 운영 운영시에 어떠한 환경이 필요한지에 대해 고민하다 보면 시스템마다 다른 아키텍처를 가져가게 된다. 어떤 시스템은 실시간 처리를 해야할 수도 있고, 어떤 시스템은 대용량의 데이터를 다루어야 할 수도 있다. 그리고 또 어떤 시스템은 트래픽이 많지 않아 단순한 요청만 처리하는 시스템일 수 있다. 각각의 특징마다 어떤 시스템은 마이크로 서비스로, 어떤 시스템은 모노리틱 구조로 구현하면 된다. 만약 모노리틱 구조로 시스템 아키텍처를 구현하더라도 소스 코드 단계에서 컴포넌트로 잘 ..
아키텍트는 프로그래밍 작업을 놓아서는 안된다. 아키텍트는 프로그래밍 작업을 통해 발생하는 문제를 경험하고 프로그래머를 지원하는 역할을 해야 한다. 시스템 아키텍처의 목표는 시스템을 쉽게 개발하고 배포하고 운영하며 유지보수 되도록 만드는 것이다. 시스템 아키텍처는 시스템이 제대로 동작하기를 최우선 목표로 삼는 것은 당연하나 아키텍처가 엉망이더라도 시스템은 제대로 동작할 가능성이 크다. 사실상 아키텍처는 운영보다 배포, 유지보수, 개발을 쉽게 하는데에 초점이 맞춰져야 한다. 아키텍처의 주된 목적은 시스템의 생명주기를 지원하는 것이다. 좋은 아키텍처는 시스템을 쉽게 이해하고, 쉽게 개발하며, 쉽게 유지보수하고, 또 쉽게 배포하게 해준다. 아키텍처의 궁극적인 목표는 시스템의 수명과 관련된 비용은 최소화하고, 프..
ADP: 의존성 비순환 원칙 간단히 말하면 컴포넌트 의존성 그래프에 순환이 있으면 안된다는 원칙이다. 최신 스프링 부트 버전에서는 컴포넌트는 아니더라도 빈의 의존성이 순환을 하게 되면 에러를 발생시킨다. 순환 의존성 제거 개발 환경을 릴리스 가능한 컴포넌트 단위로 분리한 후 컴포넌트별로 담당자 또는 담당팀을 지정한다. 컴포넌트가 동작 가능하도록 만들고 릴리스 번호를 부여해 다른 팀에서 사용할 수 있도록 만들면 다른 팀은 해당 컴포넌트를 사용하기만 하면 된다. 만약 새로운 릴리스 버전이 만들어졌다고 하면, 이것을 사용할지 이전 릴리스 버전을 사용할지는 전적으로 사용하는 사람의 몫이다. 따라서 사용하는 팀과 만드는 팀의 결합이 느슨해졌다. 이러한 구조를 잘 사용하기 위해서는 컴포넌트 의존성이 순환하지 않아야..
REP: 재사용/릴리즈 등가 원칙 재사용 단위는 릴리스 단위와 같다. REP는 당연한 것이다. 한 번에 같이 릴리즈 되어야 하는 클래스들이 한 곳에 뭉쳐야 하고, 이를 지키는 것은 너무나 당연해서 지키지 않았을 때 너무 많이 티가 난다. CCP: 공통 폐쇄 원칙 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어야 한다. 다른 말로 하면 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리해야 한다. CCP는 SRP 단일 책임 원칙을 컴포넌트 단위에서 작성한 것이다. CRP: 공통 재사용 원칙 CRP는 함께 재사용되는 경우가 많은 클래스와 모듈은 한 컴포넌트로 묶어야 한다고 말한다. 개별 클래스가 단독으로 사용되는 경우는 거의 없고 다른 클래스와 상호작용 하는 경우가 많다. CRP를 지키려면..
컴포넌트는 자바의 jar 파일과 같은 배포 단위이다. 여러 컴포넌트를 하나로 묶어서 아카이브로 만들 수도 있고, 각각의 컴포넌트를 독립적으로 배포할 수도 있다. 잘 설계된 컴포넌트는 반드시 독립적으로 배포 및 개발이 가능해야 한다. 프로그램이 커질수록 프로그램을 컴파일하고 실행하는데까지 점점 더 많은 시간이 소요되었다. 그러나 그것보다 더 빠르게 메모리의 속도가 빨라지고 가격이 저렴해지면서 이제는 링크 시간이 초 단위 수준이 되었다. 이후 액티브 X 와 공유 라이브러리 시대가 열렸고 이제는 jar 파일이나 DLL, 공유 라이브러리를 기존 애플리케이션에 플러그인 형태로 배포하는 것이 일상적인 일이 되었다. 현재 이 아키텍처가 컴포넌트 플러그인 아키텍처다.