Machineboy空

클린 아키텍쳐 4~6장 본문

Computer/CS

클린 아키텍쳐 4~6장

안녕도라 2025. 12. 3. 14:00

4장. 구조적 프로그래밍

 

발췌

 

이러한 제어 구조는 뵘과 야코피니가 데이크스트라보다 2년 앞서 발견했는데, 이 두 명은 모든 프로그램을 순차(sequence), 분기(selection), 반복(iteration)이라는 세 가지 구조만으로 표현할 수 있다는 사실을 증명했다. 이 발견은 실로 놀라웠다. 즉 , 모듈을 증명 가능하게 하는 바로 그 제어 구조가 모든 프로그램을 만들 수 있는 제어 구조의 최소 집합과 동일하다는 사실이었다.

 

데이크 스트라는 편집자에게 편지를 썼고, 편지의 제목은 "goto문의 해로움(Go To Statement Considered Harmful)"이었다. 

 

구조적 프로그래밍을 통해 모듈을 증명 가능한 더 작은 단위로 재귀적으로 분해할 수 있게 되었고, 이는 결국 모듈을 기능적으로 분해할 수 있음을 뜻했다. 즉, 거대한 문제 기술서를 받더라도 문제를 고수준의 기능들로 분해할 수 있었다. 그리고 이들 각 기능은 다시 저수준의 함수들로 분해할 수 있고, 이러한 분해 과정을 끝없이 반복할 수 있다.

 

과학은 근본적으로 수학과는 다른데, 과학 이론과 법칙은 그 올바름을 절대 증명할 수 없기 때문이다. 과학은 서술된 내용이 사실임을 증명하는 방식이 아니라 서술이 틀렸음을 증명하는 방식으로 동작한다. 각고의 노력으로도 반례를 들 수 없는 서술이 있다면 목표에 부합할 만큼은 참이라고 본다. 

 

소프트웨어 개발이 수학적인 구조를 다루는 듯 보이더라도, 소프트웨어 개발은 수학적인 시도가 아니라는 사실이다. 오히려 소프트웨어는 과학과 같다.최선을 다하더라도 올바르지 않음을 증명하는 데 실패함으로써 올바름을 보여주기 때문이다. 

 

구조적 프로그래밍은 프로그램을 증명 가능한 세부 기능 집합으로 재귀적으로 분해할 것을 강요한다. 그러고 나서 테스트를 통해 증명 가능한 세부 기능들이 거짓인지를 증명하려고 시도한다. 이처럼 거짓임을 증명하려는 테스트가 실패한다면, 이 기능들은 목표에 부합할 만큼은 충분히 참이라고 여기게 된다.

 

구조적 프로그래밍이 오늘날까지 가치 있는 이유는 프로그래밍에서 반증 가능한 단위를 만들어낼 수 있는 바로 이 능력 때문이다. 또한 흔히 현대적 언어가 아무런 제약없는 goto문장은 지원하지 않는 이유이기도 하다. 뿐만 아니라 아키텍처 관점에서는 기능적 분해를 최고의 실천법 중 하나로 여기는 이유이기도 하다.

 

paraphrasing

  • 모듈화하여 작은 단위로 나누고(기능을 구조적으로 나눌 수 있게 구성하고), 흐름을 예측할 수 없는 goto문을 지양해라!
  • 쉽게 테스트하고, 쉽게 반증할 수 있도록

 


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

 

발췌

 

좋은 아키텍처를 만드는 일은 객체 지향 설계 원칙을 이해하고 응용하는 데서 출발한다. 그렇다면 대체 객체 지향이란 무엇인가?

 

이 질문에 흔히 "실제 세계를 모델링하는 새로운 방법"이라고들 답한다. 이는 기껏해야 얼버무리는 수준에 지나지 않는다. 도대체 "실제 세계를 모델링한다"라는 말이 무엇을 의미하며, 왜 우리는 그 방향을추구해야 하는가? 이 답변이 전달하려는 의도는 객체 지향은 현실 세계와 의미적으로 가깝기 때문에 객체를 사용하면 소프트웨어를 좀 더 쉽게 이해할 수 있다는 데 있는 듯 하다. 하지만 이 의도조차 불분명하며, 그 정의가 너무 모호하다. 다시 말해 이 답변도 객체 지향이 무엇인지를 설명해주지 않는다.  


캡슐화(Encapsulation)

  • 헤더: 데이터 구조와 함수 선언
  • 구현체: 이들을 구현
C C++ C#, Java
완벽한 캡슐화
데이터 구조와 함수를 헤더 파일에 선언하고, 구현 파일에서 이들을 구현했다. 그리고 구현파일에 작성된 항목에 대해서는 어떠한 방법으로도 접근할 수 없었다.
c++의 컴파일러는 클래스의 인스턴스 크기를 알 수 있어야 해서, 헤더 파일을 사용하는 측에서 멤버 변수 x,y를 알게 된다. 헤더 파일이 사라짐.
헤더와 구현체를 분리하는 방식을 버렸다.

 

 

객체 지향 프로그래밍은 프로그래머가 충분히 올바르게 행동함으로써 캡슐화된 데이터를 우회해서 사용하지 않을 거라는 믿음을 기반으로 한다. 하지만 객체 지향을 제공한다고 주창한 언어들이 실제로는 C언어에서 누렸던 완벽한 캡슐화를 약화 시켜 온 것은 틀림없다.


상속(Inheritance)

  • NamedPoint ⊃ Point : NamedPoint데이터 구조가 마치 Point 데이터 구조로부터 파생된 구조인 것처럼 동작한다. 눈속임처럼 보이는 이 방식은 객체 지향이 출현하기 이전부터 프로그래머가 흔히 사용하던 기법이었다.
  • NamedPoint인자를 Point로 타입을 강제로 변환한 점도 확인할 수 있다. 진짜 객체 지향 언어에서는 이러한 업캐스팅이 암묵적으로 이뤄진다. 

다형성(Polymorphism)

 

getchar()함수는 STDIN에서 문자를 읽는다. 그러면 STDIN은 어떤 장치인가? putchar()함수는 STDOUT으로 문자를 쓴다. 그런데 STDOUT은 또 어떤 장치인가? 이러한 함수는 다형적이다. 즉 행위가 STDIN과 STDOUT의 타입에 의존한다.

 

getchar()입력 키보드 키보드의 입력값을 읽음
파일 파일의 내용을 읽음
putchar()출력 터미널 화면에 글자 출력
파일 파일으로 글자 출력

 

즉 코드 자체가 바뀌지 않는데 동작이 바뀌는 것 = 다형성

즉 함수를 가리키는 포인터만 바꾸면 동작이 달라진다 = 다형성

 

새로운 입출력 장치가 생긴다면 프로그램에는 어떤 변화가 생기는가? 아무런 병경도 필요치 않다. 심지어 복사 프로그램을 다시 컴파일할 필요조차 없다. 왜냐고? 복사 프로그램의 소스 코드는 입출력 드라이버의 소스 코드에 의존하지 않기 때문이다. 

 


의존성 독립(Dependency inversion)

  • 제어 흐름: 프로그램이 실행될 때 메서드가 호출되는 순서
  • 소스 코드 의존성: 코드가 다른 모듈의 정의를 참조

제어흐름은 세스템의 행위에 따라 셜정되며, 소스 코드 의존성은 제어흐름에 따라 결정된다.

 

하지만 다형성이 끼어들면 특별한 일이 일어난다. 

객체 지향 언어로 개발된 시스템을 다루는 호프트웨어 아키텍트는 시스템의 소스 코드 의존성 전부에 대해 방향을 결정할 수 있는 절대적인 권한을 갖는다. 즉 소스 코드 의존성이 제어흐름의 방향과 일치되도록 제한되지 않는다.

 

이렇게 하면 , 업무 규칙이 데이터베이스와 UI에 의존하는 대신에 시스템의 소스 모드 의존성을 반대로 배치하여 데이터 베이스와 UI가 업무 규칙에 의존하게 만들 수 있다. 

 


소프트웨어 아키텍트 관점에서 객체 지향이란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다. 

 


6장. 함수형 프로그래밍

Java Closure
가변 변수 사용
: 프로그램 중에 상태가 변할 수 있다.
예 ) 반복문에서의 i같은 것
가변 변수 X
x와 같은 변수가 한 번 초기화되면 절대로 변하지 않는다.

 

함수형 언어에서 변수는 변경되지 않는다. 

 

아키텍처를 고려할 때, 왜 변수의 가변성을 염려하는가? 경합조건, 교착상태(deadlock)조건, 동시 업데이트 문제가 모두 가변 변수로 인해 발생하기 때문이다. 하지만 자원이 무한대가 아니라 불변성은 실현 가능하겠지만 일종의 타협을 해야 한다. 

 

가변 컴포넌트와 불변 컴포넌트로 분리하는 일이다. 불변 컴포넌트에서는 순수하게 함수형 방식으로만 작업이 처리되며, 어떤 가변 변수도 사용되지 않는다. 

 

이제 프로세서가 초당 수십억 개의 명령을 수행하고 RAM용량은 수십억 바이트인 시대가 되었다. 더 많은 메모리를 확보할수록, 기계가 더 빨라질수록, 필요한 가변 상태는 더 적어진다. 

 

저장 공간과 처리 능력이 충분하면 애플리케이션이 완전한 불변성을 갖도록 만들 수 있고 따라서 완전한 함수형으로 만들 수 있다.


1946년 앨런 튜링이 전자식 컴퓨터에서 실행할 거의 최초의 코드를 작성할 때 사용한 소프트웨어 규칙과 지금의 소프트웨어 규칙은 조금도 다르지 않다. 도구는 달라졌고 하드웨어도 변했지만, 소프트웨어의 핵심은 여전히 그대로다. 소프트웨어, 즉 컴퓨터 프로그램은 순차(sequence), 분기(selection), 반복(iteration), 참조(indirection)로 구성된다.