도서/개발관련도서

[개발관련도서] 조엘 온 소프트웨어(1/3)

benjykim 2019. 12. 20. 11:35
반응형

1부 비트와 바이트: 프로그래밍 실전

2장 - 기본으로 돌아가기

사람들이 저지르는 가장 큰 실수 중 몇 가지는 최저층에서 벌어지는 몇 가지 단순한 동작원리를 자세히 알지 못하거나 아예 잘못 알고 있기 때문에 생긴다.

 

C언어의 strcat 함수와 러시아 페인트공 알고리즘을 통해 기존의 라이브러리의 성능이 좋지 않을 수도 있음을 나타냈고 더 나은 해결책을 제시했다. 또한 작성한 코드가 실제 메모리 상에서 어떻게 어떻게 동작하는지를 malloc 함수를 통해 설명했다. 저자는 strcat과 malloc이 실제로 어떻게 움직이는지를 보며 밑바닥이 어떻게 작동하는가를 알아야 한다고 말한다. 이 말인즉슨, '여러 기술을 다룰 때 밑바닥을 항상 염두하여 최상위 전략과 아키텍처 결정에 활용하라'이다.

 

요즘 입문자가 시작하기에 가장 좋은 언어가 '파이썬(Python)'이라 하는데, 이 책을 쓸 당시에는 '자바(Java)'가 지금의 파이썬을 대체하는 초보자용 언어였다. 자바는 쉽고 따분한 문자열이나 malloc과 같은 골칫덩어리를 다루는 과정에서 혼란을 겪지 않는 등 많은 이유들로 좋다고 여겨지지만, 여기에는 아래와 같은 재앙이 있다고 저자는 말한다.

 

졸업생들은 하향 평준화되어 러시아 페인트공 알고리즘을 여기저기 만들 것이고, 심지어 자신의 잘못조차 인식하지 못할 것이다. 기본적으로 문자열이 무엇인지 아주 깊은 단계에서 이해하지 못하기 때문이다.

 

따라서, 다른 이들이 뭔가를 잘하도록 가르치길 원한다면, 기초부터 시작하자.

생각해볼만한 사항: String 클래스와 StringBuilder 클래스 중 무엇을 사용해야 하는가?


3장 - 조엘 테스트: 더 나은 코드를 위한 12단계

  1. 소스코드 관리 시스템을 사용하고 있습니까?
  2. 한방에 빌드를 만들어낼 수 있습니까?
  3. 일일 빌드를 하고 있습니까?
  4. 버그 추적시스템을 운영하고 있습니까?
  5. 코드를 새로 작성하기 전에 버그를 수정합니까?
  6. 일정을 업데이트하고 있습니까?
  7. 명세서를 작성하고 있습니까?
  8. 조용한 작업 환경에서 일하고 있습니까?
  9. 경제적인 범위 내에서 최고 성능의 도구를 사용하고 있습니까?
  10. 테스터를 별도로 두고 있습니까?
  11. 프로그래머 채용 인터뷰 때 코딩 테스트를 합니까?
  12. 무작위 사용 편의성 테스트를 수행하고 있습니까?

12점 만점에 11점은 우수한 성적이지만, 10점 이하는 심각한 문제가 있다고 저자는 말한다.

 

12개 중 8번 '조용한 작업 환경에서 일하고 있습니까?' 항목이 눈에 들어왔다. 결론을 내식대로 내려보자면, 결국 프로그래머에게 질문할 땐 열심히 검색해보고 정 안될 때 질문하는 방식이 좋다는 것이다. 저자는 프로그래머를 1분이라도 방해한다면 15분에 이르는 생산성을 날려 먹는다고 말했다. 연구실에서도 오래 찾아보고 질문하는 사람이 있는가 하면 조금만 찾아보고 바로 질문하는 사람이 있다. 옆사람의 시간을 소중히 여기는 마음을 가지고 조심스레 질문하는 습관을 가지자.


4장 - 개발자가 꼭 알아둬야 할 유니코드와 문자 집합에 대한 고찰

인코딩 방식을 모르는 문자열은 아무 의미가 없다. 메모리나 파일이나 이메일 메시지 내부에 문자열이 있으면 이 문자열 인코딩이 무엇인지 알아야만 하며, 그렇지 못하면 이 문자열을 해석할 수도 없으며 사용자에게 올바르게 보여줄 수도 없다.

 

