我的架构经验系列文章 - 后端架构 - 框架层面

回到索引 http://www.cnblogs.com/lovecindywang/archive/2012/12/23/2829828.html

 

框架层面:

 

  • SOA

在这一篇中会逐个介绍一下自己对这些XXX的理解,其实每一个理念都不是莫名其妙产生的而是有产生背景的,这些时髦的名词不是用来炫耀的,而是真正要理解它们是干什么的,并且框架千万不能乱用理念也千万不能乱用,并不是把所有的这些都用上你的系统才是一个牛逼的系统,一定要适合才是最好的,并且要保持简单可靠的原则。所谓SOA,字面上来说是面向服务的架构。有的人不说SOA其实他已经SOA了,有的人大谈SOA但其实只是在用Web服务,SOA可大可小。你可以认为服务调用就是SOA了,也可以认为服务调用只是SOA中的很小一部分。个人觉得SOA的理念是说,把业务逻辑从类库的封装提升到服务的封装,并且通过不同的信道不同的编码格式来提供服务,使异构系统之间也能重用服务,说白了就是让代码从本机重用提升到了跨机器的重用。从最简单的来说,把组件封装成自制的服务,通过交换消息来使用服务提供的功能,那么就是SOA了,但这也仅仅是SOA的开始,比如你是否想过下面的问题怎么解决?

  1. 你的服务是否可以被外部的异构系统使用?
  2. 如果你的服务又需要调用另外的服务,怎么处理复杂的调用关系,怎么监控整个调用过程?
  3. 服务调用怎么纳入事务的控制中?
  4. 服务越来越多,接口越来越多,怎么知道应该调用哪个服务哪个接口?
  5. 接口的版本升级了怎么办?
  6. 服务有太多人调用,怎么进行负载均衡,怎么限制调用人数?
  7. 怎么做安全,限制服务的匿名调用?
  8. 服务怎么进行测试?
  9. 服务调用失败后怎么办?
  10. 服务怎么进行升级和重新部署?

因此,SOA其实不仅仅是调用服务,在监控和治理上有很多事情要做,SOA可大可小。不管怎么说,从理念上来说,SOA确实是一种进步,复杂逻辑都封装成服务,一个复杂的系统可能调用不同的服务就可以完成了,每一个服务都是自治的,很好的降低了系统整体的复杂度。其实一个复杂的系统如果复杂度在10000的话,那么分成四层实现10*10*10*10就可以大大降低复杂度,每一层只要做好10复杂度就好了,由上层来调用下层。OSI如果不是七层模型,而是一层模型的话很难想象怎么去处理整个复杂的过程。

 

  • RPC

字面上来说就是远程过程调用,RPC(这里我们说广义上的RPC)也可以是SOA实现的一种方式,SOA并不一定都通过Web服务实现。从实现原理上来说RPC其实并不是很复杂,无非就是客户端有一个代理,收集客户端要调用的远程方法以及参数,然后序列化成消息提交到远程,到了远程之后把消息反序列化,动态执行客户端所需要的方法(当然也包括创建对应的对象),然后把结果通过另外一个消息返回给客户端,当然其中的细节太多了。从客户端和服务端交换数据依赖的信道来说一般使用TCP或HTTP,也可能会是UDP。

  • ORM

对象关系映射解决面向对象系统和数据库阻抗不匹配的问题,大家都知道的ORM的定义。这里我想说的是ORM的出发点是好的,而且在某些应用中ORM确实可以改善代码可读性,增加编码效率,个人认为ORM是有使用情况的,不是所有的数据访问都适合使用ORM框架的,Java的SSH也有那么一点误导,Struts不是实现MVC的唯一方法,Spring不是实现IOC的唯一方法,Hibernate也不是实现数据访问的唯一方法,我觉得ORM:

  1. 它适合领域复杂的,表多的,表之间关系多的,访问量相对较小的,企业应用。
  2. 它不适合业务相对简单,表之间关系不多,访问量超大的互联网应用。

对于ORM来说要入门是简单的,但是要用好不是这么容易的:

  1. 如果没有正确使用很可能导致产生大量的SQL语句,而使用者还不知道。
  2. 如果没有正确使用很可能会拉取过多不必要的数据,而使用者还不知道。
  3. 如果没有正确使用很可能会产生性能不高的SQL语句,而使用者还不知道。

因此,即便是使用ORM也要对ORM产生的SQL语句张一个心眼,并且我们需要了解ORM中是如何做延迟加载、级联加载、主键缓存的,只有了解了这些机制才能真正用好ORM,如果对ORM不熟悉,如果在做互联网系统我觉得还是太平点吧,SQL语句精准高效。当然有的人要说了用SQL的话业务逻辑就可能不在代码中了,其实这个还是看SQL语句怎么写的,如果把SQL只是当做数据库和程序的沟通桥梁的话这不是问题,如果在SQL里面做一些判断做一些计算那就是自己的事情了。

 

  • IOC

