主管的心理反应性编程模型


本文面向希望了解什么是响应式编程的广泛读者。本文的目的是在不涉及技术细节的情况下,形成基本的反应式编程心智模型(MM RP)。

免责声明
( ) — , . , .
, : , . , , .
.

但首先,让我们解释一下本文标题中提到的思维模式和上司与之有何关系...

关于心理模型
, , , . , .
, , (. [1], [2])
? , , . (), , , . , , «», «» « » .
, , (), , - ().

这是老板们...
. «» «» , : . ( , «» , ).
, «» , , , , , . , . «» «». , , , .
, , , .., () — , , .
, .


为什么反应式编程需要您的项目?


许多不熟悉RP的人最初对他表示怀疑,怀疑这只是另一种空洞的方式,用几个漂亮的字眼掩盖了。特别是当他们得知您只能通过尝试才能评估RP时。而且由于入门门槛高,尝试起来很昂贵。我们与OOP一起生活和生活,它还缺少什么?
让我介绍一下我在这个问题上的观点。
在编程的曙光中,当大多数程序直接用汇编语言编写时,程序员的主要工作概念(心理模型的一个元素)就是一条指令或一种语言命令。一些(原始)数据被馈送到命令或指令的输入。该指令处理并发布一些输出数据。诸如Fortran之类的第一个过程编程语言的出现并没有改变问题的本质。仅数据和执行的操作(作为基本命令序列)已变得更加复杂。
随着时间的流逝,很明显,这个概念与世界的现实不是很一致。可能有很多数据,它们可能很难构造。数据及其周围的功能都可以很好地分解成几个部分,分别进行开发和维护,以及一起使用。
OOP通过多种方式解决了这些问题。典型的OOP程序员的心理模型的单元是一个对象,该对象中隐藏(封装)了数据,并以一组功能访问该数据。
OOP在许多制造和其他过程的自动化和计算机化中发挥了巨大作用。而且,他的弱点也暴露出来了。
不幸的是,在OOP中,没有这样的过程概念。
他们试图以不同方式改善局势,着重于各个方面。
因此,诞生了事件驱动编程[3],数据流编程[4],流处理[5]和其他几种范例。
我敢于引起对这些范式的拥护者和专家的批评,试图用简单的语言传达其一般本质。
这些范例以一种或另一种方式与信息流一起运行。同时,顾名思义,事件驱动编程着眼于信息流元素,数据流编程的出现过程-数据流控制(拆分,合并,转换流)以及在处理数据流时以最佳方式利用资源进行数据流处理。
响应式编程是一回事,但重点是创建,管理和使用线程的特定基本操作。那些。 RP描述了系统如何对信息流的元素做出反应(英语做出反应)。从这个意义上说,如果不是为了割耳,用俄语“试剂编程”(来自“反应”一词)或“反应编程”(来自“反应与某物”一词)是更正确的,第二个没有引起错误的关联。
我敢于表达另一种煽动性的想法。今天我们所说的是英语反应式编程(Reactive Programming)。出于历史原因之所以如此称呼,并倾向于多数意见。
这种范式本来可以被不同地称为。因此,不要只关注其当前名称,而要了解其本质。
并且尽管我将在相当抽象的级别上谈论RP,但我将RxJS库API作为具体示例。
首字母缩写词RxJS代表JavaScript的Reactive Extension,这是Reactive Programming功能的JavaScript扩展。对于许多其他编程语言,存在类似的扩展,如下图所示,摘自[6]。
反应式编程扩展

为什么RP的心理模型需要您的项目


大型项目并非一个人完成。您通常可以阅读或听到项目参与者必须说相同的语言。我的经验表明,这几乎是没有必要和不可能的。但是需要使项目参与者尽可能平等地陈述和理解项目的最基本概念。就心理模型(MM)而言,我们可以说高层MM应该尽可能相似。
但是,如果分析师在工作流和用例,模式的架构师,功能和数据结构的开发人员以及测试场景的测试人员方面进行思考,它们又有何相似之处?
我不敦促所有这些专家开始对“反应式编程”类别同时进行思考,但是我可以向他们保证,熟悉这些类别将简化并提高与同事的专业沟通的效率。之所以会发生这种情况,是因为,一方面,MM RP具有描述复杂工作流所必需的功能;另一方面,MM RP可直接转换为许多编程语言的代码。

