클린 아키텍처 정리 - 2부. 프로그래밍 패러다임

inabyss·2019년 10월 24일
0

2부. 프로그래밍 패러다임

3장. 패러다임 개요

  • 각 패러다임은 프로그래머에게서 권한을 박탈한다.
    • 부정적 의도를 가지는 추가적 규칙들을 부과함
    • 무엇을 해야하는지 보단, 무엇을 하면 안되는 지를 의도함
  • 구조적 프로그래밍
    • goto -> if/then/else ..
    • 제어흐름의 직접적 전환에 대한 규칙을 부여
  • 객체 지향 프로그래밍
    • 함수 포인터를 규칙에 따라 사용함으로 다형성이 등장
    • 제어 흐름의 간접적 전환에 대한 규칙을 부여
  • 함수형 프로그래밍
    • 근간이 되는 람다 계산법의 기초는 불변성. 심볼의 값이 변경되지 않는다.
      • 할당문이 전혀 없다는 원칙이 있으나,
      • 까다로운 조건 아래에서만 값을 변경하는 방법을 제공
    • 할당문에 대한 규칙을 부여
  • 사실 소프트웨어는 쪼개고 보면 순차, 분기, 반복, 참조로 구성된다. 그 이상도 그 이하도 아님

4장. 구조적 프로그래밍

  • 테이크스트라의 증명
    • 수학적 증명을 통해 유클리드 계층 구조를 완성하려 했으나 완성되지 못함
      • 결국 과학적 증명으로 마무리
    • goto 는 프로그램의 재귀적 모듈 분리 과정에 방해가 됨
      • 흐름이 기준없이 변경되어 합리적 분할 정복 접근 법을 사용할 수 없으므로
    • 다만 분기, 반복을 위한 goto 사용은 좋은 패턴
      • 단순한 제어 구조 - 재귀적 세분화의 가능성
    • 모든 프로그램을 순차, 분기, 반복의 구조만으로 표현 가능함이 증명됨
    • 현재의 모든 프로그래머는 구조적 프로그래머
      • 제어 흐름이 제약 없이 전환할 수 있는 선택이 언어에서 제공되지 않게 됨 (no more goto)
      • java 의 break, exception 이 goto 와 유사하긴하나 엄밀히 제약이 존재함
  • 테스트
    • 테스트는 범위 내 버그가 있다는 것을 증명할 뿐,
      프로그램 전체를 통틀어 버그가 없다는 증명은 할 수 없다
    • 프로그램이 목표에 부합할 만큼은 버그가 일어나지 않음을 증명하기 위한 방법
    • 프로그램은 논리의 영역이긴 하나, 수학적이라기보단 과학적.
      잘못되지 않은 것들을 증명함으로 올바름을 기대하게 만드는 것이 목표
  • 구조적의 가치는 반증 가능 단위를 만들어내는 능력 때문. 모듈화.
  • 아키텍쳐 관점에선 기능적 분해를 최고의 실천법 중 하나로 여김

5장. 객체 지향 프로그래밍

  • 좋은 아키텍쳐를 만드는 것은 객체 지향 설계 원칙의 이해 응용에서 출발함

  • 객체 지향의 본질. 캡슐화, 상속, 다형성

    • .. 이라 하지만 캡슐화는 객체 지향 언어로 넘어오며 오히려 사실상 약화되었음
    • 상속은 표현적 편리함을 더했을 뿐 객체 지향만의 완전 새로운 개념은 아님
    • 다형성 역시 완전 새롭지는 않지만, 포인터의 직접 제어의 의무와 제한으로부터 해방
      • 제어 흐름의 간접적 전환 규칙
      • 플러그인 아키텍처
      • 플러그인 발상의 출발 - 장치 독립적으로 프로그램이 동작하면 유용하다
  • 의존성 역전

    • 일반적 소프트웨어의 제어 흐름은 시스템 행위에 따라 결정되고,
      소스 코드 의존성은 그 제어 흐름에 따라 결정됨.
    • 하지만 다형성의 존재와 활용으로 이 규칙을 깰 수 있다.
    • 제어 흐름과는 반대로 코드 의존성으로 향하는 것이 의존성 역전
      - 아키텍트의 관점에서 다형성은 객체 지향이 제공하는 힘
      - 아키텍트는 코드 의존성을 원하는 방향으로 설정, 절대적인 제어 권한을 획득할 수 있다.
      - 업무 규칙을 의존성의 중심에 놓고 소프트웨어 구조를 설계할 수 있다
      - UI, DB 의 상세 구현은 업무 규칙의 플러그인.
      - 저레벨에 의존받지 않음
      - 컴포넌트의 분리 -> 배포 독립성 -> 개발 독립성

