拍摄者Garett Mizunaka.uns

在Ok188bet金宝搏官网cupid,我们正在为用户建立一个新的位置搜索体验,以根据国家/地区,城市名称和GPS设置自己的位置。

与早期的位置搜索体验的迭代相反,从源代码中不再静态加载所需搜索的数据。新的搜索体验由来自后端的多个数据和服务供电,为错误和成功案例提供更复杂的用户反馈。

是什么让新位置搜索UX复合物的前端是有很多活动部件。UI需要在仍在加载数据时管理用户输入。UI还需要基于搜索结果向用户显示反馈,并处理网络连接等各种错误条件和服务器端错误。在引擎盖下,用户在选择国家/地区名称时看到的简单形式必须使用来自用户的事件协调对后端的请求。

这篇文章探讨了我们在OKCupid中使用的有限状态机(FSM)的架构设计模式,以制作强大的位置搜索UX。188bet金宝搏官网

FSM的主要使用已经进入编程嵌入式系统但近年来,其他应用中的FSM出现了FSM在浏览器中管理状态建模行为, 和建筑聊天禁止。这篇文章的目标不是将FSM传授为比其替代品更好的国家管理解决方案但是,要引入一种简化系统的架构的模式,并写出可理解,可扩展的强大代码删除

什么是fsm?

FSM是一种架构设计模式,允许我们将大型系统模拟为松散耦合组件的集合。系统中的每个组件在内部状态更改时更改其行为。

FSM由国家和州过渡组成。它可以由状态机图表示。

FSM代表红绿灯

正式,

  • 状态代表系统的模式并驱动系统的输出。灯开关有两个状态:打开或关闭。红绿灯包含三个州:红色,黄色或绿色。FSM中有一个有限数量的州。每个FSM都有一个初始状态,它是系统在第一次启动时的状态。
  • 国家过渡是根据当前状态和系统输入从当前状态到下一个状态的规则。

如果我们将React组件造型为FSM,则用户,服务器或组件的呼叫者外部提供系统输入。这些包括组件道具和事件,例如按钮单击或从服务器接收某个响应。系统的输出是JSX(即,呈现的内容),因为这是最终从组件返回的内容。

作为FSM建模的React组件的输入和输出

退换出来必须互斥。这意味着给定的输入不能导致转换到两个状态。这确保了我们系统的确定性行为。

具有少数州的一个组件

您可能已经有经验建立使用组件状态的反应组件insloading.被禁用确定如何呈现。这些是可以用具有二进制状态的简单FSM建模的状态组件的示例。借助在具体示例中,让我们在迄今为止将其学到的FSMS应用于FSM的内容。

假设我们正在建立组件来自反应钩子文件。在任何给定的时间,该组件显示三条消息“加载...”,“在线”和“脱机”中的一个。

