观点

 

我在学校学到的东西

随着我们继续为我们的产品开发新的UI,我们肯定会在任何可能的地方使用FSM。

Terry Coatta,Vitrium Systems

我们有多少人没有过坐在教室里,闲散地想着:“这在现实世界中真的重要吗?”的经历? 令人好奇,并且在某种程度上令人谦卑的是,意识到有多少知识的精华确实很重要。 最近对我来说就出现了一个:有限状态机(FSM)。

为了说明FSM如何改变了我的生活——好吧,至少让我的软件开发变得更容易——我需要稍微跑题一下。 我工作的公司正在发布其产品的新版本。 之前的版本完全基于Web,但对于新版本,我们希望提高交互性。 我们选择了Flash作为构建我们部分UI的基础设施。

总的来说,我们使用Flash的体验是积极的。 构建UI组件相对容易。 标记与代码的分离意味着图形设计师可以修改组件的视觉方面,而无需开发人员的参与,并且代码风险很小。 然而,Flash事件模型起初看起来很简单,但最终却成为了我们相当多痛苦的根源。

从根本上说,事件模型存在两个问题导致了麻烦。 首先,似乎Flash中几乎所有事情都是异步发生的。 例如,当您首次将UI组件放入可视容器中以使其显示在屏幕上时,您实际上无法操作该组件的任何属性,直到您收到完成事件指示它已准备就绪为止。 另一个例子是服务器通信。 所有检索服务器数据的SOAP调用都是异步的。 我们发现所有这些异步性导致代码难以理解且不够健壮。

例如,在许多情况下,我们有必须按特定顺序调用的服务器SOAP调用序列。 我们最初尝试编写此代码的结果是灾难性的。 我们会向服务器发出第一个调用,并为其提供一个回调例程,以便在该请求完成时执行。 在该回调例程中,我们将向服务器发出第二个调用,并为其提供另一个回调例程,以便在该请求完成时执行。 更糟糕的是,有时对服务器的调用是有条件的——也就是说,它们在某些情况下会发出,而在其他情况下则不会发出。 我们的代码很快退化为一团回调方法,就像一堆散落着goto的意大利面条代码一样难以理解。

导致我们失败的第二个问题是Flash处理事件处理程序重入的方式。 我之前使用这种单线程编程类型的经验是COM及其单线程单元(STA)。 使用STA,当您处理传入事件时,COM运行时几乎可以保证您的事件处理程序将运行完成。 这是一个非常有用的属性,因为如果在处理第一个事件时将第二个事件分派给对象,则第二个事件处理程序很可能发现对象处于不一致的状态。

可悲的是,在Flash中,这种事件重入更容易发生。 事实上,我们最初尝试在Flash中编写UI代码时,充满了我们似乎会遇到随机行为的情况,最终证明这些行为正是由这种重入引起的。

好吧,关于这个故事的痛苦和折磨部分就说这么多。 我意识到我们需要一种更结构化的方式来处理我们面临的所有异步活动。 深深地埋藏在我的大脑中,自从多年前的期末考试以来一直未被打扰的知识是,有限状态机是处理具有异步事件的系统的一种方法。 因此,我们退后一步,开始勾勒出如何将我们的UI设想为FSM或FSM集合。 然后,我们开发了一种可以用来实际构建这些FSM的标准实现模式。 最后,我们删除了现有的回调和事件处理程序,并将FSM放置到位。

我不会过多地谈论代码本身,除了注意我认为显着有助于简化代码并使其更易于理解的两个原则。 我还要注意,我们正在使用模型-视图-控制器(MVC)模式。 这意味着事件/回调始终由控制器处理。 第一个原则是,控制器的事件处理程序和回调方法应不直接执行任何工作。 当事件或回调到达时,所发生的一切只是FSM被告知发生了特定事件。 这会导致FSM更改状态并执行某些操作。 第二个原则是,FSM不应包含执行与状态转换相关的操作所需的详细代码。 在我们的例子中,这些操作的逻辑实际上是控制器的一部分。

这两个原则可以简单地看作是更一般的“关注点分离”原则的表达。 FSM的目的是严格地管理状态转换。 它应尽可能与UI的实际机制隔离。 另一方面,控制器应呈现UI的抽象,该抽象隐藏了诸如页面上有什么控件以及需要如何操作这些控件以呈现特定显示之类的细节。

一旦我们有了FSM,开发过程就变得顺利得多。 FSM最令人愉快的方面之一是它们有助于快速识别编码错误。 使用FSM时最常见的错误类型是事件到达FSM,并且没有与该事件和FSM当前状态关联的相应转换。 在我们的FSM中,这会打开一个警报窗口,报告已向FSM发布了非法事件。 在FSM之前的代码中,这些类型的意外事件往往会导致控制器进入不一致的状态,但是这种不一致通常不会在稍后才显示出来,这使得调试特别具有挑战性。 FSM的“错误时停止”行为意味着我们可以快速识别问题的根源。

FSM的第二个积极方面是它们易于分析。 我的意思是,您可以相对容易地证明有关它们的某些属性。 例如,我们可以通过证明状态机中的所有路径都经过一个打开繁忙光标的状态,并且随后这些路径都经过一个再次关闭繁忙光标的状态,来证明我们正在正确处理繁忙光标的显示。 这是一个相当简单的示例,但是对于我们以前拥有的非结构化的事件处理程序和回调集合,这是一个代码存在错误的地方。

随着我们继续为我们的产品开发新的UI,我们肯定会在任何可能的地方使用FSM。 在未来,我相信它们是一种技术,我会将其应用于几乎所有UI开发,无论是Flash,还是某些小部件工具包与AJAX结合使用,甚至是典型的桌面应用程序。 UI开发始终是关于处理事件,而FSM提供了一种处理这些事件的结构化方法。

acmqueue

最初发表于Queue第5卷,第7期
数字图书馆中评论本文





更多相关文章

Shylaja Nukala, Vivek Rau - 为什么SRE文档很重要
SRE(站点可靠性工程)是一种工作职能、一种思维模式以及一套工程方法,用于使Web产品和服务可靠地运行。 SRE在软件开发和系统工程的交叉点运作,以解决运营问题并设计解决方案,从而可扩展、可靠且高效地设计、构建和运行大规模分布式系统。 成熟的SRE团队可能拥有与许多SRE职能相关的完善的文档体系。


Taylor Savage - 组件化Web
在当今的软件工程中,没有哪项任务能像Web开发那样艰巨。 Web应用程序的典型规范可能如下:该应用程序必须跨各种浏览器工作。 它必须以60 fps的速度运行动画。 它必须立即响应触摸。 它必须符合一组特定的设计原则和规范。 它必须在几乎所有可以想象到的屏幕尺寸上工作,从电视和30英寸显示器到手机和手表表面。 它必须在长期内得到良好的工程设计和可维护性。


Arie van Deursen - 超越页面对象:使用状态对象测试Web应用程序
Web应用程序的端到端测试通常涉及通过Selenium WebDriver等框架与网页进行棘手的交互。 隐藏此类网页复杂性的推荐方法是使用页面对象,但是首先要回答一些问题:在测试Web应用程序时,应创建哪些页面对象? 您应在页面对象中包含哪些操作? 给定您的页面对象,您应该指定哪些测试场景?


Rich Harris - 消除入门障碍
一场战争正在Web开发领域展开。 一方面是工具制造者和工具用户的先锋队,他们以破坏糟糕的旧观念(在这种环境中,“旧”意味着一个月前在Hacker News上首次亮相的任何事物)以及关于转译器等的热烈辩论而蓬勃发展。





© 保留所有权利。

© . All rights reserved.