惊喜,危险或RP并不是我们都习惯的方式


但是在我们根据自己的经验对反应式编程思维模型的组成进行描述之前,我想提醒读者注意其中没有的内容。而且,不仅如此,世界上对简单且可理解的OOP行为的期望也导致了可悲的后果。
我这样做并不是要吓tim,而是要引起读者的兴趣。

差异1:代替游标模型,而是计算图


我会建议许多读者在考虑下一个要实现的任务时,会想到一个心理模型,我称之为游标模型。假定将发明一种线性指令列表形式的逐步算法来解决该问题。算法的执行减少为一个接一个地逐步执行指令。您可以想象一下类似于当前执行指令的指针。执行该指令后,指针(光标)将移至列表中的下一条指令并开始执行。
在此模型中,使用条件面向对象的编程语言编写的一系列命令
1. 1 = 2
2. 2 = 3 
3. 3 = 1 + 2
4.  1, 2, 3
5. 1 = 4
6.  1, 2, 3

将给出结果
2 3 5
4 3 5

我们的光标思维模型可以完美地预测和解释这种结果。处理完第三行后,将设置值X3,并且第5行中指定的X1的新值无法更改。
在RP的世界中,根据对“ +”运算的解释,结果很可能是
2 3 5
4 3 7

在这个世界上,大多数操作都将输入参数彼此连接,从而创建计算图,当一个或多个参数发生更改时,通过这些计算图可以“推动”计算。

差异2:异步操作


在游标心智模型的计算框架中,下一个操作不能早于上一个操作开始。
考虑以下示例。假设函数f1通过用户标识符userId的值计算基本工资,函数f2根据userId和工资的值计算奖金。
那么全薪的计算可能像这样
1. X = f1(userId)
2. Y = f2(userId, X)
 X, Y

假设一名工作人员的基本工资为10,000。和1000个单位的奖金。
我们的光标心理模型会告诉您要打印的内容。
10000 1000 

asynchronous,在异步RP的世界中,取决于操作的持续时间,结果可能是
0 0 
10000 0 
0 1000 
10000 1000 

(我还没有考虑例外)。
事实是,在异步反应世界中,如果下一个操作是异步的,则下一个操作不会等待上一个操作的结束。
为了说明这一点,让我们使用下图所示的实际示例来看一些重要的细节。
该图显示了在同步(图片的上部)和异步(图片的下部)模式下彼此独立的四个指令L1,L2,L3和L4(它们的编号对我们很重要,而不是拼写)的执行时间。

如我们所见,在第一种情况下,每条后续指令都“等待”前一条指令的结尾。在异步情况下,所有指令开始同时执行。由于并行执行和使用资源,大多数指令在异步模式下运行的时间比在同步模式下运行的时间更长。但是,他们在一起将遗留工作。
两种模式下指令的完成顺序也有很大不同。在同步中:
L1, L2, L3, l4
但在异步中:
L3, L2, L1, L4


差异3:不完整的链(没有消费者)根本不起作用


在许多传统的编程语言中,通常将函数调用或对象属性与点相关联。
例如,以下JavaScript函数调用链将单词“ good”变成“ dog”:
„good“.split(„“).reverse().join(„“).replace(„oo“, „o“);

序列(链)可能很长。出于重复使用或方便的原因,可以将它们切成小块并部分执行。
将RP中的一条链分为两个部分并仅调用其中一个通常会导致结果的缺乏,因为只执行了整个链(最后是消费者)。

为什么要这样?


