第一站 - 轻松上网从此开始!

上网第一站

当前位置: > 运营 >

复杂表单应用解耦 淘宝机票订单实践

时间:2012-11-08 14:33来源:网络 作者:yangyang 点击: 我来投稿获取授权
以下内容来自网络或网友投稿,www.swdyz.com不承担连带责任,如有侵权问题请联系我删除。投稿如果是首发请注明‘第一站首发’。如果你对本站有什么好的要求或建议。那么都非常感谢你能-联系我|版权认领
背景 在web应用中,复杂表单这类web应用富交互元素多,业务逻辑复杂,犬牙交错,且需求变化频繁。及容易成为晦涩和幽暗之地,也经常是各种代码坏味道的来源。针对

  背景

  在web应用中,复杂表单这类web应用富交互元素多,业务逻辑复杂,犬牙交错,且需求变化频繁。及容易成为晦涩和幽暗之地,也经常是各种代码坏味道的来源。针对这种典型的复杂应用,本文以淘宝机票订单为例提出一种架构模式梳理和消化表单带来的复杂性。

  

 

  模块和组件划分

  解决复杂表单的的第一步,划分模块。

  概念上,为了复用和解耦方便,应将模块按照功能的内聚程度进行划分。强相关,频繁沟通和交互的功能应该归为一个模块。模块间尽量不存在依赖关系。也就是常说的“高内聚,低耦合”。

  如下图所示,淘宝机票订单页面主要有被分为7个主要模块。

  

 

  模块划分完毕,下一步确认组成模块的组件。

  关于模块和组件的区分。一般按照以下三个纬度考量。

  是否有业务逻辑参与。

  是否包含html。

  是否具备一定独立性。

  “模块”,定义为一个包含”html”、”css(图片被认为是css的一部分)“、”javascript”的代码集。模块的应用方式多为通过web模板技术(如:velocity、freemarker、php)。因为包含了html,使得模块必须通过服务端合并加载并且最终推送到用户浏览器。此外,“模块”还是具备一定独立业务和交互的集合,最好可以被其他页面引用。良好的独立性也可以帮助协同开发,在实际开发中可多人可以并行开发多个独立模块,提高效率。

  “组件”,定义为一个仅包含”css”和”javascript”的代码集。正因为不包含html,所以组件可通过javascript异步加载。因为这种可异步加载的特性,组件在复用方面的容易性远超模块。组件没有业务逻辑或者仅有少部分公共业务逻辑。业务逻辑越多,组件的可复用性就越低。

  模块、组件间通讯

  组件/模块划分的目的是将彼此间相对独立的功能分离,前面通过模块和组件的划分解决了分离问题。实际中,模块之间存在协作关系。模块间应以一种轻量的方式协作。一般的为了更好的分离和解耦,可以考虑用广播的方式在模块间沟通,考虑使用事件的方式在组件间通讯。

  如下图所示,淘宝机票订单页面的数据流向。

  

 

  不同模块在后期均有可能扩展小功能。例如不定期的活动优惠等。事件广播可以让不同模块/组件间新增功能影响面缩小。在淘宝机票订单中应用中,使用广播组件通讯主要用来完成以下意图。

  

 

  1、知会。

  知会的特性在于异步通讯。广播发起方只需要放出事件,无需等待其他关注者完成处理。称为异步广播。例如表单模块的内容变更需要知会到显示订单金额的模块,显示订单金额的模块接受事件后需要更改金额。

  基于这种方式的通讯,各模块之需要做好自己的事情,外部关注的时间广播出去即可。异步广播还有一个好处是系统坚固性比较强,广播发送者不会因为时间监听者的使用不当而异常。

  2、请求数据

  例如,模块6(负责提交)需要在被点击后从模块2(乘机人表单),模块4(联系地址)、模块7(金额计算)。获取具体数据提交。请求数据的场景特性在于,广播发起者需要等待时间处理者完成处理后再继续下一步行为。称为同步广播。同步广播的应用有些费解。代码说明原理和应用。

  基于此机制。提交模块只需要负责综合校验,浮层,网络请求及异常处理。而具体请求的内容由其他模块决定。对后续模块的扩充起到了很好的左右。

  复杂组件拆分

  模块和组件划分完毕后,可能会发现某些组件非常复杂,几乎占据了整个web应用一半以上的代码。这部分组件由纯js实现,并且使用javascript模块加载器加载。

  同一个组件大量代码纠结在一起,最终还是会导致架构腐化。因此,复杂组件需要进一步拆分。在淘宝机票订单中,乘机人信息组件是一个复杂组件。如下图所示:

  

 

  拆分这类输入型的复杂组件,一般来说有两种思路方式。

  纵切,组件树型式。

  将组件进一步划分为更细力度的输入组件,将每个输入域作为一个单独组件。最终形成一个组件树。

  

 

  这样的组织方式结构严谨层级清晰,最大的优点是很容易支持字段扩展。

  但考虑如下场景,为了尽量友好的提示用户,需要在输入域外的某处增加提示帮助。

  

 

  这种场景下组件树的组织方式每次在面对变化时就会略显手忙脚乱。难道把每个地方出现的tip都座位独立组件看待吗?

  字段级的适普性降低了适应细节调整的能力,付出的代价在于界面体验。

  横切,AOP式。

  将所有输入域抽象的看待为同一个组件。按照组件的富应用特性分层看待。在本例中,乘机人组件被按照从简单到复杂分为3个切面。

  切面1-基础展现层只负责最基础的可完成输入的表单控件,及基础dom管理。

  切面2-富展现层负责修饰base层的基础html控件,形成富输入控件。

  切面3-校验层负责对base层的输入数据进行业务级校验。

  未来,如果新增tip或者其他业务逻辑,增加一个新切面即可,完全或者很少需要修改老代码文件。

  

 

  

 

  淘宝机票订单采用了AOP这种方式,从最终代码量上来看,可以看出复杂度被比较均衡的分布到不同文件中去。

  

 

  同样,这种方式也有局限,如果需要扩展字段,那将是一个灾难,你有可能需要到每一个切面里面去做修改。

  有句老话说的好,没有最优方案,只有最适合的解决方案,任何解决方案,都需要放到具体场景中去评判。事实上,对这个问题的进一步研究,可以发现以下规律。

(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发布者资料
第一站编辑 查看详细资料 发送留言 加为好友 用户等级:注册会员 注册时间:2012-05-22 19:05 最后登录:2014-08-08 03:08
栏目列表
推荐内容
分享按鈕