programming-languages - 关于如何编写函数的编程风格问题

标签 programming-languages coding-style user-input

所以,我今天只是编码了一点,我意识到在编程功能时,我在编码风格方面没有太多的一致性。我的主要关注点之一是对其进行编码是否合适,以便您检查用户的输入在函数之外是否有效,或者只是将用户传递的值扔到函数中并检查这些值是否有效在那里。让我画一个例子:

我有一个基于环境列出主机的函数,我希望能够将环境拆分为主机块。所以用法的一个例子是这样的:

listhosts -e testenv -s 2 1

这将从“testenv”中获取所有主机,将其分成两部分,并显示第一部分。

在我的代码中,我有一个函数,你将它传递到一个列表中,它根据你的分割参数返回一个列表列表。但是,在我传递一个列表之前,我首先在 getops 过程中验证我的 MAIN 中的参数,所以在主要我检查以确保用户没有传递负面信息,我确保用户没有请求拆分比如说,4 个部分,但要求显示第 5 部分(这将是无效的),等等。

tl;dr:您会检查用户输入主类流程的有效性,还是会检查您的函数本身,并在输入有效的情况下返回有效响应,或者在输入中返回 NULL无效输入的情况?

显然这两种方法都有效,我只是想听听专家关于哪种方法更好的意见:) 感谢你们提出的任何意见和建议!仅供引用,我的示例是用 Python 编写的,但我仍然对通用编程答案更感兴趣,而不是特定于语言的答案!

最佳答案

好问题!我的主要建议是系统地处理问题。如果您正在设计一个函数 f ,这是我对它的规范的看法:

  • f的来电者的绝对要求是什么?必须见?这些要求是 f的前提。
  • 什么f为它的调用者做什么?当f返回,返回值是什么,机器的状态是什么? f什么情况下抛出异常,抛出什么异常?所有这些问题的答案构成f的后置条件。

    前置条件和后置条件共同构成 f与来电者的契约(Contract)。
    只有满足先决条件的调用者才能依赖后置条件。
  • 最后,直接针对您的问题,如果 f 会发生什么情况的调用者不满足先决条件?你有两个选择:
  • 您保证停止该程序,希望得到一条信息丰富的消息。这是一个 检查运行时错误。
  • 什么都可以。可能是段错误,可能是内存损坏,可能是f默默地返回一个错误的答案。这是一个 未经检查的运行时错误。

  • 注意一些不在此列表中的项目:引发异常或返回错误代码。如果要依赖这些行为,它们将成为 f 的一部分。的契约(Contract)。
    现在我可以改写你的问题:

    What should a function do when its caller violates its contract?



    在大多数类型的应用程序中,函数应该停止程序并检查运行时错误。如果程序是需要可靠的应用程序的一部分,则应用程序应提供外部机制来重新启动因检查的运行时错误而停止的应用程序(在 Erlang 代码中很常见),或者如果重新启动困难,则所有功能' 契约(Contract)应该非常宽容,这样“错误的输入”仍然符合契约(Contract),但 promise 总是会引发异常。

    在每个程序中,未经检查的运行时错误应该很少见 .未经检查的运行时错误通常仅在性能方面是合理的,即使如此,也仅当代码对性能至关重要时。未经检查的运行时错误的另一个来源是使用不安全的语言进行编程。例如,在 C 中,没有办法检查所指向的内存是否已实际初始化。

    你问题的另一方面是

    What kinds of contracts make the best designs?



    这个问题的答案因问题域而异。
    因为我所做的工作都不是高可用性或安全关键的,所以我使用 限制性契约(Contract)以及大量检查过的运行时错误(通常是断言失败)。当你设计一个大系统的接口(interface)和契约时,如果你保持契约简单,保持先决条件限制(严格),并且在参数“坏”时依赖检查的运行时错误,那么事情就会容易得多。

    I have a function that you pass it in a list, and it returns a list of lists based on you parameters for splitting. BUT, before I pass it a list, I first verify the parameters in my MAIN during the getops process, so in the main I check to make sure there are no negatives passed by the user, I make sure the user didnt request to split into say, 4 parts, but asking to display part 5.



    我认为这正是解决这个特定问题的正确方法:
  • 你与用户的契约是用户可以说任何话,如果用户发出一个无意义的请求,你的程序不会崩溃——它会发出一个合理的错误消息,然后继续。
  • 您与请求处理功能的内部约定是,您将只传递合理的请求。
  • 因此,您有第三个功能,在第二个功能之外,它的工作是区分有意义和无意义并相应地采取行动——您的请求处理功能获得“意义”,用户被告知“无意义”,并且所有契约(Contract)都得到满足。

  • One of my main concerns is whether or not its proper to code it so that you check that the input of the user is valid OUTSIDE of the function.



    是的。 这几乎总是最好的设计。事实上,某处可能有一个设计模式,名字很花哨。但如果没有,经验丰富的程序员已经一遍又一遍地看到了这一点。发生以下两种情况之一:
  • 解析/验证/拒绝错误消息
  • 解析/验证/处理

  • 这种设计有一种数据类型(请求)和四种功能。由于我本周要编写大量 Haskell 代码,因此我将在 Haskell 中举一个例子:
    data Request -- type of a request
    parse    :: UserInput -> Request            -- has a somewhat permissive precondition
    validate :: Request -> Maybe ErrorMessage   -- has a very permissive precondition
    process  :: Request -> Result               -- has a very restrictive precondition
    

    当然,还有很多其他方法可以做到。可以在解析阶段和验证阶段检测到失败。 “有效请求”实际上可以由与“未验证请求”不同的类型表示。等等。

    关于programming-languages - 关于如何编写函数的编程风格问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2664292/

    相关文章:

    html - 是否有任何 HTML 风格指南?

    c# - 将用户输入的搜索查询转换为用于 SQL Server 全文搜索的 where 子句

    c - 在 C 中使用用户输入执行

    c# - 如何获取绘图板笔压力值?

    types - 有类型与无类型语言

    programming-languages - 保留关键字按编程语言计数?

    algorithm - 用计算机程序解决任何问题的最小指令集

    c - 为什么 int 类型的变量在许多语言中默认是有符号的?

    vb.net - 在单个语句中编写代码然后逐步分解它是否有更多的开销?

    c# - 在没有魔数(Magic Number)的情况下使用 IComparable.Compare