更佳编程之路: 第二章_VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3858 | 回复: 0   主题: 更佳编程之路: 第二章        下一篇 
谁是天蝎
注册用户
等级:大元帅
经验:90210
发帖:106
精华:0
注册:2011-7-21
状态:离线
发送短消息息给谁是天蝎 加好友    发送短消息息给谁是天蝎 发消息
发表于: IP:您无权察看 2011-8-25 16:24:52 | [全部帖] [楼主帖] 楼主

从来没有文档太多这回事。清晰常常意味着重复。将您的代码看成是向世界展示的东西。世界上有许多人。您认为冗余的注释可能对某人大有用处。五年之后,当您添加新特性时,它甚至可能对

大有用处。

基本注释

编写程序时,使用良好的规划。不必事先确定每个细节,但是应该将程序分成几个组成部分,并且使用注释来填充间隙。

下列是我个人的编码风格。您可能不喜欢它,但是请客观地看待它,并且看看有什么可以为您及您的团队所用。

首先,考虑一下该注释的预期读者。尽量使注释足够清晰,以便第三方顾问领会。代码越复杂,就应该添加越多的注释以阐明目的。不要将注释放在以后再做;让它们成为您思考过程的一部分:问题、解决方案、注释,然后调试。在调试之前创建注释尤为重要。您自己代码中的注释将有助于更好和更快地调试。

有时不仅陈述问题的解决方案很有帮助,而且陈述问题本身也是很有帮助的。例如:

清单 1

# function: do_hosts
#
# purpose: to process every host in the /etc/hosts table and see if it
# resolves to a valid IP
#
# solution: read the list of hosts as keys in a hash, then go through
# the list of keys (hosts) and store the IP address for each host as
# the value for that key, or undef() if it doesn't resolve properly.
# Return a reference to the hash, or undef if the /etc/hosts file was
# not accessible.


推荐简化为:

清单 2

# function: do_hosts: process every host in the /etc/hosts table and
see if it
# resolves to a valid IP; return a reference to the hash (key=host,
# value=IP or undef), or undef if the /etc/hosts file was not
accessible.


还有另一种方法:

清单 3

# do_hosts: returns a ref to hash of hosts (key=host, value=IP/undef)
# from /etc/hosts


以上方法都有效,这取决于 do_hosts() 的复杂程度。如果函数只有两行,则不要浪费时间来写三段注释。但是,如果函数有几页,则不要吝惜说明。



注释程序的开头

程序应该以对其目的简要说明来开头。不要让人们滚动几页才能弄清您在做什么。如果正在使用版本控制系统(例如,CVS),则将适当的头(例如,ID 头)放在文件的开头。尽量简练。两行,最多四行,应该足以对程序进行简要描述。给出联系人姓名、电子邮件、电话号码或团队联系方式。

清单 4

#!/usr/bin/perl -w
# whodunit.pl: A script to solve a murder mystery
# by joe@shmoe.com $Id: whodunit.pl,v 1.92 2000/08/08 19:08:50 joe Exp
$


第一行上的注释是大多数 UNIX 系统上的一种标准方法,用来表示执行脚本时运行哪一个应用程序(在“!”后的所有东西被认为是解释器名称)。-w 标志表示打开警告标志 — 总是一个很好的主意,即使对于很有经验的程序员来说。

第二行(第一个注释行)是程序及其目的的简短描述。第三行(第二个注释行)给出了作者姓名和唯一标识文件的发布日期和版本的 ID 头。RCS 和 CVS 特别地使用 ID 头,它在提交脚本时自动更新。有关 RCS 和 CVS 的更多信息,请参阅本文后面的 参考资料



注释初始化节

初始化节应该在逻辑上和物理上与程序的开头分开,例如,可以通过额外注释或让它处于文件的开头来实现。初始化节,与上面描述的程序的开头相反,包含程序启动时执行的实际代码。在 Perl 中,初始化节应该由下列部分组成(最好按该顺序):

  • 模块和编译指示
  • 常量
  • BEGIN/END/INIT/CHECK 子例程
  • 初始化代码




模块和编译指示

Perl 中的 use 关键字命令解释器装入模块或者打开编译指示(“no pragma”关闭编译指示)。编译指示将解释器引入正确的方向。例如, use utf8 告诉解释器要准备好 UTF-8 编码的数据文件和流。

