컴포넌트는 자바의 jar 파일과 같은 배포 단위이다. 여러 컴포넌트를 하나로 묶어서 아카이브로 만들 수도 있고, 각각의 컴포넌트를 독립적으로 배포할 수도 있다. 잘 설계된 컴포넌트는 반드시 독립적으로 배포 및 개발이 가능해야 한다. 프로그램이 커질수록 프로그램을 컴파일하고 실행하는데까지 점점 더 많은 시간이 소요되었다. 그러나 그것보다 더 빠르게 메모리의 속도가 빨라지고 가격이 저렴해지면서 이제는 링크 시간이 초 단위 수준이 되었다. 이후 액티브 X 와 공유 라이브러리 시대가 열렸고 이제는 jar 파일이나 DLL, 공유 라이브러리를 기존 애플리케이션에 플러그인 형태로 배포하는 것이 일상적인 일이 되었다. 현재 이 아키텍처가 컴포넌트 플러그인 아키텍처다.
전체 글
의존 관계에서 구체적인 모듈을 참조해서는 안되지만 이는 사실상 불가능하다. 자바의 String 클래스가 대표적인 예인데, String 클래스는 구체 클래스이나 대부분의 모듈에서 이에 의존한다. 따라서 우리가 의존하는 것을 피해야 할 것은 변동성이 큰 구체적인 요소이다. 안정된 추상화 인터페이스를 최대한 변경하지 않고 새로운 기능을 추가할 수 있는 방법을 가장 먼저 찾아라. 변동성이 큰 구현체에 의존하는 것을 최대한 피하고 안정된 추상 인터페이스를 의존해야 한다. 변동성이 큰 구체 클래스를 참조하지 말라 추상 팩토리 사용을 고려하라 변동성이 큰 구체 클래스로부터 파생하지 말라 상속은 가장 강력한 결합이다 구체 함수를 오버라이드 하지 말라 구체적이며 변동성이 크다면 절대로 그 이름을 언급하지 말라 팩토리 소..
ISP와 언어 정적 타입 언어는 import, use, include 등과 같은 선언문을 사용해야 한다. 이로 인해 소스 코드 의존성이 발생하는데, 루비나 파이썬과 같은 동적 언어는 이러한 의존성이 아예 없어서 정적 타입 언어를 사용할 때보다 결합도가 낮은 시스템을 만들 수 있다. ISP와 아케틱처 시스템을 만들 때 특정 프레임워크를 사용하기로 강제로 결정을 내리고, 해당 프레임워크는 특정 데이터베이스를 강제로 사용해야 한다면, 시스템은 결국 데이터베이스까지 의존성을 가지게 된다. 이는 데이터베이스에 변경사항이 발생하면 프레임워크도 재컴파일 및 재배포를 해야 하고, 그렇게 되면 시스템도 재컴파일 및 재배포를 해야 한다. 또한 시스템이 전혀 사용하지 않는 데이터베이스의 특정 기능이 문제를 일으키면 시스템에..
책에서 리스코프 치환 원칙을 위반하는 좋은 예제를 정사각형/직사각형 문제로 보여준다. 사각형이라는 인터페이스가 있고 사각형 인터페이스는 가로 설정, 세로 설정 메서드를 제공한다. 그리고 이를 구현한 구현체는 직사각형 구현체와 정사각형 구현체가 있다. 사용자가 사각형 인터페이스를 사용할 때, 가로 설정과 세로 설정을 모두 사용한다고 가정하면 정사각형의 구현체를 사용한 사람은 해당 메서드가 원하는대로 동작하지 않을 것이다. 사용하는 입장에서 사용하는 것의 정확한 구현체를 알아야 한다면 이는 리스코프 치환 원칙에 위배된다. LSP는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 한다. 치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문이다.
소프트웨어 개체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다. 의존성 방향이 향하는 것은 화살표가 시작하는 곳의 변경사항을 화살표가 향하는 곳에서 지키기 위해서다. 만약 A -> B 로 화살표가 향한다면, A의 변경사항이 B에 영향을 주지 않게 하기 위함이다. 따라서 가장 중요한 비즈니스가 담긴 로직은 화살표를 받기만 하는 것이 좋고, 세부 사항으로 내려갈 수록 다른 것들을 의존해야 한다. 이런 화살표를 제어할 수 있는 가장 좋은 방법이 Interface 를 사용하는 것이다. OCP는 시스템 아키텍처를 떠받치는 원동력 중 하나다. OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는 데 있다. 이러한 목표를 달성하려면 시스템을 컴포넌트 단위..
단일 책임 원칙은 함수는 단 하나의 일만 해야 한다는 원칙이 아니라 사실은 "단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다." 라는 의미이다. 우발적 중복 단일 책임 원칙을 위반하는 대표적 사례인 우발적 중복을 살펴보자. Employee 클래스가 아래 세 가지 메서드를 가지고 있다. calculatePay() : 회계팀에서 기능을 정의하며, CFO 보고를 위해 사용 reportHours() : 인사팀에서 기능을 정의하며, COO 보고를 위해 사용 save() : 데이터베이스 관리자가 기능을 정의하며, CTO 보고를 위해 사용 calulatePay() 메서드와 reportHours() 메서드가 업무 시간을 계산하는 regularHours() 메서드를 동시에 사용한다고 했을때 CFO 팀에서 업무 ..
함수형 프로그래밍이라는 개념은 프로그래밍보다 먼저 등장했다. 정수를 제곱하기 자바 언어에서 25까지 정수 제곱을 출력하려면 아래처럼 코드를 작성하면 된다. public class Squint { public static void main(String args[]) { for (int i = 0; i < 25; i++) { System.out.println(i*i); } } } 함수형 언어인 클로저는 아래와 같다. (println (take 25 (map (fn [x] (* x x)) (range)))) 위의 코드를 쪼개보면 (println (take 25 (map (fn [x] (* x x)) (range)))) 자바에서는 가변 변수인 i를 사용하지만 클로저에서는 가변 변수가 전혀 없다. 가변 변수처럼 ..
좋은 아키텍처를 만드는 일은 객체 지향 설계 원칙을 이해하고 응용하는 데서 출발한다. 객체 지향이란? 데이터와 함수의 조합 실제 세계를 모델링하는 방법 캡슐화 상속 다형성 캡슐화? OO가 데이터와 함수를 쉽게 캡슐화하는 방법을 제공한다고 말하는데, 이는 잘못된 설명이다. OO를 기반으로 설계되지 않은 C 언어에서 오히려 더 완벽한 캡슐화를 제공한다. point.h struct Point; struct Point* makePoint(double x, double y); double distance(struct Point* p1, struct Point* p2); point.c #include "point.h" #include #include struct Point { double x, y; }; struc..
구조적 프로그래밍은 데이크스트라라는 네덜란드 프로그래머에 의해 만들어졌다. 증명 데이크스트라는 프로그래밍에도 수학의 증명을 도입하려고 했다. 프로그래머가 검증된 구조를 사용해 코드를 작성하여 이 코드가 올바르다는 사실을 스스로 증명하게 만드려고 했다. 이런 과정에서 goto 문은 단순 반복문/조건문으로 대체할 수 있다는 것을 발견했다. goto 문을 사용하면 증명을 하기가 어렵지만, 반복문/조건문은 세부 단위로 쪼갤 수 있고, 따라서 증명을 하기가 더 쉽다. 모든 프로그램을 순차, 분기, 반복이라는 세 가지 구조만으로 표현할 수 있다는 사실을 증명했다. 해로운 성명서 데이크스트라는 "goto문의 해로움"이라는 제목의 글을 썼고, 여기에 많은 사람들이 지지와 반대를 보냈다. 현재 살펴보면 goto 문은 코..
이 장에서는 세 가지 패러다임인 구조적 프로그래밍, 객체지향 프로그래밍, 함수형 프로그래밍에 대해 다룬다. 구조적 프로그래밍 구조적 프로그래밍은 최초로 적용된 패러다임으로 goto 문은 if / then / else 와 do / while / until 문으로 대체해야 한다는 것이다. 구조적 프로그래밍은 제어흐름의 직접적인 전환에 대해 규칙을 부과한다. 객체 지향 프로그래밍 객체 지향 프로그래밍은 함수 호출 스택 프레임을 힙으로 옮기면 지역 변수가 오랫동안 유지될 수 있음을 발견하고 만들어졌다. 이런 함수가 생성자가 되었고, 지역 변수는 인스턴스 변수, 중첩 함수는 메서드가 되었다. 함수 포인터를 특정 규칙에 따라 사용하는 과정을 통해 필연적으로 다형성이 등장했다. 객체 지향 프로그래밍은 제어흐름의 간접..