UI软件设计的深入讨论以及碎碎念

首先这里没想写什么代码和具体的例子(结尾部分引用了别人的关于实践的文章),完全是模型和方案层面的一些思考。然后软件设计的对错之分不是太多,这里更关注如何从一些关注点上出发通过取舍取得更多的平衡。


开篇碎碎念:程序结构和复杂度不会影响到机器执行代码的能力,但是人的阅读和理解成本会天差地别,所以大部分情况下程序首先是为人服务的。


UIuser interface),根本上它是一层人机交互界面的双向描述,对人展示系统信息,对系统传达人的命令。在形态上UI形式非常广泛,从我们每天接触的图形界面,到命令行,到语音菜单,甚至到机械按钮全部都涵盖在内。我们一般讨论的UI范围只包括数据和显示,操作的部分并不是指一个完整的客户端,本文也是按照这样的默认。

运行系统和用户之间通常需要2个方向的信息传递,从系统到人和从人到系统。从系统到人的信息传递中,首先需要读取系统内部的数据,然后换成人可以识别的形式展现出来;从人到系统的信息传递中,需要先读取显示界面上用户的操作,然后转换成系统可以识别的数据发送给系统执行。在这个过程中UI承担了两个方向上的信息传递,数据转换,协议适配,信息和操作描述,等一系列复杂的任务。在使用户的感知中,UI通常只是一个图形界面,但实际上UI还是一个有厚度有深度的复杂执行系统。UI业务的复杂性反映到了程序结构上的复杂性,这种复杂来自于多个业务模块间交错的数据流转和驱动关系。业界尝试过很多种描述这个复杂关系的软件模型,MVC是其中得到更广泛认可的一个。

在各种UI系统的设计模型中MVC在早期得到了更广泛的认可和支持。从网上借来一张n手的模型图:


这大概是MVC的第n个版本,因为在几十年的演化过程中出现了诸多的实践版本和进化方案,本文也无意追根溯源权当一个概念上的讨论基础吧。虽然我个人倒是很推荐这种V-M完全隔离的方案。

MVCUI系统定义为三个元素组成:数据(M),显示(V),控制(C)。

  • ¬M是业务数据的本地映射,为V提供业务数据基础。
  • ¬V是实际上的展现层,提供人机交互和展现界面。
  • ¬C作为控制器,负责协调M-V之间的数据流转和状态变化。

MVC是一个基于业务描述的软件模型。它确认了数据作为UI的业务基础,同时从业务职责出发划分了模块进而描述了模块间业务的流转关系。

业务本身是软件模型的基础,但是这一点却常常在设计中有意无意的被忽略了。MVC首先从业务角度出发划分出3个业务功能集合,然后通过功能集合间的关系描述了系统中连接各个业务模块的数据流转内容、形式和过程。通过这样的强制性,在MVC模型的实践过程中使用者首先就被引导开始面向ui业务过程的研究和分析,同时MVC本身的模块定义将使用者对业务的研究限定在一个合理的范围内,帮助用户划分了系统业务和UI业务的边界,对基础组件的初步定义也为实践者提供了比较完整的基本参考模型。在完成基础的业务研究和划分后,MVC模块间的关系又开始引导使用者分析业务模块间必要的交互信息和交互形式,同时对信息和形式本身也做了必要的限定,经过这个步骤使用者可以基本上得到正确的接口定义和描述。