"이메일을 읽을 수 없어요"와 같은 문제 대부분은 문자열을 인코딩 UTF-8, ASCII, ISO 8859-1, 윈도 1252 방식 중 무엇인지 알려주지 않을 경우, 올바르게 문서를 표시하지 못하거나 심지어 어디서 끝날지 추측할 수조차 없다. 이러한 단순한 사실도 모르는 프로그래머가 많다.

 

참고할만한 페이지: https://d2.naver.com/helloworld/19187


5장 - 손쉬운 기능 명세 작성법

모든 사람이 명세서 작업을 해야 한다고 생각은 하지만, 아무도 명세서 작업을 하지 않는다. 그러나 명세서 작업을 하지 않는 관례는 소프트웨어 프로젝트에서 가장 크고 불필요한 위험 요인을 짊어지는 행동이다. 명세서를 작성하지 않고 코드를 바로 작성하면, 형편없는 코드를 작성하거나 조잡한 소프트웨어를 양산하게 된다.

 

명세서 작업에서 얻을 수 있는 가장 중요한 결실은 바로 '프로그램 설계'이다. 모든 코드를 혼자 작성한다고 하더라도 본인을 위해 명세서 작업을 해야 한다. 인간 언어로 제품을 설계할 때, 수정하고 설계를 향상하려는 시도는 단 몇 분이면 충분하다. 그러나 프로그래밍 언어로 제품을 설계할 때, 설계를 여러 차례 수정하는 작업은 몇 주를 까먹는다. 여기서 더 중요한 것은, 어떤 코드를 작성하기 위해 몇 주를 날린 프로그래머는 소프트웨어 품질이 어찌 되든 코드에 상당히 집착한다는 것이다. 또한 명세서 작업을 하면 함께 일할 팀원들과 다른 부서의 팀원들은 이 명세서만을 읽으면 된다. 마지막으로, 세부 명세서 없이 일정을 계획하는 것은 불가능하다. 제품 개발에는 돈이 들어가기 때문에, 어떤 일을 하는지, 얼마나 오래 걸릴지를 알고 있어야만 한다.

 

정리해보면, 명세서 작업을 해야 하는 이유는 3가지이다.

  1. 프로젝트를 보다 신중하게 설계할 수 있고 이로 인해 제품의 품질이 향상된다.
  2. 의사소통 시간이 절약된다.
  3. 구체적인 일정을 계획할 수 있다.

명세의 종류 두 가지

  1. 기능 명세(functional specification): 완전히 사용자 관점에서 제품이 어떻게 동작할지를 서술. 기능에 대해 이야기하고, 화면, 메뉴, 대화 상자와 같은 사용자 인터페이스 부품을 명세.
  2. 기술 명세(technical specification): 프로그램의 내부 구현 기술. 지료 구조와, 관계형 데이터베이스 모델과 프로그래밍 언어, 도구, 알고리즘 선택과 같은 항목을 다룸.

