写在前面
我们做的系统要重构了,做一下Saas化升级,我也有些搞不清方向,就买了《SaaS软件工程·云计算时代的敏捷开发》这本书来学习学习。顺便呢,借此机会写写技术文章,练下文笔。
1.什么样的人适合学学SaaS软件工程
虽然大学时期我们有“软件工程”这门课程,但那时候学了就学了,也没实践过,就知道有这么个东西。等工作后,参与过很多回开发工作,不断重复的看需求、做设计、写代码以及最后部署上线这个流程。这时候就是身在其中,又是当局者迷,旁观者清了。
突然之间,我有个想法,想跳出这个小圈圈,到高一点的位置看看整个过程,看看我自己到底是在干些什么,别人又在干些什么,我们又是怎么合作,怎么实现那些需求的。
这时候就需要一些指引,帮助我们从上帝视角看看现在用的这套是怎么个运转逻辑。
2.SaaS软件工程是什么
Software as a Service,软件即服务。对照着单机软件(如:office、photoshop等)和app(如:微博、QQ等)来看,当你拿到一个新电脑或者新手机,总免不了从网上下或者用之前复制好的安装包安装半天,才能开始使用这些东西。尤其是像office这种,安装包又大下半天,没钱还要到处找破解版(* ̄(エ) ̄)。
那有没有一种方式,不用下安装包,直接连网就能用别人已经装好的了呢。已经有人用SaaS在解决这些问题了,只需要一个浏览器,打开指定网站就可以在线做表格PPT,在线P图。很明显这就是把一个软件放到企业的服务器上了,再开放给所有人使用。当有新功能或者bug修复的时候,服务端就直接更新了,而使用者什么都不用做,继续正常使用即可。
3.SaaS软件工程重要部分
3.1 代码
做为研发工程师,首先关注肯定是代码。
开放给所有人使用的软件肯定需要不断进化,人们总是想要更多的东西,不断进化的另一面就是不停的在修改代码。有经验的工程师总会接触一些遗留代码,不好的遗留代码占用空间的同时还降低了代码的阅读性,最严重的情况是堆积成一坨“屎山”。所以每次写代码的时候要把代码写得漂亮一些,总要让后面接手的人(可能就是自己)容易看得清楚明白,添加新功能时不会有太多顾虑。
3.2 架构
比代码更高一级的就是架构,这儿有个名词面向服务的架构(Service Oriented Architecture,SOA),这是一种开发思想和方法,具体落地的一种方案就是微服务。其基本思路是多个小的服务系统组合成了一个大系统,要实现某一功能,可通过若干个小服务之间相互调用来完成。这种方式易于扩展,有新功能时,加入一个新的小服务或者多调一个小服务的接口即可完成。书中给出一个书店系统的架构从传统式升级到SOA架构之后的变化。
flowchart TB
subgraph id [内部服务]
r[(评论)] <--> rs[评论子系统]
u[(用户)] <--> rs
u <--> ups[用户账户服务]
u <--> bs[购买服务]
o[(订单)] <--> bs
end
rs <--> book[书店服务]
ups <--> book
bs <--> book
book <--> cus
cus((fa:fa-user-circle-o 用户))
上面是书店服务的一个筒仓式版本的架构,各个子系统之间可相互直接调用,对外提供一个统一的API。
flowchart LR
subgraph outter [服务]
subgraph reviews [评论]
ur[(用户评论)] <--> rs[评论服务]
er[(编辑评论)] <--> rs
end
subgraph users [用户]
u[(用户)] <--> ups[用户账户服务]
end
subgraph orders [订单]
o[(订单)] <--> bs[购买服务]
end
reviews <--> users
users <--> orders
reviews <--> book[书店服务]
users <--> book
orders <--> book
end
subgraph net [网络]
accounts[(账号)] <--> sns[社交网络服务]
end
net <--> fbs[最喜爱书籍服务]
reviews <--> fbs
users <--> fbs
fbs <--> cus1((fa:fa-user-circle-o 用户1))
book <--> cus2((fa:fa-user-circle-o 用户2))
上面书店服务的SOA版本,各子系统独立分开,开放自己的API。当要开发一个新的软件功能时,直接组合已有的服务API即可。如“最喜爱的书籍服务”调用了已有的“评论服务”和“用户账户服务”,再加上新开发的服务即可完成新功能。但这也使得系统变得更加复杂,API调用的层次变多,这对工程师来说是一个棘手的挑战。
3.3 云计算
当然软件服务不是说加的就加的,得要有服务器资源才行。如今的互联网动辄成百上千万的访问量,需要大量的服务器来支撑,同时对网络带宽、服务器稳定性和安全性等等都有很高的要求。维护这么多的服务器带来的硬件成本、人力成本对大部分公司来说都是不划算的,那么从服务器中心里面租用服务器就是一种很不错的方式。在服务器中心,上万台的服务器形成了集群,所有的服务器维护操作都由服务提供商来负责,租用的公司大部分情况下只管理自己部署在服务器上的软件,按流量和时间收费。以这样的方式形成规模后,就形成了公共云服务,或者云计算。
3.4 测试
代码部署到云服务上面后,服务器的运行质量由云服务商保证,那么软件系统的质量必须通过测试确保了。测试工作主要有两个,一是验证,开发写出来的东西是不是“对的”么?二是确认,开发出来的结果是我们想要的吗?测试要尽可能详尽,就要在不同的阶段都做测试。按层级来说,分为单元测试、模块测试、集成测试和系统测试。测试的程序越复杂,想要全方位的测试就更难。想要知道都测试到什么程度了,之前预定的测试路线是否都走完了,则可以通过测试覆盖率来表示。当然测试覆盖率达到100%也并不能保证软件一定没有质量问题,因为它只是用于侧面印证测试进度。
还有一些其它的相关术语。黑盒测试是在软件外部通过运行各种测试工作,与之相对的是白盒测试,在知道软件功能运行的原理或者代码逻辑的情况下,反推出最坏的情况来进行测试。在修改旧代码后,原来已经测试过的功能,还要再测试一次,这既是回归测试。
3.5 提高生产力
如今的应用程序越来越复杂,工程师团队在构建程序时,提高生产率是很有必要的。生产率提高有四个基本的机制:简明清晰、合成、复用和工具自动化。
简明清晰很好理解,在实现功能时代码尽量少写一些代码。比如使用语法糖简化语法,变量、方法命名时尽量简单(其实命名很让人头疼)。
for(int i=0;i<list.size();i++) {
Object item = list.get(i);
// do something
}
list.forEach(item-> {// do something})
另一种让代码变得简洁的方法是提高抽象水平。抽象就是把某一些事物统一一下,省略掉细节,看成一个事物来处理。就好像上学时做物理题,不管现实中的物体长得有多奇形怪状,受力分析一律看成方块。抽象的好处是能快速的看清内容,理清逻辑,而不是一上来就被各方面的细节淹没。
生成对代码来说就是自动生成而不是手动创建。现在的大部分高级编程语言都是高度抽象的,编写的代码会自动生成底层的机器码,再由CPU执行。比如下面的Java代码和转换后的字节码。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
这也只是javap程序翻译后的字节码,起作用的主要是
0:aload_0这样的指令。可以看到如果没有java编译工具的自动生成功能,由程序员去手写这些指令是非常复杂困难的,因此生成对提高效率很有帮助。
复用就是使用过去已经做好的设计或者程序,而不是从头开始创建,程序员行话就是“不要重复造轮子”。复用不仅仅只是简单的复制+粘贴,第一要明白哪些地方是可以复用的,不能原来写了1000行代码,我就copy 1000行代码过来用,那程序多臃肿;第二复用的内容和目前实现的差异性,现在要实现的功能一定和以前有区别,要根据情况修改并测试;第三就是复用的方式有很多种,引用开放的代码库、通过设计模式扩展已有的功能等等。
程序员在软件研发过程中会用到各种工具,合理的运用这些工具实现自动化工作,减少手动处理时间,增加精确度。程序员离不开的基础工具是IDE,像idea和eclipse,这两种工具集成了开发必备的功能,还支持自定义扩展,增加想要的功能。
4.总结
软件工程在上世纪70年代就已经出现了,最开始流程十分简单,是基于计划文档的模型,按下面的流程按部就班的进行。简单的自上而下(虽然下图是横着的),就像瀑布,所以也被称为瀑布模型软件开发过程。
graph LR
需求分析 --> 架构设计 --> 研发 --> 测试 --> 使用和维护
这样的开发方式缺点也很明显,事情的发展往往不会按照最初设想的一样去进行,遇到改动时会让人十分恼火。为解决这个工程师们开发出了新的软件工作模型:螺旋模型,即把上面的流程纵向切开为多个流程,再挨个执行。还有一些其它的软件工程思想,如统一软件开发过程(RUP),结合了瀑布模型和螺旋模型,加入了商业建模阶段,重叠了各阶段的部分时间。
这些软件工程思想都制定了一系列规则,每个阶段都要产出文档,并严格按照文档执行。但现实是很少有项目能严格按照计划的流程执行,往往是计划赶不上变化。2001年,一组软件开发人员对软件工程的做了一项改革,提出了一个轻量级的软件生命周期,发布了敏捷宣言:
我们一直在实践中探寻更好的软件开发方法,身体力行地帮助他人。由此我们建立了如下价值观:
- 个体和互动高于流程和工具
- 工作的软件高于详尽的文档
- 客户合作高于合同谈判
- 响应变化高于遵循计划
也就是说,尽管右边有其价值,我们更重视左边的价值。
敏捷强调通过在编写代码之前编写基于测试驱动开发(TDD) 的测试代码来减少错误,通过用户故事来达成协议并确认客户的需求,以及用速率来衡量项目的进度。敏捷很快,一两周就会有新的版本,与上面的计划文档模型不同,软件发布不再是什么大事件。
敏捷开发并不是万能的,SaaS也可以用计划文档的方式开发,但敏捷与SaaS形成了一个绝妙的搭配,再辅助以高效的框架和工具,形成了一个完善的良性三角。