Posts 실용주의프로그래머 4장 실용주의 편집증
Post
Cancel

실용주의프로그래머 4장 실용주의 편집증

여러분은 완벽한 소프트웨어를 만들 수 없다

실용주의 프로그래머는 자신의 실수에 대비한 방어책을 마련한다.

  • Topic 23 : 코드의 공급자와 사용자는 권리와 책임에 대해 동의해야한다
  • Topic 24 : 버그상황에서 헤어나오는 도중에 어떤 손상도 입히지 않도록 보장해야한다.
  • Topic 25 : 확인을 쉽게하는 방법. 가정(assumption)을 적극적으로 검증하는 코드 작성
  • Topic 26 : 여러 시스템 리소스를 다룰때 실수 하지 않는 법
  • Topic 27 : 언제나 작은 단계를 고수해야한다.

Topic 23 : 계약에 의한 설계

DBC(Design By Contract, 계약에 의한 설계)

정확한 프로그램이란 자신이 하는 일을 적지도 많지도 않게 그만큼만 수행하는 프로그램이다. 이 주장을 문서화하고 검증하는 것이 DBC 이다.

선행조건

  • 루틴이 호출되기 전에 참이어야하는 조건. 이 선행조건이 위반된 경우 루틴이 호출되어서는 안된다. 후행조건
  • 루틴이 자기가 할 것이라고 보장하는 것. 루틴은 종료되어야하며 무한 반복은 안된다. 클래스 불변식
  • 호출자의 입장에서 이 조건이 언제나 참인 것을 클래스가 보장한다. 루틴 도중에는 참이 아닐 수 있지만, 루틴 종료 후에는 불변식이 참이 되어야한다.

만약 호출자가 모든 선행조건을 충족하면, 루틴은 종료 시 모든 후행조건과 불변식이 참이 되는 것을 보장한다. 따라서 만약 호출자나 루틴 중 어느 한쪽이라도 계약을 지키지 못하면 예외가 발생한다. 그렇기에 선행 조건을 이용해서 사용자 입력값을 검증한다거나 해서는 안된다.

호출자, 루틴 모두 입력값을 검증하지 않음. 호출자는 그냥 호출하고, 루틴은 실행 도중 예외를 발생시킴. 선행 조건은 호출자가 루틴을 부른 뒤, 루틴 자체로 들어가기 전에 보이지 않는 곳에서 검사됨.

클로져, 엘릭서 등이 이러한 DBC를 잘 지원한다.

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

이 용어가 의미하는 일반적인 개념은 상태이다. 함수형 언어에서는 보통 상태를 함수에 넘긴 후 바뀐 상태를 결과로 받는다.

DBC는 방어적 프로그래밍보다 더 효율적이고 DRY하다. 방어적 프로그램은 아무도 데이터를 검증하지 않는 상황에 대비하여 모든 사람이 데이터를 검증한다.

DBC 구현

코드를 작성하기 전에 유효한 입력범위가 무엇인지, 경계조건이 무엇인지, 루틴이 뭘 전달한다고 약속하는지, 무엇을 약속하지 않는지 나열하는 것만으로도 더 나은 코드를 작성할 수 있다. 코드에서 DBC를 지원하지 않으면 이정도가 최선이다. DBC는 설계 기법이고, 자동 검사가 없더라도 계약을 코드에 주석이나 단위 테스트로 넣어둘 수 있다

단정문

컴파일러가 계약을 검사하도록 하면 큰 도움이 된다. 몇몇 언어에서는 단정문으로 부분적으로 흉내낼 수 있다. 다만 단정문은 객체지향에서는 재정의 할때마다 일일이 작성하여야하고, 어떤 환경에서는 단정문에서 발생하는 예외를 무시하기에 완전한 방법은 아니다.

DBC와 일찍 멈추기

단정문이나 DBC 방식을 사용하여 선행조건, 후행조건, 불변식을 검증하면 더 일찍 멈추고 문제에 대한 정확한 정보를 얻을 수 있다.

의미론적 불변식

시스템에서 영원히 변경되지 않는 요구사항. 비즈니스 정책처럼 유동적으로 변하는 것에 영향을 받으면 안된다.

ex)

  • 같은 거래를 두번 처리하지 않는다
  • 오류 발생 시 소비자의 입장을 우선하라

Topic 24 : 죽은 프로그램은 거짓말을 하지 않는다.

프로그램에서 잘못된 것이 있을때 라이브러리나 프레임워크 루틴에서 먼저 잡아낼 수 있다. 빈 데이터를 받았거나, switch-case 문에서 default가 실행되었거나 하는 일이 발생할 수 있다. 이런 있을 수 없는 일이 발생했을때 우리는 그 사실을 알아야한다.

모든 오류는 정보를 준다. 오류 메시지 좀 읽어라.

잡은 후 놓아주는건 물고기뿐

어떤 개발자는 예외를 잡은 후 로그 좀 찍고 다시 예외를 올려보낸다. 하지만 실용주의 프로그래머는 굳이 잡지 않는다.

  • 애플리케이션 코드가 오류 처리 코드 사이에 묻히지 않는다.
  • 메서드에서 새로운 예외가 추가되었을때 코드를 수정하지 않아도 된다.

일찍 작동을 멈춰라

망치지 말고 멈춰라

문제를 빨리 발견하면 가능한 빨리 시스템을 멈출 수 있다.

