최상단 광고

2012년 7월 9일 월요일

실용주의 프로그램 - 2편


36. 모듈 간의 결합도를 최소화하라

 객체의 모든 메서드는 다음에 해당하는 메서드만을 호출해야 한다 라는 디미터 법칙을 따른다,
  • 객체 자신의 메서드
  • 메서드의 매개 변수로 넘어온 인자의 메서드
  • 메서드 내부에서 생성된 객체의 메서드
  • 메서드가 직접 포함하고 있는 객체의 메서드
//객체의 모든 메서드는 다음에 해당하는 메서드만을 호출해야 한다
class Demeter
{
    private A a;

    private int func() { return 0; }

    public void example(B& b)
    {
        C c = new C();
        int f = func();         // 객체 자신의 메서드
        b.invert();             // 메서드의 매개 변수로 넘어온 인자의 메서드
        a = new A();
        a.setActive();      // 메서드 내부에서 생성된 객체의 메서드
        c.print();          // 메서드가 직접 포함하고 있는 객체의 메서드
    }
}

이 법칙을 잘 따라 설계를 하되 애플리케이션에 맞게 장점과 단점을 고려한다

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

알고리즘의선택, 사용할 데이터베이스 제품 등의 시스템 심층부분들은 통합하거나 
엔지니어링 하지 말고 설정 옵션으로 구현한다.

38. 코드에는 추상화를, 메타데이터에는 세부 내용을

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

39. 작업흐름 분석을 통해 동시성을 개선하라

UML 등을 사용해 요구사항을 분석하여 작업흐름을 기록한다.
작업흐름을 분석하면서 보틀넥이 걸리는 부분을 예상 할 수 있으며
의존성이 실제 어디로 존재하는지, 어느 부분을 최적화 하는것이 좋은지 알 수 있다

40. 서비스를 사용해서 설계하라

예를들어 중앙일정관리자 대신 여러개의 독립적인 태스크들과 중앙 집중식 작업큐를 사용한다.
이렇게 하면 어떤 작업하나가 버벅대더라도 다른 작업들이 계속 큐에 들어오는 일을 가져갈 수 있으며,
개발 컴포넌트들은 자기 속도에 맞추어 일을 진행 할 수 있다.
시간적으로 결합이 끊기는 것이다.

41. 언제나 동시성을 고려해 설계하라

 이제는 거의 모든 개발자들이 다중스레드 프로그래밍을 접하게 되었다.
순차적인 시스템과 동시성있는 시스템에서의 생각은 엄연히 틀리다.
시간순서, 객체 유효상태, 의존성등을 고려한다면 더 깔끔한 인터페이스를 설계할 수 있을 것이다

42. 모델에서 뷰를 분리하라

모델과/ 뷰 / 컨트롤러를 분리하면, 적은 비용으로 큰 유연성을 얻게 된다
자바의 트리위젯이 MVC 설계에 좋은 예이다.
아래 링크를 참조

43. 칠판을 사용해 작업흐름을 조율하라

어떤 사실을 칠판에 올려 적절한 규칙이 연결되도록만 하면 되며
어떤 결과에 대한 피드백도 쉽게 다룰 수 있다.
어떤 규칙 집합이든 그 결과를 다시 칠판에 올려서 다른 규칙들이 움직이게 하면 된다.

44. 우연에 맡기는 프로그래밍을 하지 말라

우연은 잘못된 길로 가게 할 수도 있으며 그 부분은 거짓과 우연이 결합 된 곳이다.
가정하기는 쉬우나 증명하긴 어렵다. 가정 하지 말고 증명한다.
확실한 사실에 증명하지 않은 가정은 결국 어느 프로젝트에서든 재앙의 근원이 된다

45. 알고리즘의 차수를 추정하라

 알고리즘 시간에 배운 O(n)등을 써서 자신의 알고리즘의 차수를 측정한다.
측정후 차수를 더 낮출수 있는지, 만약 외부요인에 따라 달라진다면
어떻게 최적화 할 것인지 잠시 고민해보는것도 좋다.

46. 추정을 테스트 하라

추정을 했더라도 실제 데이터를 입력받아 돌아가는 코드의 수행시간을 봤을때
비로소 추정의 의미가 있다.그 후 알고리즘을 선택한다
물론 가장 빠른 알고리즘이 가장 좋은것은 아니며, 성급한 최적화를 할 필요도 없다.

47. 일찍, 자주 리팩토링 하라