저자가 명세마다 넣은 단골 항목들

  • 면책조항: "이 명세는 완벽하지 않습니다."와 같은 문구를 넣는다면, 사람들은 화풀이하기 위해 당신 사무실 문을 박차고 들어오지 않을 것이다.
  • 저자: 자신이 명세한 사항에 대해 책임감과 소유의식을 느껴야 함. 명세에서 무엇인가 잘못되면, 이를 수정할 책임 있는 명세서 소유자를 지정해야 하며, 이 사람 이름이 바로 명세서에 찍혀 있어야 한다.
  • 시나리오: 제품 사용 방법에 대한 생생한 시나리오 필요.
  • 회피 목표: 어떤 기능을 안 할 것인지 미리 서술(= "이건 절대 안 할 겁니다")
  • 개괄: 명세를 위한 목차와 유사. 간단한 흐름도이거나 광범위한 아키텍처 관점에서 바라본 토론. 숲을 보게 하는 과정
  • 세부 사항: 대부분은 발등에 불이 떨어질 때까지 세부 사항을 파악하지 않고 미룸. 가장 좋은 방법은 너무 자세히 못 견딜 만큼 따분한 세부 사항을 매 화면마다 기술하는 장을 제공하는 것.
  • 미해결 문제: 명세 첫 버전에 미해결 문제를 남겨놓아도 좋다. 적당 안 대안이 있으면 같이 논의.
  • 방주(side note): 명세를 작성하는 동안에 프로그래머, 테스터, 마케팅 팀원, 기술 집필가와 같은 다양한 청중이 있음을 기억해야 함. 명세 작성 시, 특정 그룹에 유용한 내용을 구분하여 기록하는 것도 좋음.(예, '테스팅 노트', '마케팅 노트', '문서화 노트'')
  • 명세의 지속적 개정: 명세 주기적으로 업데이트. 바뀐 내용만 볼 수 있게끔 하고 이를 팀원들과 공유

명세 작성 규칙

  1. 재미있게 쓴다
    • 예) 사용자는 새로운 Employee 테이블을 생성하기 위해 Ctrl + N를 누르고, 종업원 이름을 입력하기 시작한다. 
      > 통통 군은 연필로 키보드를 꾹꾹 누르는데 그 이유는 그의 손가락은 너무 통통하고 짧아서 키를 누르는 일이 너무 힘들기 때문입니다. 통통군은 Girlfriend 테이블을 생성하기 위해 Ctrl + N을 누르고, 종업원 이름을 입력합니다.
  2. 명세를 쓰는 작업은 머리가 돌아가도록 코드를 쓰는 작업과 유사하다
    • 예) 사용자 x가 ANSI 문자열로 나타내는 해당 사용자를 대표하는 RFC-822 순응 이메일 주소로 사상하기 위해 정의한 AddressOf(x)를 가정하자. 사용자 A와 B가 있을 때...
      > 통통군은 점심을 먹으러 가려고, 새로운 이메일 창을 열고 "To:" 상자에 커밋 주소를 입력한다. 
      기술 노트: 주소는 반드시 표준 인터넷 주소(RFC-822 순응)를 따라야 한다.
  3. 최대한 단순하게 작성하라 
    > 호흡이 긴 문장은 쪼개자. 그림은 천 마디 말보다 낫다!
  4. 여러 차례에 걸쳐 검토하고 다시 읽어라 
    > 쉽게 이해되지 않는 문장을 찾으면, 다시 작성하는 편이 좋다
  5. 표준양식은 해롭다고 간주한다 
    > 
    표준양식이 있다면, 매 기능을 위해 중요하다고 생각하는 사항을 보충하기 위해 표준양식에 수많은 절을 추가하는 작업이 하나 더 늘기 마련. 이에 따라 표준양식도 커져서, 명세 쓰는 사람의 기를 죽임

9장 - 손쉬운 소프트웨어 일정 관리법

1. 엑셀을 써라

2. 단순하게 만들어라

  • 개발자가 여러 명이라면, 각 개발자마다 개별 시트를 유지하거나 각 과업을 맡은 개발자 이름을 담은 열을 추가해도 좋다.
Feature Task Priority Orig Est Curr Est Elasped Remain
Spell checker Add Menu item 1 12 8 8 0
Spell checker Main Dialog 1 8 12 8 4
Spell checker Dictionary 2 4 4 4 0
Grammer checker Add Menu item 1 16 16 0 16

 

3. 각 기능은 과업 여러 개를 포함해야만 한다.

철자 교정기를 추가하는 작업을 예로 들었다. 이것을 추가하려면 프로그래머는 독립적인 여러 과업을 수행해야 한다. 일정은 짜는 과정에서 가장 중요한 부분은 과업 목록을 작성하는 작업이다.

 

4. 담당 프로그래머만이 제대로 일정을 짤 수 있다.

관리자가 일정을 적어 프로그래머에게 전달하는 방식은 불 보듯 뻔한 실패를 초래한다. 실제로 작업하는 프로그래머만이 기능 구현에 필요한 단계를 알 수 있고, 각 단계마다 소요되는 시간을 제대로 예측할 수 있다.

 

5. 과업을 세부적으로 나누어라.

