这是我的第一个COBOL程序,由于我不熟悉最佳实践,因此想受到批评。

特别地,我想知道如何获得更多的输入和输出。优雅,并且较少依赖于文件字段的结构。

类似于C的scanf()getch()或任何Java控制台IO例程的类将很有帮助。

https://gist.github.com/anonymous/5427201

        DATA DIVISION.
    WORKING-STORAGE SECTION.
    01 TIME-STORAGE.
        03 CURRENT-TIME-NUMERIC         PIC 9(8).
        03 ETA-NUMERIC PIC 9(8) REDEFINES CURRENT-TIME-NUMERIC.    

        03 CURRENT-TIME REDEFINES CURRENT-TIME-NUMERIC.
            05  CURRENTHOUR     PIC 99.
            05  CURRENTMINUTE   PIC 99.
            05  FILLER          PIC 9(4).
        03 ARIVAL-TIME-NUMERIC PIC 9(8).
        03 ARIVAL-TIME REDEFINES ARIVAL-TIME-NUMERIC.
            05  ARRIVALHOUR     PIC 99.
            05  ARRIVALMINUTE   PIC 99.
            05  FILLER          PIC 9(4).
    PROCEDURE DIVISION.
    BEGIN-BUG-NORMAN.
        DISPLAY "when will you be ariving?"
        DISPLAY "HH [enter]"
        ACCEPT ARRIVALHOUR
        DISPLAY "MM [enter]"
        ACCEPT ARRIVALMINUTE
        ACCEPT CURRENT-TIME FROM TIME.
        SUBTRACT ARIVAL-TIME-NUMERIC 
            FROM CURRENT-TIME-NUMERIC
            GIVING ETA-NUMERIC.
        DISPLAY "RESULTING ETA:"
        DISPLAY ETA-NUMERIC.
        DISPLAY "HOURS:"
        DISPLAY CURRENTHOUR
        DISPLAY "MINUTES:"
        DISPLAY CURRENTMINUTE

        STOP RUN.


评论

对于特权用户来说,创建COBOL标签可能会很不错。

哇,我以为我永远都看不到实际的COBOL代码-那就是将人类送往月球的原因吗?如果有什么安慰的话,我认为没有多少人[活着]熟悉COBOL最佳实践:)(没有针对任何实际的COBOL程序员的冒犯!)

@retailcoder参见exit109.com/~ghealton/y2k/y2k_humor/Cobol.html并哭泣。

@retailcoder:stackoverflow.com/questions/tagged/cobol

去年,我不得不在学校与COBOL合作。我还在做噩梦

#1 楼

我注意到了几件事:


没有身份识别部门。 “ IDENTIFICATION DIVISION对程序的执行没有影响,但是作为将程序识别给计算机的一种手段还是必需的。”-Stern&Stern
第一个REDEFINES并没有真正的理由。另外,您似乎在使用错误。重新定义子句只是引用相同工作存储位置的另一种方法。如果要存储不同的数据,则将需要不同的变量。虽然您可以继续重新定义相同的变量并以不同的方式使用它,但它可能会变得凌乱并且存储起来会更加困难。
虽然您可以拥有3级变量,但我发现最好将其递增of 5
很多时候,如果您在真实的COBOL环境中工作,则需要一个环境部门。显然这里没有,但是请记住
您应该在WORKING-STORAGE SECTION中以WS-开头所有变量名,因为如果该程序需要与任何其他程序进行交互,那么您将拥有一个LINKAGE-SECTION及其一组变量。
仅可使用句点结束段落。从技术上讲,您可以使用句号结束​​任何事情。这导致代码混乱。此外,句点将关闭所有打开的语句。如果您有一个三重嵌套的IF,并且以一个句号结尾,它将关闭所有3。到达该点时,请使用适当的瓢终止符,例如END-IFEND-PERFORM

间距也很重要。

