模糊推理 控制 易于实现_代码“易于推理”是什么意思?

模糊推理 控制 易于实现

by Preethi Kasireddy

通过Preethi Kasireddy

代码“易于推理”是什么意思? (What does it mean when code is “easy to reason about”?)

You’ve probably heard the expression “easy to reason about” enough times to make your ears bleed.

您可能已经听过“易于推理”的表达,足以让您的耳朵流血。

The first time I heard this expression, I had no idea what the person meant by it.

第一次听到这种表达时,我不知道这个人是什么意思。

Does it mean functions that are easy to understand?

它是否意味着功能易于理解?

Does it mean functions that work properly?

这是否意味着功能正常工作?

Does it mean functions that are easy to analyze?

它是否意味着易于分析的功能?

After a while, I’d heard “easy to reason about” in so many contexts that I figured it was just another semi-meaningless developer buzzword.

一段时间后,我在很多情况下都听到“容易推理”,以至于我认为这只是另一个无意义的开发人员流行语。

…But is it really meaningless?

…但这真的没有意义吗?

The truth is, the expression does have a significant meaning. It captures a fairly complex idea, which makes decoding it a bit tricky. Trickiness aside, having a high-level understanding of what “easy to reason about” code looks like absolutely helps us write better programs.

事实是,该表达确实具有重要意义。 它捕获了一个相当复杂的想法,这使其解码起来有些棘手。 除了棘手的问题外,对“易于推理”的代码看起来有高层的了解绝对可以帮助我们编写更好的程序。

To that end, this post will be dedicated to dissecting the expression “easy to reason about” as it relates to the technical conversations we have as developers.

为此,本文将专门剖析“易于推理”的表达方式,因为它与我们作为开发人员进行的技术对话有关。

了解程序的行为 (Understanding your program’s behavior)

Once you’ve written a piece of code, you typically also want to understand the program’s behavior, how it interacts with other parts of the program, and the properties it exhibits.

一旦编写了一段代码,您通常还希望了解程序的行为,程序与程序其他部分的交互方式以及所显示的属性。

For example, take the piece of code below. This should multiply an array of numbers by 3.

例如,采用下面的代码。 这应该将数字数组乘以3。

How can we test that it works as intended? One logical way is to pass a bunch of arrays as input and ensure that it always returns the array with each item multiplied by 3.

我们如何测试它是否按预期工作? 一种逻辑方法是传递一堆数组作为输入,并确保它总是返回每个项目乘以3的数组。

Looks good so far. We’ve tested that the function does what we want it to do.

到目前为止看起来不错。 我们已经测试过该功能可以完成我们想要的功能。

But how do we know it doesn’t do what we don’t want it to do? For instance, with careful inspection, we can see that the function mutates the original array.

但是,我们如何知道它没有做我们希望做的事情? 例如,通过仔细检查,我们可以看到该函数对原始数组进行了变异。

Is that what we intended? What if we need references to both the original array and the resulting array? Too bad, I guess.

那是我们想要的吗? 如果我们需要同时引用原始数组和结果数组该怎么办? 我想这太糟糕了。

Next, let’s see what happens if we pass the same array a bunch of different times — does it always return the same result for a given input?

接下来,让我们看看如果我们多次传递相同的数组会发生什么—它是否总是为给定的输入返回相同的结果?

Uh oh. It looks like when we passed the array [1, 2, 3] to the function the first time, it returned [3, 6, 9], but later it returned [ 49, 98, 147 ]. Those are very different results.

哦哦 看起来像是当我们第一次将数组[1、2、3]传递给函数时,它返回了[3、6、9] ,但后来又返回了[49、98、147] 。 这些是截然不同的结果。

That’s because the multiplyByThree function relies on an external variable multiplier. So, if the external state of the program causes the variable multiplier to change in between calls to the function multiplyByThree, the behavior of the function changes even if we pass the same array into the function.

那是因为multipleByThree函数依赖于外部变量乘数 。 因此,如果程序的外部状态导致变量乘数在对函数multipleByThree的调用之间改变,那么即使将相同的数组传递给函数,该函数的行为也会改变。

Eeek. Not looking that great anymore. Let’s dig a little deeper.

eek 看起来不再那么好了。 让我们深入一点。

So far, we’ve tested perfect array inputs. Now, what if we were to do this:

到目前为止,我们已经测试了完美的数组输入。 现在,如果我们要这样做:

What in the world?!?

到底是什么?!?

The program looked great on the surface — when we take a few minutes to evaluate it, however, it was a different story.

该程序表面上看起来很棒–当我们花几分钟时间对其进行评估时,却是另一回事了。

We saw that it sometimes returns an error, sometimes returns the same thing you passed to it, and only occasionally returns the expected result. Moreover, it has some unintended side effects (mutating the original array) and doesn’t seem to be consistent in what it returns for a given input (since it relies on external state).