导入反应,{usestate}从“反应”;friend friendstatus(props){const [ISONLINE,SETISONLINE] = USESTATE(null);使用(()=> {function handleStatusChange(status){setisonline(status.sonicline);} chatapi.subscribetofriendstatus(props.friend.id,handlestatuschange); //指定在此效果之后如何清理:返回函数cleanup(){chatapi.unsubscribefromfriendstatus(props.friend.id,handlestatuschange);};});if(iSonline === null){返回“loading ...”;返回ISONLINE?“在线”:“离线”;}

组件状态在线确定要呈现的消息并初始化空值并更新到“在线”或“离线”使用

在线让我们储存三个UI状态:加载,离线,在线。

我们可以重写基于ui状态反而。

导入反应,{usestate}从“反应”;Const Uistate = {loading:“loading”,在线:“在线”,离线:“离线”,};const uistatemessagemap = {[uistate.load]:“loading ...”,[uistate.online]:“在线”,[uistate.offline]:“离线”,};const getuistate =(status)=> {const {isonline} =状态;if(iSonline === null)返回uistate.loading;返回Isonline?uistate.online:uistate.offline};friendstatus(props){const [uistate,setuistate] = useState(uistate.loading);// init状态使用(()=> {function handleStatusChange(status){contor nextuistate = getuistate(status); setuistate(nextuistate);} chatapi.subscribetofriendstatus(props.friend.id,handlestatuschange); //指定如何清洁在此效果之后:返回函数cleanup(){chatapi.unsubscribefromfriendstatus(props.friend.id,handlestatuschange);};}); return UiStateMessageMap[uiState]; }

国家过渡发生在handlestatuschange.,这是在每个渲染中触发的使用没有第二个论点。

Setuistate(Nextuistate)负责基于系统输入(即,)引起从uistate的电流转换到下一个uistate(即,地位来自ChataPi)。

我们的系统输出是我们想要渲染的消息,即直接来自uistatemessagemap.。我们可以这样做,因为我们的系统只能处于三个州之一。当系统的输出完全取决于当前状态时,我们有一个特殊类型的FSM称为a摩尔机器。摩尔机器更具确定性,但与输入相比,对输入变化较慢的反应更慢MEALY机器。在MEALY机器中,输出取决于当前状态和系统的输入。

无论您是构建摩尔机器还是MEALY机器都真的取决于您的系统的要求。我们将在帖子的下一部分中看到如何构建一个系统,该系统是使用架构的混合摩尔和MEALY机器,该架构将状态驱动输出的实现委托给子组件。

具有许多州的一个组件

对于只有两三个州的简单组件,FSM可能是矫枉过正的。实现FSM(例如,定义所有UI状态和转换),有很多开销,以不受额外的额外效益。

对于由具有跨切割问题的许多子系统组成的复杂系统,FSM提供了巨大的好处。

考虑您的系统由多个组件组成,其中需要禁用一个组件而另一个组件加载,并且两个组件的输出确定第三组件的输出。

交叉组件依赖性可能导致组件的紧密耦合,并使封装困难,系统难以测试。

新的我们在Okcupid建立的组件允许您指定一个国家/地区和查188bet金宝搏官网询词(邮政编码或城市名称),以查找世界任何地方的位置。这似乎非常直接,直到您考虑所有边缘案例,该组件必须处理。

  • 与API的组件接口提供最佳匹配国家和查询搜索项的位置对象数组。基于该阵列的长度,该组件可以显示成功消息,各种错误消息,以及通过从最佳匹配列表中选择来消除搜索的另一个选择UI。
  • 该组件的奖金特征是,如果它在移动设备上使用,则有一个按钮可让您使用GPS位置(纬度和经度)自动找到自己。同一API接受GPS位置作为输入并与位置阵列响应。
  • 组件需要处理无效的邮政编码以及网络错误等客户端输入验证误差。
  • 此外,部件可以安装有一个预装位置,需要在国家下拉列表,邮政编码/城市名称输入和成功消息中反映出来。

如果您在JIRA票证中看到了这种设计规范,那么它似乎有点压倒。有很多需要实施的逻辑。但是,拥有前面的所有功能要求实际上是伪装的祝福 - 它使我们能够更全面地思考这个组件的设计,并选择可以有效地管理该组件所有复杂性的架构。

所有UI状态的枚举

关于使用设计师的交叉功能团队工作的一件好事是您在开始实施之前获得所有模拟。模拟可以用来设计架构。

由于这是一篇关于使用FSM的UI状态建模的文章,因此您可能已经看到了它。我们将为每个模拟分配UI状态,该模拟表示在操作中的组件的快照。

每个州的位置输出


这些图像描绘了每个状态中系统的输出(用户看到的内容)。让我们来看看输出在不同状态中的共同之处。这将为我们提供如何分开我们的想法组件进入子系统。

  • 在所有错误状态的成功状态下,将显示反馈消息。文本颜色取决于状态。
  • 在成功状态下,消歧状态和所有错误状态,在输入(复选标记和感叹号)旁边显示图标。
  • 在除了加载,国家下拉,查询输入和地理位置搜索按钮的所有状态(标有)使用当前位置)启用并接受用户的输入。

基于这些观察,我们可以开始将渲染逻辑委派给不同的呈现组件。

成分 它呈现的是什么 价值取决于 受uistates的影响
国家 下拉菜单包含从服务器检索的国家 - 找到的位置
- 用户输入
装载
QueryInput. - 包含国家/地区名称或邮政编码的输入字段
- 复选标记或感叹号用于反馈的标记图标
- 找到的位置
- 用户输入
- 装载
- 成功
- 所有错误状态
反馈 包含位置名称的成功消息 - 找到的位置
- 映射到错误状态的静态消息
- 成功
- 所有错误状态
建议 包含匹配位置的下拉菜单 来自服务器的匹配位置 歧义
GPSSearchButton. 按钮以触发GPS的位置搜索 N / A. 装载

通过委派执行这些组件的状态特定输出,我们能够转换进入通过UI状态协调的松散耦合组件的系统。我们正在封装FSM,在父组件的意义上不知道此组件中UI状态的实现。

现在我们已经定义了每个状态的状态和输出,我们将指定状态转换。

国家过渡

类似于我们所做的早些时候,我们将要实例化uistate.作为一个组成状态和变异uistate.在一个使用。评估下一个uistate.将在辅助功能中完成getouistate.。使下一个州评估的优势在显式中getouistate.是我们将能够将关注分开计算什么时候从关注点什么渲染。

召回FSM可以表示为定向图形,状态转换是节点之间的边缘。这就是我们的FSM应该是什么样的。

FSM代表位置搜索

待处理状态是初始状态第一个安装。由于组件可以安装有预装位置,因此有一个箭头直接从待处理状态到成功状态。我们还可以通过向服务器或GPS位置提供国家+查询来达到成功州。

通过客户端输入验证达到error_not_zip_code状态,不依赖于服务器请求的结果。另一方面,只有在向服务器提出请求之后才能达到所有其他错误状态。

结论

在此帖子中,我们了解了FSM是什么以及如何将复杂的反应组件建模为通过UI状态协调的松散耦合子系统的系统。此模式允许我们编写灵活,可重用和可测试的代码。

我们已经看到了一些使用React原语的方式如何完成useestate.使用。有类似JavaScript库XSTATE.machina.js.它为创建,解释和执行有限状态机和StateChart提供了更具自融合的框架。

虽然FSM是一种强大的设计模式,但对于项目来说并不总是正确的事情。当建筑设计最有效的时候最明确的产品愿景和预期,以满足如何满足全用户体验的愿景。预成熟优化可能导致更糟糕的代码可维护性。幸运的是,位置搜索项目是幸福的,具有良好的产品规划和清晰的设计目标,使得可能会破坏问题和建筑师强大的技术解决方案。