몇가지 프로그래머책에서 뽑아봄.


1. prototyping은 배움의 경험이다. prototyping의 가치는 만들어낸 코드에 있지 않고, 작성하면서 배운 교훈에 있다.



2. 요구사항을 수집하지 말고 채굴하라. 

흔히 요구사항은 바닥에 널려져 있고 단지 수집(Gethering)하는 것이라고 착각하지만 보통의 요구사항은 가정과 오해, 그리고 정치의 지층들 속에 깊이 묻혀져 있다.

그리고 요구사항은 최대한 일반적 진술로 만들고, 정책에 대한 정보는 구현에서 지원해야 할것들의 예시로 넘겨주는게 좋다. 이를테면 '해당 직원의 관리자와 인사부에서만 그의 기록을 열람할수 있다. '라는 건 요구사항이 아니다. 이를 일반적 진술로 바꾸면 "권한이 부여된 사용자만이 직원기록에 접근할 수 있다." 이고 그 정책 예로 위 말을 언급할 수 있다. 이를 좀더 추상적으로 말하면 프로그래머는 접근관리 즉 권한관리 시스템을 설계해야 한다는 뜻이다.

다음으로 요구사항은 바람과 모래와 별들의 생텍쥐페리의 말대로 완성이라는 것은 더 이상 더할것이 없을때가 아니라, 더 이상 빼낼 것이 없을때 얻게 되는 것이다.

요구사항과 관련하여 마지막으로 할 말은 사용자들이 어떤 작업을 현재 어떻게 하느냐는 것을 알아내는 것보다, 왜 그걸 하는지 그 내재적 이유를 알아내는 것이 더 중요하다. xp의 실천 원칙처럼 사용자처럼 생각하기 위해서는 사용자와 함께 일하라



3. 관련없는 것들은 서로 관련없도록 하라.

기하학에서 두 직선이 직각으로 만나는 경우 직교한다고 말한다. 컴퓨팅에서 이 용어는 일종의 독립성(independence)나 결합도 줄이기(decoupling)를 의미한다. 그게 메소드가 됐든 클래스가 됐든 컴포넌트가 됐든 프레임워크가 됐든 자족적이고, 독립적이며, 단하나의 잘 정의된 목적만 갖도록 설계하라. 

직교성의 장점으로 첫번째로 생산성 향상을 들수 있다. 
   - 변화가 국소화되어 개발시간과 테스트 시간이 줄어든다.
   - 직교적인 접근법은 재사용을 촉진한다 (시스템이 더 느슨하게 결합되어 있을 수록 재설정하고 리엔지리어링하기 쉽다.)
   - 직교적인 컴포넌트들을 결합하는 경우 미묘한 생산성 향상이 있다. (M*N)

두번째로 직교성은 리스크를 감소시킨다.
   - 감염된 코드는 격리된다.
   - 시스템이 잘 깨어지지 않는다.
   - 써드파티 컴포넌트들로 연결되는 인터페이스들이 전체개발의 작은 부분에 한정되기 때문에 특정 벤더나, 플랫폼에 덜 종속될 것이다.



4. Select 는 망가지지 않았다.

OS나 컴파일러의 버그를 발견하는 일은 정말 드물게 일어나며, 심지어 써드파티 제품이나 라이브러리일지라도 드문일이다. 버그는 애플리케이션에 잇을 가능성이 가장 크다.

디버깅 사고방식
   - 가장 속이기 쉬운 사람은 자기 자신이다.(에드워드 블워 리톤) - 고무오리
   - 디버깅할때 당황하지 마라.(근시를 조심하라)
   - select는 망가지지 않았다. OS는 아마 망가지지 않았을 것이다. 데이타베이스도 아마 괜찮을 거다.

디버깅의 순서는 첫번째가 버그 재현이다. 일단 재현이 되지 않는 버그는 무척 해결하기 어렵다. 
두번째 버그를 분리해야 한다. 버그를 일으키는 프로세스의 최소 동작 집합을 만드는 걸 말한다. 
세번째 데이타를 가시화한다. 버그를 일으키는 프로세스에서 일어나는 값의 변화를 추적하고 트레이싱 하여 실제 버그를 이때 발견하게 된다. 
네번째 버그의 증명이다.
다섯번째가 가장 중요한데 새 테스트 코드를 추가하여 같은 버그는 한번만 잡도록 한다.




5. 일찍 작동을 멈추게 하라.

보통은 죽은 프로그램이 절름발이 프로그램보다 해를 훨씬 덜 끼친다.

모든 에러는 정보를 준다. 에러가 발생할리 없다고 스스로를 설득하고선 그걸 무시하기 보다는 만약 에러가 있다만 정말로 뭔가 나쁜일이 생긴 것이라고 자신에게 이야기 해야 한다.



6. 시작한 것은 끝내라

가능하다면, 리소스를 할당한 루틴이나 객체는 해제도 자기가 책임져야 한다.