前面描述了软件模型分析的一般方法和过程,以及得到的结果。这是理论上的,因为纯粹按照这个理论执行同样会遇到尴尬和麻烦。我们假设一个实际的业务需求进行分析。我们定义n取值:10-20为可能性低显示绿色,21-30为可能性中等显示黄色,30以上可能性为高显示红色。彻底理论化的业务过程应该是这样的:首先从系统中拿到了一个数据n,然后根据n的取值范围得到可能性的判定,高、中、低,最后转换成对应的颜色识别显示出来。这个过程中总共需要2次的数据格式转换完成从一个数值转换成一种颜色,那么应该设计两个业务过程:第一次从数值转到可能性判定,这是一个系统的业务过程所以应该放到M中实现;第二次从可能性判定转换成颜色,这是一个界面的业务过程所以应该放到V中。如果按照这样的设计可以得到一个比较纯粹的软件模型,同时无论是可能性条件的改变还是界面形式的改变,调整的范围都只是在MV各自的范围内发生,这样非常符合软件设计的各项标准。但是这样的设计首先就是建立在2个假设之上的:第一界面显示形式会经常调整,第二可能性判断条件会经常调整。只有在这两个假设全部成立的基础上前面的所有优点才可能成立,否则会有这样的分析结果:本来可以简化到一次完成的计算被分成了2次在不同的地方实现,本来需要传递一次的数据变成了需要传递两次并且需要定义两个不同形式的接口。通过这样的分析可以发现前面的方案提升了模型复杂度的同时也提升了软件本身编写和维护的成本,那么从简化程序结构和代码量的角度出发,也可能将整2个转换过程合并成一个直接写到V中。单单一个n的显示就可能减少10行代码减少1个接口的定义和简化一层交互,想想看一般UI中都会有无数的n,如果每一个都能简单一些可以得到什么呢?但是这样各个模块间的独立性又受到了影响,V-M由此产生的连接可能导致系统业务与展示业务混杂起来。面对上面的2难选择,经过这些分析和权衡可以得到或者失去什么呢?MVC的实践过程中经常遇到的也大多是这些什么应该放在哪里怎么交互的问题。所以需要从每个系统中需要关注的问题点出发,对重要性和取舍关系进行排序,基本上通过从正反两个方面进行分析然后比较一下得失都还是容易得到比较合适的方案。重要的是每个系统即使是对同类型的功能,它们的设计方案都可能是不同的。

MVC提出了一个比较简单操作性高的UI模型,同时从原则和方法两个方面都给出了实践指导,降低了设计工作复杂度,帮助更多的人建立起模块、模型概念,特别是提升对接口的认知和设计水准。通过这些规范的制定简化了设计工作,广泛的提升了设计水准。

MVC的广泛使用解决了单一客户端软件设计和实现中遇到的问题,在更的高级别上还影响了软件的设计和集成方式。由于在模块内容和接口上的统一定义,基于各模块的大型组件被开发出来并且能够比较自由的连接,SSH的形成和风靡就是在这样的背景下才得以实现的。模块和接口标准化也为模块的自动化测试奠定了基础。

MVC取得了很高的成就,但也掩盖不了它带来的一些问题。首先C模块没有足够清晰的定义。MV是一个复杂业务的两端其间有些复杂的信息交互,居于中间的C职责是控制还是协调或者是集合众说纷纭,控制和协调本是两个方向的不同任务。C的模糊影响到另一个更重要的问题:模块间接口的定义。接口是软件开发中的另一个很隐蔽的萧墙,重要性之高表现为带来的麻烦很可能是繁杂而绵长的。比如Android系统中的一个函数指针类型,小小的int还是 long,导致了今天multi dex的问题,全世界范围内为解决这个问题的投入之高是很难想象的而且还将持续不短的时间。我们来列举一些接口设计中经常需要考虑的因素:可读性,当前业务,可预期业务,调用复杂度,维护复杂度,平台特性,执行性能,扩展性,接口间独立性,容错性,安全性,项目内外的一致性,与上下文模块以及第三方模块的兼容性,美感。。。。随便想想已经让人头大了。

带着MVC留下的一些疑问下面对UI的业务过程进行一次深入的分析。前面说到了UI业务的核心是双向的数据表达,下图从数据流转的角度以宽泛的UI为基础,描述了UI的基本业务模型:



UI负责在人和系统间传递信息,首先产生了人机界面层,界面层中控制展示信息和形式同时响应操作的业务过程是UI面向人的业务。另一方面在与系统的交互过程中,比如:接收来自系统的通知,根据协议持久化本地数据,与本地设备交换数据,等等,这些形成了UI面向系统的业务过程。因此UI整体上存在2个业务分层:

为了详细分析一个业务过程首先需要从顶层聚焦视点,然后抓住它的业务核心。在最顶层 UI包含的 2个方向的业务,从系统到人和从人到系统。先从系统到人角度开始分析。 UI从系统端拿到的数据首先要转换成本地的数据形式,然后根据系统的业务过程处理得到需要向人展示的数据,这些数据需要再次经过界面业务的处理才能够形成界面数据,并通过界面进行展示。抓住这个过程里的关键词可以画出下面的业务模型:

如果从用户端看是,大约是一个反向的类似过程:


前面两个模型里最不易理解的大概就是“系统业务”这个模块,那么单独说明下。在从系统到人的过程中,假设需求是温度高于50度提示温度过高,那么系统业务的职责是解析温度数据得到过高或者正常的系统判断信息,界面负责将过高这个状态展示出来。从人到系统的过程中,假设需求是温度过高后开启空调,界面得到的是人操作了开启空调的按钮,系统业务负责将这个命令转换成检查空调开启的各项前置条件以及发出开启空调的系统命令。

