做不完的应用软件
我爸是个乡村小学教师,对我所从事的软件行业一无所知,但是他对我的工作稳定性表示怀疑:“你这做软件的,要是有一天软件做完了,你岂不是要失业了?”也许他想起了他作为老师的情况,教完一批学生,下一批又上来了,一茬一茬的。于是又问我:“你们是不是一个软件接着一个软件做?”我回答他:“不是,就一个软件,好几十个人得做好几年呢。”解释了很多次仍旧没有消除他的疑问:“你们做软件怎么会一直做下去?怎么没有个做完的时候呢?”。
如果他在通往张江的地铁上,知道有那么多我伤不起的IT同类们,他也许会更加迷惑。为什么如此庞大的程序员大军,日复一日年复一年地敲着代码,生产出无数的软件,可是他们不用担心失业?为什么需要那么多看上去类似的软件?为什么这些软件永远没有做完的那天?
应用软件独一无二的地方
答案其实很简单,我们做的每一套软件,都是为了解决某个领域的业务需求。而业务需求永远没有停止变化的一天,这就是为什么应用软件永远也做不完的原因。我刚开始工作时,在一个小团队里为一家公司定制开发ERP,其实就是一个中小型的管理系统,在知道国内有用友金蝶在做ERP的时候,觉得很奇怪:有那么好的公司在做ERP,我们还有做的必要吗?客户怎么不去买用友金蝶呢?现在想来这想法很幼稚,因为每家公司的业务都是独一无二的,因此每个应用软件,即使都叫ERP,它也是独一无二的。
把独一无二的东西分离出去
想想我们为了构建一个应用软件起来,要做哪些事?最基本的三件是:Domain Business Logic、Presentation(UI展现)、Persistence(存数据库)。还有就是Authentication,Authorization,Cache等等。复杂的系统还包括:与其它系统的集成,提供Service(API)等等。
就说最基本的3件吧,稍微思考一下就会发现,只有Business Logic是独一无二的。
Presentation层是个重复重复再重复的事情,再怎么不同的应用,我们都可以用同一套工具来实现它:用Grid来展现多条记录;用Combobox来提供选择;用MVC模式来分离数据与展现……框架应运而生。
Persistence也是个重复重复又重复的事情,关系型数据库,ORM框架,NoSql……同样约定俗成。
所有的东西都可以找到框架,这就是为什么写应用软件,跟写游戏,或者写操作系统等比起来,是最没有技术含量的。
然和唯独“业务逻辑”没有框架。正是这“业务逻辑”,让每个应用软件区别于其它应用软件。因此我们决定要做一个应用软件,我们要做的就是实现客户的业务逻辑,这是唯一真正的目的。持久化,UI,Cache……,都是手段。
如何实现业务逻辑?
现在知道了,我们做的每一个系统,都在为客户交付独一无二的业务价值。这就解决了程序员们“存在的意义”的哲学问题。那么如何实现业务逻辑呢?把客户的业务需求转化为解决方案的过程,就是设计的过程。因此,这个问题可以这样问:通过何种的设计,让客户的业务需求得到满足呢?这个问题很傻,因为显而易见是通过写代码实现啊,这不是常识吗?很可惜这不是常识,因为很多团队把设计写在设计文档里了。他们把写文档说成设计,把写代码说成实现。大错特错,代码是唯一的设计,MsBuild把代码build成exe才是实现!用Unit Test确保自己的设计(即代码)正确反应了自己脑中的设计意图,用Integration Test来确保自己的设计(即代码)正确地满足客户的需求,有着这种认识和追求的程序员,是我想要共事的程序员。
想起来,台湾习惯把程序员说成“设计师”,是更贴切的。把代码当做设计的程序员是幸福的,比较一下大楼的设计人员,当他们设计好的方案(设计图纸)一旦被建筑工人们开始“实现”的时候,他们的设计几乎就不能再改了,因为“实现”的成本太昂贵了。而作为软件设计师,我们的“建筑工人”MsBuild包工头以及它的团队(CPU,RAM等小兵)是多么的廉价和高效,几秒钟就把我们的设计给实现了。这就是我们能够利用“重构”技术的理由。(想象一下如果大楼设计人员也这么说:“你们先按照这方案盖起来,我看效果,然后再调整(重构)”……)
与传统行业的设计师相比,我们软件设计师能得到的反馈更快更多(因为我们面对的是电脑),这就是我们幸福的地方,也是我们应该利用的地方。准备写个“软件开发中的反馈系统”系列文章阐述此问题。
在哪里实现业务逻辑?
用代码实现业务逻辑,那么,在代码的哪个地方呢?有很多个地方:
1,前些年很常见如今被人很鄙视的一种是,存储过程。这种曾经非常流行的技术,自然有它产生的原因。存储过程是什么?是数据库里的东西,而且是关系型数据库里的东西。很多人的思维是这样的:当他试图理解一个业务逻辑时,他心里想的是表以及表与表之间的关系,这就是Database-Driven逻辑,在这种逻辑下,把业务逻辑写在存储过程里,是很自然的事情。如果把思维切换到Domain-Driven的模式中:业务逻辑是我的核心,持久化只是一个辅助的手段,我可以用关系型数据库,也可以用NoSql,而NoSql根本没有存储过程,如此,你把业务逻辑写在存储过程中让人情何以堪啊?
2,写在UI里,这就要提到当年的RAD之王Delphi了。并不是说在Delphi里只能这么做,而是说Delphi里很多人就这么做,UI直接绑定DataSet,用户点击了某按钮,直接在IDE里双击该按钮,生成Btn1_Click方法,把业务逻辑通通写在那。这么做有一万种缺点,但有一个优点,就是RAD中的R(Rapid)。哥用这种方式写过好几年的Delphi,不堪回首。
3,写在MVC的Controller里,其实等同于2。现在Asp.net MVC框架很热,可是很多人不知道MVC本质上是啥东西。虽然它有个“M”,可是他在分层的架构体系里,只是非核心的Presentation层的一个pattern而已。跟Domain层毫无关系。
4,最好的方式,当然是写在一个独立的Domain Layer里。别忘了业务逻辑是一个应用系统唯一独一无二的地方。
如何实现Domain Layer(Business Logic Layer)?
我做过几次技术面试,一般都会有个问题:“你能说说你对架构的理解吗?”得到的回答,第一句往往是:“关于架构,一般是分成3层,Presentation,Business Logic,Persistence……”。这句话即使是很Junior的人也能说得上来,可是再往下问就能问出有意思的东西了:3层之间的依赖关系是怎样的?
一般的回答是:Presentation依赖于Business Logic, Business Logic依赖于Persistence。
可是既然每个应用系统的“业务逻辑”才是应用系统存在的理由,才是开发它的目的所在。而UI展现、数据库存储、Cache等都是为了实现“业务逻辑”这个目的所提供的手段,都有成熟的框架、模式可用,都可以是雷同的。
那么为什么“业务逻辑”要依赖于“存储技术”?为什么“目的”要依赖于“手段”?
待续……