使每个模块的注释在水平方向上排列整齐,并且每个模块或编译指示有一个注释,是大有好处的。

清单 5

use Data::Dumper; # for debugging printouts
use strict; # be strict - pragma for the
interpreter
use POSIX; # use the POSIX functions


第一次这样做时,只需要复制和粘贴就可以将模块和编译指示放入新程序。我建议“strict”编译指示。此外,它还将确保您诚实地声明变量,以我的经验,这是 Perl 中的错误源,就象内存分配是 C/C++ 中的错误源一样。

请使用 perldoc 命令来察看所有模块和编译指示文档。例如, perldoc strict 说明了有关 strict 编译指示的所有信息 — 它可以做什么,如何使用,等。

某些编辑器具有总是将注释放在特定位置的良好能力(在 Emacs 中,indent-for-comment 命令自动完成该操作)。您自己应该彻底熟悉编辑器的命令。这值得花时间。



常量

虽然可以作为另一个 Perl 编译指示来查看常量,但是它们应该有自己的节。它们的注释应该类似于模块和编译指示的注释,但是,如果将箭头对齐,将更好看:

清单 6

use constant ALPHA => 1; # alpha code
use constant BETA => 2; # beta code
use constant GAMMA => 3; # gamma code
use constant USER => 4; # user ID offset
use constant GROUP => 5; # group ID offset
use constant DEPT => 6; # dept. ID offset





BEGIN/END/INIT/CHECK 子例程

象注释常规子例程一样注释 BEGIN/END/INIT/CHECK 子例程(有关更多信息,请参阅 perldoc perlmod )。在文件的任何位置都可以创建它们,并且有可能多次定义它们。我建议将它们放在文件的开头或结尾,这样易于找到它们。请注意只有一行的 BEGIN 函数不需要详尽的注释。

清单 7

# BEGIN: executed at startup, assigns 'root' to the USER environment
variable
BEGIN
{
$ENV{USER} = 'root';
}





初始化代码

实际代码出现在初始化节的最后。同样,如果可能,在单个块中将注释对齐。

清单 8