用户对view的操作一部分是向系统发出指令,还有一部分是对view本身的调整。加上这个数据流向,可以将上面的业务模型整合起来得到一个基于数据流转的整体UI系统业务模型:



在这样一个模型中已经完整的描述了UI中数据流转的业务过程,以及在这个业务过程中担任主要职责的各个业务模块。每个业务模块都有清晰地功能定义和边界描述,同时定义了模块间流转的数据内容和形式(限于画图空间边界数据和形式请看前面两张单向数据流转分析图)。

如果直接用MVC的形式套接,我们大约可以得到下图的描述:


图中M-V的基础部分划分是比较清晰的,但是出于不同的认知方式和各自需要解决的问题(比如:系统数据更新时采用推或者拉的方式传达到view,数据更新后以消息或者内容的方式进行传达,等等),C的范围划分和C-MV的边界在各个实践方法中存有很大的区别。

我的项目里用到了MVVM,于是接下来我们碎碎念一些MVVM的事情。

MVVM也是从MVC演化出来的,我们前面讨论的MVC大约是这样的:


MVVM的模型大约是这样的:


通过提出VM的模块,开始关注数据格式转换这个数据业务过程中的重要问题, MVVM模型从整体上强化了数据的操作和流转这样的业务概念。更加明确的定义了数据流转的形式,以VM作为媒介和边界,提供VM间的数据交互和格式转换。从定义上切分了V-M模块间的关系,在MVC中没有明确过且在诸多实践版本中存在MVC三者间同时保持连接的关系被直接打破了。

将前面的UI业务模型与MVVM套接,描述如下:


图中M的划分是我个人推荐的实践形式。在上图中还可以看到UI系统中系统业务的部分还没有被覆盖,并且在MVVM中依然没有提供具体的实践指导。从图中我们还可以开启另外一些思考。

VM从定义上只是一个数据承载的媒介,其中承载的是V可以直接识别的数据和格式,也许我们可以直接把它理解为一个数据容器,但是在实际应用中很难排除掉一些数据转换的操作。此时它对数据理解的范围又成为这部分设计的关键了,因为格式转换的缺失和错位很容易导致与其他模块间的业务侵染。如果VM与特定的V实现版本绑定则会造成VM的中立性缺失,任何V的变化都会直接映射到VM上产生接口的变化,进而向后推广直接影响到VM另一端的业务层,这样的形式造成了V对后端模块的侵染。如果VM中直接承载业务数据V端还需要进一步的解释才能够使用,那么业务层的任何调整也都会相应的反映到V端,同样造成了业务对V端的侵染。如果在任何一个方向上产生了过度的侵染VM本身作为边界定义和划分的意义就非常不明显了。使用中需要尽可能的保持VM的中立地位,弱化V或者业务层对他的直接映像,这样才可能发挥它边界划分和接口定义的价值。

另外VM是描述M-V间关系的重要部件,它划分了它们各自的功能也定义了其中的边界,它的从属关系成为了关键之一。如果将VM定义为V的数据容器则它应该是在V内部创建,这样的形式会把V-VM绑定。如果将VM定义为业务层的数据发布接口则它应该在业务层创建,这样的形式会把VM和业务层绑定。无论哪一种都会削弱VM的中立性,中立性的削弱了那么它作为中间接口的意义也势必降低。这时候可能需要引入IOC的方法,由第三方负责产生VM并负责V和业务层的粘合,以保持各方的独立性。

MVVM从模型的角度对模块的内容和边界做了比较清晰的划分,能够从软件基础质量的角度帮助实践者。

当前对于MVVM的实践更多的关注在V-VM间的动态绑定,我看到的DataBinding主要提供了这样一些价值:

  • ¬简化了V上的元素发现和维护,节省了大量且与业务无关的find操作,以及对应的显示元素变量的维护。
  • ¬削弱对显示元素的操作,同时提升了数据操作的概念,让开发者将更多的精力集中于业务过程的描述。

动态绑定更加关注于将显示界面的复杂维护工作从UI中剥离,让软件更多的聚焦在它的价值核心业务描述。但并不是采用了动态绑定就等于使用了MVVM模型,整体上MVVM模型的效果还是严重依赖于实践者对UI系统业务的分析和理解以及各个模块的定义和划分。

这里有另 一篇别人写的文章,可以算是IOS方面的实践讨论。我写的都是理论应用它算是提供一个实践参考吧,关键字:关于MVC、MVVM等一大堆思想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值