목적
문서화를 제대로 해 놓지 않은 프로그램은 한번쯤은 잘 작동하겠지만 별로 쓸만하지 못합니다. 규모가 작고 중요하지도 않으며 단기간만 사용할 프로그램이라면 주석이 적어도 충분할 것입니다. 그러나 웬만한 프로그램은 코드 자체 이외에 문서가 전혀 없는 경우, 유지하기도 힘들고 시대에 뒤떨어지기 쉽습니다. 초보자들이 들으면 놀라겠지만, 문서화에 약간만 노력을 기울이면 작은 프로젝트에서도 효과를 볼 수 있습니다.
여러분이 신이거나 변화가 전혀 없는 세상에서 살고 있는 사람이 아니라면, 언젠가는 여러분이 이전에 만들었던 코드를 다시 볼 일이 있을 것입니다. 그리고 예전에 그 코드를 만들면서 어떤 결정을 했는지 궁금해질 것입니다. 만약 예전에 결정했던 것을 문서화해 놓지 않았다면, 똑같은 실수를 범하게 되거나, 그때에는 쉽게 설명할 수 있었던 문제를 보고 당황하게 될 것입니다. 문서화를 잘 해 놓지 않으면 두 벌 일을 해야 할 뿐만 아니라 코드의 질이 떨어지기 쉽습니다. 이것은 여러분이 문제의 특성을 명확히 파악하고 있지 못하면 좋은 해결책을 찾을 수 없는 것과 같습니다.
문서화를 어떻게 하는지 익히는 것은 어려운 일이고, 경험과 공학적 판단력도 있어야 합니다. 문서화를 너무 엉성하게 하는 것도 문제지만, 지나치게 하는 것도 좋지 않습니다. 문서를 너무 자세하게 만들면 읽는 사람에게 엄청난 부담을 주고 유지하는 것도 큰일이 됩니다. 올바른 것만 문서화하는 것이 중요합니다. 너무 길어서 읽기 부담스러운 문서라면 아무에게도 도움이 되지 않습니다.
초보자들은 쉬운 문제에만 노력을 기울이는 경향이 있습니다. 쉬운 문제는 문서화하기도 쉽기 때문입니다. 그러나 이건 시간 낭비입니다. 쉬운 것을 문서화해 봤자 얻을 것은 아무 것도 없고, 쓸데없는 문서만 남을 뿐입니다. 또 초보자들은 문서화를 싫어하는 경향이 있습니다만 이건 짧은 생각입니다. 설계에 문제점이 몇 가지 있다거나, 문제의 일부가 명확하지 않다거나, 어떤 코드에서 버그가 생기기 쉽다거나 하면 이런 점을 문서화하십시오. 이렇게 함으로써 다른 사람이 여러분의 프로그램을 볼 때 미심쩍은 부분에 대해서 고민하는 시간을 줄여줄 수도 있고, 다시 그 문제에 뛰어들 때 어디를 살펴봐야 하는지 기억해낼 수도 있습니다. 또 이것을 바탕으로 보다 정확하고 쓸만한 문서를 만들 수 있습니다.
언제 문서화를 할지도 생각해 볼 필요가 있습니다. 실험 중에는 문서화를 연기하는 것이 좋을 때도 있지만, 경험 많은 개발자는 임시 코드를 짤 때나 처음에 문제를 분석할 때나 초안을 만들 때도 체계적으로 문서화를 합니다. 이렇게 문서화를 하면 실험의 생산성도 높아진다고 합니다. 게다가 개발자들은 문서화하는 습관을 들여 놓았기 때문에 일을 하면서 자연스럽게 문서화를 할 수 있습니다.
이 문서에서는 소프트웨어 프로젝트 문서화를 어떻게 할지 지침을 제시합니다. 여기서는 개요와 필수 요소 몇 가지만 얘기하고 구체적인 것은 여러분 자신의 판단에 맡깁니다. 문서화를 기계적으로 지루하게 하면 절대로 안 됩니다. 그렇게 만든 문서는 쓸모도 없고 읽기 힘들게 될 것이 뻔합니다. 의식적으로 문서화를 하십시오. 왜 문서화를 하고 있는지, 과연 시간을 최대한 효율적으로 쓰고 있는 것인지 생각하면서 하라는 뜻입니다.
여러분은 이 문서를 마음대로 긁어갈 수 있습니다. 원본 제작자들이 신경 쓰지 않는 범위라면 말입니다.
개요
보고서는 아래에 있는 구조를 따르도록 하십시오. 각 항목별로 분량을 제시하고 있는데 이것은 반드시 따라야 하는 것은 아닙니다. (역주: 이 문서가 원래 MIT의 소프트웨어 공학 실습 프로젝트를 기준으로 한 것이라 자료구조 과제에 적용하기에는 분량이 상당히 많으니 그대로 따를 필요는 없습니다.)
1. 요구 조건
풀고 있는 문제와 그 해법을 기술합니다. 이 절은 구현자뿐만 아니라 사용자를 위한 것이기도 하므로, 특정 구현 방법을 자세히 써 놓으면 안 됩니다. 프로그램을 구현하고 유지 관리하는 사람들만을 위한 내용은 문서의 다른 부분에 들어갈 것입니다.
- 개요(1쪽 이내). 프로그램의 목적과 기능에 대해 설명합니다.
- 수정 spec. 프로그램의 동작에 관한 자세한 명세서(spec.)가 주어지더라도 어떤 부분은 정의가 잘 안 돼 있거나 분명하지 않을 수 있습니다. 따라서 여기에서 여러분이 수정하거나 확장한 부분을 설명하는 것은 물론, 요구 사항을 어떤 의미로 가정(assume)하였는지 명확히 기술해야 합니다.
- 사용자 설명서 (1 - 5 쪽). 사용자가 어떻게 해야 프로그램을 사용할 수 있는지, 어떤 명령을 할 수 있는지, 어떤 명령행 인자(command-line argument)를 줄 수 있는지 등을 자세하게 기술합니다. 구체적인 형식은 여기에서 얘기하지 말고 부록으로 따로 써 놓습니다. 동작 환경에 대한 가정은 여기에 분명하게 쓰여 있어야 합니다. 프로그램이 특정한 시스팀 상에서만 돌아간다거나 어떤 디렉토리에 있어야 제대로 작동한다거나 다른 응용 프로그램이 있어야 한다는 등의 얘기를 말하는 것입니다. 이 설명서는 개요와 함께 프로그램 사용자에게 필요한 정보를 제공해야 합니다.
- 성능 (0.5 쪽). 프로그램이 제대로 동작하려면 어느 정도 자원이 필요하고, 시간이 얼마나 걸릴지 등을 얘기합니다.
- 문제 분석 (2 - 10 쪽). 문제를 분명하게 설명합니다. 아직 논의하지 않았다면 여기서 설계 뒤에 숨어 있는 개념적인 모델을 설명합니다. (user interface까지 설명할 수도 있습니다) 문제 분석은 보통 여러 문제 객체 모델과 그것들이 이루는 집합과 관계에 대한 정의, 몇 가지 까다로운 문제에 대한 논의를 포함합니다. 객체 모델의 목표는 코드가 아니라 문제 영역에서 나옵니다. 객체 모델은 도표와 중요한 원문상의 제약을 모두 포함하고 보기 쉽도록 깔끔하게 정리해 놓아야 합니다. 또 여기서는 고려했지만 채택하지 않은 대안들을 채택하지 않은 이유와 함께 기술해야 합니다. 또 해결하지 못한 논쟁점, 아직 명확하지 않아서 나중에 풀어야 할 숙제 등도 기술합니다.
수정 명세서(spec.)나 사용자 매뉴얼을 작성할 때 예시를 드는 것이 좋습니다. 여기서 예시란 특별한 목표 또는 그 목표를 달성하기 위해서 사용자가 할 일을 나열한 것을 뜻합니다. 의뢰자(client)는 할 일 목록을 살펴보고 사용자 인터페이스(user interface)가 합리적인지 아닌지 판단합니다. 모든 사용자의 요구를 만족할 수 있는 충분한 예시를 제공한다면 의뢰자는 이 프로그램을 신뢰할 수 있게 됩니다.
2. 설계
여러분의 구현 전략을 (high-level picture로) 제시합니다.
- 개요 (0.5 - 3 쪽). 설계 전체의 개요를 기술합니다. 최상위 단계의 구조, 특별한 논점, 라이브러리(library)나 기타 외부에서 가져온 모듈, 결정하지 못했거나 바뀔 가능성이 있는 부분 등을 지적합니다. 또, 잘못되었을 수 있는 결정이나 유연성과 성능 사이의 trade-off 등 이 설계에서 나타날 수 있는 문제점도 기술합니다.
- 실행시간 구조 (1 - 5 쪽). 프로그램을 실행할 때 어떤 상태 구조를 갖게 되는지 객체 모델을 통하여 묘사합니다. 여기서는 각 객체간의 관계를 보여주는 것이 목적이기 때문에 추상 데이터 타입(ADT, abstract data type)의 표현은 감추어야 합니다. 객체 모델은 도표와 중요한 원문상의 제약을 모두 포함하고 보기 쉽도록 깔끔하게 정리해 놓아야 합니다. 표현법이 일반적이지 않거나 특별히 복잡하거나 전체 설계 상에서 매우 중요한 부분이라면 데이터형의 표현을 설명해야 합니다. 추상화 함수나 표현 제약 조건은 코드 자체에서 자연스러운 장소에 나타나야 한다는 점을 명심하십시오.
- 모듈 구조 (1 - 5 쪽). 모듈 연관 도표를 통하여 프로그램의 문법적 구조를 기술합니다. 여기에는 패키지 구조, 인터페이스, 클래스를 포함해야 합니다. 다만 Java API의 관계까지 보여줄 필요는 없습니다. 여러분의 도표는 보기 쉽도록 잘 정리해 놓아야 합니다. 특정 문법 구조를 선택한 이유나 특정 디자인 패턴을 사용한 이유 등도 설명합니다. 예를 들어 객체를 분리하는 인터페이스를 만들었다면 무엇을 왜 분리하였는지 설명합니다.
설계를 하면서 객체 분할이나 다른 결정을 왜 했는지 설명하려면 그런 결정을 함으로써 얼마나 설계를 단순하고, 확장성 있고 분할 가능하게 하였는지 등 비슷한 소프트웨어 공학적 목표를 달성하는데 어떤 도움이 되었는지를 입증해야 합니다.
3. 검사
여기서는 여러분이 만든 시스템을 확인하고 검증하기 위해 사용한 방법을 설명합니다. (실제 시스템에서 이것은 요구 절에서 설명한 문제에 대한 해법으로서 시스템이 적합한지 결정하기 위한 사용자 테스트나 알고리즘이 옳은지 검증하는 실행 테스트를 포함할 수 있습니다.) 여러분의 시스템 설계를 전달하기 위해서 코드를 보이거나 클래스를 나열하기만 하면 안 되는 것과 같이, 단지 수행한 테스트를 나열하기만 해서는 안 됩니다. 테스트 방법을 어떻게 선택하였고, 그 테스트로 충분한 것인지, 문서를 읽는 사람이 이 테스트에서 빠진 중요한 점이 없다는 것을 어떻게 확신할 수 있는지, 이 시스템이 현장에서 정말 예상대로 작동할 것인지 등을 논합니다.
- 방법 (1 - 2 쪽). 검사 방법을 설명합니다. 블랙 박스(black box)와 유리 박스(glass box, white box), 하향식(top down)과 상향식(botton up), 사용한 시험 환경 종류나 test drivers, 시험 데이터 출처, test suites, 적용 기준, 컴파일-시간 검사 vs. 실행 시간 가정(assertions), 여러분의 코드에 대한 증명 등이 있습니다. 여러분은 프로그램의 각 부분마다 서로 다른 방법을 사용하거나 여러 방법을 조합해서 사용하려고 할 수도 있습니다. 이럴 때에는 여러분이 어떤 방법을 선택했는지 그 이유를 같이 제시합니다.
여러분이 선택한 방법으로 어떤 에러를 찾을 수 있는지 설명합니다. (그리고 찾을 수 없는 것은 무엇인지도 설명합니다) 설계에서 어떤 점이 이러한 에러 검사의 난이도에 영향을 주는지 논합니다.
- 검사 결과 (0.5 - 2 쪽). 어떤 검사를 완료했고 어떤 것이 남아 있는지 요약합니다. 어떤 모듈 검사했고, 얼마나 철저하게 검사했는지를 적습니다. 그리고 코드의 신뢰성 정도를 기술합니다. 어떤 종류의 에러를 제거하였는가? 어떤 종류가 남아 있을 것인가?
4. 영향
사후 관리라고도 부르는 이 절에서는 특정 실수나 성공을 일반화하고 규칙으로 정리해서, 여러분이나 다른 이들이 나중에 소프트웨어를 개발할 때 사용할 수 있도록 합니다. 여러분이 가장 황당했던 점은 무엇인지, 시작할 때 필요한 정보는 무엇인지, 개발중에 생길 수 있는 문제점을 어떻게 피할 수 있는지 얘기합니다.
- 평가 (0.5 - 1 쪽). 여러분이 성공이라고 생각하는 것과 실패라고 생각하는 것(풀지 못한 설계상 문제점, 성능 문제 등)을 얘기합니다. 여러분의 설계에서 중요한 것이 무엇인지 확인합니다. 여러분이 자랑할만한 설계나 구현 기술을 지적합니다. (자랑할만 하면 추가 점수가 약간 있습니다)
- 배운 점 (0.2 - 1 쪽). 이 프로젝트를 통하여 어떤 점을 배웠는지 기술합니다. 다음에 같은 일을 하게 된다면 어떤 다른 방법을 쓸 수 있을지, 설계나 구현상 문제를 어떻게 해결할 수 있을지 등을 얘기합니다. 그 밖에 문제를 일으킬 수 있는 요소에 대해서도 여기서 설명하거나 다음 절에서 설명합니다.
- 알려진 버그와 한계 여러분의 구현이 어떤 점에서 spec.을 만족시키지 못하는지 기술합니다. 정확하게 기술하도록 하십시오 여러분의 프로그램에 버그나 미구현사항이 있을 경우 감점하겠지만, 그러한 에러나 문제의 원인을 정확히 지적하면 부분 점수를 받을 수도 있습니다.
5. 부록
부록은 상위 수준을 이해하기 위해서 필요하지는 않지만 실제 상황에 응용하기 위해서 필요한 하위 수준 사항에 대한 상세한 내용을 포함합니다. 또는 문서의 다른 곳에서 주장한 것을 검증합니다.
- 형식. 파일 입출력, 커맨드 라인 인자, 사용자와 프로그램간 대화, 네트웤 상에서 메시지 형식 등 프로그램이 보증하거나 가정하는 모든 포맷을 기술합니다. These should be broken down into user-visible formats, which are conceptually part of the user-visible requirements and user manual, and internal formats that are conceptually part of other components of your documentation.
- 모듈 spec. 여러분은 코드에서 spec.을 뽑아서 여기에서 제시해야 합니다. 여러분이 javadoc형식으로 주석을 달아 놓았다면 코드로부터 자동으로 spec.문서를 만들 수 있을 겁니다. 추상 타입의 spec.은 개요, spec. 필드, spec. 제약 등을 포함해야 합니다. 추상화 함수나 표현 불변량은 타입의 명세에 속하지 않습니다.
- Test cases. Ideally, your testbed reads tests from a file of test cases in a format that is convenient to read and write. You need not include very large test cases; for example, you might just note the size of a random input generated for stress testing, and provide the program that generated the tests. Indicate for each group of tests what they are for (e.g., "stress tests, huge inputs", "partition tests, all combinations of +/-/0 for integer args").
코드 문서화
명세 단계 주석
추상 데이터 타입(ADT). 모든 ADT(class나 interface)는 다음과 같은 내용을 포함해야 합니다.
- 개요: 이 ADT가 무엇을 나타내고, 다른 타입으로 변할 수도 있는지 없는지 여부를 한두 줄로 기술합니다.
- 명세 필드 목록: 이것은 단 한개만 있을 수도 있습니다. 예를 들자면 집합 ADT는 원소의 집합을 나타내기 위해서 elems라는 필드 하나만 가질 수도 있습니다. 명세 필드는 각각 이름, 타입, 짧은 설명을 포함하고 있어야 합니다. 메쏘드 명세를 쉽게 기술하기 위해서 파생 필드를 정의하는 것이 유용할 때도 있습니다. 파생 필드를 정의할 때는 그것이 파생 필드라는 것을 표시하고, 다른 필드로부터 어떻게 파생시켰는지를 씁니다. 어떤 명세 필드는 명세 불변량이 있어서 가질 수 있는 값이 제한됩니다. 이 경우에는 명세 불변량을 일일이 열거해야 합니다.
Method Specifications. 모든 public 메쏘드, public클래스, 복잡한 private 메쏘드는 명세 주석을 포함해야 합니다. 메쏘드 명세는 이 메쏘드를 사용하기 전에 먼저 갖춰야 하는 조건, 이 메쏘드를 수행하면 변경되는 것, 발생 가능한 예외, 기타 효과, 반환값 등 specifications handout 에 기술돼 있는 사항을 포함합니다.
구현 단계 주석
구현시 참고 사항. 클래스 주석은 다음과 같은 내용을 포함해야 합니다. (이것들은 문서의 설계란 중 실행시간 구조 에도 나올 수 있습니다) 여기에서는 '표현'과 '구현'이라는 용어를 혼용합니다.
- 추상화 함수: 명세 필드를 표현 필드를 이용하여 정의합니다. 이것은 ADT class에만 필요하고 예외나 몇몇 GUI 도구 등에는 필요하지 않습니다.
- 구현 불변량(representation invariant, RI): RI는 구현이 있는 클래스에 필요합니다. (interface나 대부분의 예외에는 필요하지 않습니다) We strongly recommend that you test invariants in a checkRep() method where feasible. 어떤 것이 null이 될 수 있는지 없는지 주의하여야 합니다.
- 복잡한 클래스라면 구현 선택(구현 원칙이라고도 함)에 대한 설명을 답니다. 어떤 trade-off가 있었고, 어떤 구현이 왜 선택되었으며 다른 방법을 사용하지 않은 이유는 무엇인지 설명합니다.
Runtime assertions. 이것들은 현명하게 다루어야 합니다. runtime assertion을 이용하여 어떻게 코드의 질을 높이는지 Writing Solid Code by Steve Maguire, Microsoft Press, 1995. 라는 책에서 다루고 있습니다. 번역서로 버그 안녕이라는 책이 있습니다.
Comments. 여러분은 코드에 주의 깊고 세련되게 주석을 달아야 합니다. 스타일에 대해서는 Java Code Convention과 이 handout 을 참고하는 것이 좋습니다. 주석 스타일이나 일반적인 프로그래밍에 대해서 다루는 책으로는 The Practice of Programming by Brian W. Kernighan and Rob Pike, Addison-Wesley, Inc., 1999. 라는 책이 있습니다. 번역서로 프로그래밍의 모든 것이라는 책이 나와 있습니다. 또는 이곳 에서 맛을 볼 수 있습니다.
참고사항
이 문서는 MIT의 6.170 소프트웨어 공학 실습 강좌가 원 출처로 SNU의 2003년 1학기 4190.102A 컴퓨터 프로그래밍 강좌에서 발견하고 내용이 좋다고 판단하여 옮겨 왔습니다. 번역하면서 대부분은 원문의 의미를 살리려고 하였으나 일부 자료구조 강좌에 맞게 수정하거나 덧붙인 부분이 있습니다. 전혀 저작권 허락을 받고 한 일이 아니기 때문에 자료구조 수강생만 보시기 바랍니다. 오역이 무수히 많을 것이므로 지적해 주시면 감사하겠습니다. 원문은 여기 에서 보실 수 있습니다.- 위에도 써 놓았지만 이것은 문서화 도움글일 뿐 반드시 이 형식대로 맞추어야 하는 것은 아닙니다. 여기에서 중요하다고 하여도 불필요한 내용은 과감히 빼고, 아무런 언급이 없어도 필요한 내용은 넣어야 합니다. 보고서는 프로그램을 이해하는데 도움을 주기 위해서 쓰는 것입니다.
- 1, 2, 4번은 자료구조 보고서에서 중요하게 여길 항목입니다. 그런데 3번 등 몇몇 항목은 소프트웨어 공학 강좌에 맞춰져 있으므로 자료구조 보고서에 무리하게 적용할 필요는 없습니다.
- 영어 원문을 그대로 남겨놓은 곳은 자료구조 보고서를 작성할 때는 읽을 필요가 없는 부분입니다. 하지만 일반적인 소프트웨어 프로젝트 보고서를 쓸 때는 읽어보는 것이 좋습니다.
MIT 6.170 home page로 가기.
SNU 4190.204 home page로 가기.
이 한글 문서에 문제가 있거나 질문할 것이 있으면 조교에게 연락 주세요.
최종 수정일 : 2005년 9월 14일
