라이브러리 작성자를 위한 정보성 문서 작성 모범 사례
라이브러리 작성자를 위한 정보성 문서 작성 모범 사례
라이브러리에 제공하는 문서는 매우 중요해요. 문서가 사용자가 라이브러리를 조사할지, 프로젝트에 채택할지, 어려움을 만났을 때 끝까지 시도할지를 결정할 수 있거든요. 오늘날 개발자는 언어, 라이브러리, 프레임워크, 플랫폼 사이에서 전례 없이 많은 선택지를 마주해요. 그래서 사용자를 끌어들이고 정보를 주는 게 핵심이에요. 그렇지 않으면 사용자는 다른 선택지를 쫓아갈 테니까요.
라이브러리의 가장 초기 버전에서는 사용자 피드백이 거의 없을 거예요. 다행히도 문서를 만들고 다듬는 일은 프로젝트의 품질을 크게 높여주는 피드백 루프 역할을 해요. 그래서 문서 작성은 결코 부담으로 여겨져서는 안 되고, 라이브러리를 만들 때 우선순위에서 밀려나서도 안 돼요.
효과적인 문서는 사용자에게 정보를 줄 뿐 아니라 라이브러리의 개발과 개선을 이끌어요. 문서가 개발 과정을 안내할 수 있는 몇 가지 핵심 방식을 소개할게요:
- 라이브러리가 무엇을 하는지, 누가 사용해서 이익을 얻을지, 대안 접근법에 비해 어떤 장점이 있는지 몇 단락으로 설명할 수 있어야 해요. 그럴 수 없다면 프로젝트의 범위와 목표를 다시 생각해 봐야 해요.
- 잠재적인 사용자를 최대한 빨리 실행할 수 있게 해 주는 "시작하기(Getting Started)" 가이드를 만들 수 있어야 해요. 무엇이 '빠른' 것인지는 문제 도메인에 따라 다르지만, 다른 플랫폼의 비슷한 라이브러리와 비교해 볼 수 있어요. 이 가이드는 사용자를 피드백 루프에 연결해서, 항상 신뢰할 수 있는 결과를 내면서 점점 더 쉽고 빨라지게 해야 해요. 이 가이드를 만들면 사용자의 진행을 막을 수 있는 복잡도의 급격한 증가(절벽 지점, cliff edge)를 식별하는 데도 도움이 돼요.
- 함수를 문서화하는 행위 자체가 모든 엣지 케이스를 고려하게 만든다는 점도 있어요. 유효한 입력 범위, 던져질 수 있는 예외, 작업이 늘어날 때 성능이 어떻게 저하되는지 같은 것들이죠. 이는 함수 시그니처와 내부 구현의 개선으로 이어지는 경우가 많아요.
- 라이브러리 초기화에 필요한 코드가 항상 작업 수행에 필요한 코드를 압도한다면, 설정 옵션을 다시 생각해 보세요.
- 표준 옵션으로 기본 작업을 수행하는 명확한 예시를 만들 수 없다면, 일상 사용을 위해 API를 최적화하는 걸 고려해 보세요.
- 실제 데이터 소스와 온라인 서비스를 쓰지 않고도 라이브러리를 테스트하는 방법을 보여줄 수 없다면, 네트워크(그리고 일반적으로 외부 세계)에 접근하는 컴포넌트에 대한 테스트 더블(test double)을 제공하는 걸 고려해 보세요.
라이브러리에 대한 문서를 빨리 제공할수록, 실제 사용자가 빨리 테스트할 수 있어요. 이 테스트에서 나온 피드백을 설계 개선에 쓸 수 있죠.
출처: Best practices for library authors to create informative documentation
본문
포괄적인 문서 제공하기
라이브러리는 사용자가 최소한의 노력으로 채택할 수 있도록 충분한 문서를 제공해야 해요. 이 문서에는 다음이 포함되어야 해요:
- 시작하기 가이드
- API에 대한 심층 설명
- 흔한 사용 사례에 대한 더 긴 예시(레시피라고도 함)
- 블로그, 기사, 웨비나, 컨퍼런스 발표 같은 리소스로의 링크
시작하기 가이드는 라이브러리가 지원 빌드 시스템과 어떻게 통합되는지 다뤄야 해요. 가장 흔히 쓰이는 엔티티에 대한 간단한 설명과, 사용 방법에 대한 작은 예시를 포함해야 해요. 라이브러리가 외부 세계와 상호작용하는 지점마다 환경을 설정하는 데 필요한 단계와 그 단계가 성공적으로 완료되었는지 확인하는 방법을 지정해야 해요. 필요한 단계가 없다면 그 사실을 명시적으로 밝혀야 해요.
가능하면 지원하는 라이브러리 버전마다 문서의 별도 버전을 제공하세요. 이렇게 하면 사용자가 너무 오래되었거나 너무 최신인 정보를 보는 걸 막을 수 있어요. 불가능할 때는, 재설계된 API 부분과 관련된 문서 섹션을 명확히 표시하세요.
사용자 페르소나 만들기
의도한 대상을 분명히 이해하지 않고 문서를 만들고 평가하는 것은 어려워요. 문서를 읽을 사용자 유형별로 여러 페르소나(persona)를 정의하는 것이 도움이 될 수 있어요.
사용자가 작업해야 하는 기존 소프트웨어 스택 같은 제약을 고려하세요. 문서 검토자는 이런 페르소나를 채택해서 결론을 더 의미 있게 만들 수 있어요.
사용자에 대한 구체적인 정보가 부족할 때는 비관적으로 가정하는 게 최선이에요. 예를 들어 Kotlin의 최신이거나 가장 진보된 기능에 대한 전문성을 가정하지 마세요. 코드 예시는 최대한 단순하게 유지하세요.
페르소나는 특히 시간, 예산 제약, 비밀 유지 계약 때문에 실제 사용자를 상담할 수 없을 때 유용해요. 시간이 지나 사용자를 더 잘 이해하게 되면, 페르소나를 실제 필요에 더 정확히 맞게 다듬으세요.
가능하면 예시로 문서화하기
예시를 통한 문서화(documentation by example)는 사용자에게 기본 개념을 설명하는 가장 비용 효율적인 방법 중 하나예요. 가능하면 현재 다루는 주제나 개념을 설명하거나 보여주는 간단하고 명확한 코드 예시를 제공하세요.
KDoc 문서 형식은 문서 주석에서 Markdown을 이용한 인라인 마크업을 쓸 수 있게 해 줘요. 주석에 인라인 코드 스니펫을 사용해서 API 사용법을 보여주세요. 예시는 코루틴 라이브러리 테스트 디스패처의 소스 코드와 렌더링된 문서를 참고하세요.
이런 예시를 제공하면 예상 입력, 가능한 출력, 실패 모드에 대한 긴 설명을 쓸 필요가 없어져요. 다만 각 예시의 맥락과 그것이 관련된 상황이 명확해야 해요. 주석 없는 샘플 프로그램 폴더를 제공하는 것만으로는 문서가 아니에요.
API를 철저히 문서화하기
지원하는 모든 API 진입점은 KDoc으로 문서화해야 해요.
Kotlin의 문서 엔진인 Dokka는 기본적으로 출력에 공개 선언만 포함해요. 단순성(Simplicity) 섹션에서 논의한 것처럼, 공개 API를 최소화하고 사용자가 접근하길 원하지 않는 공개 진입점을 제거해야 해요. 사용자로부터 숨길 수 없어서 접근성을 제어할 수 없는 API가 있다면, suppress 지시어로 문서에서 제외하세요.
진입점의 설명은 함수가 무엇을 하는지에 대한 명확하고 높은 수준의 설명으로 시작하세요. 시그니처를 자연어로 그대로 옮겨 적는 건 피하세요.
예를 들어 "String을 받아 Connection을 반환한다"라고 말하는 대신, "입력 문자열이 가리키는 데이터베이스에 연결을 시도해서, 성공하면 Connection을 반환하고 그렇지 않으면 ConnectionTimeoutException을 던진다"라고 하는 게 낫죠.
각 입력의 예상 값과 입력이 다를 때의 동작을 지정하세요. 유효한 값의 범위와 유효하지 않은 값이 주어졌을 때 무슨 일이 일어나는지 설명해요. 예를 들어 문자열 입력이 URL이어야 한다면, 문자열이 비었을 때, 유효하지 않을 때, 지원하지 않는 프로토콜을 쓸 때, 존재하지 않는 위치를 가리킬 때 어떻게 되는지 설명하세요.
API 진입점이 던질 수 있는 모든 예외를 문서화하세요. 일반 설명에서는 실패 조건을 다루고, 예외 섹션은 자세한 정보를 위해 남겨두세요. 이렇게 하면 가독성이 좋아지고 독자가 집중할 수 있어요. 대신 이 정보를 일반 설명에 자연스럽게 포함하세요. 가능하면 사용 예시를 제공하는 것도 사용자가 API를 올바르게 사용하는 법을 이해하는 데 도움이 돼요.
참고: 문서의 명확성과 효과를 높이려면 기술 문서 작성(technical writing)을 배워보는 걸 권장해요. Google의 이 강좌(1부와 2부) 같은 자료를 살펴보는 것도 좋아요.
람다 파라미터 문서화하기
API 진입점이 람다를 받을 때, 사용자는 라이브러리가 사용자를 대신해 실행할 어떤 기능을 제공하고 있는 거예요. 이것은 최소한 두 영역에서 추가 문서가 필요해요.
첫째, 람다가 예외를 던지면 어떻게 되는지 문서화하세요. 다음 질문을 다루는 걸 고려해 보세요:
- 즉시 실패를 일으킬까, 람다가 반복적으로 호출될까, 아니면 대체(fallback) 동작이 있을까?
- 호출하는 함수가 종료해야 한다면, 람다에서 던져진 예외를 다시 던질까, 아니면 다른 예외를 던질까?
- 예외가 다르다면, 원래 예외를 포함할까?
또한 함수가 inline으로 선언되지 않았다면, 동시성과 관련된 특별한 동작을 문서화하세요. 다음이 다뤄지는지 확인하세요:
- 람다가 호출자와 같은 스레드에서 호출될까?
- 람다가 호출자와 같은 스레드에서 호출되지 않는다면, 어떤 스레드(또는 스레드 풀)에서 호출될까?
- 람다의 여러 복사본이 병렬로 실행될 수 있을까?
- 그 스레드를 사용하는 다른 작업이 무엇일까?
- 사용자가 라이브러리가 사용할 스레드를 지정할 수 있을까?
- 여러 람다가 호출되는 곳에서, 시퀀싱에 대해 어떤 보장이 제공될까?
문서에서 명시적 링크 사용하기
API 진입점이 라이브러리의 다른 기능과 완전히 독립적인 경우는 매우 드물어요. 일반적으로 호출은 특정 순서로 이뤄져야 하고, 특정 작업을 수행하는 여러 옵션이 있으며, 관련 작업을 수행하는 진입점은 비슷한 방식으로 사용돼요. 예를 들어 format과 parse 같은 함수는 서로를 거울처럼 비춰요.
@see 태그나 내부 링크를 사용해서 이런 관계를 문서에서 명시적으로 만들어 보세요. 이렇게 하면 독자가 정보를 함께 묶어(chunk) 더 잘 통합된 라이브러리의 정신적 지도를 만들 수 있어요.
가능하면 자기 완결적이 되기
입력이 무엇이 유효한지 설명할 때, W3C, IEEE, Unicode Consortium 같은 기관이 만든 관련 표준을 그냥 언급하고 싶어질 수 있어요. 이런 링크를 제공하는 건 도움이 될 수 있지만, 공백 문자의 집합 같은 기본 정보를 알아내려고 독자가 외부 명세까지 찾아보게 강제해서는 안 돼요.
가능한 한 문서는 자기 완결적(self-contained)이어야 해요. 사용자가 각 API 진입점의 전형적인 사용법을 이해할 수 있을 만큼 충분한 정보를 제공해야 해요. 흔한 사용에서는 일어나지 않을 엣지 케이스에 대해서는 사용자를 외부 문서로 안내할 수 있어요.
간단한 언어 사용하기
문서를 만들 때는 간단하고 명확한 언어를 쓰는 것이 중요해요. 이렇게 하면 영어가 모국어가 아닌 사람을 포함한 전 세계 사용자가 내용에 접근할 수 있어요. 독자를 혼란스럽게 할 수 있는 복잡한 단어, 전문 용어, 라틴어 표현, 관용구는 피하세요. 대신 직관적인 언어와 간결한 문장을 사용하세요.
간단한 영어는 필요할 때 문서를 번역하기도 더 쉽게 만들어요. 명확하고 모호함이 없는 텍스트는 오해의 위험을 줄이고 전반적인 가독성을 높여요.
더 알아보기
- 심적 복잡성 최소화하기 — Minimizing mental complexity 페이지
- 하위 호환성 유지하기 — Backward compatibility
- 멀티플랫폼용 Kotlin 라이브러리 만들기