是什么让 Perl 代码变得可维护?

发布于 2024-10-05 18:13:15 字数 375 浏览 10 评论 0原文

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

虽然我有时确实因编写糟糕的脚本而感到内疚,但我觉得我也用 Perl 编写了一些非常清晰且可维护的代码。但是,如果有人问我什么使代码清晰且可维护,我将无法给出自信的答案。

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

I've been writing Perl for several years now and it is my preferred language for text processing (many of the genetics/genomics problems I work on are easily reduced to text processing problems). Perl as a language can be very forgiving, and it's possible to write very poor, but functional, code in Perl. Just the other day, my friend said he calls Perl a write-only language: write it once, understand it once, and never ever try to go back and fix it after it's finished.

While I have definitely been guilty of writing bad scripts at times, I feel like I have also written some very clear and maintainable code in Perl. However, if someone asked me what makes the code clear and maintainable, I wouldn't be able to give a confident answer.

What makes Perl code maintainable? Or maybe a better question is what makes Perl code hard to maintain? Let's assume I'm not the only one that will be maintaining the code, and that the other contributors, like me, are not professional Perl programmers but scientists with programming experience.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

屋顶上的小猫咪 2024-10-12 18:13:15

是什么导致 Perl 代码难以维护?几乎任何使其他程序无法维护的事情。假设除了旨在执行明确定义的任务的简短脚本之外的任何内容,这些是:

  • 全局变量
  • 缺乏关注点分离:整体脚本
  • 不使用自文档标识符(变量名称和方法名称)。例如,您应该从变量的名称中知道其用途。 $c 不好。 $count 更好。 $token_count 很好。
    • 拼写标识符。程序大小不再是最重要的问题。
    • 名为 doWork 的子例程或方法不执行任何操作
    • 可以轻松地从另一个包中找到符号的来源。使用显式包前缀,或通过 use MyModule qw(list of import) 显式导入使用的每个符号
  • Perl 特定的:
    • 过度依赖快捷方式和模糊的内置变量
    • 滥用子例程原型
    • 不使用严格并且不使用警告
  • 重新发明轮子而不是使用已建立的库
  • 不使用一致的缩进风格
  • 不使用水平和垂直空格来引导读者

等等。

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

人们往往会将 Perl 程序员为了好玩而做的事情(例如,JAPH、高尔夫等)与优秀的 Perl 程序应该是什么样子混为一谈。

我仍然不清楚他们如何能够在头脑中分离 代码IOCCC 来自可维护的 C.

What makes Perl code unmaintainable? Pretty much anything that makes any other program unmaintainable. Assuming anything other than a short script intended to carry out a well defined task, these are:

  • Global variables
  • Lack of separation of concerns: Monolithic scripts
  • NOT using self-documenting identifiers (variable names and method names). E.g. you should know what a variable's purpose is from its name. $c bad. $count better. $token_count good.
    • Spell identifiers out. Program size is no longer of paramount concern.
    • A subroutine or method called doWork doesn't say anything
    • Make it easy to find the source of symbols from another package. Either use explicit package prefix, or explicitly import every symbol used via use MyModule qw(list of imports).
  • Perl-specific:
    • Over-reliance on short-cuts and obscure builtin variables
    • Abuse of subroutine prototypes
    • not using strict and not using warnings
  • Reinventing the wheel rather than using established libraries
  • Not using a consistent indentation style
  • Not using horizontal and vertical white space to guide the reader

etc etc etc.

Basically, if you think Perl is -f>@+?*<.-&'_:$#/%!, and you aspire to write stuff like that in production code, then, yeah, you'll have problems.

People tend to confuse stuff Perl programmers do for fun (e.g., JAPHs, golf etc) with what good Perl programs are supposed to look like.

I am still unclear on how they are able to separate in their minds code written for IOCCC from maintainable C.

甩你一脸翔 2024-10-12 18:13:15

我建议:

  1. 不要对 Perl 太聪明。如果您开始使用代码打高尔夫球,则会导致代码更难阅读。您编写的代码需要可读且清晰,而不是聪明。
  2. 记录代码。如果是模块,请添加描述典型用法和方法的 POD。如果是程序,请添加 POD 来描述命令行选项和典型用法。如果存在复杂的算法,请将其记录下来并提供参考(URL)(如果可能)。
  3. 使用 /.../x 形式的正则表达式,并记录它们。并不是每个人都很好地理解正则表达式。
  4. 了解什么是耦合,以及高/低耦合的优缺点。
  5. 了解什么是内聚力,以及高/低内聚力的优缺点。
  6. 适当地使用模块。一个定义良好、包含良好的概念可以构成一个很棒的模块。目标是重用此类模块。不要仅仅为了减小整体程序的大小而使用模块。
  7. 为您的代码编写单元测试。一个好的测试套件不仅可以让您证明您的代码今天可以工作,而且明天也可以。它还可以让您在未来进行更大胆的更改,并确信您不会破坏旧的应用程序。如果你确实破坏了一些东西,那么,你的测试套件不够广泛。