$| = 1;
# auto-flush the output
$Data::Dumper::Terse = 1; # produce human-readable
Data::Dumper output
# define the configuration variables
my $config = AppConfig->new();
$config->define(
# list of undo commands
'UNDO' => { ARGCOUNT => ARGCOUNT_LIST },
# file to log data
'LOG_FILE' => { ARGCOUNT => ARGCOUNT_ONE },
);
$config->file(whodunit.conf'); # load the whodunit
configuration file


初始化代码打开自动刷新(auto-flushing)显示(因此,将立即显示输出),然后告诉 Data::Dumper 模块产生可读的输出,最后创建 AppConfig 配置。



注释常规代码

注释常规代码很容易。如果可能,只要将注释对齐,尽量简练,当事情不清楚时,不要害怕深入解释它们。

清单 9

print Dumper \%ENV; # print the full ENV hash
# get the environment variable names that begin with USER
@user_vars = grep(/^USER/, keys %ENV);
# print the values in all the variables that begin with USER, using a
# hash slice
print Dumper @ENV{@user_vars};
print "Done\n"; # print "done" message
# TODO: find better method of sorting variables
# TODO: use Data::Dumper with variable names


请注意,注释从第 0 列或第 40 列开始。一致性使注释更具可读性。同样,必要时,多行注释会更好。还可以使用注释来记录在哪里发生了功能丢失、错误或不完整。如果想遍历所有代码并且查看还有哪些东西不完整,则“TODO”字很有用 — 一个快速的 grep 命令将打印出所有 TODO 项。

不必注释每行代码,但是,请记住当调试或扩展程序时,注释是一种最好的资源。任何其它来源的程序员文档往往落后于实际代码,除非程序员非常勤奋。



注释循环和条件语句

应该象注释常规代码和函数一样注释循环和条件语句。对循环编号以便以后标识它们似乎有些过分。更好的方法是使用折叠编辑器,折叠循环时,它可以将整个循环显示成一行(折叠标记之间的行是隐藏的,但它们仍然存在)。考虑一下如 XML/HTML 开始/结束标记这样的折叠的标记,它们是可以嵌套的。您最喜爱的编辑器可能已经支持折叠。(X)Emacs 就支持折叠,它不是使用 Outline 就是使用 folding.el 方式。

清单 10

# go through all the numbers between 2 and 200, and print a message
# for each one
foreach my $counter (2 .. 200)
{
       print "Whoa, the counter is $counter!\n";
}


总是陈述循环的目的和边界。例如,“count from 2 to 200”很好,但是“process array”则不好。如果逻辑条件影响边界,同样陈述它们,但不在循环的顶部。循环顶部的摘要不应该记录常规迭代的异常,除非它们对循环非常重要。您自己判断吧。



注释程序的最终阶段

在许多方面,程序的结尾是最繁琐的。工作已经完成,数据结构已经进入休眠状态(在 Perl 中不必担心内存释放),并且现在离结尾只差几行了。不要让这愚弄了您 — 程序的结束行可能与其它行一样危险。在这里,注释最不起眼的行,因为调试程序员所做的第一件事就是查看程序的退出行为。

清单 11

# delete old files, warn if they can't be removed
foreach (@myfiles)
{
       unlink $_ or warn "Couldn't remove $_: $!";
}
print "whodunit.pl is done!\n"; # tell the user we're done
exit; # exit peacefully





编写程序的 POD 文档和帮助

旧式纯文档(Plain old documentation (POD))是将 Perl 脚本放入脚本本身的一种方法。 perldoc perlpod 命令将告诉您有关 POD 文档及其语法的更多信息。好的 POD 文档意味着用户可以快速和有效地访问程序的帮助。花时间学习 POD 语法:编写手册将更容易。另外,POD 与各种手册格式化程序兼容,因此可以从同一文档生成一个纯文本文件、UNIX 风格的帮助手册页和专业 LaTeX 文件。POD 是一个十分有限的格式,但是足够满足大多数文档的需要。

通常,下列节应该出现在 POD 文档中:NAME、SYNOPSIS、DESCRIPTION、OPTIONS、RETURN VALUE、ERRORS、DIAGNOSTICS、EXAMPLES、ENVIRONMENT、FILES、CAVEATS/WARNINGS、BUGS、RESTRICTIONS、NOTES、SEE ALSO、AUTHORS 以及 HISTORY(从 perldoc pod2man 中可以找到有关每节的更多信息;请记住这些是建议而不是命令)。

某些程序员对其程序设置 -h 开关以对程序调用 perldoc,因此打印出 POD 文档,就象用户输入 perldoc whodunit.pl 一样。这里的问题是用户不想从 -h 开关获取更多的额外信息。他只想要选项的摘要和列表。因此,更好的方法是编写从使用 -h 开关产生的单独帮助处理程序。

清单 12

# print_help: help handler, prints out help for whodunit.pl and exits
sub print_help
{
       # print the help itself
       print << EOHIPPUS;
       This is help for the whodunit.pl program.
      You can pass options to whodunit.pl as command-line arguments. For
      example:
      ..../whodunit.pl -h
      ..../whodunit.pl -show suspects
      List of options:
      -h : print this help
      -show : show the suspects, victims, or detectives (all of them if no
       second argument is specified)
      -quiet : print no information other than the killer's name
      EOHIPPUS
       exit; # do nothing else, just exit quietly
}


请注意 print_help 文档本身。POD 文档和其它联机帮助的外观同样也很重要。用户首先看的不是手册。使用 -h 标志或者查看 POD 文档会方便得多。注意冒号的对齐、行之间的空格和整体整洁。表面的外观往往比程序提供的实际功能更重要。编写得好的程序首要的是应该具有良好的文档。

某些程序员喜欢在程序中包含 POD 文档来代替常规注释。这样的 POD 注释自己用某行上的 =pod 开头(还有其它选项,在 perlpod 文档中解释),并且自己以 =cut 在某行结束。 =pod 行告诉 Perl 编译器停止解释每件事,直到 =cut 行为止,事实上从脚本本身排除了那个文本块。如果用户也是程序员,这当然好,但是如果普通用户只想查看脚本的文档而不是代码本身的注释,这可能会把他们弄糊涂。这个方法还将文档散布在整个代码中。应该限制它的使用。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论