已经在另一个答案中解决了逻辑问题,因此在此我不再赘述。我在下面的代码中添加了我的建议:

        INDENTIFICATION DIVISION
        PROGRAM-ID. THE-TIMER.
        AUTHOR. name.
        DATE-WRITTEN. date.
        DATE-COMPILED. date.
        *****************************************************************
        *header comment about the program change logs ect               *
        *****************************************************************

        DATA DIVISION.
        WORKING-STORAGE SECTION.

        01 TIME-STORAGE.
            05 WS-CURRENT-TIME        PIC 9(8).
               10  WS-CURRENTHOUR     PIC 99.
               10  WS-CURRENTMINUTE   PIC 99.
               10  WS-FILLER          PIC 9(4).

            05 WS-ARIVAL-TIME         PIC 9(8).
               10  WS-ARRIVALHOUR     PIC 99.
               10  WS-ARRIVALMINUTE   PIC 99.
               10  WS-FILLER          PIC 9(4).

            05 WS-ETA                 PIC 9(8).
               10 WS-ETAHOUR          PIC 99.
               10 WS-ETAMINUTE        PIC 99.
               10 WS-FILLER           PIC 9(4).


        PROCEDURE DIVISION.

            BEGIN-BUG-NORMAN.

            DISPLAY "when will you be ariving?"
            DISPLAY "HH [enter]"
            ACCEPT WS-ARRIVALHOUR
            DISPLAY "MM [enter]"
            ACCEPT WS-ARRIVALMINUTE

            ACCEPT WS-CURRENT-TIME FROM TIME
            SUBTRACT WS-ARIVAL-TIME 
                FROM WS-CURRENT-TIME
                GIVING WS-ETA

            DISPLAY "RESULTING ETA: "
            DISPLAY ETA-NUMERIC
            DISPLAY "HOURS: "
            DISPLAY CURRENTHOUR
            DISPLAY "MINUTES: "
            DISPLAY CURRENTMINUTE

            IF WS-ETAHOUR > 5
               DISPLAY " It could be a while"
            END-IF

            STOP RUN.


评论


\ $ \ begingroup \ $
哦,不!真正了解COBOL而不是仅仅阅读它的人! (好答案,顺便说一句)
\ $ \ endgroup \ $
–rolfl
2014年1月3日,13:39

\ $ \ begingroup \ $
谢谢!我是新来的一个代码审查和stackoverflow的新人,但读者却很长。我只想回馈!
\ $ \ endgroup \ $
– SaggingRufus
2014年1月3日,13:59

\ $ \ begingroup \ $
谁能告诉我为什么我的代码块不会缩进?
\ $ \ endgroup \ $
– SaggingRufus
2014年1月3日14:01

\ $ \ begingroup \ $
我不确定为什么PROCEDURE DIVISION上的缩进是错误的(原始文本是错误的,而不是标记),但是,我添加了额外的空格。我现在将代码对齐到第12列。
\ $ \ endgroup \ $
–rolfl
2014年1月3日14:22

\ $ \ begingroup \ $
它可能会影响初始编译,仅此而已。编译时,已编译的代码将存储在装入库中,以由JCL运行或由CICS调用。我个人和同事一样添加了它们,因为可读性大大提高了。我也看到人们评论了这些话。在我看来,代码的可读性比初始编译时间更为重要。
\ $ \ endgroup \ $
– SaggingRufus
2014年1月8日12:21



#2 楼

尽管代码简洁明了(COBOL始终是....; ;-)),但是我发现您的计算中存在一些逻辑缺陷。

具体来说,请考虑当前时间14450000(2:45 pm)和用户输入[HH]的15和[MM]的15作为他的ETA(3:15 pm)

,您的减法将存储1445000015150000之间的差。存储在ETA-NUMERIC中的差异将是00700000,并且代码将显示HOURS:00MINUTES:70,但是,我们知道它们之间只有30分钟。

代码没有考虑到分钟是基本时间-60。

评论


\ $ \ begingroup \ $
感谢您指出逻辑错误。我还未能找到与jodatime等效的cobol。该公司有很多内部日期处理代码,但是尝试理解有点麻烦。我发现所有可能起作用的库都不会与我们被迫使用的标志一起编译。
\ $ \ endgroup \ $
– Ape-in​​ago
2014年1月4日14:35

#3 楼

在大多数情况下,您假设有效的数值不会使您更快地获得s0c7。用外行术语来说,系统完成代码为0C7,也称为s0c7。这意味着“试图对非数字数据执行数字运算”。顺便说一句,如果用户输入的空格表示零,bam,s0c7。

因此最佳做法是添加“如果WS-CURRENTHOUR是数字,则....”

当然,您可能需要组合许多检查,但这会使有意义的错误消息更加困难。

#4 楼

搜索“最佳实践”是值得称赞的,应该会使您受益。

但是,即使在50年以上的时间里,也不要期望“最佳实践”的存在和不存在达成共识。