일정이 제대로 돌아가게 만드는 가장 중요한 요소. 과업은 날짜 단위가 아니라 시간 단위로 측정할 수 있어야 한다. 위의 표와 같이 과업을 나누지 않고 그저 '철자 교정기'라는 과업을 통째로 쥐고 있다면 얼마나 오래 걸릴지 알 수 없다. 저자 경험적으로, 각 과업은 적게는 2시간, 많게는 16시간 이내에 처리할 수 있어야 한다. 일정 중 1주일이 넘어가는 과업이 있으면, 충분히 쪼개지지 않았다고 봐야 한다.

 

6. 원본과 현재 예측을 동시에 유지하라.

과업을 일정에 추가할 때는, 과업이 얼마나 오래 걸릴지 시간 단위로 예측해서 원본 Ori [inal], 예측 Est [imate], 현재 예측 Curr[ent] Est[imate] 열에 기록해라. 시간이 지남에 따라 과업이 예상보다 길어지거나 짧아질 경우 필요에 따라 현재 예측 Curr Est 열을 갱신할 수 있다. 지속적으로 일정을 갱신하다 보면, 언젠가는 일정이 제대로 맞아떨어질 것이다. 평범한 프로그래머는 1년 정도만 경험하면 훌륭하게 일정을 작성한다. 과업이 끝나면, 현재 예측 Curr Est과 경과 Elapsed 필드를 동일하게 만들고, 잔재 Remain 필드를 다시 계산해서 0으로 만든다.

 

7. 경과(Elasped) 열은 매일 갱신하라.

 

8. 일정에 휴가나 휴일 같은 항목을 넣어라.

일정을 연간 단위로 짠다면 아마 열흘에서 보름 정도는 휴가를 간다. 이 시간들도 특별 항목으로 정해 일정에 추가해야 한다.

 

9. 일정에 디버깅 시간을 넣어라.

 

10. 일정에 통합 시간을 넣어라.

프로그래머가 2명 이상이라면, 서로 삐걱거리는 작업 진행 때문에 조정이 필요한 사항이 늘 존재한다. 기능들을 합칠 때 많은 오류도 발생할 수 있으므로, 일정에 통합 시간을 정식 항목으로 넣어라.

 

11. 일정에 여유 기간을 두어라.

고려해야 할 두 가지 중요한 여유기간.

  1. 원래 예측 지보다 작업 시간이 더 길어지는 과업에 필요한 여유 기간
  2. 기존에 계획하지 않았던 일이 생길 때를 위한 여유 기간

12. 관리자가 프로그래머에게 일정을 단축하도록 절대 강요하지 못하게 하라.

소프트웨어 관리자들이 빠듯한 일정을 잡아서 더 빨리 일을 처리하도록 프로그래머에게 동기부여할 수 있다고 자만한다. 그러나 일정이 조금이라도 늦어지면 프로그래머는 우울해지고 침체된다.

 

또한 개발자가 얼마나 피곤하지 생각하지도 않고 모든 사람이 엄청나게 힘들게 일하도록 하는 방법은 코드 생산성을 20% 정도 높일 수 있으나 디버깅 시간은 2배로 늘어날 것이다.

 

13. 일정은 장난감 블록과도 같다.

일정 유지 노력에 대한 부수 효과는 기능 제거 작업을 수행하도록 압박하는 데 있다. 만일 두 가지 기능을 구현해야 한다고 생각해보자. 하나는 진짜 유용하거나 제품을 멋지게 만들어주는 기능이며, 나머지 하나는 너무나도 간단하고 개발자는 만들고 싶어 안달을 부리지만, 실용성이 떨어지거나 마케팅 목적만 달성하는 쓸데없는 기능이다.

 

일정을 짜 놓지 않았다면, 개발자는 쉽고 재미있는 기능부터 먼저 구현할 것이다. 그러고 나면 시간이 부족해지니, 유용하고 중요한 기능을 구현하기 위한 일정을 늦출 수밖에 없다.

 

일정을 미리 짜 놓았다면, 작업을 시작하기 전에 무엇을 잘라내야 할지 알 수 있다. 기능을 검토해서 가치 치는 과정을 거침으로써, 더 좋은 기능으로 무장한 제품을 더 빨리 출시할 수 있다.


10장 - 일일 빌드는 당신의 친구입니다.

