목적: Software engineering의 이해
3장. 기본적인 도구THE BASIC TOOLS
많은 신참 프로그래머들은 예컨대 특정 통합 개발 환경IDE 같은 전동도구 하나만 고집하는 실수를 저지르고, 그 편한 인터페이스에서 떠날 생각을 하지 않는다. 이건 정말 실수다. IDE가 강제하는 편리함의 울타리 바깥에서도 능숙하게 작업할 수 있어야 한다. 유일한 방법은 기본 도구 세트를 늘 쓸 수 있도록 예리하게 유지하는 것이다.
3.1. 일반 텍스트의 힘
일반 텍스트란 사람이 직접 읽고 이해할 수 있는 형태의 인쇄 가능한 문자로 이루어진 텍스트를 말한다. 단점은 (1) 압축된 이진 포맷을 사용하는 것보다 더 많은 공간을 차지할 수 있고, (2) 일반 텍스트 파일을 해석하고 처리하는 데에 더 많은 계산이 필요할 수 있다.
20. 지식을 일반 텍스트로 저장하라
텍스트의 힘
사용자가 더 많은 공간을 차지하게 하고 혹은 더 느리게 같은 기능을 요구하는 경우는 그다지 많지 않은 것 같은데 일반 텍스트로 고생을 하는 이유는 뭘까? 도대체 이득이 뭔가?
- 구식이 되는 것에 대한 보험 사람이 읽을 수 있는 형태의 데이터와 자명한 데이터는 어떤 다른 형태의 데이터와 그걸 생성한 애플리케이션 보다 더 오래 살아남을 것이다.
- 호환성 소스코드 관리 시스템, 컴파일러 환경, 에디터, 단독으로 사용되는 필터에 이르기까지 컴퓨팅 세계의 거의 모든 도구들은 일반 텍스트를 다룰 수 있다.
- 더 쉬운 테스트 만약 시스템 테스트를 구동하게 할 합성 데이터를 만들기 위해 일반 텍스트를 사용한다면, 특별한 도구를 만들어야 할 필요 없이 간단히 테스트 데이터를 추가, 업데이트, 수정할 수 있다.
최소 공통분모Lowest Common Denominator
이질적인 환경에서는 일반 텍스트의 장점이 모든 단점을 보상하고도 남는다. 모든 참가자가 공통의 표준을 사용해서 소통하도록 할 필요가 있다면, 일반 텍스트가 바로 그 표준이다.
유닉스 철학
유닉스는 작고 예리한 각각의 도구가 한 가지 일만 잘 하도록 만들자는 철학에 따라 설계된 것으로 유명하다. 이 철학은 라인 중심의 일반 텍스트 파일을 기반으로 공유하기 때문에 가능하다. 시스템 관리를 위해 사용되는 데이터베이스(사용자, 패스워드, 네트워크 설정 등등)는 모두 일반 텍스트 파일로 저장된다. (솔라리스 같은 몇몇 시스템에서는 퍼포먼스 최적화를 위해 특정 데이터베이스를 이진 형태로 관리하기도 한다. 하지만 여전히 일반 텍스트 버전은 이진 버전에 대한 인터페이스로 유지된다.)
시스템이 고장 났을 때, 복구를 위해서는 최소한의 환경밖에 사용할 수 없는 경우가 있다(예컨대, 그래픽 드라이버를 액세스할 수 없는 등). 이런 상황에서 여러분은 일반 텍스트의 단순함에 고마움을 느끼게 될 것이다.
3.2. 조개 놀이Shell Games(Shell의 유용함)
텍스트 파일들을 다루는 프로그래머에겐 명령어 Shell이 작업대가 된다. Shell 프롬프트에서 모든 종류의 도구를 불러 쓸 수 있다.
GUI 인터페이스와 IDE에서 자라난 프로그래머들에게 이건 좀 극단적으로 보일지도 모른다. 마우스로 포인팅하고 클릭함으로써 결국 모든 걸 똑같이 잘 할 수 있는 것 아닌가?
대답은 ‘아니오’다. GUI 인터페이스는 훌륭한 것이고, 몇 가지 간단한 조작에는 그게 더 빠르고 편리할 수도 없다. 하지만 모든 작업을 GUI로만 한다면, 여러분이 가진 환경의 전체 능력을 이용하지 못하게 된다. 일반적인 작업을 자동화할 수 없고, 쓸 수 있는 도구의 풀 파워를 사용할 수 없다. 게다가 도구를 결합해서 자신에게 꼭 맞는 매크로 도구를 만들 수가 없다. GUI의 장점은 WYSIWYG What You See Is What You Get, 즉 여러분이 보는 것이 여러분이 얻는 것이라는 것이다. 단점은 WYSIAYG What You See Is All You Get, 즉 여러분이 보는 것이 여러분이 얻는 전부라는 것이다.
실용주의 프로그래머로서 여러분은 늘 임시변통의 작업을 수행하길 원한다. 해당 GUI가 지원하지 않을 수도 있는 그런 작업 말이다. 명령 줄은 쿼리나 기타 다른 작업을 수행하기 위해 몇 개의 명령어를 재빨리 결합하려 할 때 사용하기 좋다.
몇 가지의 예
소스의 zip/tar 아카이브를 만들어라
- Shell… zip archive.zip *.h *.c
tar cvf archive.tar *.h *.c - GUI… ZIP 유틸리티를 불러내 ‘Create New Archive’를 선택하고, 이름을 입력하고, add 대화상자에서 소스 디렉터리를 선택하고, 필터를 ‘*.c’라고 하고 ‘Add’를 클릭한 다음, 다시 ‘*.h’라고 필터를 변경하고 또 ‘Add’를 클릭한다. 그리고 아카이브를 닫는다.
지난 주 중에 변경되지 않은 자바 파일은 어느 것들인가?
- Shell… find . –name ‘*.java’ –mtime +7 –print
- GUI… ‘파일 검색’으로 찾아가서, ‘Named’ 필드를 클릭하고, ‘*.java’라고 입력한 다음, ‘Date Modified’ 탭을 선택한다. 그러고는 ‘Between’을 선택한다. 시작하는 날짜를 클릭하고 일주일 전의 날짜를 입력한다. ‘Find Now’를 클릭한다.
21. 명령어 Shell의 힘을 이용하라
명령어 Shell을 갖고 놀다 보면, 여러분이 얼마나 더 생산적이 될 수 있는지 놀라게 될 것이다.
주(註): Shell 프로그래밍에 대한 보다 자세한 자료는『유닉스 파워 툴』을 참조하세요.
3.3. 파워 에디팅(생산성 증가를 위한 핵심 기능을 제공하는 범용 에디터의 마스터)
하나의 에디터
에디터 하나를 골라서 완전히 마스터하고, 모든 편집 작업에 그 에디터를 사용하라. 여러분이 만약 텍스트 편집 전반에 하나의 에디터(혹은 하나의 바인딩 세트)를 사용한다면 텍스트를 조작할 때 멈추고 생각하고 할 필요가 없을 것이다. 에디터는 여러분 손의 연장이 될 것이다. 키가 텍스트와 생각 사이로 미끄러지면서 노래를 부를 것이다. 그것이 우리의 목표이다.
선택한 에디터가 사용하는 모든 플랫폼에서 가능한지 확인하라. emacs, vi, CRiSP, Brief 등은 다중 플랫폼에서 사용가능하고 종종 GUI와 텍스트 화면 버전 모두를 지원한다.
22. 하나의 에디터를 잘 사용하라
주(註): emacs도 상당히 유명한 에디터인데 써 본일도 없을뿐더러, 사용하는 개발자도 본적이 없다. 참고로 본인은 vi또는 vim을 선호하는데 IDE인 eclipse에서도 vi plugin을 이용해서 사용할 수 있다.
에디터의 기능
우리가 생각하는 그럴싸한 에디터라면 갖추어야 할 기능을 몇 가지 나열해 보겠다.
- 설정변경 가능 에디터의 모든 요소를 기호에 맞게 다시 설정할 수 있어야 한다.
- 확장 가능 새로운 언어나 텍스트 포맷(XML, HTML 버전 9 등)의 뉘앙스를 ‘가르칠’ 수 있어야 한다.
- 프로그램 가능 복잡하고 다단계의 작업을 수행할 수 있도록 에디터를 프로그램 할 수 있어야 한다. 매크로나 내장 스크립팅 프로그래밍 언어를 통해 가능하다.
여기에 더해, 많은 에디터는 특정 프로그래밍 언어를 위한 고유의 기능을 제공하기도 한다.
- 구문 강조syntax highlighting
- 자동 완성
- 자동 들여쓰기
- 코드나 문서 상용어구 지원
- 관련 도움말 시스템
- IDE 기능(컴파일, 디버그 등)
여기에서 어디로 가나
만약 자신이 이렇다면 | 이걸 고려해 보라… |
---|---|
나는 여러 개의 에디터에서 기본적인 기능만을 사용한다. | 강력한 에디터 하나를 골라서 그걸 제대로 익혀라. |
선호하는 에디터가 있긴 한데, 그 기능을 모두 사용하진 않는다. | 그걸 배워라. 입력해야 하는 키 개수를 줄여라. |
선호하는 에디터가 있고 가능하다면 그걸 사용한다. | 이미 하는 작업 외에 좀 더 많은 작업에 사용하도록 확장해 보라. |
나는 여러분들이 바보라고 생각한다. 원도우 메모장은 이제까지 만들어진 에디터 가운데 최고다. | 여러분이 그 에디터를 사용하면 행복하고, 또 생산적이라면 그걸 사용해라. 하지만 스스로가 ‘에디터 선망envy’에 걸릴 수 있다는 생각이 들면 스스로의 위치를 재평가할 필요가 있을 것이다. |
어떤 에디터가 있나?
괜찮은 에디터 하나를 마스터할 것을 추천했는데, 우리는 어느 에디터를 추천 하는가? 흠, 우리는 그 질문을 피하려고 한다. 에디터의 선택은 개인적인 것이다.(어떤 이는 심지어 종교적인 것이라고 할 것이다!)
3.4. 소스코드 관리
소스코드 관리 시스템 혹은 좀 더 넓은 의미의 형상 관리configuration management 시스템은 소스코드나 문서 관련의 모든 변화를 기억한다. 더 좋은 것들은 컴파일러나 OS 버전까지도 기억할 수 있다. 적절히 설정된 소스코드 관리 시스템을 쓰면 소프트웨어의 이전 버전으로 언제든 되돌아갈 수 있다.
(1) 훌륭한 SCCS는 변화를 관찰 기록하면서 다음과 같은 질문에 답할 수 있다. 코드의 이 라인은 누가 바꿨을까? 현재 버전과 지난 주 버전 간의 차이는 무엇인가? 이번 릴리스에 코드를 몇 줄 바꿨는지? 어느 파일들이 가장 자주 바뀌는지? 이런 종류의 정보는 버그 추적bug-tacking이나, 감사, 퍼포먼스, 품질 관리 목적으로 매우 귀중하게 쓰일 수 있다.
또한, (2) SCCS는 소프트웨어의 릴리스를 구분하게 해줄 것이다. 일단 어떤 릴리스가 구분되면, 여러분은 언제나 거꾸로 돌아가서 그 이후에 생겼던 변화에 상관없이 해당 릴리스를 재생산해 낼 수 있다.
마지막으로, (3) 어떤 제품들에서는 두 사람 이상의 사용자가 동일한 파일들에 대해 동시 작업을 할 수 있다. 심지어는 하나의 파일을 동시에 수정할 수도 있다. 파일들을 저장소로 다시 보낼 때 시스템이 수정사항들을 합쳐준다. 이런 시스템은 위험해 보이지만 여러 크기의 프로젝트에서 잘 작동한다.
23. 언제나 소스코드 관리 시스템을 사용하라
소스코드 관리와 빌드
전체 프로젝트를 소스코드 관리 시스템의 보호막 아래에 두는 것에는 엄청나게 큰 이득이 숨겨져 있다. 제품 빌드가 자동화 되고 그것을 반복할 수 있게 되는 것이다.
하지만 우리 팀은 소스코드 관리 시스템을 사용하지 않는데
스스로 부끄러워해야 한다! 후후후.
3.5. 디버깅debugging
디버깅의 심리
디버깅은 단지 문제 해결이라는 사실을 포용하고, 그 방식으로 공략하라. 다른 사람의 버그를 발견한 후, 그 버그를 만들어낸 부정한 범죄자를 비난하는 데에 시간과 노력을 들이는 수가 있다. 어떤 회사에서는 비난이 문화의 일부고 거기서 카타르시스를 얻을 수도 있다. 하지만 기술의 전당에서는 남을 비난하기 보다 문제를 고치는 데에 집중하고 싶어 한다.
24. 비난 대신 문제를 해결하라
디버깅 사고방식
디버깅을 시작하기에 앞서서 올바른 사고방식을 갖는 게 중요하다. 자신의 자아를 보호하기 위해 매일 사용하는 많은 방어시설을 꺼버려야 하고, 여러분에게 부과되는 프로젝트의 압력을 무시해서 스스로를 편안하게 만들어야 한다. 무엇보다도 다음의 디버깅 제일 법칙을 기억하라.
25. 디버깅을 할 때 당황하지 마라
버그를 목격하거나 혹은 버그 보고서를 보는 순간 첫 반응이 “그건 불가능해”라면 여러분은 두말할 필요 없이 틀렸다. “하지만 정말 그럴 리가 없는데”로 시작하는 일련의 사고에 신경세포 하나라도 소모하지 마라. 왜냐하면 분명히 그런 일은 일어날 수 있으며, 실제로도 일어났기 때문이다.
어디에서 시작할까
앤디는 대규모 그래픽 애플리케이션 프로젝트에서 일한 적이 있다. 릴리스가 가까워졌을 때, 특정한 붓으로 한 획을 긋기만 하면 애플리케이션이 멈춰 버린다고 테스터들이 보고했다. 해당 프로그래머는 아무 문제가 없다고 반론했다. 그는 스스로 한 획을 그어봤고 별 문제 없이 잘 작동했다. 똑같은 실랑이는 며칠간 반복되었고 사람들의 감정은 점점 악화되었다.
결국에는 (1) 한 방에 모든 사람을 모았다. 테스터는 문제의 브러시 툴을 선택하고 우상단에서 좌하단으로 한 획을 그렸고, 애플리케이션은 작동을 멈췄다. 프로그래머는 작은 목소리로 “이런”하면서 자신은 (2) 테스트할 때 단지 좌하단에서 우상단으로 획을 그렸는데 어떤 버그도 드러나지 않았다고 부끄러워했다.
- 처음에 받은 자료 이상을 얻기 위해서 버그를 보고한 사용자를 인터뷰할 필요도 있다.
- 인공 테스트(예컨대 프로그래머가 밑에서 위로 획을 그은 것)는 애플리케이션을 충분히 테스트하지 못한다. 경계 조건boundary condition과 실제 최종사용자 사용 패턴 모두를 철저히 테스트해야 한다. 이걸 체계적으로 할 필요가 있다.
디버깅 전략
무든 일이 벌어지고 있는지 안다고 스스로 생각한다면, 이번에는 프로그램은 어떻게 생각하는지 알아내야 할 차례다.
- 데이터를 가시화하라(디버거debugger) 데이터와 데이터들 사이에 존재하는 모든 상호관계를 시각화할 수 있는 디버거를 사용하면 자신의 데이터에 대해 훨씬 더 깊은 통찰을 얻을 수 있다. 이하는 책을 참고.
- 트레이싱tracing 트레이싱 구문은 ‘여기까지 도달’이나 ‘x값=2’ 등의 화면 혹은 파일에 출력하는 작은 진단용diagnostic 메시지를 일컫는다. IDE 형태의 디버거에 비하면 원시적인 기법이긴 하지만, 디버거가 진단할 수 없는 몇 가지 종류의 에러를 진단하는 데에는 효과적이다.
- 고무 오리 문제의 원인을 찾는데 매우 단순하지만 꽤나 유용한 기법으로, 누군가에게 그걸 설명하는 단순한 방법이 있다.
너무 당연한 얘기지만, 누군가에게 문제를 설명하게 되면 혼자 코드를 살펴 볼 때는 당연히 여기고 지나갈 것을 명시적으로 이야기해야 한다. 이런 가정들 몇 가지를 발화発話하게 되면, 문제에 대한 새로운 통찰을 별안간 얻을 수 있다. - 제거 과정 OS, 컴파일러 혹은 써드파티 제품에 버그가 있을 수도 있다. 하지만 처음부터 그런 생각을 하진 말라. 개발하고 있는 애플리케이션 코드에 버그가 존재할 가능성이 훨씬 더 크다. 애플리케이션 코드가 라이브러리를 잘못 호출하고 있다고 가정하는 것이 라이브러리 자체에 문제가 있다고 가정하는 것보다 일반적으로 득이 된다. 설사 써드파티 제품에 문제가 있다고 하더라도, 버그 리포트를 제출하기 전에 여전히 자신의 코드를 제거해야만 한다.
놀람의 요소
뭔가 잘못될 때 놀라는 정도는 실행되는 코드에 갖는 신뢰와 믿음의 정도에 정비례한다. 그렇기 때문에 뭔가 예상 못한 ‘놀라운’ 실패를 대면했을 때 자신이 세운 가정들이 잘못되었다는 것을 깨달아야 한다. 버그에 관련한 루틴이나 코드가 제대로 작동한다고 ‘안다’고 해서 대충 얼버무려 지나치지 마라. 그것을 증명하라. 이 맥락안에서, 이 데이터로, 이 경계조건 하에서 증명하라
27. 가정하지 마라. 증명하라
(1) 버그를 마주치면, 단순히 그걸 고치는 것을 넘어서, 왜 이 실패가 더 일찍 발견되지 않았을까 생각해 볼 필요가 있다. 버그를 미리 잡을 수 있도록 단위 테스트나 다른 테스트를 수정할 필요가 있는지 고려하라.
이런 작업을 하는 중, (2) 이것과 동일한 버그가 있을 여지가 있는 다른 코드가 있는가? 그것들을 찾아서 고쳐야할 때는 바로 지금이다.
(3) 이 버그를 고치는 데 긴 시간이 걸린다면 왜 그런지 자문하라. 다음번에는 이 버그를 좀 더 쉽게 고칠 수 있도록 할 수 있는 뭔가가 있을까? 더 나은 테스팅 훅을 만들어 넣거나, 로그 파일 분석기를 작성할 수도 있겠다.
이 모두를 행해서, 바라건대 다음번에는 놀라지 않게 되기를.
디버깅 체크 리스트
- 보고된 문제가 내재하는 버그의 직접적 결과인가 아니면 단순히 증상일 뿐인가?
- 버그가 정말로 컴파일러에 있나? OS에? 혹은 여러분 코드에 있나?
- 이 문제를 동료에게 상세히 설명한다면 어떻게 말하겠는가?
- 의심가는 코드가 단위 테스트를 통과한다면, 테스트는 충분히 완전한 것인가? 이 데이터로 단위 테스트를 돌린다면 무슨 일이 생기는가?
- 이 버그를 야기한 조선이 시스템의 다른 곳에도 존재하는가?
3.6. 텍스트 처리
3.7. 코드 생성기
출처
인사이트 – 앤드류 헌트, 데이비드 토머스의 실용주의 프로그래머The Pragmatic Programmer