[실용주의 프로그래머 with 노개북] #06 4장 실용주의 편집증

londev·2022년 3월 24일
0

오늘 TIL 3줄 요약

  • 완벽한 소프트웨어는 없으므로 방어적으로 프로그래밍해야 한다.
  • 모듈실행의 전후조건과 불변의 요구사항을 명확히 함으로서 프로그램의 정확성을 보장한다.
  • 이는 DBC(Designed By Contract), assertion을 이용한 설계/표현/테스트를 통해 가능해진다.

TIL (Today I Learned) 날짜

2022.03.24

오늘 읽은 범위

4장 실용주의 편집증

책에서 기억하고 싶은 내용을 써보세요.

  • Tip 36 여러분은 완벽한 소프트웨어를 만들 수 없다.
  • 우리는 늘 다른 사람의 코드??우리의 높은 기준에는 못 미칠지도 모르는 코드??를 접하고, 적절한지 아닌지 알 수 없는 입력을 처리하고 있다. 그래서 우리는 방어적으로 코딩하라고 배운다.

Topic 23 계약에 의한 설계

  • 지난 수천 년간 우리가 얻은 해법 중 몇 가지는 소프트웨어를 만드는 데에도 적용할 수 있다. 정직한 거래를 보장하는 최선의 해법 중 하나는 계약contract이다.

DBC

  • 버트런드 마이어Bertrand Meyer는 에펠Eiffel이라는 언어를 만들면서 계약에 의한
    설계Design By Contract, DBC설계 개념을 개발했다.
  • 프로그램의 정확성을 보장하기 위해 소프트웨어 모듈의 권리와 책임을 문서화하고 합의하는 데에 초점을 맞춘다.
  • 뭔가를 시작하기 전에 해당 함수는 세상의 상태에 대해 어떤 전제 조건을 갖고 있을 테고, 루틴이 끝난 후에는 세상의 상태가 어떠할 것이라고 선언할 수 있을 것이다. 마이어는 이런 전제와 선언을 다음과 같이 설명한다.
  • 선행 조건precondition
    루틴이 호출되기 위해 참이어야 하는 것. 즉, 루틴의 요구 사항이다. 루틴의 선행 조건이 위반된 경우에는 루틴이 호출되어서는 안 된다. 제대로 된 데이터를 전달하는 것은 호출하는 쪽의 책임이다.
  • 후행 조건postcondition
    루틴이 자기가 할 것이라고 보장하는 것. 즉, 루틴이 완료되었을 때 세상의 상태다. 루틴에 후행 조건이 있다는 것은 곧 루틴이 종국에는 종료될 것이라는 걸 의미한다. 무한 반복은 허용되지 않는다.
  • 클래스 불변식class invariant
    호출자의 입장에서 볼 때는 이 조건이 언제나 참인 것을 클래스가 보장한다. 루틴의 내부 처리 도중에는 불변식이 참이 아닐 수도 있지만, 루틴이 끝나고 호출자로 제어권이 반환되는 시점에는 불변식이 참이 되어야 한다.
  • 루틴과 그 루틴을 호출하려는 코드 간의 계약
    만약 호출자가 루틴의 모든 선행 조건을 충족한다면 해당 루틴은 종료 시 모든 후행 조건과 불변식이 참이 되는 것을 보장한다

클래스 불변식과 함수형 언어

  • 에펠이 객체 지향 언어였던 탓에 마이어는 이 개념을 클래스 불변식이라고 이름 붙였다.이 용어가 진짜로 의미하는 것은 상태state다.
  • 함수형 언어에서는 보통 상태를 함수에 넘긴 후 바뀐 상태를 결과로 받는다. 불변식이라는 개념은 이런 상황에서도 똑같이 유용하다.

DBC 구현

  • DBC는 결국 설계 기법이다. 자동 검사가 없더라도 계약을 코드에 주석이나 단위 테스트로 넣어둘 수 있고, 여전히 실질적인 소득이 있다.