6장. 함수형 프로그래밍

  • 함수형 언어에선 기본적으로 변수를 변경하지 않는 것을 원칙으로 함 = 불변성

    실제로는 기조를 가진다 정도가 적당할듯. 지향.
    완전 함수는 불변이 전제 조건이지만, 불완전 함수도 존재하며
    대부분의 함수형 언어들이 무조건 불변 변수만 다루는 것은 아님. Scala ..

    그렇다고 불변이라는 특성을 지향한다는 것을 무시하면 어차피 함수형 프로그래밍이 아니다.

  • 불변성과 아키텍쳐

    • 경합 조건, 교착 상태, 동시성 문제는 모두 가변 변수의 상태 변화 제어로부터 발생
    • 동시성은 아키텍트가 지대한 관심을 가져야 하는 영역
    • 불변성은 실현 가능하지만 타협이 필요함
  • 가변성의 분리

    • 어플리케이션 내부의 요소를 가변 컴포넌트와 불변 컴포넌트로 분리하라

      • 불변 컴포넌트는 변수의 상태를 변경할 수 있는 하나 이상의 비순수 컴포넌트와 통신
    • 이 분리 아래 가변 변수들을 보호하는 적절한 수단을 동원해 뒷받침 해야 함

      • ex. 클로저 언어의 atom => compare and swap 알고리즘 => java 의 Atomic

      atom 은 간단한 부분에서나 커버가 가능. 어쨌거나 결국 트랜잭션 관리.

    • 가능한 많은 처리를 불변 컴포넌트로 옮기고, 가변 컴포넌트의 역할을 줄이는 것이 좋다.

      가능한 범위에서 비즈니스 로직은 불변 컴포넌트에서,
      상태 변경을 동반한 트랜잭션 관리 영역의 역할을 줄인다는 컨셉으로

  • 이벤트 소싱

    • 상태가 아닌 트랜잭션 자체를 연속적으로 저장하고, 이들의 누적을 계산하는 발상

      • 다만 트랜잭션의 단위가 얼마나 늘어날지는 모르므로 중간 상태를 저장 관리
      • 중간 상태가 업데이트 된 이후의 계산은 다시 트랜잭션들을 계산 -> 최종 값

      이런 형태는 이벤트 소싱이라는 것을 의식하지 않은 상태에서
      기존 업무 로직에서 의외로 자주 접하기도 하고 사용해왔다.

      단지 트랜잭션 자체는 단순 추적 로그성으로 취급하는 경향이 있고,
      완전 불변으로 관리하느냐 마느냐는 또 케이스 바이 케이스로 다르게 적용되어 있음
      경우에 따라서는 메인 상태의 보조 상태의 역할로 구현하기도 했음

      하지만 엄밀히 말해 이벤트 소싱의 개념은 모든 트랜잭션 자체들을
      불변의 상태로 모두 기록하고, 이들을 리플레이 시키는 것.
      리플레이 시작 지점이 타협점. -> 동시성 문제를 해소함

      • 저장소는 가격이 저렴하다. 과거와 비교할 수 없는 수준.
        • 소프트웨어의 가치를 고려하면 저장할 데이터의 증가로 인한 저장소 비용은 무의미
profile
Optional.ofNullable(studying) .ifPresent(Blog::write) .orElseThrow(() -> new IdiotPleaseDoStudying());

0개의 댓글