Docstring
Python에서는 언어 차원에서 문서화를 위해 docstring이라는 기능을 제공합니다.
기본적으로 그 내용은 PEP-257에서 명세하는 규칙에 따라 주석을 작성하면, 해당 주석이 달린 객체의 __doc__
attribute로 주석의 내용을 읽을 수 있도록 하는 것입니다.
def hello():
"""
Print greeting message in console
"""
print("Hello World")
print(hello.__doc__) # Print greeting message in console
경험적으로 이 기능은 REPL이나 IPython, Jupyter Notebook 등과 같이 인터프리터에 직접 명령을 입력하는 상황에서 유용한 것 같습니다. IDE 지원 없이도, 라이브러리의 사용법을 쉽게 알 수 있으니까요.
나쁜 아이디어
그러나 __doc__
attribute를 기반으로 API 문서를 생성하는 건 좋은 생각이 아닌 것 같습니다. __doc__
attribute에 접근하기 위해서는 우선 docstring이 포함된 코드를 실행(evaluate)해야 하기 때문입니다.
- 이렇게 문서화를 위해 코드를 실제 런타임에서 실행하는 것은 일반적인 방법도 아니고1,
- 문서를 생성하는 작업이 의도치 않은 side-effect를 발생시킬 여지도 있습니다.
- 사용하는 라이브러리나 코드가 작성된 방식에 따라서, 어플리케이션을 시작하기 위해서 추가적인 설정을 작성하고 관리해야할 수도 있습니다2.
- 대부분의 경우 성능 측면에서도 좋지 않은 방법입니다3.
독립적으로 실행되지 않는 NumPy나 Pandas 같은 라이브러리에서는 괜찮을지 모르겠지만, 런타임에 다양한 의존성이 주입되고 초기화 동작이 실행되는 서버 어플리케이션에서는 위와 같은 문제점들에 부딪힐 수밖에 없습니다.
안타깝게도, Python 생태계에서는 런타임에서 __doc__
attribute를 사용하는 방식이 널리 쓰이고 있습니다. 가장 대표적인 sphinx-apidoc, mkdocstrings 두 라이브러리가 모두 그렇습니다.
다른 아이디어
다행히 다른 접근 방식을 택한 라이브러리도 있습니다. Pydoc-Markdown은 lib2to3
를 사용해서 코드를 정적으로(statically) 분석하고 문서를 생성합니다.
아쉬운 점이 있다면, lib2to3
는 그 목적 상 deprecate가 예정되어 있다는 점입니다.
lib2to3 - 2to3’s library
Deprecated since version 3.10: Python 3.9 will switch to a PEG parser (see PEP 617), and Python 3.10 may include new language syntax that is not parsable by lib2to3’s LL(1) parser. The lib2to3 module may be removed from the standard library in a future Python version. Consider third-party alternatives such as LibCST or parso.
사실 Pydoc-Markdown에서 개인적으로 아쉬웠던 점은 한 가지 더 있습니다. MkDocs, Hugo, Docusaurus와의 연동을 지원하긴 하지만, 기본적으로 각 문서화 도구의 설정을 Pydoc-Markdown가 생성하고 필요한 동작을 대신 수행하는 구조를 갖고 있습니다. 이러한 설계는 (지향하는 철학의 차이라고 생각하긴 하지만) 저는 개인적으로 선호하지 않습니다.
사용하려고 하는 문서화 도구의 생태계를 온전히 활용하기도 쉽지 않고, 문서화 도구의 인터페이스가 변경되면 사용이 어려워질 수도 있다는 점에서 future-proof가 되지 않기 때문입니다. Python 외의 다른 언어로 작성된 코드의 문서를 함께 생성하기도 쉽지 않습니다.
대안
그래서 저는 새로운 라이브러리를 만들기로 했습니다. mkdocs-yaarg-plugin을 소개합니다.
yaarg는 아래와 같은 특징과 장점이 있습니다.
- Python 코드를 정적으로 파싱해서 문서를 생성합니다.
- 언어에 대해 독립적(language agnostic)입니다.
- 우선은 Python을 지원하지만, 다음으로는 JSDoc을 지원할 예정입니다.
- 이러한 확장을 염두에 두고 유연한 구조로 개발되었습니다.
- 생성되는 문서의 형식에도 특별한 제약을 두고 있지 않기 때문에, 유효한 마크다운이기만 하면 되기 때문에 해당 언어의 생태계에 이미 있는 도구를 재사용하기 쉽습니다.
- 애초에 마크다운에는 HTML 코드를 그대로 사용할 수 있기 때문에 기존 도구가 꼭 마크다운 출력을 지원할 필요도 없습니다.
아직은 MVP 수준의 기능밖에 없지만, 지금 일하고 있는 팀의 상당히 큰 코드베이스에 적용해서 큰 문제 없이 사용하고 있습니다.