什么使Perl代码可维护?

Dan*_*age 23 perl maintainability

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

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

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

Sin*_*nür 30

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

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

等等等

基本上,如果你认为Perl是-f>@+?*<.-&'_:$#/%!,并且你渴望在生产代码中写这样的东西,那么,是的,你会遇到问题.

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

我仍然不清楚他们如何能够将他们为IOCCC编写的代码与可维护的C 分开.

  • +1"过度依赖捷径和模糊的内置变量". (3认同)
  • @DVK我发现短变量名称完全可以接受,如果它们的上下文使其目的明显. (2认同)

Pau*_*ham 15

我建议:

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

但总的来说,你足够关心可维护性来询问有关它的问题这一事实告诉我你已经处在一个好地方并且思考正确的方式.


Axe*_*man 13

我没有使用Perl的所有最佳实践,但这就是达米安写的东西.无论我是否使用所有建议,它们都至少值得考虑.


Eug*_*ash 9

什么使Perl代码可维护?

至少:

use strict;
use warnings;
Run Code Online (Sandbox Code Playgroud)

有关一些通用指南,请参阅perldoc perlstyle,以使您的程序更易于阅读,理解和维护.


DVK*_*DVK 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程序.现在不要感觉像本尼迪克特阿诺德,如果你添加100-200空行到那些1000,以使事情更具可读性.

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

  • 正确的垂直对齐.见证之间的区别:

    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) {
    
    Run Code Online (Sandbox Code Playgroud)

    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) {
    
    Run Code Online (Sandbox Code Playgroud)

    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) {
    
    Run Code Online (Sandbox Code Playgroud)

    就个人而言,我更倾向于通过对齐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  ) {
    
    Run Code Online (Sandbox Code Playgroud)

    作为旁注,在某些情况下,通过首先没有这么长的表达式,可以使代码更具可读性/可维护性.例如,如果if(){}块的内容是a return,则执行多个if/unless语句,每个语句都具有返回块可能更好.