可能,许多读者已经在问自己一个问题:“这些反应灵敏的程序员,他们没有集体发疯吗?为什么需要这样的编程?”
我不能预测波兰共和国的创造者和专家将回答这个问题,但是我的回答是:这样的程序设计是必要的,因为现实世界中的许多对象的行为都是这样。
计算图 -这是Excel的基础,不仅使会计师,而且项目经理都从中受益。
异步操作。当您在厨房里煮咖啡或茶时,您是否一直站在厨房里看着咖啡壶或茶壶?没有。当您现在正在做其他事情时,设备会沸腾水并完成其工作。
完整的运营链。尝试从墙壁插座上拔下台灯,然后按下开关。灯不会由此亮起。仅在从电源到用电者之间有完整的链条时,此对象才起作用。现实世界中有很多(即使不是大多数)这样的对象。

我想向您保证,由于RP的出现,您对传统编程和游标MM的了解不应丢入垃圾箱。响应式编程使它们独自存在,并通过对新类型的对象进行新操作来扩展它们。方式-我们稍后再讨论。

心理模型编程的空间及其在MM RP中的位置


在谈到RP在程序设计的一般情况下时,作者经常提到两个维度-处理对象的复杂性和操作的同步性/异步性。可以在《 RxJS in Action》 [7]一书的“何时何地使用RxJS”一章中找到这种分类的示例。
在这种分类中,对象的维度分为单个对象和多个对象:数组,列表等。操作分为同步和异步。
因此,这种分类将编程领域分为四个区域。RP是负责使用异步操作处理多对象的这些领域之一。
我发现这种分类非常有趣,但是我想从心理模型的角度来看它。下表列出了它们。
单一值和对象, ,
, (Stream)
, (Promise)(Workflow)

我们假设指令和光标的心理模型不需要进一步说明。
该循环是MM指令和游标的扩展,由于该循环的附加指令或返回到某个点。这允许单个对象的一组处理指令“循环”包装,从而处理许多此类对象。在这种情况下,光标会像以前的模型一样在循环内移动,并且到达过渡点后,如果所有对象都已处理,则它会跳转到开始或循环的处理停止。
喷射。该思维模型与上一个思维模型之间的区别在于,
指向已处理对象的光标保留在原处,而对象本身“在其上方”运行。
让我们用两个例子来看一下。如果您绘制木栅栏,则类似于游标模型,您会在木板之间移动。但是,传送带上的工人仍然留在原处,并且类似于喷射模型,要加工的零件自己也接近了它。这些对象通常用术语Java Stream来表示,例如用Java语言。
信号。该MM最容易与十字路口的交通信号灯关联。异步对象会定期轮询公共变量的状态,并在更改其状态后执行某些操作。 (例如交通信号灯前的驾驶员)
正在等待。这种心理期望模型的一个合适的比喻是您上次上班时期望的纸上信或Emall。可能会有肯定或否定的答案。您收到信件后的行为在很大程度上取决于其内容。英语术语Promise通常用于描述这类对象。从用户的角度来看,对于提供服务的承包商而言,这是一种期望。
从描述中可以看出,沿着每个维度(表中从上到下或从右到左)的移动意味着心理模型发生了质的变化。
从表中可以看出,喷射机和期望值是我们感兴趣的东南单元格左侧和顶部的邻居。与它们相比,居住在我们感兴趣的细胞中的流动心理模型有什么新变化?

什么是扩展名?


与Expects相比,Streams的扩展在于,预期信息不会到达一次,而是可以到达许多部分。在这种情况下,该过程可能会结束而不会结束。那些。经过一系列成功的上菜后,我们将收到错误通知。另外,添加了信息的另一个版本-流程结束的通知。
例如,这意味着可以接收预期信息的几个(但不是全部)部分和(没有错误消息)有关处理结束的消息。
再次回想一下,在等待中,对于结果信息,我们只有两个替代选项。
Mental Jet模型非常适合理解,讨论和实现转换相同类型的对象序列的过程。 MM Stream在以下方面进行了扩展:
  • 可能有很多喷气机,我们可以将它们合并在一起
  • 射流可能是异质的
  • 我们可以根据不同的标准将飞机分为新飞机
  • 我们可以在一个流的框架内“关闭”和/或将它们转换为新的。