private void readCustomer(final String fName, Customer cRec){
   cFile = fopen(fName, "r+") ;
   fread(cRec, sizeof(cRec), 1, cFile) ;
}

private void write Customer(Customer cRec){
   rewind(cFile) ;
   fwrite(cRec, sizeof(cRec), 1, cFile) ;
   fclose(cFile) ;
}

void updateCustomer(const String fName, double newBal){
   Customer cRec ;
   readCustomer(fName, cRec) ;
   cRec.balance = newBal ;
   writeCustomer(cRec) ;
}

위의 updateCustomer 함수는 read 호출 - value없데이트 - write 호출로 이루어져있고 별 문제 없어보이지만 깨지기 쉽다.  
정책상의 변화로 newBal이 0보다 큰경우에만 수정이 가능하도록 바꼈다고 해보자

void updateCustomer(const String fName, double newBal){
   Customer cRec ;
   readCustomer(fName, cRec) ;
   if (newBal >= 0.0) {
        cRec.balance = newBal ;
        writeCustomer(cRec) ;
   }
}
와 같이 무심코 바꾼 코드는 심각한 문제를 내포하게 된다. 논리상으로는 그럴듯해보이지만 newBal < 0 일때는 fread만 발생하고 fclose를 하지 않아 리소스의 손실이 발생하게 된다.

정확히 바꿔야 한다면 아래와 같이 바꿔야 한다.

void updateCustomer(const String fName, double newBal){
   Customer cRec ;
   readCustomer(fName, cRec) ;
   if (newBal >= 0.0) {
        cRec.balance = newBal ;
        writeCustomer(cRec) ;
   } else {
       fclose(cFile) ;
   }
}

하지만 그리 깔금해 보이지 않는다.

그보다는

private void readCustomer(File cFile, Customer cRec){
   fread(cRec, sizeof(cRec), 1, cFile) ;
}

private void write Customer(File cFile, Customer cRec){
   rewind(cFile) ;
   fwrite(cRec, sizeof(cRec), 1, cFile) ;
}

void updateCustomer(const String fName, double newBal){

   File cFile = fopen(fName, "r+");
   Customer cRec ;
   readCustomer(fName, cRec) ;
   if (newBal >= 0.0) {
        cRec.balance = newBal ;
        writeCustomer(cRec) ;
   }
   fclose(cFile) ;
}

와 같이 애초에 updateCustomer 함수가 리소스를 할당하고 해제하는 역할을 같이 담당하는게 좋다. 처음 예처럼 리소스를 할당하는 부분과 해제하는 부분을 각기 다른 메소드에 넣는다면 잠재적인 에러를 유발시킬 수 있다.



7. 통합하지 말고 설정하라.

비지니스 로직, 법률, 경영자의 취향 등을 수용하느라 코드를 변경할 때마다 새로운 버그가 시스템을 깨드릴수 있는 위험을 낳게 된다. 그러므로 세부사항에서 벗어나자. 아무리 뛰어난 천재라도 세부사항에 집착하면 그 재능이 발휘되지 않는다. (머피의 제 8법칙)

우선 시스템을 되도록 설정 가능하게 만들자, 배경색, 프롬프트 텍스트 뿐 아니라 알고리즘의 선택, 사용할 데이타베이스 제품, 미들웨에 기술, 사용자 인터페이스 스타일, 사용자 선호사항, 설치 디렉토리 등을 말이다.

이러한 방식을 메타데이터 주도 애플리케이션이라고 하는데 코드에서는 추상화를, 메타데이타에는 세부 내용을 (구체적인 것보다 추상적인것이 더 오래간다.) 담는다. 요구사항처럼 프로그램은 최대한 일반화 해서 만들고, 세부사항들은 가능하면 컴파일된 코드 기반 바깥으로 빼라.

이 방식은 아래와 같은 장점이 있다.
   - 설계의 결합도를 줄여 좀더 유연하고 적응성 있는 프로그램을 만들수 있다.
   - 세부사항을 코드 밖으로 몰아냄으로써 보다 강하고 추상적인 디자인을 만들수 있다.
   - 애플리케이션을 커스터마이징 하기 위해 다시 컴파일 할 필요가 없다.
   - 메타데이타는 범용 프로그래밍 언어보다 문제 도메인에 가까운 방식으로 표현될수 있다.
   - 동일한 애플리케이션 엔진과 상이한 메타데이타를 이용해 여러 다른 프로젝트를 진행할 수 있게 된다.





'Framework > 아키텍쳐 일반' 카테고리의 다른 글

Class Design  (0) 2009.03.07
나쁜 디자인의 징후  (0) 2009.02.22
Design Principle - SRP  (0) 2009.02.22
Method Design  (0) 2009.02.11
Bleujin Framework 활용 : HTML Parsing  (0) 2009.01.16
Posted by bleujin