但总的来说,您足够关心可维护性并提出相关问题,这一事实告诉我您已经处于一个好的位置并且以正确的方式思考。

I suggest:

  1. Don't get too clever with the Perl. If you start playing golf with the code, it's going to result in harder-to-read code. The code you write needs to be readable and clear more than it needs to be clever.
  2. Document the code. If it's a module, add POD describing typical usage and methods. If it's a program, add POD to describe command line options and typical usage. If there's a hairy algorithm, document it and provide references (URLs) if possible.
  3. Use the /.../x form of regular expressions, and document them. Not everyone understands regexes well.
  4. Know what coupling is, and the pros/cons of high/low coupling.
  5. Know what cohesion is, and the pros/cons of high/low cohesion.
  6. Use modules appropriately. A nice well-defined, well-contained concept makes a great module. Reuse of such modules is the goal. Don't use modules simply to reduce the size of a monolithic program.
  7. Write unit tests for you code. A good test suite will not only allow you to prove your code is working today, but tomorrow as well. It will also let you make bolder changes in the future, with confidence that you are not breaking older applications. If you do break things, then, well, your tests suite wasn't broad enough.

But overall, the fact that you care enough about maintainability to ask a question about it, tells me that you're already in a good place and thinking the right way.

小姐丶请自重 2024-10-12 18:13:15

我没有使用全部 Perl 最佳实践,但这就是 Damian写它是为了。无论我是否使用所有建议,它们至少都值得考虑。

I don't use all of Perl Best Practices, but that's the thing that Damian wrote it for. Whether or not I use all the suggestions, they are all worth at least considering.

染墨丶若流云 2024-10-12 18:13:15

什么使 Perl 代码易于维护?

至少:

use strict;
use warnings;

请参阅 perldoc perlstyle 了解一些通用指南,这些指南将使您的程序更易于阅读和理解,并维持。

What makes Perl code maintainable?

At the least:

use strict;
use warnings;

See perldoc perlstyle for some general guidelines that will make your programs easier to read, understand, and maintain.

勿忘初心 2024-10-12 18:13:15