因此,我们确定了MM RP(流)在编程对象的空间或横向中的位置。现在,让我们降低鸟瞰图,并仔细研究Streams及其心理模型。

其生命周期的各个阶段和阶段


作为一个近似值,可以将RP流量想象为水在水管中的流动或电流。应当记住,与任何其他类比一样,该类比也有其局限性,并不总是适用。
说到流程,可以区分以下重要方面:

  1. 每个线程都以某种方式出现
  2. 他正以某种方式走向消费者。
  3. 和他一起途中发生了什么(他变了)
  4. 它可以分为几个流或与其他流合并
  5. 消费者以某种方式使用流程,停止存在。

列出的方面同时是流程中各个元素生命周期的各个阶段。
让我们使用RxJS函数示例更详细地考虑它们。

线程创建


可以从被动元素(例如程序中的数组或对象列表,字节,文件行等)创建流。这种流源称为冷流(尽管从技术上讲,对冷流源有更准确的定义)。
所谓的温泉“过着自己的生活”,如果您不及时连接到温泉,信息将丢失。此类别包括有关在计算机,平板电脑,智能手机上的用户操作的信息,例如,有关击键,鼠标移动或触摸屏幕的信息。在此类别中,还包括各种协议(例如HTTP)所请求的数据,来自各种传感器的数据。
应当指出,有所谓的“暖”弹簧。另外,一些“热”弹簧可以被“冷却”,而“冷”可以被“加热”。但是您应该在特殊文献中对此进行阅读,例如,在书[7]中。
对于我们来说重要的是要知道,所有创建流的操作都会创建相同类型的对象,无论内容如何,​​都可以通过相同的操作对其进行进一步处理。在本文中,我们将这些对象称为流。相应的英文名称是Observable。

消费者流动与流程转型


流转换操作既可以在到达消费者的途中也可以自己执行。在这两种情况下,流元素的处理操作都是严格顺序的,即 仅在上一个操作完成并将结果传递给它之后,才严格执行下一个操作。
与Stream不同,Stream在某些编程语言中是具有自己的语法和语义的语言构造,而JavaScript中的RxJS之类的反应式扩展则被迫使用可扩展语言的语法和基本语义。因此,RxJs实现了pipe()函数,您可以在其中对函数进行调用-流本身及其各个元素的处理程序。
重要的是要注意,只有特殊的,可传递管道的函数才能成为流处理程序。

“三相流”


如果我们继续用电力进行类比,那么我们正在考虑的流动可以称为三相。除了传输基本信息的“普通线”之外,还有“错误线”和“流终端线”。转换操作不仅允许更改对象,还可以将其重定向到另一个“电线”。例如,在使用HTTP协议处理服务器使用中的所谓错误时,将使用此技术。例如,如果一台服务器没有响应,则可以尝试请求另一台服务器,而不会通知用户请求第一台服务器失败的信息。
这是您的心理流量模型的另一个非常重要的元素。如果在传统的编程范例中错误是作为错误代码从处理功能返回的,或者应该作为中断(异常)被拦截,则在流中,错误“流”与主通道无关。
在那里可以进行处理。例如,如果用户输入了错误的密码,可能会给他们一个额外的机会尝试一次或多次输入。

拆分和合并流


流的拆分分为两个阶段。在第一阶段,启动空线程。然后,在第二阶段(流处理阶段)中,在处理功能之一中,将对元素进行分析并将其重定向到所需的流。从技术上讲,有很多方法可以做到这一点。例如,将其从当前线程中删除或克隆后再在新线程中启动它。
您可以以惊人的多种方式将多个流合并为一个。
我想到的最简单的方法是按照接收顺序将它们合并,或者首先从第一个流中合并所有内容,然后从第二个流中合并所有内容。
图片中以下所示的方法允许两个流之一形成一个包含来自第一流和第二流的对象的有序对的对象。在这种情况下,如果其中一个流中出现新元素,则会形成一对新的对。A包含一对严格每个流的最后一个元素。这导致可以在几对中包含相同元素的事实。
本示例中使用的图形符号称为Marble图,在解释拆分和合并流的语义方面非常有效。
如果您对此主题感兴趣,建议您研究资源上的操作及其大理石图[8]。


