[初心者适用]如何为代码编写基本的文档
事先声明一下,这篇文章是为完全没有任何文档编写经验,并且正在使用Visual Studio的同学们准备的,不一定适用于老鸟以及其他IDE爱好者 🙂
Ok, alpha版本的一个严重的问题便是,我们没有任何的文档积累;所以在Beta版本的开发中,PM准备彻底消灭这种无文档的编码风格。
既然要让大家写文档,那么总该有个文档规范吧!理论性的东西我就不多讲了,这里我就讲一个“南七规范”——简单实用,不用费脑子。
南七规范 v1.0
不知道提到“文档”,同学们首先会想到什么东西——不过我估计大概是这样的风格——工程里面有一个doc目录,然后里面有各种不同开发人员维护的xxx.txt文件(或者微软式xxx.doc);诚然,有很多工程的文档组织形式就是这样的,但是这样做也有缺点,就是文档可能一旦被写出来就落后于代码了——离代码太远。还有一点就是分开维护的文档可能覆盖面太窄——代码中会出现很多没有在文档中提到的方法。
所以在这里向大家介绍另外一种维护文档的方法——注释法(名字是我自己发明的,不要打我)。意思是说,程序员只需要在每个函数(或者类)开始之前加上一段特殊格式的注释,然后就可以用专门的工具扫描整个代码树然后转换成按照架构组织好的(带有多种目录,甚至还可以搜索)html或pdf文档。
这种方法的优点在于,当一个方法被重构的时候,程序员可以轻而易举地修改文档,做到二者同步,而且如果保持每天都把文档给Build出来的话,可读性又很高。
我们的南七规范规定——必须给每个函数加上文档,所以在每个函数前面,都必须写一份注释。
上个例子吧。
///<summary>
/// Initialize the resources, and starts a new game.
///</summary>
///<param name="songID">The ID of selected song.<remarks>The track selector should make sure
/// that this id is within [0..SongCount-1], otherwise the game will crash.</remarks></param>
///<param name="level">The difficulty level, cound be 0(easy) or 1(hard)</param>
void StartGame(int songID,int level)
{
SoundGame.gps = new GamePlayScreen();
SoundGame.gps.Layer = 1;
GamePlayScreen.selectedSongID = songID;
GamePlayScreen.selectedSongLevel = level;
GamePlayScreen.startGameTime = TimeSpan.FromSeconds(-2);
ScreenManager.AddScreen(SoundGame.gps, null);
SoundGame.gps.InitializeGameLoop();
}
注意代码上面的那段注释,特殊之处在于普通注释都是两道杠,这个文档注释是三道杠,尽显尊贵。看到这里大家可能会说,麻烦!我告诉你,一点都不麻烦,只要你是在使用Visual Studio,那么你把光标停在函数头的前面,按一个三道杠——啪,自动补出来了,剩下的工作就是往里面填入内容而已!
聪明的同学们可能已经观察出来了——三道杠里面套的不就是一些XML形式的结构么?(再不明白的话,就像HTML一样)于是就挨个填内容吧——下面来几个裸按三道杠补出来的样板做示范——
///<summary>
///
///</summary>
///<param name="position"></param>
///<param name="tag"></param>
private void AddButton(Rectangle position,int tag)
{
TransparentButton tbutton = new TransparentButton(position,tag, this);
buttonList.Add(tbutton);
}
这便是在任意一个函数前面按下三道杠之后自动补全的结果。可以看到整个XML结构分为两个部分,一个叫summary,另一个是一堆param。
summary部分是对这个函数的作用,行为的描述,我的建议是,这里的描述要像说明书一样——你在写注释的时候就要假设有个十万个为什么正在问你,这个函数应该怎么用,输入什么,吐出来什么,副作用是什么——但是不要牵扯到太多内部实现的细节——什么把XXX对象加入到_YYY队列中——这明显不是说明书应该做的事情,要想弄清楚这些事情,最好的方式是读代码(相信我,这种情况下看代码比看注释清楚又高效)
于是我们为AddButton函数填入如下文档:
///<summary>
/// Register a button to the system, so that it will be displayed and handled on the game screen.
///</summary>
///<param name="position">The position description rectangle of the button.</param>
///<param name="tag">The global-unique ID of the button.</param>
private void AddButton(Rectangle position,int tag)
{
TransparentButton tbutton = new TransparentButton(position,tag, this);
buttonList.Add(tbutton);
}
接下来再来看一份糟糕一点的文档:
///<summary>
/// Add a TransparentButton to the buttonList
///</summary>
///<param name="position">Position.</param>
///<param name="tag">The tag of the button.</param>
private void AddButton(Rectangle position,int tag)
{
TransparentButton tbutton = new TransparentButton(position,tag, this);
buttonList.Add(tbutton);
}
为什么说它糟糕?第一,它有很多内部实现,现在看着代码可能感觉不出来,但是当这份文档最终编译成pdf之后就能体会到这种痛苦了——文档阅读者根本不明白你在说什么(否则为什么他不直接去看代码呢?)第二,定义不清晰——用Position解释Position是废话;”The tag of the button”最终没有解释Tag是个什么玩意。
希望这样介绍一下能让同学们明白好的文档和差的文档有什么区别。 🙂
另外补充一点,XML结构的文档实际上是可以嵌套的,例如你可以在summary里面嵌套code
///<summary>
///请看代码
///<code>
/// 床前明月光();
/// 疑是地上霜();
/// 举头望明月();
/// 低头思故乡();
///<code/>
///</summary>
等等,具体你在三道杠内部打一个<然后能够用的东西就会被补全出来了。注意这里嵌套的结构实际上的作用是对格式进行指定,例如<code>段会用等宽字体,等等。
Ok,ok finally假设大家都这样去写码了,接下来怎么办?这里简单提一下一个叫doxygen的开源工具。doxygen正是前文提到的那个能自动扫描代码树并且生成html或者latex(于是就可以编译成pdf)文档的工具,这个工具太出名了,以至于随便放狗一搜就能得到其使用方法,这里我就不多讲了。 🙂 总之就这样几个步骤——1. doxygen -g得到一个配置文件样本 2.稍微修改一下,例如是否递归找文件 3.doxygen doxyFile 4.验收你的漂亮的文档网页或者PDF。
基本上就讲这么多了,祝大家好运 🙂