适用于 AI 的 Visual Studio 工具
微软认知服务(影像服务/实体搜索服务)的使用
商业应用软件的架构设计
ASP.NET 核心 Web 应用程序
休息 应用程序接口
服务端的测试技术
软件工程中的需求演进处理
下面我们会用讲故事的方式来说明这个问题,人物和情节纯属虚构。
场景:Bob同学有一天在网上看到了一张建筑物的图片,大发感慨:“好漂亮啊!这是哪里?我要去亲眼看看!”Bob同学不想问别人,可笑的自尊心让他觉得这肯定是个著名的建筑,如果自己不知道多丢脸!怎么解决Bob同学的烦恼呢?
我们看看微软认知服务是否能帮助到Bob同学,打开这个链接:
具有 OCR 和 AI 的 Azure AI 视觉 | Microsoft Azure
向下卷滚屏幕,到“识别名人和地标”部分,在“图像URL”编辑框里输入了这张图片的网络地址,然后点击“提交”,一两秒后,就能看到关于这张图片的文字信息了(见下图),原来这个建筑叫做“Space Needle“!但是呢,不太人性化,因为是JSON文件格式的,幸好Bob同学是个程序员,Bob同学想把这个场景做成一个实际的应用,以帮助他人解决类似问题。
Bob同学刚学习了微软认知服务的应用教程,于是打开Windows 10 PC,启动VS2017,安装了Visual Studio Tools for AI后,先在Server Explorer->AI Tools->Azure Cognitive Services上点击鼠标右键,Create New Cognitive Service,API 类型选择ComputerVision (如果已经有了就不需要重复申请了),得到了Key和Endpoint,按照教程所讲述的过程,花了一两个小时,就把应用做好了。
目前Bob的同学的应用架构是这样的:
Bob同学很满意地试着自己的作品,长城,天安门,故宫......但是,Bob同学忽然想到,如果出门在外遇到一个漂亮建筑,没有PC,只有手机怎么办?于是Bob同学又启动了VS2017,创建了一个Xamarin项目,重用了PC上的code,把这个场景搞定了:拿起Android或者iOS手机,对着建筑物一框,几秒后就会有结果返回,告诉用户眼前的这个建筑叫什么名字。太方便啦!
所以,Bob同学的应用架构进化了一些:
Bob同学用手机给很多同学们安装后显摆了几天,有人问他:“Space Needle是啥?”
"这个......这个......哦!你可以在Bing上搜索一下啊!”
"你的程序能不能顺便帮我们搜索一下呢?"
"嗯......啊......当然啦!“硬着头皮说了这句话后,Bob同学赶紧回去查微软认知服务的网站了。宾果游戏! 在这里了:
https://azure.microsoft.com/zh-cn/services/cognitive-services/bing-entity-search-api/
与前面的教程里描述的类似,申请了搜索服务后,也得到了Endpoint和Key,照猫画虎地把客户端改了一下,增加了搜索服务的功能,衔接到了地标识别逻辑的后面,也就是把地标识别的结果“Space Needle“作为关键字传送给实体搜索服务,然后再把结果展示出来。
注意这里要申请的API在Bing.Search.v7里面,技术文档在这个链接里面。
于是Bob同学的应用架构变成了这个样子:
这个图的连接线看着好奇怪,黄色的线为什么不连接到左侧的客户端上呢?这里特意这样画,为了表示黄色的连接(REST API调用)是接在蓝色的连接之后的,有依赖关系。在下一个场景里,大家会看到更复杂的例子。
在一阵手忙脚乱的部署之后,所有的同学的手机都可以使用这个新App了,Bob同学很自豪。这时,学习委员走过来了(也是体育课代表),问Bob:"出门旅游的机会不多,我想用这个App做更多的日常的事情,比如扫一张照片,就能知道这个明星的名字和背景资料,或者是照一件衣服就能知道在哪里买,还有看到一个电话号码后,想用手机扫一下就能记录下来......这些能办到吗?"
Bob同学边听边镇静地点头,其实后背都湿透了,嘴上不能服软:"我回去想想办法吧!"
Bob同学翻阅了微软认知服务的所有技能,在纸上画了一个草图,来解决学习委员的问题:
同时有三根蓝线都从同一个客户端连接到不同的认知服务上,是因为客户端程序并不知道要识别的物体是建筑物呢,还是人脸呢,或是电话号码呢?需要一个个的去尝试调用三个API,如果返回有效的结果,就代表识别出了该实体的类型。
画完图后,本来以为会轻松的Bob同学,忽然发现他需要不断更新三个客户端的代码:PC,Android,iOS,来满足更多的学习委员的需要(如同右侧那个上下方向的箭头一样是可扩充的),然后再分别发布出去!并且他意识到了另外一个问题:每个客户端需要访问认知服务四次才能完成这个场景!不但网络速度对用户体验造成了影响,而且流量就是钱啊!如果将来需要支持更多的识别类型,连接线的增长速率将会是几何级别的!
怎么办?
Bob同学想起了刚买到的《构建之法》第三版,仔细阅读了第9,10,11三章,明白了一些基本的概念:
需求是不断演进的,任何一个软件都需要不断迭代
定位典型用户(学习委员)和常用场景(出门旅游还是宅在家里)
在需求分析阶段,要搞清楚在现实世界里,都有哪些实体,如何抽象出我们真正关心的属性和方法
PM/用户提出的需求,程序员需要认真理解,深入到实际问题中进行抽象,找到实体和属性/方法在软件系统中的表现,构建框架,然后再编码(想明白了再动手,不能头疼医头,脚疼医脚)
“我要重构!”房间里响起了Bob同学的呐喊声。
小提示:需求的"演进"与"变化"是两回事儿,不要混为一谈来掩盖项目经理对需求的分析与把握的不足。简单地举例来说,当项目经理说"地标识别看上去很少有人用,废掉吧,咱们做个名人识别",这个属于需求变化。
微软认知服务应用方式有两大类:
用客户端直接访问认知服务
客户端通过中间服务层访问认知服务
第一种模式很好理解:微软认知服务7x24小时在云端提供服务,开发者在智能手机或者PC上编写客户端应用程序,调用REST API直接访问云端。但是这种模式有一些潜在的问题,如:
客户端代码量大逻辑复杂
客户端需要密集发布并持续维护
客户端与服务器端耦合度高
客户端多次访问服务器
网络安全性低
无论客户端有多少,依赖的认知服务有多少,其实还是下图所示的模式:
目前Bob同学就是使用这种方式,来不断演进他的应用,终于遇到了棘手的问题。
为什么呢?因为客户端一旦发布到用户手里,对发布者来说就比较被动了,需要非常小心地维护升级,每次都要全面测试,测试点多而复杂。即使有应用商店可以帮助发布,但要把所有用户都升级到最新版本,还是需要很长时间的,这意味着你还需要向后兼容。
第二种模式可以用简单的图来表示:
有规模的商业化应用,一般都采用这种模式搭建应用架构,以便得到以下好处:
客户端代码量小逻辑简单
客户端不需要密集发布和维护
客户端与认知服务的耦合度低
客户端单次访问服务器
网络安全性高
拉个表格,一目了然:
直接访问模式 | 中间服务层模式 | |
---|---|---|
客户端代码 | 量大,逻辑复杂 | 量小,逻辑简单 |
发布与维护 | 密集,改一点儿东西都需要重新发布新版本 | 中间层服务能屏蔽大量逻辑,不需要在客户端代码中体现 |
客户端与认知服务的耦合度 | 极高 | 很低 |
客户端与认知服务的通信量 | 频繁,多次 | 单次 |
对认知服务密钥的保护 | 低,用Fiddler就可以“看到”认知服务密钥 | 高,把费德勒叫来也不行 |
服务器端代码 | 无 | 有 |
多种客户端支持 | 复杂 | 简单 |
如果有了中间服务层,客户端的工作就简化到只做与中间服务层通信,提交请求,接收数据,用户交互等等,而复杂的商业逻辑,可以在中间服务层实现。而且在更新业务逻辑的时候,大多数情况下,只需要修改中间服务层的代码,无需更新客户端。
对于多种客户端的支持问题,用微软VS2017提供的跨平台Xamarin架构可以解决,开发者只需要写C#程序,就可以把应用部署在Windows/Android/iOS设备上,一套代码搞定。
如果关注于对认知服务的使用,也可以用另外一种分类方式:
单独使用某个服务
串行使用两个以上的服务
并行使用两个以上的服务
串并行混合使用三个以上的服务
比如上面的最后的场景,实际上是第四种方式:先并行使用了地标识别、名人识别、OCR,然后又串行使用了实体搜索服务。
我们来帮助Bob同学重新设计一下他的应用架构:
上图只是个粗略的架构,中间服务层具体如何实现呢?