使用流


为了使用流的元素,用户或客户端必须首先订阅它。通常,在处理结束时,他应该取消订阅,因为垃圾收集器在尝试使用订阅者时不能总是自动取消订阅。
许多客户端可以订阅一个线程。在RxJs中,订阅功能称为subscribe()。在大多数情况下,建议在其中放置流的“正常”元素的处理调用,错误处理程序以及(相对很少)流终止处理程序。
流的每个订户都接收其元素的副本或原始元素的克隆。为了不引起问题,以这样的方式实现流,即,为处理而接收的元素变得不可变。在某些情况下,仍然可以绕开此限制,但最好不要这样做。

溪流的危险魅力


流是非常复杂的对象,有点类似于数学中的积分。知道它们的存在甚至可以粗略地想象它是什么是一回事,而能够使用它们则是另一回事。
理解它们正常运行所必需的内部逻辑,需要大量的智力投入。
流本质上与函数式编程紧密相关。为了充分利用流程,了解如何构建和应用二阶函数(这些函数以其他函数作为参数)是很有用的。
然后,气流的美丽和优雅将完全展现给您。
溪流具有传染性。了解了它们的美丽之后,我想在所有任务中使用它们,这当然不是必需的。
建议在哪些任务中使用流程,以及在哪里使用传统方法,每个人都可以自己决定。

总结


在本文中,我试图向您介绍反应式编程的心理模型(MM RP),甚至部分地将它们置于您的意识中。让我们再次重复要点。

  1. MM RP是特殊的,与传统编程的心理模型不同。
  2. 在进行响应式编程时,我们必须记住,在MM的其他区域中建立良好的某些部分(例如游标,调用链或循环)不起作用,或者它们不能那样工作。
  3. RP的主要心理模型是“三通道流”,具有用于“正常”元素,错误和有关流末尾信息的通道。
  4. 流可以是无限的。
  5. «», «» «» . «» «».
  6. . (, ). .
  7. , .
  8. , .
  9. . .
  10. , «».


如果您对此主题感兴趣,则可以使用网站上提供的模拟器来“播放”流[8]。
如果您想更好地理解RP的概念,我建议您通读本书[7],当然,还要熟悉《反应宣言》 [11]。
通过阅读有关反应性系统的设计和建模的书籍[9]和[10],您将达到形成自己的MM RP的新高度。

文献和参考


  1. 编程是思想的具体化。(有关Habr的文章。Habr.com/ ru / post / 425321
  2. Sirotin V. RPSE:作为软件工程范式的验证。arxiv.org/abs/1810.01904
  3. 事件驱动的编程。en.m.wikipedia.org/wiki/Event-driven_programming
  4. Dataflow-programming. en.m.wikipedia.org/wiki/Dataflow_programming
  5. Stream-processing. en.m.wikipedia.org/wiki/Stream_processing
  6. Rx-Extensions: reactivex.io/languages.html
  7. RxJS in Action. – 4. August 2017. Paul P. Daniels (Autor), Luis Atencio. Manning Publications. ISBN-13: 978-1617293412
  8. RxJS online Documentstion. xgrommx.imtqy.com/rx-book/index.html
  9. Reactive Design Patterns. 2017. Roland Kuhn Dr., Brian Hanafee, Jamie Allen. Manning Publications. ISBN-13: 978-1617291807
  10. Functional and Reactive Domain Modeling. 2016. Debasish Ghosh.Manning Publications. ISBN-13: 978-1617292248
  11. The Reactive Manifesto www.reactivemanifesto.org


: geralt

Source: https://habr.com/ru/post/undefined/


All Articles