[Architecture Design] 跨平台架构设计
跨越平台
Productivity Future Vision 2011
在开始谈跨平台架构设计之前,请大家先看看上面这段影片,影片内容是微软在2011年所描绘的未来生活蓝图。在观看的过程中,请大家以「软件开发人员」的角度来思考,想想软件开发人员在其中扮演甚么样的角色。
「Productivity Future Vision 2011」 这段影片里面所描绘未来产品,把时间轴拉到现在来看,其实有许多概念已经悄悄融入我们的生活之中。像是影片中出租车车窗上显示预计到达时间这样的功能,现今许多的车款都已经配备抬头显示器,用来在车窗上显示目前油量、前进速度、轮胎胎压...等等信息。另外像是影片中透过手机汇款给演奏老人的功能,目前生活中也可以透过NFC小额付款机制,来提供电子付款。回过头仔细检视一下影片内容、并且对照现在的现实生活,其实会很有感触的发现:「随着时间的流逝、现在就是过去的未来」。
但在感叹着科技进步的同时,将关注点拉回到「软件开发人员」这个工作冈位上。会发现不管未来的科技多进步,总是离不开软件开发人员的努力:抬头显示器需要软件搜集信息、NFC小额付款需要软件发起交易、智能型手机需要软件提供APP...等等,在未来科技发展的过程中,软件都扮演了举足轻重的地位。甚至我们可以大胆的预测,未来是属于软件开发人员的舞台,软件在生活中将会无所不在。
而「软件在生活中将会无所不在」,这句话背后的意思,也就是说开发人员势必要能在:云端平台、移动平台、嵌入平台...等等异质平台上,具备跨平台开发应用程序的能力,才有机会在未来舞台上拥有一席之地。
Windows Everywhere
接着,将视野拉回软件开发人员每天的工作冈位上。一直以来我的工作都是以C#做为主要的开发语言,在早期,以C#所开发出来的应用程序只能执行在PC平台上,随着Windows Phone的诞生让.NET开发人员可以跨足到行动平台开发、接着XBOX的诞生让.NET开发人员可以跨足到游戏平台开发。.NET开发人员站在微软这个巨人的肩膀上,随着微软的脚步前进,慢慢扩展自己的开发版图。
而后续紧随着Windows 10的出现,将所有PC平台、行动平台、游戏平台...等等平台整合封装为单一平台,减少跨平台开发应用程序时所需要越过的学习门坎,更进一步加快.NET开发人员扩展开发版图的脚步。
Software Everywhere
当然,软件业界很大,微软也只是其中的一员。近年软件业界的潮流,随着智能型手机的普及,让Android、iPhone等行动平台,深入到每个人的生活之中。而物联网概念的风行,也让Arduino、Raspberry Pi等嵌入平台,默默的被人们所关注。但因为这些平台,没有微软这样的公司整合开发底层系统来减少不同平台之间的差异,所以造成不同平台有不同的开发语言、不同平台有各自需要越过的学习门坎。这些不同平台之间的差异,对于想要跨平台开发应用程序的开发人员来说,会是一股沉重的学习负担,毕竟人的智慧、精力是有上限的,没有人能够熟知所有的开发语言规则、了解所有的开发技术细节。
Development Everywhere
为了减少开发人员跨平台开发应用程序时的困扰,微软这个巨人迈出了它的一小步,为每个异质平台建立一层抽象的执行环境:CoreCLR。这个CoreCLR的解决方案,主要封装各种平台底层,提供开发人员统一的函式库、一致的执行环境,让开发人员能够使用同一种语言,来跨平台开发应用程序。另外,微软也透过策略伙伴所建置的Xamarin这个解决方案,提供开发人员能够使用同一种语言,来跨平台开发应用程序的用户接口。(Arduino、Raspberry Pi的CoreCLR尚未获得官方证实)
微软透过提供CoreCLR、Xamarin这两个整合性的解决方案,减少跨平台开发应用程序时所需要越过的学习门坎,更进一步加快.NET开发人员扩展开发版图的脚步。至此,也真正的让.NET开发人员能够跨出微软的生态圈,开发任意平台之上的应用程序。从这个角度去看,我想这会是影响.NET开发人员职业生涯很重要的一大步。
Application Everywhere
微软为开发人员,铺平了跨平台开发应用程序的最后一哩路,让开发人员能够使用同一种语言,开发任意平台上的应用程序。接着就轮到开发人员接棒,要开始思考如何让应用程序能够跨平台执行。
以CoreCLR这个封装各种平台底层、提供一致执行环境的跨平台解决方案来说,因为种种硬件限制、平台特性的考虑,微软采用的设计方式是将原本完整的CLR,拆解出必要部分来做为CoreCLR的核心模块、其余部分则依平台特性来提供功能模块。这样做的好处,除了能够降低CoreCLR封装平台底层时的复杂度之外,也精简CoreCLR所占的内存大小,让CoreCLR能够适应于更多硬件等级不高的异质平台。但是,随之而来的坏处也很明显:哪些没有被纳入核心的功能模块不是所有平台都能使用。例如:提供剖析XML格式的函式库,可能被纳入功能模块,然后只有PC平台提供该模块,而嵌入平台不提供。这样在我们的程序使用剖析XML这个函式库的开发情景中,就会发生在嵌入平台上,因为没有提供对应的功能模块,所以造成应用程序无法执行的困境。
像这样被排除在CoreCLR核心模块之外的功能模块还有很多,开发人员可以从软件架构设计的层面切入,在规划软件架构的时候就切割与功能模块的相依性,让应用程序单单只依赖必要的核心模块。而在需要使用功能模块的功能时,则是套用依赖注入的模式,依照平台特性来注入平台所支持的功能模块,这样就能避免直接引用功能模块所带来的困扰。
接下来的内容,会以上述相同内容的角度来做说明,探讨如何从软件架构设计的层面切入,一步一步处理应用程序跨平台执行时,常会遇到的几个问题挑战、以及对应问题的解决方案。
架构设计
分层架构
一个跨平台执行的应用程序,可以选用3-Layer架构设计,做为应用程序的分层架构。3-Layer架构设计有着简洁、清晰、易懂...等优点,以此架构为核心延伸扩展去处理跨平台执行时所会遇到的各种问题挑战,这样可以大幅降低开发人员学习门坎,快速让团队里的每个开发人员都能发挥出实质战力。在3-Layer架构设计中将软件开发所产出的程序代码,依照不同用途归类为:系统表示层、领域逻辑层、数据存取层。其中:
系统表示层 (Presentation Layer),用来归类「提供操作接口」的相关程序代码。例如:提供Textbox接受用户输入地址数据、透过MessageBox通知用户处理结果、甚至是提供Web API给远程系统使用,这些程序代码都会被归类在表示层之中。
领域逻辑层 (Domain Layer),用来归类「封装系统逻辑」的相关程序代码。例如:商城系统的商品数据、购物车、对账单,或者是出勤系统的上下班记录、员工数据…等等,这些程序代码都会被归类在领域逻辑层 之中。
资料存取层 (Access Layer),用来归类「实作数据存取」的相关程序代码。例如:将数据存放到SQL Server、或者是从远程WebService取得数据…等等,这些程序代码都会被归赖在存取层之中。
透过套用这样的3-Layer架构设计,在开发过程中能够减少需要思考的设计内容,让开发人员一次只需要思考某个面向的设计内容。而在后续的维护过程中,也让开发人员能够分门别类的去理解既有的程序内容。
但是光只有3-Layer架构设计,并不足以提供应用程序跨平台执行的能力,因为每个平台所支持的执行档格式不尽相同:在PC平台上会以EXE档做为执行档、在Android需要将软件内容包装为APK文件才能交付客户使用,在Raspberry Pi中则是需要透过刻录Binary档的方式才能执行。而在3-Layer架构设计中只定义了:使用接口、领域逻辑、数据存取...等等程序代码,如何归类至不同的层级,并没有定义该如何将应用程序封装为不同平台的执行档。
为了解决要依平台来编译执行档才能执行的问题,开发人员可以在分层架构中,加入额外的一层Hosts Layer(程序执行层)。加入Host层后,所有可以被编译成为执行档的执行档项目,都会被归类在Host层之中,其余的系统表示层、领域逻辑层、数据存取层则是被归类为一般的函式库项目,而其中执行文件项目用来组合各种函式库项目,建立出不同平台的应用程序。透过这样切割执行档项目、函式库项目的方式,后续只要想在哪个平台上执行应用程序,就在Host层中加入一个对应平台的执行文件项目,接着组合函式库项目来进行编译、产生执行档,就能够提供该平台版本的应用程序,这也就提供了应用程序跨平台执行的能力。
Database跨平台解决方案
每个平台所能支持使用的数据储存设备不尽相同:在移动平台上可以会选用SQLite作为储存设备、在云端平台上可能会选用Azure SQL做为储存设备、在嵌入平台上则可能选择EEPROM做为储存设备。当应用程序跨平台执行时,第一个会遇到的问题挑战就是:数据储存模块无法跨平台。
为了解决数据储存模块无法跨平台的问题,开发人员可以在架构设计的层级,套用IoC模式来切割应用程序与数据储存模块的之间相依性。套用IoC模式之后,应用程序就只相依于自己定义的数据存取接口,不再相依于特定平台的数据存取模块。接着只要在应用程序启动时,注入依照平台特性所实作的数据存取接口,就可以建立动态更换数据储存模块的功能,进而提供应用程序跨平台执行的能力。
以一个计算BMI数值的应用程序来说,需要将使用者输入的身高体重的储存起来,提供下次使用者查询使用。当开发人员依照解决方案建立应用程序后,应用程序执行时,会先依照执行平台建立储存设备相关类别来提供应用程序使用。执行在移动平台会使用SQLite做为储存设备、执行在嵌入平台上则是会使用EEPROM做为储存设备,透过这样的方式让应用程序跨平台执行时依然可以正常的将资料存放到储存设备之中。
参考数据:
DI Framework跨平台解决方案
使用面向对象技术开发的应用程序,常常会搭配依赖注入模块用来在应用程序之外透过配置的方式,来动态更换应用程序所使用的功能模块。但因为目前CoreCLR还算是在发展中的技术,所以在这个时间点会很尴尬的发现,常见的MEF、Unity、Spring...等等依赖注入模块,还没有跟上这波的改变来更新版本,所以目前无法跨平台来使用。
为了解决依赖注入模块无法跨平台的问题,开发人员可以在架构设计的层级,选择套用Factory模式来取代依赖注入模块所提供的功能。套用Factory模式之后,应用程序就只相依于自己定义的功能模块工厂,不再相依于无法跨平台执行的依赖注入模块。虽然Factory模式只能生成加入项目参考的已知功能模块,但是一般的项目其实都还没有到达需要动态挂载功能模块的规模。所以透过Factory模式来生成注入对象,已经能够满足大部分项目的需求,并且提供应用程序跨平台执行的能力。
以一个加密User密码的应用程序来说,需要将用户输入的密码加密后传输到远程验证。当开发人员依照解决方案建立应用程序后,应用程序不需要引用外部的依赖注入模块,而只需要使用内建的加密模块工厂,生成系统所使用的加密规则模块,就可以让应用程序正常的提供软件功能。
参考数据:
UI Framework跨平台解决方案
每个平台所使用的用户界面框架不尽相同:在Windows Phone中可以使用XAML来定义用户接口、在Android中使用XML来定义页面排版、在iPhone中则是使用StoryBoard来描述页面流程。当开发需要用户接口的跨平台应用程序时,最大的一个问题挑战就是:每个平台的用户接口框架都不同,应用程序无法跨平台执行。
为了解决用户接口框架无法跨平台的问题,开发人员可以在架构设计的阶段,直接选用Xamarin.Forms来做为Presentation Layer的用户接口框架。使用Xamarin.Forms做为用户接口框架之后,开发人员只需要依照Xamarin.Forms所定义的编码规则来撰写XAML档案。在应用程序执行的阶段,Xamarin.Form所内建Render Engine就会将XAML档案内容渲染成为执行平台所能呈现的用户接口,直接提供应用程序跨平台执行的能力。
以一个计算房贷利息的应用程序来说,需要在用户接口上显示输入贷款金额、利息成数这两个文字对话框,提供用户输入相关数据。当开发人员依照解决方案,使用Xamarin.Forms建立应用程序后,应用程序执行在Windows Phone,就会使用Windows Phone的控件来呈现画面;而应用程序执行在iPhone,则是会使用iPhone的控件来呈现画面。
参考数据:
Log Framework跨平台解决方案
一个应用程序的开发,Log是一个不可或缺的功能。不管是做问题的追查、或是状态的分析,有了Log的辅助,让开发人员再发生问题的时候有迹可循。而这些提供Log功能的讯息纪录模块,开发人员可以选用.NET内建的EventLog、或者是第三方的Log4net...等等来使用。但是同样因为目前CoreCLR还算是在发展中的技术,所以上述这些常见的讯息纪录模块,还没有跟上这波的改变来更新版本,所以目前无法跨平台来使用。
为了解决讯息纪录模块无法跨平台的问题,开发人员可以在架构设计的层级,套用IoC模式来切割应用程序与讯息纪录模块的之间相依性,让应用程序只相依于自己定义的讯息纪录接口,并且为这个讯息纪录接口套用Service Locator模式来建立全局通用的对象参考。接着只要在应用程序启动时,生成依照平台特性所实作的讯息纪录接口,并且注入到全局通用的对象参考中,就可以完成动态更换讯息纪录模块的功能,进而提供应用程序跨平台纪录Log的能力。
参考数据:
放眼未来
Microsoft HoloLens
讨论了几个应用程序跨平台执行时,常会遇到的问题挑战、以及对应的解决方案后,相信开发人员对于如何开发跨平台应用程序有个一定程度的了解。接着,请大家再看看上面这段影片,影片内容是微软预计要推出的产品:Microsoft HoloLens。在观看的过程中,同样请大家以「软件开发人员」的角度来思考,想想软件开发人员在其中能扮演甚么样的角色。
第一次看这段影片的时候,微软这个主打3D扩增实境的产品:Microsoft HoloLens,马上深深震撼了我的心。透过3D显示、加上扩增实境的功能组合,让现实与虚拟的界线变得模糊,开发人员完全能够在扩增实境中虚拟出各种输入输出设备,来提供使用者使用。这无形中,就打破了现今硬件输入输出方式固定、开发成本过高的限制,让软件的各种概念、发想不再被硬件所局限,只要你想得出来就能够实现。虽然我们还没有使用过Microsoft HoloLens的实际成品,但是想象这个技术成熟的那一天,低头问问自己:「当硬件不再成为捆绑,软件你敢飞得多远」,相信每个人都能看到一个不同的世界。
最后,期许大家能够打破心的限制,设计出更多推动人类进步的软件。谢谢。