리팩토링 해야 할 것들의 명단을 만들고 유지하면서,
일정에 그것들을 리팩토링 할 시간을 확실히 포함시켜 둔다.
리팩토링에 본질은 재설계다.
아무부분이나 닥치고 삭제 해버리면서 분해하는것이 아니다
다음은 마틴 파울러가 손해 < 이득 이 되는 리팩토링에 관련한 조언이다
  • 리팩토링 + 새로운 기능 추가는 하지 말 것
  • 할 수 있는한 테스트들을 돌려본다 ( 변경으로 인한 오류를 빨리 찾을 수 있음)
  • 단계를 나누어 신중히 작업하며, 한 단계가 끝날때마다 테스트를 돌린다 ( 디버깅 작업을 피할 수 있음)


48. 테스트를 염두에 두고 설계하라

루틴하나를 설계하더라도 테스트하는 코드를 설계하는 것이 좋다.
테스트 통과 후 요구사항을 처리하는 코드를 설계하다보면
자연스럽게 생각나지 않았을 경계조건이나 다른 문제들을 고려하게 된다.
또한 해당 인터페이스가 고정되기 전에 미리 시험을  해볼 수도 있다


49.  소프트웨어를 테스트하라. 그렇지 않으면 사용자가 테스트 하게 될 것이다

모든 소프트웨어는 언젠가는 테스트 한다.
따라서 우리팀이 하지 않는다면 사용자가 테스트를 하게 될 것이며 그것은 곧 사용자와의 신뢰와도 관계가 있다.
따라서 소프트웨어를 철저하게 테스트 할 계획을 세워야 한다.

50. 자신이 이해하지 못하는, 위저드가 만들어준 코드는 사용하지 말라

코드를 자동으로 생성하는 위저드 자체를 반대하는 것이다.
하지만 위저드를 사용했는데 위저드 코드를 모두 이해하지못한다면 
이미 애플리케이션은 내것이 아니다.
그 애플리케이션을 이후에 유지보수하지도 못할 것이고 디버깅해야 할 때가 오면 고생 할 것이다.


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

요구사항은 어떤 것이 성취되어야 한다는 진술이다.
요구사항은 분명하기 주어지지 않으며 정책가은 수시로 바뀌는 것들도 요구사항속에 넣지 않는다.
따라서 어떻게 하느냐도 중요하지만 왜 하느냐라는 내재적 이유를 알고
요구사항을 분석하다보면 설계를 보다 자연스럽게 할 수 있을 것이다

52. 사용자처럼 생각하기 위해 사용자와 함께 일하라

사용자가 직접 되어보는것도 좋고 QA팀원들에게 자문을 얻는 것도 좋다
이러한 요구사항 채굴과정은 사용자층이 바라는 시스템이 무엇인지 배우면서 
사용자 층과 관계를 설정하기 시작하는 단계이다

53. 구체적인것보다 추상적인 것이 더 오래간다

Y2K 문제는 대략 2가지 요인에서 발생하는데 하나는 현 비즈니스 관행 너머를 보는데 실패,
또 DRY 원칙을 어겼기 때문이다.
일반적인 관행으로 2자리 숫자를 쓰게 되었는데,
자료 입력, 보고, 저장등을 위해 두자리 숫자 년도가 필요했을 지라도,
이 두자리 숫자가 실은 날짜를 줄여쓴 사실이라다라는 추상화가 있어야 했다

54. 프로젝트 용어사전을 사용하라

개발자(프로그래머, 아티스트, 기획, 디자이너 등등)과 사용자가 동일한 것을
다른 이름으로 가리키거나 같은 이름을 다른것으로 지칭하는 프로젝트는 성공하기 어렵다.
모든 참가자가 쉽게 접근할 수 있도록 프로젝트 문서(용어사전 포함)를 내부 웹사이트나
하이퍼텍스트 문서로 표현하면 다양한 사용자의 필요를 충족 시킬 수 있으며
원활한 의사소통을 할 수 있을 것이다


55. 생각의 틀을 벗어나지 말고 틀을 찾아라

간단한 예를 들어보자
오직 직선 세개만으로 아래 그림에 나오는 모든 점을 연결하고 선을 긋기 시작한 지점으로 돌아오는 경로를 생각해보자
(단, 종이에서 펜을 떼거나 전에 그었던 직선을 다시 따라가면 안된다)

풀리지 않는 문제와 마주쳤다면, 생각해 볼 수 있는 모든 가능한 해결 경로를 눈앞에 나열해 본다.
아무리 쓸모없고 바보같이 보이는 경로라도 절대 버리지 않는다.
이 후 하나씩 목록을 점검하며 왜 그 경로가 불가능한지 설명한다.
그렇게 제약들을 범주로 나누거 우선순위를 매긴다.
목공은 어떤 일을 시작할때 그 일에서 가장 긴 조각을 자르고 남은 나무에서 작은 조각들을 잘라낸다
한번 잘 생각해보고 답은 포스트 가장 아래에 있다.