단정문

  • 몇몇 언어에서는 조건문을 실행 시점에 확인하는 단정문을 사용해서 부분적으로나마 흉내 낼 수 있다.

DBC와 일찍 멈추기

  • 단정문이나 DBC 방식을 사용하여 선행 조건과 후행 조건, 불변식을 검증하면 더 일찍 멈추고, 문제에 대한 보다 정확한 정보를 알려줄 수 있을 것이다.
  • 문제를 찾고 원인을 밝히기 위해서는 사고가 난 지점에서 일찍 멈추는 것이 유리하다.

의미론적 불변식

  • 의미론적 불변식semantic invariant을 사용하면 일종의 철학적 계약인 절대 어겨서는 안 되는 요구 사항을 표현할 수 있다.
  • 의미론적 불변식은 무언가가 품은 진짜 의미의 중심이 되어야 하며, 훨씬 역동적으로 변하는 비즈니스 규칙처럼 일시적인 정책에 영향을 받으면 안 된다.

Topic 25 단정적 프로그래밍

  • 하지만 물론 그런 일은 절대 일어나지 않을 거야라는 생각이 든다면 그런 일을 확인하는 코드를 추가하라. 가장 간단하게 추가하는 방법은 단정문assertion을 사용하는 것이다. 대부분의 언어 구현에서 조건이 참인지 거짓인지 확인하는 assert의 일종을 찾을 수 있을 것이다. 이런 단정문은 엄청나게 유용하다. 매개 변수나 결과가 절대 null이어서는 안 된다면 명시적으로 검사하라. assert (result != null);
  • 하지만 진짜 오류 처리를 해야 하는 곳에 단정을 대신 사용하지는 말라. 단정은 *결코 일어나면 안 되는 것들을 검사한다.
  • 성능 문제가 있다있다 하더라도 정말 문제가 되는 단정문만 끄도록 하자

Topic 26 리소스 사용의 균형

  • 촛불 하나를 켜는 건 곧 그림자도 하나 던지는 거란 말이다.- 어슐러 K. 르 귄(Ursula K. Le Guin), 어스시의 마법사
  • 자신이 시작한 것은 자신이 끝내라. 팁이 가르쳐 주는 것은 이상적으로 말해서 리소스를 할당하는 루틴이 해제 역시 책임져야 한다는 것이다.
  • 열기와 닫기가 같은 곳에 있고, 모든 열기에 상응하는 닫기가 있다는 것도 분명해 보인다.
  • 많은 현대 언어에서는 리소스의 유효 범위를 블록 같은 것으로 감싸서 지정할 수 있다.

중첩 할당

  • 한 번에 여러 리소스를 사용하는 루틴
  • 리소스를 할당한 순서의 역순으로 해제하라. 이렇게 해야 한 리소스가 다른 리소스를 참조하는 경우에도 참조를 망가트리지 않는다.
  • 코드의 여러 곳에서 동일한 구성의 리소스들을 할당하는 경우에는 언제나 같은 순서로 할당해야 교착deadlock 가능성을 줄일 수 있다. 프로세스 A가 resource1을 이미 확보하고서 resource2를 획득하려고 하고 있는데 프로세스 B는 resource2를 확보한 상태로 resource1을 막 요청하려고 한다면, 두 프로세스 모두 영원히 기다리게 될 것이다.

객체와 예외

  • 객체 지향 언어로 프로그래밍을 한다면 리소스를 클래스 안에 캡슐화하는 것이 유용할 수 있다. 특정 유형의 리소스가 필요할 때마다 그 클래스의 객체를 생성하면 된다. 그 객체가 스코프를 벗어나거나 가비지 컬렉터가 객체를 수거해 가면 객체의 소멸자가 클래스 안에 들어 있는 리소스를 해제한다.이 접근법은 예외 때문에 리소스 해제가 제대로 되지 않을 수 있는 언어로 작업할 때에 특히 쓸모 있다.
  • C++나 러스트 같은 언어의 일반적인 스코프 규칙에서는 함수나 블록 종료, 예외 등으로 변수가 스코프를 벗어나면 변수의 메모리가 해제된다. 그런데 이 변수의 소멸자에 외부 리소스를 정리하는 기능을 끼워 넣을 수 있다.
  • finally 절의 코드는 try~catch 블록에서 예외가 발생하는지와 상관없이 언제나 실행된다.
  • 자료 구조에서 최상위 구조의 메모리 할당을 해제할 경우 어떻게 처리해야 할까? 크게는 다음 세 가지 방법이 있다.
  • 최상위 구조가 자기 안에 들어 있는 하위 구조들을 해제할 책임을 진다. 하위 구조들은 또다시 재귀적으로 자기 안에 들어 있는 자료들을 해제할 책임을 지고, 이런 식으로 반복된다.
  • 최상위 구조가 그냥 할당 해제된다. 최상위 구조가 참조하던 하위 구조들은 연결이 끊어져서 다른 곳에서 참조하지 않는다면 외톨이가 된다.
  • 최상위 구조가 하나라도 하위 구조를 가지고 있으면 자신의 할당 해제를 거부한다.
  • 선택은 각 자료 구조의 상황에 따라 달라진다. 하지만 언제나 어떤 것을 선택할지 확실하게 정하고 그에 따라 일관성 있게 구현해야 한다.

균형을 점검하기

  • 우리는 언제나 정말로 리소스가 적절하게 해제되었는지 실제로 점검하는 코드를 작성하는 것을 좋아한다. 대부분의 애플리케이션에서 이 말은 보통 리소스의 종류별로 래퍼wrapper를 만들고 그 래퍼들이 모든 할당과 해제 기록을 보관하는 것을 뜻한다.

Topic 27 헤드라이트를 앞서가지 말라

  • 마찬가지로 소프트웨어 개발에서도 우리의 헤드라이트는 제한되어 있다. 우리는 너무 먼 미래는 내다볼 수 없고, 정면에서 벗어난 곳일수록 더 어둡다. 그래서 실용주의 프로그래머에게는 확고한 규칙이 있다.Tip 42 작은 단계들을 밟아라. 언제나.
  • 더 진행하기 전에 피드백을 확인하고 조정하라. 피드백의 빈도를 여러분의 제한 속도라고 생각하라. 너무 큰 단계나 작업은 하지 않게 될 것이다.
  • 미래가 어떤 모습일지 더 많이 예측하려 할수록 여러분이 틀릴 가능성은 계속 높아질 것이다. 불확실한 미래에 대비한 설계를 하느라 진을 빼는 대신 언제나 교체 가능한 코드를 작성하여 대비하면 된다.

오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요

  • DBC의 개념이 조금은 낯설었다. 아직 테스트에 대한 개념도 제대로 잡혀있지 않은 상태라 조금 혼란스러웠다.
  • 모듈실행의 전후조건, 불변식 검증을 통해 코드의 문제발생 지점에서 신속하게 멈출 수 있다는 게 흥미롭게 느껴졌다. 디버깅을 하다보면 문제의 원인이 아닌 영역까지 체크해보며 시간을 허비하는 때가 있기때문에.

궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.

  • TDD는 테스트 중인 코드 내의 내부 불변식을 확인하는 것에 초점을 두지 않는다. 그보다는 공개 인터페이스를 확인하는 블랙박스 방식에 더 가깝다.
  • DBC는 방어적 프로그래밍보다 더 효율적이고 더 DRY하다. 방어적 프로그래밍에서는 아무도 데이터를 검증하지 않는 상황에 대비하기 위해 모든 사람모든 사람이 데이터를 검증한다.

오늘 읽은 다른사람의 TIL

profile
pending...

0개의 댓글