我们看到它有时返回错误,有时返回您传递给它的东西,并且仅偶尔返回预期结果。 而且,它具有一些意外的副作用(使原始数组发生突变),并且对于给定输入返回的结果似乎不一致(因为它依赖于外部状态)。

Now, let’s look a slightly different multiplyByThree function:

现在,让我们看一个稍微不同的multipleByThree函数:

Just like above, we can test for correctness.

就像上面一样,我们可以测试正确性。

Looking good so far.

到目前为止看起来不错。

Let’s also test to see if it does what we don’t want it to do. Does it mutate the original array?

让我们也测试一下是否可以完成我们不希望做的事情。 它会改变原始数组吗?

Nope. The original array is intact!

不。 原始数组完好无损!

Does it return the same output for a given input?

对于给定的输入,它是否返回相同的输出?

Yep! Since the multiplier variable is now within the scope of the function, even if we declare a duplicate multiplier variable in the global scope, it won’t affect the result.

是的 由于乘数变量现在位于函数的范围内,因此即使我们在全局范围内声明重复的乘数变量,也不会影响结果。

Does it return the same thing if we pass a bunch of different types of arguments?

如果我们传递一堆不同类型的参数,它是否会返回相同的东西?

Yep! Now the function behaves more predictably — it either returns an error or a new resulting array.

是的 现在,该函数的行为更具可预测性-它返回错误或新的结果数组。

At this point, how confident are we that this function does exactly what we want it to do? Have we covered all the edge cases? Let’s try a few more:

在这一点上,我们对这个功能确实能够实现我们想要的功能充满信心吗? 我们涵盖了所有极端情况吗? 让我们再尝试一些:

Damn. Looks like our function still needs a little work. When the array itself contains unexpected items, like undefined or strings, we see weird behavior again.

该死的。 看起来我们的功能仍然需要一点工作。 当数组本身包含意外项目( 如未定义或字符串)时,我们会再次看到怪异的行为。

Let’s try to fix it by adding another check in our for-loop checking for invalid array elements:

让我们尝试通过在for循环检查中添加另一个检查无效数组元素来解决此问题:

With this new function, why not try those two edge cases again:

有了这个新功能,为什么不再次尝试这两个边缘情况:

Sweet. Now it also returns an error if any of the items in the array are not numbers instead of some random funky output.

甜。 现在,如果数组中的任何项目不是数字,而是一些随机的时髦输出,它也会返回一个错误。

最后,一个定义 (Finally, a definition)

By going through the the above steps, we’ve slowly built up a function that is easy to reason about because it has these key qualities:

通过上述步骤,我们逐步构建了一个易于推理的函数,因为它具有以下关键特性:

  1. Does not have unintended side effects

    没有意外的副作用
  2. Does not rely on or affect external state

    不依赖或不影响外部状态
  3. Given the same argument, it will always return the same corresponding output (also known as “referential transparency”).

    给定相同的参数,它将始终返回相同的对应输出(也称为“ 参照透明性 ”)。

我们可以保证这些属性的方法 (Ways we can guarantee these properties)

There’s a lot of different ways we can guarantee that our code is easy to reason about. Let’s take a look at a few:

我们可以通过很多不同的方式来保证我们的代码易于推理。 让我们看一些:

单元测试 (Unit tests)

Firstly, we can write unit tests to isolate pieces of code and verify that they function as intended:

首先,我们可以编写单元测试来隔离代码段并验证它们是否按预期运行:

Unit tests like these help us verify that our code behaves correctly and give us living documentation about how small pieces of the overall system work. The caveat with unit tests is that unless you’re very thoughtful and thorough, it’s incredibly easy to miss problematic edge cases.

像这样的单元测试可以帮助我们验证我们的代码是否正确运行,并为我们提供有关整个系统的小部分工作方式的实时文档。 单元测试的警告是,除非您非常周到和透彻,否则遗漏有问题的边缘情况非常容易。

For example, we would never have figured out that the original array is being mutated unless we somehow thought to test for it. So our code is only as robust as our tests.

例如,除非我们以某种方式考虑对其进行测试,否则我们永远不会弄清楚原始数组是否正在被突变。 因此,我们的代码仅与测试一样强大。

种类 (Types)

In addition to tests, we might also use types to make it easier to reason about code. For example, if we were using a static type checker for JavaScript like Flow, we could ensure that the input array is always an array of numbers:

除了测试,我们还可以使用类型来简化代码推理。 例如,如果我们对像Flow这样JavaScript使用静态类型检查器,则可以确保输入数组始终是数字数组:

Types force us to explicitly state that the input array is an array of numbers. They help create restrictions on our code which prevent many kinds of runtime errors like we saw earlier. In our case, we no longer have to think about checking to make sure that each item in the array is a number — this is a guarantee given to us with types.

类型迫使我们明确声明输入数组是数字数组。 它们有助于对我们的代码创建限制,以防止像我们前面看到的多种运行时错误。 在我们的例子中,我们不再需要考虑确保数组中的每个项目都是数字,这是对类型的保证。