控制反转依赖注入不是嘴上说说的,它是一个非常实用的理念。有的人即使在使用了IOC之后还没有意识到为什么要使用IOC,我总喜欢在面试的时候问为什么要用容器来创建对象,自己手动new出来有什么不好?有的人回答是手动new出来的性能不高,容器创建的是唯一的对象,那我就会问自己写一个单例的对象也是一样的,为什么要容器创建?其实这样的理解是有误的。个人认为管理对象的生命周期只是IOC容器的一个作用,IOC容器的意义在于:

  1. 管理了对象之间的关系。在OO中组合很有用,如果对象之间有复杂关系的话,那么我们就必须在new对象的时候来构建这种关系,这些关系其实都写死在代码中了。并且我们通过代码会直接把实际的类型写死,降低了针对接口编程的意义。如果能在配置文件中根据自己的需求来配置这种关系,由容器动态创建对象和对象之间关系的话,那么我们就把代码中依赖提取到了外部,由外部注入进去。在一个分层的应用程序中,我们不仅仅注入平行层级的对象,还可以注入下级对象,实现从上到下的自动注入,整个系统就非常灵活。
  2. 管理了对象的生命周期。有的时候出了单例或是new出来的对象,还会有根据线程、根据请求来的特殊声明周期的对象,如果手写代码来管理声明周期一来很麻烦,二来也不方便调整,通过容器来管理对象的声明周期简单高效,并且我们很容易对容器进行扩展提供不同的声明周期的字典即可扩展生命周期的类型。

 

  • AOP

面向切面编程对于职责分离和提高可测试性都很重要。一般来说代码有两种方式织入,静态的和动态的。所谓静态的就是在编译之前直接改了要包装的类,然后把关注点的入口方法封装进去一起编译的编译时增强。所谓动态的就是在运行的时候动态修改代码动态编译的运行时增强。一旦有了AOP,那么我们的事务、日志、权限、缓存之类和业务无关的代码就可以不出现和混在业务代码中了,根据需要进行配置就可以对任意的代码进行这些横切关注点的增强。一旦这些代码有修改,我们也只需要修改配置,而不是在代码中的几千个几万个地方去查找修改。

 

  • MVC

MVC对于网站特别是互联网网站来说是一种非常好的里面,MVC的优点体现在:

  1. 职责分离,不再是所有的代码都混在一起了,V和C的分离尤其重要。
  2. 职责分离早就了可以进行单元测试,可测试性也是重要的一环,对C可以进行单元测试是非常重要的。
  3. 大多数MVC框架都提供了AOP的织入点,在实现职责分离的时候还能实现横切关注点的自动执行和可替换性。

在实现MVC的时候我们不仅仅是能把MVC框架用上去就好了,要尽可能实现:

  1. C中的诸如缓存、权限、日志之类的横切关注点务必提取出来通过AOP实现,不要和C的其它业务性逻辑混在一起。
  2. C中的Action可以重用的尽量重用,Action的结果可以重用的也尽量重用。
  3. 可以考虑MVC和IOC相结合,把C用到一些服务或DAO动态注入进来。
  4. 对于V尽量确保V中不要有后端代码,V可以让前端开发直接编辑,由后端开发嵌入比较简单的Tag。如果VM明确的话,前端甚至可以直接写V。

 

  • TDD

测试驱动开发又是一个不小的概念。各种平台也有各种框架来实现Mock来实现单元测试。工具再好没有正确的编码理念也是没用的,要实现所有的代码都能通过单元测试来验证必要的几个因素包括:

  1. 程序没有很复杂的上下文环境,或者说上下文环境是可以被模拟的,否则怎么测试?
  2. 程序模块的职责是单一的清晰的,如果一个模块做了几十件事情,有几百个分支的话是很难测试,测试的粒度越是细越是容易测试。

针对现在大多数项目无法进行TDD,甚至无法进行单元测试的原因是因为往往时间很赶,只能有时间实现最基本的业务逻辑,而单元测试其实编码的时间不会比实际的编码少的,甚至更多。个人认为可以根据项目的性质不同来看,如果这个项目本来就是CRUD的,或者是一个临时的项目,单元测试TDD的意义不大。但如果这个项目是一个要被很多人使用的类库或者框架性质的项目,没有单元测试是无法想象的:

  1. 如果一个类库提供了100个功能,你不可能在修改了一个点之后就去手动测试一下这100个功能,必须通过自动化的手段进行。
  2. 类库需要确保在所有的边界情况都考虑到,手动测试或者黑盒测试是很难覆盖所有情况的。
  3. 如果你的类库没有提供单元测试,类库的使用者怎么在他们的执行环境来验证类库的可用性呢?因此还不仅仅是给自己用,别人还要使用你的单元测试来确保类库在自己的运行环境下可以正常工作。

 

  • 其它

在这里先想总结一下,个人觉得这么多XXX中最需要有的就是MVC和IOC了,至于AOP有了当然更好,至于ORM和SOA则是看需求了,对于TDD么如果你在写一个类库或框架那是必须的,否则很难想象这套代码的稳定性会有多高。除了上面提到那那些XXX其实还有很多作为基础框架需要实现的东西,以前画过一个脑图参考http://www.cnblogs.com/lovecindywang/archive/2012/01/11/2318973.html。作为框架我觉得有一些要素是需要满足的:

  1. 尽量保持框架对外的接口是很简单的,复杂的东西应该在框架内部处理掉,对框架的使用者透明。
  2. 框架的异常处理要完善,日志记录要完善,框架由于是对开发者透明的,因此最好在异常信息和日志信息中写明要调用者和框架的使用者怎么样去做才能解决这个问题而不是仅仅是说出了什么错。
  3. 一个完善的框架应该内建性能检测机制,或者提供http的接口可以让外部了解到框架内部的运行状况。
  4. 框架要做好测试,确保在不同的线程环境和不同的配置情况下框架都能正常运行。
  5. 框架最好有性能测试,让使用者明确这个框架能提供的性能,以便正确判断是否可以满足自己的需求。

 

 

posted @ 2012-12-23 15:50 lovecindywang 阅读(...) 评论(...) 编辑 收藏