题
我已经写了Perl几年了,这是我对文本处理的首选语言(我处理的许多遗传学/基因组问题很容易减少到文本处理问题)。 Perl作为一种语言可能非常宽容,并且可以在Perl中写入非常糟糕但功能性的代码。就在前几天,我的朋友说他叫Perl 只写 语言:写一次,了解一次,并且从不尝试在完成后返回并修复它。
虽然有时我肯定会写不好的脚本,但我觉得我也写了一些非常清晰和可维护的代码。但是,如果有人问我什么 制作 代码清晰可维护,我将无法给出一个自信的答案。
是什么使Perl代码可维护?还是一个更好的问题是,什么使Perl代码难以维护?假设我不是唯一一个维护该代码的人,而像我这样的其他贡献者不是专业的Perl程序员,而是具有编程经验的科学家。
解决方案
是什么使Perl代码无法实现?几乎所有使任何其他程序都无法实现的东西。假设除了一个简短的脚本以外的任何事情都打算执行明确的任务,这些都是:
- 全局变量
- 缺乏关注的分离:整体脚本
- 不使用自我文件标识符(可变名称和方法名称)。例如,您应该知道变量的目的是什么。
$c
坏的。$count
更好的。$token_count
好的。- 拼写标识符。程序大小不再是最重要的问题。
- 称为子例程或方法
doWork
什么都不说 - 使从另一个软件包中找到符号来源很容易。使用明确的软件包前缀,或明确导入通过
use MyModule qw(list of imports)
.
- 特定于Perl:
- 过度依赖短距离和晦涩的内置变量
- 滥用子例程原型
- 不使用
strict
并且不使用warnings
- 重新发明轮子,而不是使用已建立的库
- 不使用一致的凹痕样式
- 不使用水平和垂直空白空间来引导读者
等等等等等等
基本上,如果您认为Perl是 -f>@+?*<.-&'_:$#/%!
, ,您渴望在生产代码中编写类似的内容,那么,是的,您会遇到问题。
人们倾向于将Perl程序员娱乐(例如Japhs,Golf等)与Perl计划的外观混淆。
其他提示
我建议:
- 不要对Perl太聪明。如果您开始使用代码打高尔夫球,它将导致难以阅读的代码。您编写的代码需要可读性和清晰度,而不是聪明。
- 记录代码。如果是一个模块,请添加描述典型用法和方法的POD。如果是程序,请添加POD来描述命令行选项和典型用法。如果有毛茸茸的算法,请记录并提供引用(URL)(URL)。
- 使用正则表达式的/.../x形式,并记录下来。并非每个人都很好地了解Regexes。
- 知道什么是耦合,以及高/低耦合的利弊。
- 知道什么是凝聚力,以及高/低凝聚力的利弊。
- 适当使用模块。一个很好的定义明确,牢固的概念是一个很好的模块。重复使用此类模块是目标。不要仅使用模块来减少整体程序的大小。
- 为您的代码编写单元测试。良好的测试套件不仅可以证明您的代码今天正在运行,而且明天也是如此。它还可以让您在将来做出更大胆的更改,并充满信心您不会打破较旧的应用程序。如果您确实破坏了事情,那么,您的测试套件不够广泛。
但是总的来说,您足够关心可维护性来提出问题的事实告诉我,您已经处于一个很好的位置并以正确的方式思考。
我不使用所有 PERL最佳实践, ,但这就是达米安(Damian)写的。无论我是否使用所有建议,它们都至少值得考虑。
对于我在其他答案中没有提到的代码可读性非常重要的一个因素是空白的重要性,这既是perl-agnoftic又是特定于perl特定的。
Perl可以让您编写非常简洁的代码,但是Consise Chunks并不意味着他们必须全部捆绑在一起。
当我们谈论可读性时,空白空间具有很多含义/用途,并非全部使用,但最有用的是:
令牌周围的空间可以更轻松地视觉分开。
由于线噪声字符的普遍性,即使在最佳风格的Perl代码中,该空间在Perl中也非常重要。
我发现
$myHashRef->{$keys1[$i]}{$keys3{$k}}
与分布相比,在生产紧急情况中凌晨2点,可阅读不足:$myHashRef->{ $keys1[$i] }->{ $keys3{$k} }
.附带说明,如果您发现代码从相同的根开始进行大量深嵌套的参考表达式,则应绝对考虑将该根分配给临时指针(请参阅Sinan的评论/答案)。
当然,部分但非常重要的特殊情况是正则表达式。在我召回的所有主要材料(PBP,Regex O'Reilly Book等)中,差异被说明为死亡。
正确和均匀的凹痕。哦。明显地。然而,由于cr缩的凹痕,我看到了太多的代码100%无法读取,而当一半代码被一个人用编辑使用4个字符选项卡的人缩进的一半时,甚至不太可读,而另一位编辑使用的人则使用了8个字符选项卡。只需将您的血腥编辑器设置为柔软(例如空间启发)标签,并且不会使其他人痛苦。
逻辑上分开的代码单元(两者和仅一组行)周围的空线。您可以在1000行良好的Perl中编写10000行Java程序。现在,如果您向那些1000的1000添加100-200个空线,以使事物更可读。
将Uber-Long表达式分为多行,紧随其后的是...
正确的垂直对齐。见证:
if ($some_variable > 11 && ($some_other_bigexpression < $another_variable || $my_flag eq "Y") && $this_is_too_bloody_wide == 1 && $ace > my_func() && $another_answer == 42 && $pi == 3) {
和
if ($some_variable > 11 && ($some_other_bigexpression < $another_variable || $my_flag eq "Y") && $this_is_too_bloody_wide == 1 && $ace > my_func() && $another_answer == 42 && $pi == 3) {
和
if ( $some_variable > 11 && ($some_other_bigexpression < $another_variable || $my_flag eq "Y") && $this_is_too_bloody_wide == 1 && $ace > my_func() && $another_answer == 42 && $pi == 3) {
就我个人而言,我更喜欢通过对齐LHS和RHS再修复垂直对齐的一步(在长期SQL查询的情况下,这是尤其可以阅读的,但也可以在Perl代码本身中,这两个较长的条件都这样的长条件以及许多分配和分配行和。哈希/数组初始化):
if ( $some_variable > 11 && ($some_other_bigexpression < $another_variable || $my_flag eq "Y") && $this_is_too_bloody_wide == 1 && $ace > my_func() && $another_answer == 42 && $pi == 3 ) {
附带说明,在某些情况下,通过首先没有如此长的表达方式,代码可以使代码变得更加可读/可维护。例如,如果内容的内容
if(){}
块为areturn
, ,然后做多个if/unless
陈述每个具有回报块可能更好。
我认为这是人们被告知Perl不可读的问题,他们开始对自己的代码的可持续性做出假设。如果您足够认真地将可读性视为质量代码的标志,那么这种批评不适用于您。
大多数人在讨论可读性时会引用Regexes。 Regexes是嵌入Perl中的DSL,您可以阅读或不阅读它们。如果有人不能花时间理解许多语言如此基本和必不可少的东西,那么我就不关心试图弥合一些推断的认知差距……他们应该只是人来读书,阅读perldocs,并在必要时提出问题。
其他人会引用Perl对@_,$!等等。这些都很容易被歧视...我对使Perl看起来像Java不感兴趣。
所有这些怪癖和诉讼的好处是,用语言写的代码库通常是简短而紧凑的。我宁愿阅读十行Perl,而不是一百行Java。
对我来说,“可维护性”的比简单地拥有易于阅读的代码。编写测试,做出断言...尽一切努力依靠Perl及其生态系统,以保持代码正确。
简而言之:编写程序要首先正确,然后安全,然后表现出色。...一旦实现了这些目标,就会担心让弯腰靠近火。
我想说的是包装/对象模型,这些模型会反映在.pm文件的目录结构中。对于我的博士学位,我写了很多perl代码,然后再用。它用于自动胶乳图生成器。
我会说一些 积极的 使Perl可维护的事物。
的确,您通常不应该太聪明,而真正密集的陈述 return !$@;#%
等等,但是使用列表处理操作员,大量的巧妙 map
和 grep
和list-context从 split
和类似的操作员,以功能样式编写代码可以为可维护性做出积极的贡献。在我的最后一个雇主中,我们还拥有一些以类似方式起作用的时髦的哈希操作功能(hashmap
和 hashgrep
, ,尽管从技术上讲,我们只给了他们尺寸均匀的列表)。例如:
# Look for all the servers, and return them in a pipe-separated string
# (because we want this for some lame reason or another)
return join '|',
sort
hashmap {$a =~ /^server_/ ? $b : +()}
%configuration_hash;
也可以看看 高阶Perl, http://hop.perl.plover.com - 如果您可以防止元编程妨碍自身,则可以很好地利用元编程可以使定义任务更加连贯和可读。