文档是开发人员经常忽略的工作,有时也被管理人员忽略。这通常是由于开发周期结束时缺乏时间,以及人们认为自己不擅长写作的事实。其中有些确实很糟糕,但大多数都能够生成良好的文档。
在任何情况下,结果都是由匆忙编写的文档组成的杂乱无章的文档。开发人员最讨厌做这种工作。当现有文档需要更新时,情况会变得更糟。许多项目只是提供了糟糕的、过时的文档,因为经理不知道如何处理这些文档。
但是,在项目开始时设置文档过程,并将文档当作代码模块来处理,这使得文档编制更加容易。当遵循一些规则时,写作甚至可以变得有趣。
本章提供了一些开始记录项目的技巧:
- 总结最佳实践的七条技术写作规则
- StructuredText primer,它是大多数 Python 项目中使用的纯文本标记语法
- 构建良好项目文档的指南
编写好的文档在很多方面都比编写代码容易。大多数开发人员认为这很难,但是通过遵循一组简单的规则,它变得非常容易。
我们在这里谈论的不是写一本诗集,而是一篇可以用来理解设计、API 或构成代码库的任何内容的综合文本。
每一个开发者都能生产出这样的材料,本节提供了七条规则,适用于所有情况:
- 分两步写作:专注于想法,然后回顾和塑造你的文本。
- 针对读者:谁来读?
- 使用简单的风格:保持笔直和简单。使用好语法。
- 限制信息范围:一次介绍一个概念。
- 使用真实的代码示例:“Foos”和“bar”应该避免。
- 用一种轻而充分的方法:你不是在写一本书!
- 使用模板:帮助读者养成习惯。
这些规则大多是从 Andreas Rüping 的《敏捷文档:为软件项目生成轻量级文档的模式指南》、Wiley中得到启发和改编的,这本书专注于在软件项目中生成最佳文档。
彼得·肘部在牛津大学出版社的*著作《用力量写作:掌握写作过程的技巧》*中解释说,任何人几乎不可能一次写出完美的文本。问题在于,许多开发人员编写文档,并试图直接写出一些完美的文本。他们在这项练习中取得成功的唯一方法是在每两句话后停止写作,把它们读回,并做一些更正。这意味着他们同时关注文本的内容和风格。
这对大脑来说太难了,结果往往不如预期的好。在对文本的含义进行全面思考之前,我们花费了大量的时间和精力来润色文本的风格和形状。
另一种方法是放弃文本的风格和组织,专注于其内容。所有的想法都写在纸上,不管它们是怎么写的。开发人员开始编写一个连续的流,当他或她犯语法错误时,或者对于与内容无关的任何事情,都不会暂停。例如,只要把想法写下来,句子是否勉强可以理解并不重要。他或她只是写下他想对一个粗略的组织说些什么。
通过这样做,开发人员将注意力集中在他或她想说的话上,并且可能会从他或她脑海中获得比他或她最初认为的更多的内容。
自由写作的另一个副作用是,与主题没有直接关系的其他想法很容易进入大脑。一个好的做法是,当它们出现时,把它们写在第二张纸或屏幕上,这样它们就不会丢失,然后回到主要的文字上。
第二步是重读全文并加以润色,以便大家都能理解。润色文本意味着增强其风格,纠正其错误,稍微重新组织它,并删除它所拥有的任何冗余信息。
当专门用于编写文档的时间有限时,一个好的做法是将这段时间分成两半,一部分用于编写内容,另一部分用于清理和组织文本。
关注内容,然后关注风格和清洁度。
在撰写内容时,作者应该考虑一个简单的问题:谁来阅读?
这并不总是显而易见的,因为技术文本解释了一个软件是如何工作的,并且通常是为每个可能获得和使用代码的人编写的。读者可以是正在寻找问题的适当技术解决方案的研究人员,也可以是需要用它实现功能的开发人员。设计师也可以从架构的角度来阅读它,以了解包是否符合他或她的需求。
好的文档应该遵循一个简单的规则,每个文本应该只有一种阅读器。
这种哲学使写作更容易。作者确切地知道他或她所面对的是什么样的读者。他或她可以提供简明、准确的文档,而不是含糊地针对所有类型的读者。
一个好的做法是提供一个小的介绍性文本,用一句话解释文档的内容,并将读者引导到适当的部分:
Atomisator is a product that fetches RSS feeds and saves them in a database, with a filtering process.
If you are a developer, you might want to look at the API description (api.txt)
If you are a manager, you can read the features list and the FAQ (features.txt)
If you are a designer, you can read the architecture and infrastructure notes (arch.txt)通过以这种方式指导读者,您可能会生成更好的文档。
在你开始写作之前先了解你的读者群。
塞思·戈丁是营销领域最畅销的作家之一。您可能想阅读互联网(上免费提供的释放艾德病毒、哈切特书籍http://www.sethgodin.com/ideavirus/downloads/IdeavirusReadandShare.pdf )。
不久前,他在博客上做了一个分析,试图了解他的书为什么卖得这么好。他列出了市场营销领域的所有畅销书,并比较了每一本书中每句话的平均字数。
他意识到他的书每句话的字数最少(十三个字)。赛斯解释说,这个简单的事实证明,读者更喜欢简短的句子,而不是长而时髦的句子。
通过保持句子简短,你的写作将减少提取、处理和理解内容的脑力消耗。编写技术文档旨在为读者提供软件指南。这不是一个虚构的故事,应该更接近你的微波炉注意,而不是最新的斯蒂芬·金小说。
要记住的几个技巧是:
- 使用简单的句子。它们不应超过两行。
- 每一段最多由三句或四句话组成,表达一个主要思想。让你的文字呼吸。
- 不要重复太多。避免新闻风格的想法被反复重复,以确保他们被理解。
- 不要用几个时态。大多数时候,现在时态已经足够了。
- 如果你不是一个真正优秀的作家,就不要在课文中开玩笑。在一篇技术性的文章中要搞笑真的很难,很少有作家能掌握它。如果你真的想提炼一些幽默,把它放在代码示例中,你会很好的。
你不是在写小说,所以风格要尽量简单。
软件中有一个简单的不良文档的迹象,你正在寻找一些你知道存在于某处但你找不到的信息。在花了一段时间阅读目录之后,您开始尝试几个单词组合来 grep 文件,但无法获得您想要的内容。
当作者没有按主题组织文本时,就会发生这种情况。它们可能提供大量的信息,但只是以整体或非逻辑的方式收集。例如,如果读者正在寻找应用程序的总体情况,那么他或她不必阅读底层的 API 文档。
为避免这种影响,段落应集中在给定章节的有意义标题下,全局文档标题应以简短的短语合成内容。
目录可以由所有章节的标题组成。
撰写标题的一个简单实践是问自己:“我要在谷歌上键入什么短语才能找到这个部分?”
富和酒吧都是坏公民。当读者试图理解一段代码如何与用法示例一起工作时,有一个不切实际的示例将使其更难理解。
为什么不使用一个真实的例子呢?通常的做法是确保每个代码示例都可以剪切并粘贴到实际程序中。
为了展示一个坏用法的例子,假设我们想展示如何使用parse()函数:
>>> from atomisator.parser import parse
>>> # Let's use it:
>>> stuff = parse('some-feed.xml')
>>> next(stuff)
{'title': 'foo', 'content': 'blabla'}更好的示例是,当解析器知道如何使用 parse 函数返回提要内容时,该函数作为顶级函数提供:
>>> from atomisator.parser import parse
>>> # Let's use it:
>>> my_feed = parse('http://tarekziade.wordpress.com/feed')
>>> next(my_feed)
{'title': 'eight tips to start with python', 'content': 'The first tip is..., ...'}这一细微的差别听起来可能有些过分,但实际上它使您的文档更加有用。读者可以将这些行复制到 shell 中,理解 parse 使用 URL 作为参数,并返回包含博客条目的迭代器。
当然,给出一个现实的例子并不总是可能或可行的。这对于非常通用的代码尤其如此。即使是这本书也很少出现名称上下文不重要的模糊foo和bar字符串。无论如何,你应该一直努力将这种不切实际的例子减少到最少。
代码示例应该可以在实际程序中直接重用。
在大多数敏捷方法中,文档不是第一公民。与详细的文档相比,制作工作正常的软件是最重要的。因此,正如 Scott Ambler 在其著作敏捷建模:极限编程和统一过程的有效实践**John Wiley&Sons中所解释的,一个好的实践是定义真正的文档需求,而不是创建一组详尽的文档。
例如,让我们看一个简单项目的示例文档——ianitor,它在 GitHub 上的下可用 https://github.com/ClearcodeHQ/ianitor 。它是一个帮助在 Consor service discovery 集群中注册进程的工具,因此它主要针对系统管理员。如果你看一下它的文档,你会发现这只是一个文档(T1 文件)。它只解释了它的工作原理和使用方法。从管理员的角度来看,这就足够了。他们只需要知道如何配置和运行该工具,没有其他人会使用ianitor。本文档通过回答一个问题来限制其范围,“如何在我的服务器上使用ianitor?”
维基百科上的每一页都是相似的。一边有一些框用来总结日期或事实。文档开头是一个目录,其中包含指向同一文本中锚的链接。最后总是有一个参考部分。
用户已经习惯了。例如,他们知道可以快速查看目录,如果没有找到他们要查找的信息,他们将直接转到参考部分,查看是否可以找到有关该主题的其他网站。这适用于维基百科上的任何页面。你学习了维基百科方式来提高效率。
因此,使用模板强制使用文档的通用模式,从而使人们能够更高效地使用模板。他们习惯了这种结构,知道如何快速阅读。
为每种文档提供一个模板也为编写者提供了一个快速的开始。
reStructuredText 也称为 reST(参考http://docutils.sourceforge.net/rst.html )。它是 Python 社区中广泛使用的一种纯文本标记语言,用于记录包。reST 的优点在于文本仍然可读,因为标记语法不会像 LaTeX 那样混淆文本。
以下是此类文件的示例:
=====
Title
=====
Section 1
=========
This *word* has emphasis.
Section 2
=========
Subsection
::::::::::
Text.reST 以docutils的形式出现,该软件包提供一套脚本,用于将 reST 文件转换为各种格式,例如 HTML、LaTeX、XML,甚至是 S5,Eric Meyer 的幻灯片放映系统(请参阅http://meyerweb.com/eric/tools/s5 )。
作者可以专注于内容,然后根据需要决定如何呈现内容。例如,Python 本身被记录到 reST 中,然后用 HTML 呈现以构建http://docs.python.org 和其他各种格式。
开始编写 reST 时应知道的最低要素是:
- 截面结构
- 列表
- 内联标记
- 文字块
- 链接
本节是对语法的快速概述。更多信息,请访问快速参考 http://docutils.sourceforge.net/docs/user/rst/quickref.html ,这是一个开始工作和休息的好地方。
要安装重构文本,请安装docutils:
$ pip install docutils例如,docutils包提供的rst2html脚本将在给定 reST 文件的情况下生成 HTML 输出:
$ more text.txt
Title
=====
content.
$ rst2html.py text.txt
<?xml version="1.0" encoding="utf-8" ?>
...
<html ...>
<head>
...
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>
<p>content.</p>
</div>
</body>
</html>文档的标题及其部分使用非字母数字字符加下划线。它们可以在上划线并加下划线,通常的做法是在标题上使用这种双重标记,并在章节中保留一个简单的下划线。
在章节标题下划线最常用的字符按以下优先顺序排列:=, -, _, :, #, +, ^。
当一个字符用于一个节时,它与它的级别相关联,并且必须在整个文档中一致地使用它。
考虑下面的代码,例如:
==============
Document title
==============
Introduction to the document content.
Section 1
=========
First document section with two subsections.
Note the ``=`` used as heading underline.
Subsection A
------------
First subsection (A) of Section 1.
Note the ``-`` used as heading underline.
Subsection B
------------
Second subsection (B) of Section 1.
Section 2
=========
Second section of document with one subsection.
Subsection C
------------
Subsection (C) of Section 2.图 1 重新构造转换为 HTML 并在浏览器中呈现的 DText
reST 为具有自动枚举功能的项目符号列表、枚举列表和定义列表提供可读的语法:
Bullet list:
- one
- two
- three
Enumerated list:
1\. one
2\. two
#. auto-enumerated
Definition list:
one
one is a number.
two
two is also a number.图 2 呈现为 HTML 的不同类型的列表
可以使用内联标记设置文本样式:
*emphasis*:斜体字**strong emphasis**:黑体字pyinline preformated:内联预格式化文本(通常为单间距,类似于终端)- ``a text with a link
_:只要文档中提供了超链接,就会替换为超链接(参见链接部分)
当您需要展示一些代码示例时,可以使用文字块。两个冒号用于标记块,这是一个缩进段落:
This is a code example
::
>>> 1 + 1
2
Let's continue our text不要忘记在::之后和块之后添加一个空行,否则将无法渲染。
请注意,冒号字符可以放在文本行中。在这种情况下,它们将替换为各种呈现格式的单个冒号:
This is a code example::
>>> 1 + 1
2
Let's continue our text如果不想保留单个冒号,可以在前导文本和::之间插入空格。在这种情况下,::将被解释并完全删除。
图 3 reST 中呈现为 HTML 的代码示例
只要文档中提供了文本,文本可以通过以两点开头的特殊行更改为外部链接:
Try `Plone CMS`_, it is great ! It is based on Zope_.
.. _`Plone CMS`: http://plone.org
.. _Zope: http://zope.org通常的做法是在文档末尾对外部链接进行分组。当要链接的文本包含空格时,必须用```py(倒勾)字符包围。
也可以通过在文本中添加标记来使用内部链接:
This is a code example
.. _example:
::
>>> 1 + 1
2
Let's continue our text, or maybe go back to
the example_.
```py
部分也是可以使用的目标:
Introduction to the document content.
First document section.
-> go back to Section 1_
# 建立文档
指导读者和作者的一个更简单的方法是为他们中的每一个人提供帮助和指导,正如我们在本章上一节所学到的那样。
从作者的角度来看,这是通过拥有一组可重用的模板以及一个描述如何以及何时在项目中使用它们的指南来实现的。它被称为**文档组合**。
从读者的角度来看,能够毫不费力地浏览文档,并习惯于高效地查找信息,这一点很重要。通过构建一个**文档景观**来完成。
## 建立投资组合
一个软件项目可以拥有多种文档,从直接引用代码的低级文档到提供应用程序高级概述的设计文档。
例如,Scott Ambler 在他的书*敏捷建模:极限编程和统一过程的有效实践**John Wiley&Sons*中定义了大量文档类型。他构建了一个从早期规范到运营文档的投资组合。甚至项目管理文档也包含在内,因此整个文档需求都是用一组标准化的模板构建的。
由于完整的投资组合与用于构建软件的方法密切相关,因此本章将只关注您可以根据特定需求完成的通用子集。建立一个有效的投资组合需要很长时间,因为它抓住了你的工作习惯。
软件项目中的一组常见文档可分为三类:
* **设计**:包括提供架构信息和底层设计信息的所有文档,如类图或数据库图
* **用法**:包括所有关于如何使用软件的文档;这可以是烹饪书、教程或模块级帮助的形式
* **操作**:提供如何部署、升级或操作软件的指南
### 设计
创建此类文档时,重要的一点是确保目标读者完全了解,并且内容范围有限。因此,设计文档的通用模板可以为编写者提供一个简单的结构和一些建议。
这种结构可能包括:
* 标题
* 著者
* 标签(关键字)
* 说明(摘要)
* 目标(谁应该读这个?)
* 内容(带图表)
* 对其他文件的参考
打印时,内容最多应为三到四页,以确保限制范围。如果它变得更大,则应将其拆分为多个文档或汇总。
该模板还提供了作者的姓名和标签列表,以管理其演变并简化其分类。这将在本章后面介绍。
reST 中的示例设计文档模板可以如下所示::Author: Document Author :Tags: document tags separated with spaces
:abstract:
Write here a small abstract about your design document.
.. contents ::
Explain here who is the target readership.
Write your document here. Do not hesitate to split it in several sections.
Put here references, and links to other documents.
### 用法
用法文档描述了如何使用软件的特定部分。本文档可以描述低级部分,如函数如何工作,也可以描述高级部分,如用于调用程序的命令行参数。这是框架应用程序文档中最重要的部分,因为目标读者主要是要重用代码的开发人员。
三种主要的文件是:
* **配方**:这是一个简短的文档,解释如何做某事。这类文档针对一个读者群,并侧重于一个特定主题。
* **教程**:这是一份分步文档,解释如何使用软件的一项功能。本文档可以参考配方,每个实例仅面向一个读者。
* **模块助手**:这是一个低级文档,解释模块包含的内容。例如,当您通过模块调用`help`内置程序时,可以显示此文档。
#### 配方
配方回答了一个非常具体的问题,并提供了解决方案。例如,ActiveState 在线提供了一个庞大的 Python 配方库,开发人员可以在这里描述如何用 Python 做一些事情(请参阅[http://code.activestate.com/recipes/langs/python/](http://code.activestate.com/recipes/langs/python/) 。这样一套与单个区域/项目相关的食谱通常被称为*食谱*。
这些食谱必须简短,结构如下:
* 标题
* 提交人
* 最后更新
* 版本
* 类别
* 描述
* 源代码(源代码)
* 讨论(解释代码的文本)
* 评论(来自网络)
通常情况下,它们只有一个屏幕长,不涉及太多细节。此结构完全符合软件的需要,并且可以在通用结构中进行调整,其中添加了目标读者,并用标签替换类别:
* 标题(短句)
* 著者
* 标签(关键字)
* 谁应该读这个?
* 先决条件(例如,要阅读的其他文档)
* 问题(简短描述)
* 解决方案(主文本,一个或两个屏幕)
* 参考资料(指向其他文件的链接)
日期和版本在这里没有用处,因为项目文档应该像项目中的源代码一样进行管理。这意味着处理文档的最佳方法是通过版本控制系统进行管理。在大多数情况下,这与用于项目代码的代码存储库完全相同。
配方的简单可重用模板如下所示::Author: Recipe Author :Tags: document tags separated with spaces
:abstract:
Write here a small abstract about your design document.
.. contents ::
Explain here who is the target readership.
Write the list of prerequisites for implementing this recipe. This can be additional documents, software, specific libraries, environment settings or just anything that is required beyond the obvious language interpreter.
Explain the problem that this recipe is trying to solve.
Give solution to problem explained earlier. This is the core of a recipe.
Put here references, and links to other documents.
#### 教程
教程的目的不同于食谱。它不是为了解决一个孤立的问题,而是描述如何一步一步地使用应用程序的功能。这可能比配方更长,并且可能涉及应用的许多部分。例如,Django 在其网站上提供了教程列表。*编写第一款 Django 应用程序,第 1 部分*(参考[https://docs.djangoproject.com/en/1.9/intro/tutorial01/](https://docs.djangoproject.com/en/1.9/intro/tutorial01/) 在几个屏幕中解释了如何使用 Django 构建应用程序。
此类文件的结构应为:
* 标题(短句)
* 著者
* 标签(单词)
* 说明(摘要)
* 谁应该读这个?
* 先决条件(例如,要阅读的其他文档)
* 教程(正文)
* 参考资料(指向其他文件的链接)
#### 模块助手
可以添加到我们集合中的最后一个模板是模块助手模板。模块帮助器引用单个模块,并提供其内容的描述以及使用示例。
一些工具可以通过使用`pydoc`提取文档字符串和计算模块帮助来自动构建此类文档,例如如 Epydoc(参见[http://epydoc.sourceforge.net](http://epydoc.sourceforge.net) )。因此,可以基于 API 自省生成广泛的文档。这种文档通常在 Python 框架中提供。例如,Plone 提供了一个[http://api.plone.org](http://api.plone.org) 服务器,用于保存模块帮助程序的最新集合。
这种方法的主要问题是:
* 没有对文档真正感兴趣的模块执行智能选择
* 文档可能会混淆代码
此外,模块文档提供了一些示例,这些示例有时涉及模块的几个部分,并且很难在函数和类的 docstring 之间进行划分。模块 docstring 可以通过在模块顶部写入文本来实现这一目的。但最终会产生一个由文本块而不是代码块组成的混合文件。当代码表示的长度小于总长度的 50%时,这相当令人困惑。如果你是作者,这是非常好的。但是当人们试图阅读代码(而不是文档)时,他们将不得不跳过 docstrings 部分。
另一种方法是在自己的文件中分离文本。然后可以通过手动选择来决定哪个 Python 模块将具有其模块帮助文件。然后可以将文档从代码库中分离出来,并允许它们过自己的生活,我们将在下一部分中看到。这就是 Python 的文档记录方式。
许多开发人员不同意文档和代码分离比 docstring 更好这一事实。这种方法意味着文档过程完全集成到开发周期中;否则它很快就会过时。docstrings 方法通过提供代码与其使用示例之间的接近性来解决此问题,但不会将其提升到更高的级别—可以作为普通文档的一部分使用的文档。
模块助手的模板非常简单,因为在编写内容之前,它只包含少量元数据。未定义目标,因为希望使用模块的是开发人员:
* 标题(模块名称)
* 著者
* 标签(单词)
* 所容纳之物
### 注
下一章将介绍使用 doctest 和模块助手的测试驱动开发。
### 操作
操作文档用于描述如何操作软件。考虑以下几点:
* 安装和部署文档
* 行政文件
* 常见问题(FAQ)文档
* 解释人们如何做出贡献、寻求帮助或提供反馈的文档
这些文档非常具体,但它们可能使用前面部分中定义的教程模板。
# 制作自己的投资组合
我们前面讨论的模板只是您可以用来记录软件的基础。随着时间的推移,您最终将开发自己的模板和文档制作风格。但是,始终要记住项目文档的轻量级但充分的方法:添加的每个文档都应该有一个明确定义的目标读者群,并且应该满足实际需要。不应该编写没有增加实际价值的文档。
每个项目都是独特的,并且有不同的文档需求。例如,使用简单的小型终端工具肯定只能使用一个`README`文件作为其文档环境。如果目标读者被精确地定义并一致地分组(例如,系统管理员),那么使用这种最小的单文档方法是完全好的。
另外,不要过于严格地应用提供的模板。作为示例提供的一些附加元数据在大型项目或严格形式化的团队中都非常有用。例如,标记旨在改进大型文档中的文本搜索,但在仅由少数文档组成的文档环境中不会提供任何价值。
此外,包括文档作者并不总是一个好主意。这种方法在开源项目中尤其值得怀疑。在这些项目中,您将希望社区也对文档做出贡献。在大多数情况下,无论是谁作出贡献,只要有必要,这些文件都会不断更新。人们倾向于将文档*作者*也视为文档*所有者*。如果每个文档都指定了作者,这可能会阻止人们更新文档。通常,版本控制软件提供的关于真实文档作者的信息比显式提供的元数据注释更清晰、更透明。真正推荐明确作者的情况是各种设计文档,特别是在设计过程严格形式化的项目中。最好的例子是包含 Python 语言增强建议的一系列 PEP 文档。
## 营造景观
上一节中构建的文档组合提供了文档级别的结构,但没有提供一种方法来对其进行分组和组织,以构建读者将拥有的文档。这就是 Andreas Rüping 所称的文档景观,指的是读者在浏览文档时使用的心理地图。他得出结论,组织文档的最佳方法是建立一个逻辑树。
换句话说,组成公文包的不同类型的文档需要在目录树中找到一个位置。作者在创建文档时,以及读者在寻找文档时,必须清楚地看到这个位置。
浏览文档时的一个很大的帮助是在每一个级别上的索引页,它可以驱动作者和读者。
构建文档环境分两步完成:
* 为制片人(编剧)建树
* 在生产者树上为消费者(读者)构建一棵树
生产者和消费者之间的这种区别很重要,因为他们在不同的地方以不同的格式访问文档。
### 制作人布局图
从制作人的角度来看,每个文档的处理与 Python 模块完全相同。它应该存储在版本控制系统中,并像代码一样工作。作家们并不关心他们的散文的最终外观,只要有,他们只想确保他们正在写一份文件,因此这是关于所涉及主题的唯一真相来源。存储在文件夹树中的重构文本文件可与软件代码一起在版本控制系统中使用,是为生产者构建文档环境的方便解决方案。
按照惯例,`docs`文件夹用作文档树的根目录:$ cd my-project $ find docs docs docs/source docs/source/design docs/source/operations docs/source/usage docs/source/usage/cookbook docs/source/usage/modules docs/source/usage/tutorial
请注意,树位于`source`文件夹中,因为`docs`文件夹将用作根文件夹,以便在下一节中设置专用工具。
在此基础上,可以在每个级别(根目录除外)添加一个`index.txt`文件,解释文件夹包含的文档类型,或总结每个子文件夹包含的文档。这些索引文件可以定义它们包含的文档列表。例如,`operations`文件夹可以包含可用的操作文档列表:This section contains operations documents:
− How to install and run the project − How to install and manage a database for the project
重要的是要知道,人们往往忘记更新这样的文档列表和目录。所以最好让它们自动更新。在下一小节中,我们将讨论一个工具,在许多其他特性中,它也可以处理这个用例。
### 消费者的布局
从消费者的角度来看,编制索引文件并以易于阅读且外观良好的格式呈现整个文档非常重要。网页是最好的选择,并且很容易从重构的文本文件生成。
**狮身人面像**[http://sphinx.pocoo.org](http://sphinx.pocoo.org) 是一组脚本和`docutils`扩展,可用于从文本树生成 HTML 结构。例如,这个工具用于构建 Python 文档,许多项目现在都在使用它来编制文档。在其内置功能中,它提供了一个非常好的浏览系统,以及一个轻量级但足够的客户端 JavaScript 搜索引擎。它还使用`pygments`呈现代码示例,这会产生非常好的语法亮点。
Sphinx 可以很容易地配置为与前面部分中定义的文档环境保持一致。可与`pip`作为`Sphinx`组件轻松安装。
开始使用狮身人面像最简单的方法是使用`sphinx-quickstart`脚本。此实用程序将与`Makefile`一起生成一个脚本,可用于在每次需要时生成 web 文档。它将以交互方式询问您一些问题,然后引导整个初始文档源代码树和配置文件。一旦完成,您可以随时轻松调整它。假设我们已经引导了整个 Sphinx 环境,我们希望看到它的 HTML 表示。这可以使用`make html`命令轻松完成:project/docs$ make html sphinx-build -b html -d _build/doctrees . _build/html Running Sphinx v1.3.6 making output directory... loading pickled environment... not yet created building [mo]: targets for 0 po files that are out of date building [html]: targets for 1 source files that are out of date updating environment: 1 added, 0 changed, 0 removed reading sources... [100%] index looking for now-outdated files... none found pickling environment... done checking consistency... done preparing documents... done writing output... [100%] index generating indices... genindex writing additional pages... search copying static files... done copying extra files... done dumping search index in English (code: en) ... done dumping object inventory... done build succeeded. Build finished. The HTML pages are in _build/html.

图 4 使用 Sphinx 构建文档的示例 HTML 版本–[http://graceful.readthedocs.org/en/latest/](http://graceful.readthedocs.org/en/latest/)
除了文档的 HTML 版本外,该工具还构建自动页面,如模块列表和索引。Sphinx 提供了一些`docutils`扩展来驱动这些功能。主要有:
* 建立目录的指令
* 可用于将文档注册为模块帮助器的标记
* 在索引中添加元素的标记
#### 在索引页上工作
Sphinx 提供了一个`toctree`指令,可用于在文档中插入目录,并链接到其他文档。每一行必须是一个文件及其相对路径,从当前文档开始。还可以提供 Glob 样式名称来添加多个与表达式匹配的文件。
例如,`cookbook`文件夹中的索引文件(我们之前在制作人的环境中定义过)可以如下所示:Welcome to the Cookbook.
Available recipes:
.. toctree:: :glob: *
使用此语法,HTML 页面将显示`cookbook`文件夹中可用的所有重构文本文档的列表。此指令可用于所有索引文件,以构建可浏览的文档。
#### 注册模块助手
对于模块助手,可以添加一个标记,使其自动列出并在模块的索引页面中可用:.. module:: db.session
The module session...
注意这里的`db`前缀可以用来避免模块冲突。Sphinx 将使用它作为模块类别,并将该类别中以`db.`开头的所有模块分组。
#### 添加索引标记
另一个选项可以通过将文档链接到条目来填充索引页:.. module:: db.session
.. index:: Database Access Session
The module session...
索引页中将添加两个新的条目`Database Access`和`Session`。
#### 交叉引用
最后,Sphinx 提供了一个内联标记来设置交叉引用。例如,到模块的链接可以这样做::mod:db.session
这里,`:mod:`是模块标记的前缀,``db.session``是要链接到的模块的名称(如之前注册的);请记住`:mod:`和前面的元素都是斯芬克斯在 StructuredText 中引入的特定指令。
### 注
斯芬克斯提供了更多的功能,你可以在其网站上发现。例如,*autodoc*功能是一个很好的选择,可以自动提取 doctest 来构建文档。参见[http://sphinx.pocoo.org](http://sphinx.pocoo.org) 。
## 文件构建和持续集成
从消费者的角度来看,Sphinx 确实提高了阅读文档的可读性和体验。如前所述,当它的某些部分与代码紧密耦合时,它特别有用,例如以剂量或模块辅助的形式。虽然这种方法确实更容易确保文档的源版本与文档中的代码相匹配,但并不保证文档读者能够访问最新的编译版本。
如果文档的目标读者对命令行工具不够精通,并且不知道如何将其构建为可浏览和可读的形式,那么仅有最少的源代码表示也是不够的。这就是为什么在提交/推送对代码存储库的任何更改时,自动将文档构建为消费者友好的表单非常重要。
托管使用 Sphinx 构建的文档的最佳方法是生成 HTML 构建,并将其作为静态资源与您选择的 web 服务器一起使用。Sphinx 提供了适当的`Makefile`来使用`make html`命令构建 HTML 文件。由于`make`是一个非常常见的实用程序,因此将此流程与[第 8 章](08.html "Chapter 8. Managing Code")、*管理代码*中讨论的任何连续集成系统进行集成应该非常容易。
如果你正在用 Sphinx 记录一个开源项目,那么通过使用**阅读文档**([可以让你的生活更轻松 https://readthedocs.org/](https://readthedocs.org/) )。这是一项免费服务,用于托管 Sphinx 开源 Python 项目的文档。该配置完全没有任何麻烦,并且非常容易与两种流行的代码托管服务集成:GitHub 和 Bitbucket。在实践中,如果您的帐户已正确连接,并且代码存储库已正确设置,那么只需单击几下即可在读取文档时启用文档托管。
# 总结
本章详细说明了如何:
* 使用一些规则来提高写作效率
* 使用重构文本,蟒蛇的乳胶
* 构建文档组合和环境
* 使用 Sphinx 生成有用的 web 文档
当记录一个项目时,最困难的事情是保持它的准确性和最新性。使文档成为代码存储库的一部分使它变得更容易。从这里开始,每次开发人员更改模块时,他或她也应该更改相应的文档。
在大型项目中,这可能非常困难,在模块的标题中添加相关文档的列表在这种情况下会有所帮助。
确保文档始终准确的补充方法是通过 doctest 将文档与测试结合起来。这将在下一章中介绍,该章介绍测试驱动的开发原则,然后介绍文档驱动的开发。