除此之外,您还应该为自己的网站制定一套“本地标准”。这些你应该坚持下去,其他人也应该坚持下去。如果它们包含愚蠢的内容,请尝试进行讨论,但此后再达成共识。如果每个人都有最好的机会理解其他人编写的代码,情况将会更好。传统上,COBOL系统是团队合作的结晶,因此理解他人的代码并使其易于理解非常重要。

有时本地标准并不是很多人所描述的最佳实践。在过去的某些时候,它们可能至少是一种良好的做法,但是本地标准变化缓慢。

您在评论中询问空白行。也许40年前(较少依赖特定站点的硬件)没有空白行是有意义的。每个空白行都是一张打孔卡。每张卡都需要一些时间才能读取。每张卡都可能出现故障,并阻塞读卡器,或者被拒绝。

即使过了这么短的时间,CPU的运行速度也没有今天那么快。因此,仅读取空白行以让编译器忽略即可,这会对大型程序的编译器吞吐量产生一定的影响,并且可能只有一个地址空间专门用于编译并一天24小时运行,所以累加很少。

今天,完全不用担心。使您的程序对人类可读。编译器将始终进行管理,是我们在阅读程序时需要帮助,因此请把它交给我们。

A. MOVE B TO C. PERFORM D. D. MOVE E TO F. PERFORM I. I. MOVE Z TO Q.


那是“有效的” COBOL。从理论上讲,编译起来比编码8条单独的行(甚至没有空行)要快,但要弄清楚人类要了解的情况需要花费多长时间。

NEW-CLIENT-RECORD.

    [all the stuff you need to do for establishing a new client record]

    PERFORM                       NEW-CLIENT-SUB-RECORD
    .
NEW-CLIENT-SUB-RECORD.

    [all the stuff you need to do ...]

    PERFORM                       CLIENT-COMPLIANCE-VERIFICATION
    .

CLIENT-COMPLIANCE-VERIFICATION.

    [all the stuff you need to do ...]
    .


不要尝试使用REDEFINES“保存存储”。定义单独的字段,并避免在编写代码时或在两个月内有人(也许您)对粗心的更改进行“副作用”头痛的情况。

对所有内容使用好名字。放弃有关VAR1或I,J,K的任何想法。

IF VAR1(J)>7
    MOVE "Y" TO VAR4
END-IF


您希望调试该代码还是编写以下代码:

IF CT-OF-APPLES-IN-STOCK ( WAREHOUSE-STOCKED-IN )
    GREATER THAN MAX-CT-FOR-PERISHABLES-TYPE-P014 [which has a value of 7]
    SET OVERSTOCKED-ORANGES        TO TRUE
END-IF


实际上,看,你甚至不能写关于橘子的东西,对吗?在撰写本文时,您甚至可以问自己(看看规格,问分析师/设计师/业务用户),这应该是苹果的“数量”,还是“盒子”或“托盘”之类的东西,因为仓库中的苹果通常不会单独存放。

尝试从VAR1 / I垃圾中获取有用的东西,您将花费大量时间来追踪字段的内容以及内容

使程序可读。无所事事会使事情变得晦涩。遵守当地标准。

阅读手册。阅读其他人的代码。实验。考虑一下人们的建议以及它给您带来的好处。例如,您会发现WS01-data-name,WS02-data-name等。W很有用,其余的都是废话。定义数据时会造成挫败感。如果不重命名所有内容,就不可能将新数据包括在与之相关的一组现有数据中。您会发现规定此类情况的当地标准。尝试进行更改,但如果失败,则顺其自然(当然,请编写一些宏/脚本来为您工作)。

评论


\ $ \ begingroup \ $
我什至没有想到它可能已经在打孔卡上开始了。除此之外,似乎确实有很多真正的旧代码必须在时间限制内工作。 ;
\ $ \ endgroup \ $
– Ape-in​​ago
2014年2月1日19:30在

\ $ \ begingroup \ $
可悲的是,即使是新开发的东西也仍然在写那些限制。我最终把所有必须处理的COBOL都花光了。但是我确实了解了各种编程反模式。我想我会喜欢像第二个示例那样编写代码。我最大的问题是没有可遵循的真正标准,也没有任何推动它实现的动力。我想到的是,您提到的内容应该与大多数编程语言中的课程相提并论,但我认为情况不再如此。
\ $ \ endgroup \ $
– Ape-in​​ago
2014年2月1日19:40



\ $ \ begingroup \ $
@ Ape-in​​ago我很同情。它是一种可以很好或不好使用的语言。许多使用不当的人认为使用得当。
\ $ \ endgroup \ $
–比尔·伍德格
2014年2月1日在22:01