프로그래밍 패러다임
구조적 프로그래밍
- 구조적 프로그래밍은 제어흐름의 직접적인 전환에 부과되는 규율이다.
- 에츠허르 비버 다익스트라는 프로그램의 동작을 수학적 원리로 검증하려는 도중 알고리즘에 대해 기본적인 증명을 작성할 수 있는 방법의 필요성을 느꼈으나 이 과정에서 goto문장이 모듈을 분할 정복하여 재귀적으로 작은 단위로 분해하는 과정을 방해한다는 사실을 발견한다. 그러나 goto 문장이 반복, 분기만을 위해 사용된다면 모듈을 세분화 하는것이 가능하였고 모든 프로그램은 순차, 분기문, 반복문으로 표현할 수 있다는 결론에 이른다. 이 결론은 구조적 프로그래밍이라는 패러다임이 되어 현재까지 프로그램을 검증이 가능한 단위로 분할할 수 있도록 해 준다.
객체 지향 프로그래밍
- 객체 지향 프로그래밍은 제어흐름의 간접적인 전환에 부과되는 규율이다.
- 캡슐화 : 객체 지향언어는 프로그래머가 캡슐화된 데이터를 오용하지 않을 것이라는 믿음 하에 완벽한 캡슐화(.h와 .c파일의 분리)와 캡슐화의 편의성 사이의 어느 점에서 타협점(public, private, protected와 같은 접근 제한자, 헤더파일 분리방식 버림)을 제공했다. 그러나 C에서 누렸던 완벽한 캡슐화는 점점 약화된 것이 틀림없다.
- 상속 : 상속도 객체 지향 이전에 이미 존재했다. 그러나 객체 지향은 이를 훨씬 편리한 방식으로 제공한다.
- 다형성 : 다형성도 객체 지향 이전에 이미 존재했다. 그러나 기존의 다형성은 함수 포인터를 사용했었고, 이 방식은 위험했다. 프로그래머가 포인터 초기화 등의 특정 관례를 직접 따라야 했고, 그렇지 않았을 경우의 버그는 찾기가 힘들었다. 객체 지향은 이런 관례를 없애 주며 다형성을 대수롭지 않은 일로 만들었다. 다형성이 대수롭지 않아 지며 플러그인 아키텍처를 어디서나 사용할 수 있게 되었고, 의존성 역전을 통해 소스 코드 의존성을 제어 흐름에 관계없이 원하는 방향으로 설정할 수 있게 해 주었다. 이를 통해 비즈니스 룰에 UI나 DB같은 부가요소를 플러그인과 같이 조립할 수 있게 되었고, 독립적인 개발과 배포가 가능해 졌다.
- 결론 : 객체 지향이란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다.
함수형 프로그래밍
- 함수형 프로그래밍은 변수 할당에 부과되는 규율이다.
- 함수형 언어에서 한번 초기화된 변수의 값은 변경되지 않는다. 변수의 값이 변경되지 않는다면 경합 조건 문제와 같은 동시성 문제는 발생 가능성이 없다는 장점이 있다. 그러나 저장공간이 무한하고, 프로세서의 속도가 무한히 빠르다는 전제 하에서만 가능하기 때문에 타협점이 필요하다. 즉 가변 검포넌트와 불변 컴포넌트를 분리하는 것, 그리고 이벤트 소싱 전략이다.
Class와 Method단위의 설계원칙(SOLID)
단일 책임 원칙(SRP : Single Responsibility Principle)
- 하나의 모듈은 하나의 액터에 대해서만 책임져야 한다.
개방-폐쇄 원칙(OCP : Open-Closed Principle)
- 소프트웨어 개체는 확장에는 열려있어야 하고, 변경에는 닫혀 있어야 한다.
리스코프 치환 원칙(LSP : Liskov Substitution Principle)
- S타입이 T타입의 하위형이라면 필요한 프로그램 속성의 변경없이 T타입 객체를 S타입 객체로 치환할 수 있어야 한다.
인터페이스 분리 원칙(ISP : Interface Segregation Principle)
- 클라이언트 모듈이 자신이 이용하지 않는 메서드에 의존해서는 안된다. 모듈의 불필요한 부분으로 부터 인터페이스를 분리해야 한다.
의존성 역전 원칙(DIP : Dependency Inversion Principle)
- 상위 모듈(정책)은 하위 모듈(세부사항)에 의존해서는 안된다. 하위 모듈이 상위 모듈에 의존해야 한다.
- 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.
컴포넌트
- 컴포넌트는 배포의 단위이다. (.jar파일 등)
컴포넌트 응집도 원칙
재사용/릴리즈 등가 원칙(REP : Reuse/Release Equivalence Principle)
공통 폐쇄 원칙(CCP : Common Closure Principle)
- 동일한 이유로 동일 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라. 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 묶어라.
- 컴포넌트 단위의 SRP과 같다.
공통 재사용 원칙(CRP : Common Reuse Principle)
- 컴포넌트 사용자들을 필요하지 않는 것에 의존시키기 마라.
- 컴포넌트 단위의 ISP와 같다.
- REP와 CCP는 포함 원칙이며, 컴포넌트를 크게 만든다.
- CRP는 배제 원칙이며, 컴포넌트를 작게 만든다. 따라서 세 원칙 사이에 균형이 필요하다.
컴포넌트 결합 원칙
의존성 비순환 원칙(ADP : Acyclic Dependencies Principle)
- 컴포넌트 의존성 그래프에 순환이 있어서는 안된다.
안정된 의존성 원칙(SDP : Stable Dependencies Principle)
안정된 추상화 원칙(SAP : Stable Abstractions Principle)
- 컴포넌트는 안정된 정도만큼만 추상화 되어야 한다. 안정성 때문에 확장이 불가능 하지 않도록 추상화 되어야 한다. 반대로 불안정한 컴포넌트는 코드가 쉽게 변경될 수 있도록 구체적이어야 한다.
안정성과 추상성의 관계
- 안정성 측정 : 패키지 내부 클래스가 의존하는 외부 클래스 수 / (패키지 내부 클래스가 의존하는 외부 클래스 수 + 패키지 외부 클래스가 의존하는 내부 클래스 수). 0이면 최고로 안정적이며 1이면 최고로 불안정하다.
- 추상성 측정 : 패키지 내의 추상 클래스 수 / 패키지 내의 총 클래스 수
- 안정성과 추상성을 각각 X축, Y축으로 하는 그래프를 그리고 각 축의 범위가 0부터 1일 때, 모든 클래스들은 (0,1)과 (1,0)을 잇는 직선에 가까워야 한다.
- (0,0)점과 가까운 지역은 안정적면서 구체적이다. 추상적이지 않아 확장하기 처려운데 안정적이라 변경하기도 힘들어 고통의 지역이라 불린다.
- (1,1)점과 가까운 지역은 불안정적이면서 추상적이다. 이 컴포넌트를 외부에서 의존하지 않아 불안정하며 패키지의 대부분이 추상적이다. 아무도 사용하지 않는 인터페이스만 있는 패키지를 의미 하며 쓸모없는 구역이라 불린다.
- 고통의 지역과 쓸모없는 구역은 피하는 것이 좋다.
아키텍처
- 아키텍처란 시스템의 형태를 말한다.
- 아키텍처는 시스템의 동작보다는 구조를 통한 생명주기의 지원을 목표로 한다.
- 아키텍처는 시스템의 유스케이스, 즉 시스템의 의도를 지원해야 한다.
- 아키텍처는 시스템의 운영 작업을 가능하도록 해야 한다.
- 시스템의 아키텍처는 개발조직의 의사소통 구조와 동일해야 한다.
- 아키텍처는 컴포넌트를 분할하여 즉각적인 배포를 가능하도록 해야 한다.
- 아키텍처는 유스케이스를 중심에 두고 나머지 프레임워크, DB, UI와 같은 도구와는 격리시켜야 한다.