얼랭과 엘릭서는 “방어적 프로그램은 시간낭비고, 그냥 멈추는 게 낫다”라는 철학을 가지고 있다. 프로그램이 실패하면 멈추고, 이런 실패는 슈퍼바이저가 관리한다. 슈퍼바이저는 코드를 실행하고, 실패 시 처리할 책임이 있다. 슈퍼파이저가 실패하면 슈퍼바이저의 슈퍼바이저가 처리한다. 이러한 슈퍼바이저 트리 기법은 효과적이어서 고가영성, 결함 감내 시스템에서 얼랭이나 엘릭서를 채택하는 요인이 된다.

어떤 환경에서는 멈추는게 적절하지 않을 수 있다. 그러나 있을 수 없는 일이 발생했다면 프로그램은 더이상 유효하지 않다고 할 수 있기에 가능한 빨리 종료되는 것이 좋을 수 있다.

일반적으로 죽은 프로그램이 끼치는 피해는 이상한 상태의 프로그램이 끼치는 피해보다 적다.


Topic 25 : 단정적 프로그래밍

단정문으로 불가능한 상황을 예방하라.

코딩할때 절대 일어나지 않을 일은 없다. 그런 생각이 든다면, 그것을 확인하는 코드를 추가하라. 다만, 오류처리를 해야하는 곳에서 단정을 대신 사용하지는 말라. 단정은 결코 일어나면 안되는 것들을 검사한다.

ex) 아래와 간은 코드는 작성해서는 안된다.

1
2
3
puts("Y나 N을 입력하세요")
ch = gets[0]
assert((ch == 'Y') || (ch == 'N')) 

단정이 실패한다고 바로 프로세스를 종료시킬 필요는 없다. 예외를 잡고 오류처리 루틴을 실행할 수도 있다. 다만, 단정을 실패하게 한 잘못된 정보를 사용하지는 말라.

단정 기능을 켜둬라

테스트는 모든 버그를 발견할 수 없고, 일어날 수 없는 일은 일어날 수 있다. 따라서 단정기능을 실제 환경에서 끄는 것은 문제가 될 수 있다.

성능상 이슈가 있다면 정말 문제가 되는 단정문만 꺼라.


Topic 26 : 리소스 사용의 균형

리소스 사용을 위한 간단한 팁들이 있다.

자신이 시작한 것은 자신이 끝내라

리소스 사용을 시작한 곳에서 리소스 할당을 해제하여야한다.

지역적으로 행동하라

잘 모르겠으면 스코프를 줄여라.

중첩할당

  • 리소스를 할당한 순서의 역순으로 해제하라. 그래야 한 리소스가 다른 리소스를 참조하는 경우에도 참조를 망가트리지 않는다
  • 코드의 여러 곳에서 같은 구성의 리소스를 참조하면 항상 같은 순서로 할당하라. 그래야 교착상태에 빠지지 않는다.
    • ex) resource1, resource2가 필요할때 항상 1 -> 2로 할당하라.

균형잡기와 예외

예외를 처리할때 리소스 해제는 다루기 어려울 수 있다. 이때는 두가지 방법을 사용할 수 있다.

  1. 변수 스코프를 사용한다. ex) c++, 러스트의 스택변수
  2. try-catch 블록에서 finally 절 사용

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

우리는 너무 먼 미래를 내다볼 수 없고 정면에서 벗어난 곳일수록 더 어둡다

작은 단계들을 밟아라. 언제나.

언제나 신중하게 작은 단계들을 밟아라. 더 진행하기 전에 피드백을 확인하고 조정하라. 너무 큰 단계나 작업은 하지 않게 될 것이다.

ex) 피드백이란?

  • REPL의 결과
  • 단위 테스트
  • 사용자 데모 및 사용자와의 대화

너무 큰 작업이란 예언을 하는 모든 작업을 뜻한다. 불확실한 미래에 대비한 설계를 하기보단 언제나 교체 가능한 코드를 작성하여 대비하여라.


후기

이번 장은 코딩할 때 발생할 수 있는 이슈들에 대비하기 위한 팁들을 소개하는 장이었다.

일어날 수 없는 일이란 없고, 이에 대비하기 위한 단정문에 대한 얘기가 많이 나왔다. 개인적으로 단정문을 사용한 적은 없어서 내용이 잘 이해가 되지 않았다. 평소에는 if 문을 통해 조건을 확인하고 거짓이면 함수를 종료하는 식으로 하였는데, 이 방법과 단정문을 사용한 방법에 어떤 차이가 있는지 확실히 이해가 되지는 않았다.

다만 몇가지 얻어갈 것은 있었다.

  1. DBC의 개념은 함수를 설계할때 도움이 될거 같다. 선행조건, 후행조건, 불변식을 지키며 계약 이상의 것을 하지않는 함수라는 개념으로 예측 가능한 함수를 설계가능할거 같다.
  2. 문제가 발생하면 가능한 빨리 멈추는 것이 좋다라는 내용도 적용하기 좋다.
  3. 예외 발생 시 catch 한 후 로그찍고 다시 그대로 올려보내는 것보다, 잡지 않고 올려보내거나 이왕 잡았으면 적절히 처리하여 다른 예외를 발생 시키는 것이 좋아보인다. (이 부분은 책에서 말하는 바와 다를 수 있다)
  4. 리소스 사용에 관한 팁들도 도움이 될거 같다.
  5. 작은 작업을 한 후 피드백(테스트든 사용자든)을 받는 과정을 반복하여야하고, 너무 큰 작업을 한번에 하지 말라는 팁도 도움이 될거 같다.
This post is licensed under CC BY 4.0 by the author.

실용주의프로그래머 3장 기본도구

실용주의프로그래머 5장 구부러지거나 부러지거나

Comments powered by Disqus.