• 소프트웨어 아키텍처는 코드로부터 시작한다.
  • 프로그래밍 언어는 쉴 틈 없이 쏟아져나왔으며, 프로그래밍 패러다임도 몰아쳤다.
    • 패러다임: 프로그래밍을 하는 방법으로 대체로 언어에 독립적이다. 패러다임은 어떤 프로그래밍 구조를 사용할지, 그리고 언제 이 구조를 사용해야 하는지를 결정한다.

패러다임 개요

  • 구조적 프로그래밍: 제어흐름의 직접적인 전환에 대해 규칙을 부과한다.
    • 무분별한 점프는 프로그램 구조에 해롭다는 사실을 제시했다.
  • 객체 지향 프로그래밍: 제어흐름의 간접적인 전황에 대해 규칙을 부과한다.
    • 함수 호출 스택 프레임을 힙으로 옮기면, 함수 호출이 반환된 이후에도 함수에서 선언된 지역변수가 오랫동안 유지될 수 있음을 발견했다.
  • 함수형 프로그래밍: 할당문에 대해 규칙을 부과한다.
    • 람다 계싼법을 사용한다. 람다 계산법의 기초가 되는 개념은 불변성과 심볼의 값이 변경되지 않는다는 개념이다.
    • 함수형 언어네는 할당문이 전혀없다.
  • 각 패러다임은 무엇을 해야 할지를 말하기보다는 무엇을 해서는 안 되는지를 알려준다.
  • 각 패러다임이 우리에게서 무언가를 빼앗는다.

구조적 프로그래밍

  • 데이크스트라는 수학자가 유클리드 계층구조를 사용하는 방식을 프로그래머도 사용할 수 있다고 믿었따. 픅로그래머는 입증된 구조를 이용하고, 이들 구조를 코드와 결합시켜 코드가 올바르다는 사실을 스스로 증명하게 되는 방식이었다.

  • 데이크스트라는 연구를 진행하면서 goto 문장이 분할 정복 접근법을 방해하는 경우가 있다는 사실을 발견했다.

  • 뵘과 야코피니는 모든 프로그램을 순차, 분기, 반복이라는 세가지 구조만으로 표현할 수 있다는 사실을 증명했다.

  • 여러 논쟁 끝에 goto 문장은 계속 뒤편으로 밀려났고, 마침내 거의 사라졌다.

  • 구조적 프로그래밍을 통해 모듈을 증명 가능한 더 작은 단위로 재귀적으로 분해할 수 있게 되었고, 이는 결국 모듈을 기능적으로 분해할 수 있음을 뜻했다.

  • 테스트는 버그가 있음을 보여줄 뿐, 버그가 없음을 보여줄 수는 없다.

  • 구조적 프로그래밍은 프로그램을 증명 가능한 세부 기능 집합으로 재귀적으로 분해할 것을 강요한다.

    • 그리고 나서 테스트를 통해 증명 가능한 세부 기능들이 거짓인지 증명하려고 시도한다.
    • 거짓임을 증명하려는 테스트가 실패한다면, 이 기능들은 목표에 부합할 만큼 충분히 참이라고 여기게 된다.
  • 구조적 프로그래밍이 오늘날까지 가치 있는 이유는 프로그래밍에서 반증 가능한 단위를 만들어 낼 수 있는 능력때문이다.

객체 지향 프로그래밍

  • OO의 본질을 설명하기 위한 세 가지 부류
    • 캡슐화
    • 상속
    • 다형성
  • 데이터와 함수를 쉽고 효과적으로 캡슐화하는 방법을 OO 언어가 제공하고 있다.
    • 이를 통해 구분선 바깥에서 데이터는 은닉되고, 일부 함수만이 외부에 노출된다.
    • 하지만 실제 많은 OO 언어가 헤더와 구현체를 분리하는 방법을 모두 버렸고, 캡슐화를 거의 강제하지 않는다.
    • OO 프로그래밍은 프로그래머가 충분히 올바르게 행동함으로써 캡슐화된 데이터를 우회해서 사용하지 않을거라는 믿음을 기반으로 한다.
  • 상속은 단순히 어떤 변수와 함수를 하나의 유효 범위로 묶어서 재정의하는 일에 불과하다.
  • OO 언어가 있기 전에도 함수 포인터를 이용해서 다형성을 표현할 수 있었다.
    • OO 언어는 다형성을 좀 더 안전하고 더욱 편리하게 사용할 수 있게 해준다.
    • 다형성으로 플러그인 아키텍처가 가능해졌다. 플러그인 아키텍처는 입출력 장치 독립성을 지원하기 위해 만들어졌고, 등장 이후 거의 모든 운영체제에서 구현되었다.
    • 다형성으로 의존성 역전이 가능해졌다. 의존성 역전으로 아키텍트는 시스템의 소스 코드 의존성 전부에 대해 방향을 결정할 수 이쓴 절대적인 권한을 갖는다. 의존성 역전으로 배포 독립성과 개발 독립성을 갖는다.
  • OO란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다.

함수형 프로그래밍

  • 함수형 언어에서는 변수는 변경되지 않는다.
  • 아키텍처를 고려할 때 불변성이 중요한 이유: 경합 조건, 교착 상태, 동시 업데이트 문제가 모두 가변 변수로 인해 발생하기 때문이다.
  • 저장 공간이 무한하고 프로세서의 속도가 무한히 빠르다는 전제하에서는 불변성이 실형 가능하지만, 실제에서는 일종의 타협이 필요하다.
    • 가장 중요한 타협 중 하나는 애플리케이션, 또는 애플리케이션 내부의 서비스를 가변 컴포넌트와 불변 컴포넌트로 분리하는 일이다. 이렇게 분리하고 가변 변수들을 보호하는 적절한 수단을 동원해 뒷받침해야 한다.
    • 현명한 아키텍트라면 가능한 한 많은 처리를 불변 컴포넌트로 옮겨야 하고, 가변 컴포넌트에서는 가능한 한 많은 코드를 빼내야 한다.
  • 저장 공간과 처리 능력의 한계가 급격히 사라지고 있어서 이벤트 소싱이 가능해졌다.
    • 이벤트 소싱은 상태가 아닌 트랜잭션을 저장하는 전략이다.
    • 데이터 저장소에서 변경과 삭제가 전혀 발생하지 않으므로 동시 업데이트 문제 또한 일어나지 않는다.