56. 준비가 되었을때 시작하라

지휘자는 오케스트라 앞에서서 연주를 시작하기 가장 좋은 순간이라고 느낄때까지 기다린다
마음속에서 "기다려" 라고 들려오는 목소리에 귀를 기울여야 한다.
우리들은 지금까지 개발자로서 경력을 쌓으며 이와 비슷한 일을 해오고 있다.
여러가지 일을 시험해보았고 어떤것이 잘됐고 어떤것이 그렇지 않았는지 보았다.
경험과 지혜를 축적해왔디.
소프트웨어 개발은 완벽히 과학이라고는 아직은 할 수 없다
수행능력에 직감이 일조하도록 놓아두자

57. 어떤일들은 설명하기보다 실제로 하는 것이 쉽다

 신발끈을 묶는 방식을 아이에게 설명한다고 했을 때,
대부분 "엄지손가락과 검지손가락을 둥글게 잡아서 한족 끝이 왼쪽 끈의 아래와 왼쪽을 지나가게...."
라고 말하는 시점에서 포기할 것이다
정말 설명이 경이적일 정도로 어렵다. 하지만 우리들 대부분은 의식적으로 생각하지 않고 신발끈을 묶을 수 있다

58. 형식적 방법의 노예가 되지 마라

 형식적 방법이 나쁘다는 것이다.
그것을 맹목적으로 받아들이지 말라는 것이다.
형식적 방법에는 몇가지 단점들이 있다
  • 다이어그램+추가 설명을 이용해 요구사항을 포착한다 
  • 이런 그림은 최종 사용자는 설계자들의 그림을 전혀 이해하지 못하므로 설계자가 해석해주어야 한다 
  • 가능하면 프로토타입을 사용자에게 보여주고 직접 다루는 것이 좋다

  • 전문화를 권장하는 것 같이 한 집단은 데이터모델작업, 아키텍처를 보는 작업, 유스케이스를 모으는 작업을 한다.
  • 이러한 방식은 결국 의사소통의 부족과 노력의 낭비로 이어진다.
  • 작업중인 시스템을 전체적으로 이해하는 것이 좋다
  • 동적으로 연결해야 할 객체들 사이에 정적인 관계를 설정하도록 권장하는 것은 분명 문제가 있다

59. 비싼 도구가 더 좋은 설계를 낳지는 않는다

 사람들이 펼치면 몇백 평이 넘을 클래스 다이어그램 종이 뭉치와 유스케이스 150개를 들고 회의에 들어오더라도
그것 또한 여전히 틀릴 가능성이 있는 요구사항과 설계에 대한 그들의 해석일 분이다.
도구의 결과물을 볼때 비용따위는 생각하지 않도록 하는 것이 좋다

60. 팀을 기능 중심으로 조직하라

 팀을 또 다시 기능적으로 작은 팀으로 나누어 최종 시스템의 특정한 기능측면에 책임을 지도록 한다
팀이 개개인의 강점 위에 스스로 내부를 조직하게 한다.
이렇게 하면 팀들은 분리해서 어떤 변화가 생기더라도 전체가 영향 받는 일이 없게 된다
DB를 갑작스럽게 바꾸기를 사용자가 원한다면 영향 받는 것은 DB팀 뿐이어야 한다


61. 수작업 절차를 사용하지 말라

 셸 스크립트나 배치 파일들을 사용하거나 자동화 도구를 사용한다면 
사람들은 어느정도 동일한 환경에서 개발 할 수 있으며,일정을 세우는 것에도 많은 도움이 될 것이다

62. 일찍 테스트하라. 자주 테스트 하라. 자동으로 테스트 하라

 코드는 작성하자마자 테스트 해야 한다
그 작은 잔챙이들은 자라는 속도가 순식간이라 거대한 상어가 되는 성질이 있다.
상어를 잡는 일은 상당히 힘들다. 그 만큼 버그가 빨리 발견되면 고치는 비용이 적다


63. 모든 테스트가 통과하기 전엔 코딩이 다 된것이 아니다

 어떤 코드를 만들었다는 이유만으로 클라이언트나 상사에게 완료되었다고 할 수 없다
코드는 가능한 모든 테스트를 통과 한 후 높은 수준의 신뢰를 얻었을 때만이 완료된 것이다.
항상 무엇을 어떻게 언제 테스트 할지 고민해보자

