태그 - TIL, nomadcoder, 개발자북클럽, 노개북, 서평, 책
우리는 완벽한 소프트웨어를 만들 수 없다.
완벽한 소프트웨어는 존재하지않는다. 누구도 완벽한 소프트웨어를 만들지 못했다.
프로그래머들은 '방어적'으로 코딩한다. 조금이라도 의심스러운 면이 들면 주어진 모든 정보를 확인한다. 하지만 실용주의 프로그래머는 한걸음 더 나아가 '자기자신도 믿지 않는다.' 자신의 실수에 대비한 방어책을 마련한다.
계약은 자신과 상대편의 권리 및 책임을 정의한다. 그뿐만 아니라 한쪽이 계약을 어겼을 경우 대응도 계약사항에 포함된다.
소프트웨어 모듈이 서로 소통하는것을 돕기위해 동일한 개념을 사용할 수 있다.
단순하지만 강력한 기법으로 프로그램의 정확성을 보장하기 윟 소프트웨어 모듈의 권리와 책임을 문서화 하고 합의하는데에 초점을 맞춘다.
정확한 프로그램이란 무엇인가? 자신이 하는 일이라고 주장하는 것보다 많지도 적지도않게 딱 그만큼만 하는 프로그램이다. 주장을 문서화 하고 검증하는것이 계약에 의한 설계의 핵심이다.
소프트웨어 시스템의 모든 함수와 메서드는 항상 뭔가를 한다. 그리고 뭔가를 시작하기전에 함수는 세상의 상태에 대해 어떤 전제 조건을 갖고있을 테고, 루틴이 끝난 후에는 세상의 상태가 어떠할 것이라고 선언할 수 있을 것이다.
1. 선행조건
루틴이 호출되기위해 참이어야 하는것. 루틴의 요구사항이다. 위반된경우 호출이 되어산 안된다. 제대로된 데이터를 전달하는 것은 호출하는 쪽 책임이다.
2. 후행조건
루틴이 자기가 할 것이라 보장하는것. 즉 루틴이 완료되었을때 세상의 상태이다. 후행조건이 있다는 것은 루틴이 종국에는 종료될것 을 의미한다.
3. 클래스 불변식
이 조건이 언제나 참인것을 클래스가 보장한다. 루틴의 내부처리 도중에 불변식이 참이 아닐 수도 있지만 루틴이 끝나고 호출자로 제어권이 반환되는 시점에는 불변식이 참이 되어야한다.
루틴과 그 루틴을 호출하는 코드간의 계약
만약 호출자가루틴의 모든 선행 조건을 충족한다면 해당 루틴은 종료시 모든 후행 조건과 불변식이 참이되는것을 보장한다.
만약 계약당사자중 어느한쪽이라도 계약내용을 지키지 못한다면 해결방안이 실행된다.
무슨일이든지, 계약에 부응하지못하는 것은 버그라는 것이다. 결코 발생해서는 안되는 일이며, 그렇기 때문에 선행조건을 이용해서 사용자 입력값을 검증한다거나 해서는 안된다.
게으름뱅이 코드?
자신이 수용할것은 엄격하게 확인하고, 내어줄 것에 대해서는 최소한도를 약속하는 것이다. 무엇이든 수용하고 결과로는 무엇이든 다 내어준다고 계약에 씌여있다면 정말 많은 코드를 작성해야한다.
이 용어가 진짜로 의미하는것은 상태이다. 객체지향 언어의 상태도 클래스의 인스턴스와 관련이 있다. 하지만 다른언어도 마찬가지로 '상태'가 있다. 함수형 언어는 보통 상태를 함수에 넘기고 바뀐상태를 결과로 받는다. 불변식이란 개념은 이런상황에도 똑같이 유용하다.
계약에의한 설계(DBC)와 테스트 주도개발
단위테스트, 테스트 주도개발, 속성 기반 테스트, 방어적 프로그래밍을 열심히 실천하더라도 DBC가 필요하다. 테스트는 프로그램의 정확성이라는 보다 넓은 주제에 속하는 서로 다른 접근방법이다. 둘 다 가치가있고 각기 다른 상화에서 쓸모가 있다.
DBC | TDD |
---|---|
Mock 필요(가짜객체) | |
모든 경우를 다룸 | 한가지의 경우만 다룸 |
설계,개발,유지보수 전체에 걸쳐 활용 | '테스트' 할때만 수행됨. |
'내부 불변식' 확인보다 공개인터페이스를 확인하는 블랙박스 | |
방어적인 프로그래밍보다 더 효율적이고 DRY하다. |
TDD는 멋진 기법이다. 하지만 많은 다른 기법과 마찬가지로 '정상경로'에만 집중하도록 유도하기도한다.
입력범위,경계조건,루틴이 뭘 전달 하고 약속하는지, 중요하게는 무엇을 약속하지 않는지를 나열 하는 것만으로 더 나은 소프트웨어를 작성하는데에 엄청난 도움이 된다. DBC는 결국 설계 기법이다. 이런것들을 명시하지 않으면 되돌아가고, 많은 프로젝트가 시작하고, 끝나고 실패할것이다.
단정문
객체지향언어에서는 상속계층에 따라 '단정문'이 밑으로 전파되도록 할 수없다. 이 뜻은 계약이 있는 부모 클래스 메서드를 재정의 하면 해당 계약을 구현하는 단정문은 올바르게 호출되지 않는다.
근본적으로 계약이 자동으로 집행되지 않는다는 것이다.
계약이행을 위해 단정문을 사용했다면, 후행조건에서 사용할 정보를 저장하는 선행조건속에 추가해야한다.
(단정문 부터 이해하기 힘들다.. 라는 느낌이 강했다. , DBC와 일찍 멈추기,의미론적 불변식, 동적계약과 에이전트)
'그런 일은 절대 일어날 리 없어!'. 대다수가 코드를 작성할때 파일이 성공적으로 닫혔는지 , 혹은 트레이스 문이 예상대로 찍혔는지 확인하지 않았던 적이 있을것이다. 문제의 코드는 정상적인 상황에서는 실패하지 않았을 것이다. 하지만 우리는 방어적으로 코딩하고 있다. 필요한 라이브러리들이 올바른 버전으로 로드되었는지, 데이터가 우리생각대로인지 확인해야한다.
모든 오류는 정보를 준다. 오류가 발생할 리 없다고 자신을 설득하고선 그것을 무시하면안된다. 제발 오류메세지를 읽어보자.
기본 원칙은 같다. 방금 있을 수 없는 일이 발생했다는 것을 코드가 발견했다면, 프로그램은 더는 유효하지 않다고 할 수 있다. 이 시점 이후 하는일은 모두 수상쩍은 일이된다. 되도록 빨리 종료할 일이다.
자기 비난에는 사치성이 있다. 우리가 자신을 비난할때, 다른사람은 우리를 비난할 권리가 없다고 우리는 느낀다 . - 오스카 와일드
"그런 일은 절대 일어날 리 없어"
단정문으로 불가능한 상황을 예방하라!
언어구현에서 조건이 참인지 거짓인지 확인하는 것을 찾을수 있을것이다. 이런 단정문은 엄청나게 유용하다.
알고리즘 동작을 검사하는데에도 유용하며, 제대로 작동하는지 확인할 수있다.
하지만 오류처리를 해야하는 곳에 단정을 대신 사용하지 말아야한다. 단정은 결코 일어나지 말아야 할것들을 검사하는것이다.
단정의 기능을 켜둬라
첫째, 테스트는 모든 버그를 발견할 수 없다. 프로그램이 조금만 복잡해져도 코드가 거칠수 있는 경로의 전체 조합중 비율이 적기때문이다.
둘째, 낙관주의자들은 우리의 프로그램이 험한세상속에 돌아간다는 사실을 잊는다. 쥐가 통신케이블을 갉아먹든, 누군가가 게임을해서 메모리를 잡아먹는다던가 하는 일들이다. 우리의 첫번째 방어선은 '가능한한' 오류를 모두 검사해보는것이고 그 다음은 그러고도 놓친것을 잡아내기 위해 단정을 사용하는 것이다.
성능에 문제가 있다 하더라도,
정말 문제가 되는 단정문만 끄도록 하자.
(책 , 뷰어기준 191, 166 page)
많은 개발자가 리소스할당과 해제를 다루는 일관된 방침을 갖고있지 않다. 한가지 팁을 제안한다면,
"자신이 시작한 것은 자신이 끝내라"
리소스를 할당하거나 함수나 객체가 리소스를 해제하는 책임역시 져야 한다는 뜻이다. 이상적으로 말해서 리소스를 할당하는 루틴 해제 역시 책임져야 한다는 것이다. 코드를 약간 리팩터링해서 이를 적용할 수 있다.
(책 뷰어, 194 page , 169 page)
예측은 힘들다, 특히 미래에 대해서는
'헤드라이트'는 투사 거리 라고 부르는 범위까지만 밝힐수 있다. 이 범위 바깥은 빛이 너무 분산되어 효과가 떨어진다. 마찬가지로 소프트웨어 개발에서도 우리의 '헤드라이트'는 제한되어있다.
우리는 너무 먼 미래는 내다 볼 수 없고, 정면에서 벗어난 곳일수록 더 어둡다.
그래서 실용주의 프로그래머에게는 확고한 규칙이 있다.
언제나 신중하게 단계들을 밟아라.
더 진행하기전에 피드백을 확인하고 조정하라.
피드백의 빈도를 여러분의 제한속도라 생각해라.
미래의 유지보수를 고려해서 설계를 해야 한다지만, 우리가 볼 수 있는 미래까지만 고려해야한다. 미래가 어떤 모습일지 더 많이 예측하려 할수록 우리가 틀릴 가능성이 높다. 그 대신 언제나 교체 가능한 코드를 작성하여 대비하면된다. 우리의 코드를 더 적절한 무언가로 대체하기 쉽게 설계해야한다.
미래에 대한 확신이 있떠라도 저 모퉁이 너머에 '블랙스완'이 기다리고 있을 수 있다.
전체적으로 이해하기 난해한 파트가 제법있었다. 특히 25번, 26번째 토픽.. 다른사람들의 리뷰를 보고 이해하는 방향으로 가야할 듯 싶다. 오늘은 복습하는 것과 발맞추어, 어떤 분의 리뷰를 읽고 진행하였는지도 동시에 적으려고 한다.