不变性 (Immutability)

Lastly, another thing we can do is use immutable data. Immutable data just means that the data cannot be changed once it’s created. This helps avoid unintended side effects.

最后,我们可以做的另一件事是使用不可变数据。 不可变的数据只是意味着一旦创建数据就无法更改。 这有助于避免意外的副作用。

In our earlier example, for instance, if the input array were immutable, it would have prevented the unpredictable behavior where the original array is mutated. And if the multiplier were immutable, it would prevent situations where some other part of the program can mutate our multiplier.

例如,在我们前面的示例中,如果输入数组是不可变的,那么它将防止原始数组发生突变时发生不可预测的行为。 而且,如果乘数是不可变的,它将防止程序的其他部分可以使乘数发生变化的情况。

Some of the ways we can reap the benefits of immutability is by using a functional programming language that inherently ensures immutability or by using an external library, like Immutable.js, that enforces immutability on top of an existing language.

我们可以利用不变性的好处的一些方法是使用一种功能性编程语言来固有地确保不变性,或者使用外部库(例如Immutable.js)在现有语言之上实施不变性。

As a fun exploration, I’ll use Elm, a typed functional programming language, to demonstrate how immutability helps us:

作为一个有趣的探索,我将使用一种类型化的函数式编程语言Elm来演示不变性如何帮助我们:

This little snippet does the same thing as our JavaScript multiplyByThree function from before, except it’s now in Elm. Since Elm is a typed language, you’ll see on line 6 that we define the input and output types for the function multiplyByThree as both being a list of numbers. The function itself uses the basic map operation to generate the resulting array.

这个小片段与JavaScript的遍历功能相同,只是现在在Elm中 。 由于Elm是一种类型化的语言,因此您会在第6行看到我们将函数multipleByThree的输入和输出类型定义为数字列表。 该函数本身使用基本映射操作来生成结果数组。

Now that we’ve defined our function in Elm, let’s do one last round of the same tests we did for our earlier multiplyByThree function:

既然我们已经在Elm中定义了函数,那么让我们做最后一轮的测试,该测试与我们之前的multiByThree函数相同:

As you can see, the result is what we expected and the originalArray has not been mutated.

如您所见,结果是我们所期望的,而且originalArray还没有发生突变。

Now, let’s throw Elm for a trick and try mutating the multiplier:

现在,让我们把Elm当作一个把戏,然后尝试改变乘数:

Aha! Elm restricts you from doing this. It throws a very friendly error.

啊哈! 榆木限制您执行此操作。 它抛出一个非常友好的错误。

What if we were to pass a string as an argument, instead an array of numbers?

如果我们将字符串作为参数而不是数字数组传递呢?

Looks like Elm caught that as well. Because we declared the argument as a List of numbers, we cannot pass anything but a List of numbers even if we tried!

看起来榆树也抓住了这一点。 因为我们将参数声明为数字列表,所以即使尝试,我们也只能传递数字列表!

We cheated a little bit in this example by using a functional programming language which has both types and immutability. The point I wanted to prove is that with these two features, we no longer have to think about manually adding checks for all the edge cases in order to gain the three properties we discussed. Types and immutability guarantee that for us, and in turn, we can reason about our code more easily ?

在本示例中,我们使用了一种既具有类型又具有不变性的功能编程语言,以作弊。 我想证明的一点是,有了这两个功能,我们不再需要考虑为所有边缘情况手动添加检查以获取我们讨论的三个属性。 类型和不变性为我们提供了保证,进而可以使我们更轻松地推理代码?

现在轮到您对代码进行推理了 (Now it’s your turn to reason about your code)

I challenge you to take a moment next time you hear someone say, “XYZ makes it easy to reason about code” or “ABC makes is difficult to reason about code.” Replace that fancy buzzword with the properties mentioned above, and try to understand what the person means. What properties does the piece of code have that makes it easy to reason about?

下次您听到有人说“ XYZ使代码推理变得容易”“ ABC使代码推理变得困难”时 ,我挑战您花点时间 用上面提到的属性替换该时髦的流行语,并尝试理解该人的含义。 代码段具有哪些属性可以使推理变得容易?

Personally, doing this exercise has helped me critically think about code and, in turn, has motivated me think about how to write programs that are easier to reason about. I hope it does the same for you too!

就个人而言,进行此练习可以帮助我批判性地考虑代码,进而促使我考虑如何编写更易于推理的程序。 我希望它也对您有帮助!

I’d love to hear your thoughts on other properties that I might have missed that you think are important. Please leave your feedback in the comments!

我很想听听您对其他物业的想法,我可能会错过您认为重要的事物。 请在评论中留下您的反馈!

翻译自: https://www.freecodecamp.org/news/what-does-it-mean-when-code-is-easy-to-reason-about-4e6f63eb386f/

模糊推理 控制 易于实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值