일일 빌드 장점

  • 버그 수정 시, 테스터는 새 버전을 빠르게 얻어서 해당 버그를 수정했는지 바로 작업 가능
  • 개발자는 테스트용 장비를 별도로 두지 않고서도 변경내역 직전에 생성한 시스템의 버전 중 어느 버전도 망가뜨리지 않았다고 좀 더 확신할 수 있음
  • 정기적인 일일 빌드 바로 직전에 변경을 체크인한 개발자는 어느 누고도 컴파일이 불가능한 상황을 만들어 버리지 않으리라는 사실을 안다. 쉽게 말해 '빌드를 깨버리는' 어떤 파일을 체크인해 다른 사람을 방해하지 못한다.
  • 미완성된 제품을 사용해야 하는 마케팅, 베타 고객 사이트와 같은 외부 그룹은 안정적인 빌드를 구해서 잠시 사용 가능
  • 모든 일일 빌드 모음 유지하면, 새로운 버그가 출현했는데 이유를 밝히기 어려울 때, 과거 이력을 통해 버그가 코드에 처음 출현한 시점 파악 가능
  • 프로그래머가 수정한 문제를 테스터가 보고할 때, 테스터는 문제를 확인한 빌드 번호를 말해줄 수 있음. 프로그래머는 내역을 체크인한 시각을 살펴봐서 해당 문제를 해결했는지 확인 가능

일일 빌드 팁

  • 코드 체크아웃에서 시작해 일반 사용자가 내려받을 수 있도록 결과물을 올바른 웹서버에 올리는 작업까지, 일일 빌드 스크립트로 전체 최종 빌드를 수행할 수 있게 만드는 작업이 중요.
  • 코드를 외부로 선적할 때 사소한 버그를 하나 발견하고, 이 버그를 일일 빌드 서버에 슬쩍 수정한 다음 내보내는 짓은 미친 짓이다. 파일은 모두 다시 체크아웃한 다음에 완벽하고 깨끗한 일일 빌드로 만들어낸 코드만 외부로 선적해야 한다.
  • 컴파일러 경고를 최대한 켜고 아주 사소한 경고가 발생할 때도 일일 빌드를 멈추게 하라
  • 일일 빌드가 깨졌다면, 팀 전체 작업을 중단할 각오를 해라. 문제점을 수정할 때까지 빌드를 반복해라.
  • 일일 빌드 스크립트는 전체 개발팀에게 이메일로 실패를 통보해야만 한다. (grep으로 error나 warning을 첨부하자)
  • 일일 빌드를 깨버린 사람은 다음에 다른 사람이 빌드를 깰 때까지 일일 빌드를 책임지고 수행하게 하는 방법도 있다.
  • 팀이 모두 같은 시간대에 일한다면, 점심시간에 빌드를 해라. 점심 먹기 전 최신 코드를 올바르게 체크인한다. 식사 시간 동안에 빌드가 돌아가고 식사 끝나고 왔을 때 확인하자.
    • 팀이 상이한 시간대에 작업한다면, 일일 빌드 일정을 조정해서, 특정 시간대에 있는 사람이 다른 시간대에 있는 사람을 방해하지 않도록 하자.

11장 - 고리타분한 버그 수정

개발자로서 완벽한 버그 수정은 좋은 일인가?

> 버그 수정은, 수정한 버그 가치가 수정 비용을 넘어설 때만 의미가 있다.

 

수정할 가치가 있는 버그를 찾아내는 방법

  1. 찾아낸 버그를 모두 확인해라
  2. 경제적인 피드백을 확인해라
  3. 버그를 모두 수정하는 작업이 어떤 값어치가 있는지 계산해라

최종 버그 수정 작업에 열을 쏟느니 차라리 무언가 다른 작업을 하는 쪽이 훨씬 더 큰 금전적인 가치를 창출할 수 있을지도 모른다. OS/2 사용자를 위한 버그 수정과 제네럴 일렉트릭사에 소프트웨어 20,000본을 판매할 수 있는 새로운 기능을 추가하는 작업 사이에서 결정을 내려야 한다면, 후자가 더 중요하지 않겠는가.


1부 나머지 장들도 찾아서 보면 많은 조언을 얻을 수 있을 것이다. 책을 정리하는 과정이 꽤나 오래 걸려서 살짝 부담이 되지만, 그래도 일단 정리하는 것이 맞다고 생각한다. 꾸준히 읽고 기록하자. 

 

 

 

반응형