64. 파괴자를 써서 테스트를 테스트 하라

 완벽한 소프트웨어는 없으므로 테스트 소프트웨어도 완벽하다고 할 수 없다
프로젝트 파괴자를 임명해서 테스트릍 테스트 한다.
파괴자의 역할은 소스트리의 카피를 별도로 만들어 취한뒤 고의로 버그를 심고 테스트가 잡아내는 지 검증하는 것이다

65. 코드 커버리지보다 상태 커버리지를 테스트하라

 커버리지 분석도구는 테스트 중에 코드를 지켜보고 코드의 어느라인이 실행되지 않았는지 기억한다
이러한 도구들 덕에 테스트가 얼마나 포괄적인지 대한 대체적인 느낌은 가질 수 있으나
100% 신뢰하지는 않아야 한다.
프로그램의 모든 상태를 분별해서 판단해야 할 것이다

int test (int a , int b)
{
    return a / (a + b);
}

위 코드는 이론상으로 1,000,000 가지의 논리적 상태를 갖지만 그 가운데 999,999개만 제대로 작동 할 것이다
제대로 작동하지 않는 논리도 ( a, b 모두가 0일때 ) 분명히 있다

철저한 테스트를 하자.

"아주 단순하게 만들어서 명백히 결함이 없도록 하는 것과 다른 하나는 아주 복잡하게 만들어서 명백한
결함이 없도록 하는 것이다" 라는 토니 호아의 명언 과
"테스팅은 버그의 존재만 보여줄수 있지 버그의 부재는 보여 줄수 없다" 라는 
다익스트라의 명언을 잘 생각해보자

66. 버그는 한 번만 잡아라

 테스터가 버그를 잡으면 그 순간이 그 버그를 찾는 마지막 순간이 되어야 한다.
그 이후는 해당 버그를 확인할 수 있게 자동화 테스트들을 수정해야 한다
어차피 버그는 또 다시 일어난다
자동화 테스트가 우리를 대신해 찾아 줄 버그를 추격할 시간은 없다
새 코드 ( 새 버그)를 작성하는데 시간을 보내야 한다

67. 한국어도 하나의 프로그래밍 언어인 것처럼 다루라

프로젝트에서 생산되는 문서에는 소스코드, 주석, 설계와 테스트 문서 에 내부문서
외부로 출간되는 매뉴얼 같은 외부문서로 나뉜다.

이러한 문서는 무엇인지 불문하고 잘 작성해야 한다.
모든 문서는 코드의 거울이기 때문이다 

68. 문서가 애초부터 전체의 일부가 되게하고, 나중에 집어넣으려고 하지 말라

 소스코드의 주석, 테스트 문서등 포매팅된 문서를 만들 되 
이들은 애초부터 전체의 일부가 되는 것이 좋다.
나중에 집어넣을 때는 고려해야 할 점이 너무 많다

69. 사용자의 기대를 부드럽게 넘어서라

 기대를 사용자와 개발자가 상호 소통한다.
사용자들이 기대하는 것보다 조금만 더 해준다면 사용자와 
개발자의 관계는 두고두고 좋아질 것이며 신뢰성도 두터워 질 것이다.
단, 기능팽창으로 시스템에 부담을 주지 않아야 한다 
그러한 예에는 아래와 같은 것들이 있다

  • 풍선 혹은 툴팁 도움말
  • 키보드 단축키
  • 사용자 매뉴얼의 부록으로 만든 빠른 참조
  • 하이라이팅
  • 로그 분석기
  • 자동 설치
  • 시스템 상태 체크 도구
  • 각 회사나 조직을 위해 만든 스플래시 스크린
  • 훈련 목적으로 여러버전의 시스템을 실행 시킬 수 있는 기능

70. 자신의 작품에 서명하라

 자신의 코드는 좋게 보고 동료들의 코드는 깎아 내리는 편견을 갖지 않도록 한다
같은 맥락에서 다른사람들의 코드를 존중 해주어야 한다.

또한 자신의 소유권에 대한 긍지를 가지도록 해야 한다
"내가 이걸 만들었으며, 내 작품의 품질을 보증합니다" 라는 것이 우리들의 서명으로 인식해야 한다
우리들의 서명이 곧 품질의 보증수표로인식 되게 해야 한다
코드에 붙여진 이름을 보고 이 사람이 만든 것은
튼튼하고 잘 작성되었으며 훌륭히 문서화 되었을 것이라고 기대되도록 만든다

("시드 마이어의 문명" 같은....)


댓글 없음: