什么使Perl代码可维护?

时间:2010-12-03 19:27:09

标签: perl maintainability

我已经写了几年Perl了,它是我文本处理的首选语言(我工作的许多遗传学/基因组学问题很容易被简化为文本处理问题)。 Perl作为一种语言可能非常宽容,并且可以在Perl中编写非常差但功能强大的代码。就在前几天,我的朋友说他称Perl为只写语言:写一次,理解一次,永远不要试图在完成后再回过头来修复它。

虽然我有时一直在编写糟糕的脚本,但我觉得我还在Perl中编写了一些非常清晰且可维护的代码。但是,如果有人问我使代码清晰可维护,我将无法给出自信的答案。

是什么让Perl代码可维护?或者更好的问题是什么使Perl代码难以维护?让我们假设我不是唯一一个维护代码的人,其他贡献者,比如我,不是专业的Perl程序员,而是具有编程经验的科学家。

8 个答案:

答案 0 :(得分:30)

是什么让Perl代码无法维护?几乎任何使其他程序无法维护的东西。假设除了用于执行定义良好的任务的短脚本之外的任何内容,它们都是:

  • 全局变量
  • 缺乏关注点分离:单片脚本
  • 不使用自我文档标识符(变量名称和方法名称)。例如。你应该知道变量的目的是什么。 $c不好。 $count更好。 $token_count好。
    • 拼出标识符。程序大小不再是最重要的问题。
    • 名为doWork的子程序或方法没有说什么
    • 可以轻松找到其他包中的符号来源。使用显式包前缀,或显式导入通过use MyModule qw(list of imports)使用的每个符号。
  • Perl的具体:
    • 过度依赖捷径和晦涩的内置变量
    • 滥用子程序原型
    • 未使用strict而未使用warnings
  • 重新发明轮子而不是使用已建立的库
  • 未使用一致的缩进样式
  • 不使用水平和垂直空白来指导读者
等等等。

基本上,如果您认为Perl是-f>@+?*<.-&'_:$#/%!,并且您希望在生产代码中编写类似的内容,那么,是的,您会遇到问题。

人们倾向于混淆Perl程序员为了娱乐而做的事情(例如,JAPH,高尔夫等)以及Perl程序看起来应该是什么样的。

我仍然不清楚他们如何能够将codeIOCCC编写的内容与可维护的C分开。

答案 1 :(得分:15)

我建议:

  1. 不要太熟悉Perl。如果你开始使用代码打高尔夫球,它将导致难以阅读的代码。你编写的代码需要更易读,更清晰。
  2. 记录代码。如果是模块,请添加描述典型用法和方法的POD。如果是程序,请添加POD以描述命令行选项和典型用法。如果有毛茸茸的算法,请记录它并尽可能提供引用(URL)。
  3. 使用正则表达式的/.../x形式,并记录它们。不是每个人都能理解正则表达式。
  4. 了解耦合是什么,以及高/低耦合的优缺点。
  5. 了解凝聚力是什么,以及高/低凝聚力的利弊。
  6. 适当使用模块。一个定义良好,包含良好的概念是一个很好的模块。目标是重复使用这些模块。不要简单地使用模块来减小单片程序的大小。
  7. 为您的代码编写单元测试。一个好的测试套件不仅可以让你证明你的代码今天有效,而且明天也有用。它还可以让您在未来进行更大胆的更改,并确信您不会破坏旧的应用程序。如果你确实破坏了,那么,你的测试套件还不够广泛。
  8. 但总的来说,你对可维护性的关注程度足以提出问题,这告诉我你已经处在一个好地方并且思考正确的方式。

答案 2 :(得分:13)

我没有全部使用Perl Best Practices,但这就是达米安写的东西。无论我是否使用所有建议,它们都至少值得考虑。

答案 3 :(得分:9)

  

是什么让Perl代码可维护?

至少:

use strict;
use warnings;

请参阅perldoc perlstyle了解一些可使您的程序更易于阅读,理解和维护的一般指导原则。

答案 4 :(得分:5)

我在其他答案中没有提到的代码可读性非常重要的一个因素是空白的重要性,它既是Perl不可知的,也是Perl特定的。

Perl允许你编写非常简洁的代码,但是构建块并不意味着它们必须全部聚集在一起。

当我们讨论可读性时,白色空间有很多意义/用途,并非所有这些都被广泛使用但最有用:

  • 令牌周围的空间更容易在视觉上分开。

    这个空间在Perl中非常重要,因为即使在最好的Perl代码中,线路噪声字符也很普遍。

    我发现$myHashRef->{$keys1[$i]}{$keys3{$k}}在生产紧急情况中间凌晨2点的可读性低于间隔时间: $myHashRef->{ $keys1[$i] }->{ $keys3{$k} }

    作为旁注,如果你发现你的代码执行了很多深层嵌套的引用表达式,都是以相同的根开头的,那么你应该考虑将这个根分配给一个临时指针(参见Sinan的评论/答案)。

    部分但非常重要的特殊情况当然是正则表达式。在我记得的所有主要材料(PBP,RegEx O'Reilly书等等)中,差异被说明为死亡,所以除非有人在评论中提出例子,否则我不会进一步延长这篇文章。

  • 正确均匀的压痕。 D'哦。明显。然而,由于蹩脚的缩进,我看到太多的代码100%无法读取,当编辑器使用4个字符选项卡而另一个编辑使用8个字符TAB的人使用TAB缩进一半代码时,甚至更不可读。只需将血腥编辑器设置为软(例如空间仿真)TAB,不要让其他人痛苦。

  • 在逻辑上分开的代码单元(包括块和只是几组线)周围的空行。你可以在1000行好的Perl中编写一个10000行的Java程序。现在不要觉得像本尼迪克特·阿诺德那样,如果你为这些1000添加100-200个空行以使事情更具可读性。

  • 将超长表达式分成多行,紧接着是......

  • 正确垂直对齐。见证:

    之间的区别
    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(){}块的内容是return,则执行多个if/unless语句,每个语句都有一个返回块可能更好。

答案 5 :(得分:4)

我认为这是一个人们被告知perl不可读的问题,他们开始对自己代码的维护性做出假设。如果您认真考虑将可读性视为质量代码的标志,那么这种批评很可能不适用于您。

大多数人在讨论可读性时会引用正则表达式。正则表达式是嵌入在perl中的dsl,您可以阅读它们。如果有人不能花时间去理解许多语言的基本和必要的东西,我并不关心试图弥合一些推断的认知差距......他们应该只是做人,阅读perldocs,并在必要时提出问题

其他人会引用perl使用的短格式变量,例如@_,$!这些都很容易消除歧义......我对使perl看起来像java不感兴趣。

所有这些怪癖和perlism的优点是用该语言编写的代码库通常简洁紧凑。我宁愿阅读10行perl而不是100行java。

对我而言,“可维护性”远远超过简单易读的代码。编写测试,做出断言......做其他一切你可以做的事情,依靠perl及其生态系统来保持代码的正确性。

简而言之:编写程序首先是正确的,然后是安全的,然后是表现良好的....一旦达到这些目标,就会担心在近火时蜷缩起来很好。

答案 6 :(得分:2)

我会说包装/对象模型,它们反映在.pm文件的目录结构中。对于我的博士学位,我写了很多Perl代码,之后我重复使用。它适用于自动LaTeX图生成器。

答案 7 :(得分:1)

我会谈谈一些积极的事情,以使Perl可以维护。

确实,你通常不应该对la return !$@;#%之类的真正密集语句过于聪明,而是使用列表处理运算符,如map和{{ 1}}和list-context从grep和类似运算符之类的返回,以便以函数式编写代码可以对可维护性做出积极贡献。在我的上一个雇主,我们也有一些时髦的哈希操作函数,它们以类似的方式工作(splithashmap,但从技术上讲,我们只提供了偶数大小的列表。例如:

hashgrep

另请参阅高阶Perl http://hop.perl.plover.com - 如果您可以保持元编程本身不妨碍元编程,那么良好地使用元编程可以使定义任务更加连贯和可读。