对于代码可读性非常重要的一个因素是空白的重要性,这一点我在其他答案中没有提到过,它既与 Perl 无关,又在某些方面与 Perl 相关。

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

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

  • 标记周围的空格可以更轻松地在视觉上分隔它们。

    这个空间在 Perl 中尤为重要,因为即使在最佳风格的 Perl 代码中也普遍存在行噪声字符。

    我发现 $myHashRef->{$keys1[$i]}{$keys3{$k}} 在生产紧急情况下的凌晨 2 点与间隔时间相比可读性较差:
    $myHashRef->{ $keys1[$i] }->{ $keys3{$k} }

    作为旁注,如果您发现您的代码执行大量以相同根开头的深层嵌套引用表达式,那么您绝对应该考虑将该根分配给临时指针(请参阅 Sinan 的评论/答案)。

    一个部分但非常重要的特殊情况当然是正则表达式。 因此我不会进一步延长这篇文章,除非有人在评论中请求示例。

  • 缩进正确且均匀。噢。明显地。然而,我看到太多的代码由于蹩脚的缩进而 100% 不可读,而且当一半代码由一个使用 4 个字符制表符的编辑器使用制表符缩进的代码和另一个使用 8 个字符制表符的编辑器的人用制表符缩进时,可读性更差。只需将你该死的编辑器设置为软(例如空间模拟)TAB,不要让其他人痛苦。

  • 逻辑上独立的代码单元周围的空行(块和行集)。你可以用 1000 行好的 Perl 编写一个 10000 行的 Java 程序。现在,如果您在这 1000 行中添加 100-200 行空行以使内容更具可读性,那么您就不会像 Benedict Arnold 那样了。

  • 将超长表达式拆分为多行,紧接着...

  • 正确的垂直对齐方式。见证之间的区别:

    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 && $王牌> 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
        && $王牌> 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
        && $王牌> my_func()
        && $another_answer == 42
        && $pi == 3 ) {
    

    顺便说一句,在某些情况下,通过首先不使用如此长的表达式,可以使代码更具可读性/可维护性。例如,如果 if(){} 块的内容是 return,则执行多个 if/unless 语句,每个语句都有一个 return块可能会更好。

One factor very important to code readability that I haven't seen mentioned in other answers is the importance of white space, which is both Perl-agnostic and in some ways Perl-specific.

Perl lets you write VERY concise code, but consise chunks don't mean they have to be all bunched together.

White space has lots of meaning/uses when we are talking about readability, not all of them widely used but most useful:

  • Spaces around tokens to easier separate them visually.

    This space is doubly important in Perl due to prevalence of line noise characters even in best-style Perl code.

    I find $myHashRef->{$keys1[$i]}{$keys3{$k}} to be less readable at 2am in the middle of producion emergency compared to spaced out:
    $myHashRef->{ $keys1[$i] }->{ $keys3{$k} }.

    As a side note, if you find your code doing a lot of deep nested reference expressions all starting with the same root, you should absolutely consider assigning that root into a temporary pointer (see Sinan's comment/answer).

    A partial but VERY important special case of this is of course regular expressions. The difference was illustrated to death in all the main materials I recall (PBP, RegEx O'Reilly book, etc..) so I won't lengthen this post even further unless someone requests examples in the comments.

  • Correct and uniform indentation. D'oh. Obviously. Yet I see way too much code 100% unreadable due to crappy indentation, and even less readable when half of the code was indented with TABs by a person whose editor used 4 character tabs and another by a person whose editor used 8 character TABs. Just set your bloody editor to do soft (e.g. space-emulated) TABs and don't make others miserable.

  • Empty lines around logically separate units of code (both blocks and just sets of lines). You can write a 10000 line Java program in 1000 lines of good Perl. Now don't feel like Benedict Arnold if you add 100-200 empty lines to those 1000 to make things more readable.

  • Splitting uber-long expressions into multiple lines, closely followed by...

  • Correct vertical alignment. Witness the difference between:

    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) {
    

    and

    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) {
    

    and

    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) {
    

    Personally, I prefer to fix the vertical alignment one more step by aligning LHS and RHS (this is especially readable in case of long SQL queries but also in Perl code itself, both the long conditionals like this one as well as many lines of assignments and hash/array initializations):

    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  ) {
    

    As a side note, in some cases the code could be made even more readable/maintainable by not having such long expressions in the first place. E.g. if the contents of the if(){} block is a return, then doing multiple if/unless statements each of which has a return block may be better.

最偏执的依靠 2024-10-12 18:13:15

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

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

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

所有这些怪癖和优点的好处是,用该语言编写的代码库通常简洁紧凑。我宁愿读十行 Perl,也不愿读一百行 Java。

对我来说,“可维护性”不仅仅是拥有易于阅读的代码。编写测试、做出断言...尽一切努力依靠 Perl 及其生态系统来保持代码正确。

简而言之:编写程序首先是正确的,然后是安全的,然后是性能良好的......一旦实现了这些目标,然后担心是否能舒服地蜷缩在火边。

i see this as an issue of people being told that perl is unreadable, and they start to make assumptions about the maintability of their own code. if you are conscientious enough to consider readability as a hallmark of quality code, chances are this critique doesn't apply to you.

most people will cite regexes when they discuss readability. regexes are a dsl embedded in perl and you can either read them or not. if someone can't take the time to understand something so basic and essential to many languages, i'm not concerned about trying to bridge some inferred cognitive gap...they should just man up, read the perldocs, and ask questions where necessary.

others will cite perl's use of short-form vars such as @_, $! etc. these are all easily disambiguated...i'm not interested in making perl look like java.

the upside of all of these quirks and perlisms is that codebases written in the language are often terse and compact. i'd rather read ten lines of perl than one hundred lines of java.

to me there is so much more to "maintainability" than simply having easy-to-read code. write tests, make assertions...do everything else you can do to lean on perl and its ecosystem to keep code correct.

in short: write programs to be first correct, then secure, then well-performing....once these goals have been met, then worry about making it nice to curl up with near a fire.

☆獨立☆ 2024-10-12 18:13:15

我想说的是包装/对象模型,它反映在 .pm 文件的目录结构中。为了攻读博士学位,我编写了很多 Perl 代码,之后我又重复使用这些代码。它用于自动 LaTeX 图表生成器。

I would say the packaging/object models, that gets reflected in the directory structure for .pm files. For my PhD I wrote quite a lot of Perl code that I reuse afterwards. It was for automatic LaTeX diagram generator.

守护在此方 2024-10-12 18:13:15

我将谈论一些积极的事情来使 Perl 易于维护。

确实,您通常不应该太聪明地使用像 return !$@;#% 之类的非常密集的语句,但要聪明地使用列表处理运算符,例如 mapgrep 以及 list-context 从 split 之类的操作符返回,以便以函数式风格编写代码可以做出积极的贡献可维护性。在我的上一个雇主中,我们也有一些以类似方式工作的时髦哈希操作函数(hashmaphashgrep,尽管从技术上讲,我们只向它们提供偶数大小的列表)。例如:

# 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;

另请参阅高阶 Perlhttp://hop.perl.plover.com - 如果您可以防止元编程本身妨碍的话,充分利用元编程可以使定义任务更加连贯和可读。

I'll talk some positive things to make Perl maintainable.

It's true that you usually shouldn't get too clever with really dense statements a la return !$@;#% and the like, but a good amount of clever using list-processing operators, like map and grep and list-context returns from the likes of split and similar operators, in order to write code in a functional style can make a positive contribution to maintainability. At my last employer we also had some snazzy hash-manipulation functions that worked in a similar way (hashmap and hashgrep, though technically we only fed them even-sized lists). For instance:

# 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;

See also Higher Order Perl, http://hop.perl.plover.com - good use of metaprogramming can make defining tasks more coherent and readable, if you can keep the metaprogramming itself from getting in the way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文