엔티티
- 핵심 업무 규칙을 구체화, 캡슐화 한다. 이 규칙은 업무를 프로그램으로 처리하던 사람이 처리하던 상관없이 적용되는 규칙이다. 어느것에도 의존하지 않고 POJO 클래스로 만들어 져야 한다.
유스케이스
- 애플리케이션에서의 업무규칙이다. 시스템의 모든 유스케이스를 캡슐화 한다. 엔티티에 의존하며 엔티티가 어떻게 동작할지 제어한다.
인터페이스 어댑터
- 내부 세계(엔티티+유스케이스)와 외부 세계(DB, 웹 등)를 이어주는 어댑터이다. MVC 아키텍처를 모두 포괄하는 계층이다. 모델은 그저 데이터 구조이며 컨트롤러 -> 유스케이스 -> 프레젠터 -> 뷰로 전달되며 가장 편리한 형식으로 변환된다.
프레임워크와 드라이버
- 계층의 가장 바깥쪽 구조로써 모든 세부사항이 위치한다.
험블 객체 패턴
- 테스트하기 쉬운 행위와 그렇지 못한 행위를 서로 나눠담는 디자인 패턴. 예를들어 단위 테스트가 어려운 UI의 경우 데이터를 표시하는 View와 데이터를 ViewModel로 변환하여 View에게 전달하는 Presenter로 나눠 View(험블)는 최대한 간단하게 유지하고 Presenter는 테스트가 가능한 객체로 유지한다. 이러한 험블 객체 패턴은 테스트 하기 좋은 부분과 어려운 부분을 분리시켜 아키텍처 경계를 정의하는데 도움을 준다.