再谈设计和编码

标签: 设计 编码 | 发表时间:2015-10-30 09:24 | 作者:
出处:http://kb.cnblogs.com/

  这篇文章谈下编码中的一些细节问题,在谈之前首先还是要继续推荐下《代码大全》这本书,该书在很多公司都会被推荐为新人入职后的必读书,即使在互联网和敏捷开发环境下,该书对于新人仍然有仔细阅读和体会的必要,要明白架构和设计思维的基础仍然是编码思维,面向对象思维的基础仍然是代码本身的逻辑和结构,如果不能写出高质量的代码,那么架构和面向对象思想很多内容往往难以真正落地。

  对于这篇文章,结合一个最简单的业务功能场景来讲解,即采购订单新增这个业务功能和场景。

  拿到这个功能需求后当然是首先要详细阅读具体的业务功能需求,在阅读完后第一需要思考的不是业务流程,不是数据库表,而是首先应该思考该功能对应的核心领域对象究竟是什么?以这个功能为例,可以很明细的看到核心对象是采购订单,这是一个有明确业务含义的对象,可以看到后续很多的业务操作和方法都将围绕采购订单这个对象展开。核心主对象明确后再分析该功能需要依赖的附属对象,比如:

  • 供应商:基础主数据对象,依赖原因是需要在创建采购订单的时候选择供应商
  • 采购类型:数据字典类对象,依赖原因同样需要在创建订单的时候选择
  • 订购商品:基础主数据对象,一张订单在创建的时候都必须要选择购买的一个或多个商品和数量信息

  该问题做了基本的思考后,再回答我们具体使用的语言和开发框架,比如基于标准的java ssh框架来开发该功能,要明白我们一般选择了某种框架后基本的分层思路就已经确定了。当我们拿到一个现成的框架后,在基于这种框架做完练习后,首先要思考的就是这种框架本身的运行机制是如何的?各层之间的调用逻辑和分工是如何的?各层有哪些约束和边界,在业务实现过程中涉及到的业务规则,逻辑和数据处理究竟应该放在哪层去实现。这些问题必须在编码中搞清楚,而不是依葫芦画瓢而不知其所以然。

  对于我们使用的分层框架基本运行机制和逻辑了解清楚后,基于拿到业务功能需求要开始思考的就不是框架和分层的问题了,而是我们应该在每个分层中设计哪些类?每个类应该有哪些核心方法?类和类之间如何衔接和实现内部调用。单表功能做多了最容易犯错的地方就是完全的数据库表式思维模式,即任何一个数据库表都会有对应的展现页面,控制类,service类和dao类,完全一对一映射和调用。在这种思维模式下忽略了最前面思考的对象的本质,在领域模型里面一个核心就是我们关心的是有明确业务含义的对象,而不是数据库表。数据库表和dao层只是在最终持久化要做的事情而已。

  基于上面的分析可以看到,对于订单创建的时候供应商信息的获取应该是供应商类完成的职责,对于采购类型可能则是一个数据字典的common类完成的职责。而对于核心的订单类可以看到,我们需要的领域服务或方法很简单,即:

public void savePurchaseOrder(COrderEntity order);

  订单应该做为一个核心的领域对象来处理,但是实际在后台操作则涉及到OrderHeader和OrderDetail两张数据库表,任何一张订单的保存都涉及到对两张数据库表的操作。可以看到如果对应的业务功能没有明确的对订单明细的操作规则和方法,那么在Service层没有必要根据头和明细定义两个Service类,只需要一个OrderService类即可。在该类中实现所有的订单保存前数据准备和逻辑校验。

  在这一个步骤想清楚后,即对于订单新增功能可以看到,即在页面和展现层进行新增订单操作,在点击保存按钮的时候应该将页面上的订单数据信息传递到action层进行基本的数据完整性校验,然后再将订单数据以json或已经实例化好的订单实体类传递到逻辑层的savePurchaseOrder方法去处理。而savePurchaseOrder要做的事情就是进行数据准备和转换,再调用Dao层的订单头和订单明细保存方法进行数据保存,并控制好事务处理。

  基于该逻辑思路我们就基本可以写出各个分层的核心方法和方法实现,实现最基本的订单保存功能。在整个过程中我们始终围绕订单这个核心对象展开。逻辑层的savePurchaseOrder这个方法是核心,即从展现层到此是准备好订单实例数据,从该层到Dao层是实现数据最终的持久化和事务控制。

  对于业务规则可以分为两类规则,即一类规则是数据参考完整性规则,比如数据类型,数据的长度,2个数据属性间简单控制逻辑(比如订单类型为A时候,发运地址必须输入等);还有一类即较为复杂的数据处理规则或需要调用后台数据库实现的控制逻辑(订单总金额>1000的时候用户信用等级必须>B级,在订单保存前还需要再实时检查商品库存信息是否足够等)。对于两类规则的基本原则就是第一类可以在action层实现,而第二类数据则需要在业务逻辑层来实现。

  对于逻辑层的savePurchaseOrder方法最终应该相当简单,即首先进行业务规则教育,在通过后再调用订单保存方法进行订单保存操作。类似如下:

public void savePurchaseOrder(COrderEntity order)
{
if !validBusinessRule1(order) return;
if !validBusinessRule2(order) return;

//校验通过后调用订单保存方法
saveOrderInfo(order);
}

  在该实现中可以看到首先进行了子方法的拆分,保持订单保存方法本身的简洁和代码可读性。其次需要考虑对于拆分的处理规则的方法是否需要拆分到单独的业务规则类里面。这里要看情况来处理,即对于业务规则本身有比较高的复用性时候最好拆分为单独的业务规则类来处理(比如在订单分发或订单拆分业务功能中仍然需要使用同样的业务规则,那么规则单独拆分到类是有必要的),如果功能确实够简单也可以考虑不拆分。

  以上都思考完成后基本的框架和设计实现逻辑就都清楚了,下一步则过渡到具体的编码实现环节。基于任何语言的编码其核心都是算法和数据结构,而在这两者里面最基本的又是变量和数据类型,程序控制逻辑(判断和循环等),变量定义的规范性,数据类型选择的合理性,控制逻辑代码的清晰度都将直接影响到编码本身的健壮性和可读性,这些最基本的内容才是写出高质量代码的关键,也是类似《代码大全》书籍所一直强调的内容。

  代码本身具备足够的自解释性,源代码的设计核心就是我们的命名,方法的拆分,控制逻辑要清晰,代码具备足够的可读性往往则不再需要过多的注释。子方法的拆分是另外一个重点,对于子方法的拆分不仅仅是考虑到方法的复用性问题,有时候一两行代码也需要拆分,其核心原因包括两个,一个是拆分后增加了代码的可读性,其次是增加代码的可扩展性,即后续拆分的子方法往往存在规则或逻辑变更和扩展的可能等。

  任何一段代码本身的结构化和逻辑化是面向对象编程的基础,而结构化后最直观的体现就是代码的可读性和可维护性。软件质量的衡量不仅仅是简单功能的实现,而是在各种非常规场景下的边界和异常处理能力,因此代码本身的健壮性是另外一个重点。任何在编码阶段的工作都必须时刻关注这两个重点,才可能不断提升最基本的编程思维和编码能力。

相关 [设计 编码] 推荐:

再谈设计和编码

- - 博客园_知识库
  这篇文章谈下编码中的一些细节问题,在谈之前首先还是要继续推荐下《代码大全》这本书,该书在很多公司都会被推荐为新人入职后的必读书,即使在互联网和敏捷开发环境下,该书对于新人仍然有仔细阅读和体会的必要,要明白架构和设计思维的基础仍然是编码思维,面向对象思维的基础仍然是代码本身的逻辑和结构,如果不能写出高质量的代码,那么架构和面向对象思想很多内容往往难以真正落地.

编码

- - 人月神话的BLOG
前面谈需求,架构和设计都比较多,今天谈一下编码方面的内容,做一个好的程序员不容易,很多时候不是体现在需求和架构能力的缺少上面,更多的是体现在最基础的编码和实现能力的不足上面. 编码是一个技术活,需要大量的脑力活动,但是很多人确可以把编码做为一个体力活,我在这里想继续强调的是如果编码是一个完全的重复体力劳动的话,那么所有工作就一定是可以自动化掉的,在这个时候你原来所有的工作没有任何的价值体现而被完全替代.

字符编码

- - 博客 - 伯乐在线
伯乐在线注:本文来自文章作者 @acmerfight 的投稿( 原文链接). 如果其他朋友也想投稿,请发邮件至 [email protected],或直接给 @伯乐在线官方微博 私信投递. 你是否认为“ASCII码 = 一个字符就是8比特”. 你是否认为一个字节就是一个字符,一个字符就是8比特.

将URL编码?

- - JavaScript - Web前端 - ITeye博客
    URL一般只能由字母、数字、$ - _. * ' ( ) 等一些字符构成. 那么当URL中需要用到汉字时怎么办,譬如有这样的URL: "www.test.com/search?name=张三",此时,只有通过将URL进行编码的方式进行传递了.     Javascript编/解码方法:.     如果对上面的URL(www.test.com/search?name=张三)进行编码的话.

编码风格不是编码规范

- - 外刊IT评论
我并不认为程序员是一个情绪特别丰富的群体. 但有一些事情却能很容易刺激程序员的神经,那就是代码格式和布局. 如果看到一个函数的括弧在同一行上没有闭合,我的眼睛会喷血. 如果看到有人没有 恰好的在两个函数间留一空行,我的小腿会抽筋. 但重点在这里——除非是在家里开发自己的业余爱好软件,我的这些个人喜好其实是无关紧要的.

理清URL编码

- winners - Thinking for Fun
关于URL编码,RFC1738做了如下的规定:. “Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*’(),” [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”.

编码那些事

- winners - UEDMAGAZINE
前端开发中编码的问题一向是让人头疼的,尤其是在以gbk为基础页面编码的淘宝,情况更加复杂,除了常见的页面文件的编码之外,对不同编码js/css文件的引用、meta的charset设置、表单提交的URL编码等问题的处理稍微粗心就会出问题,特别是ajax中的编码转换,始终缺乏统一方便的解决方案,今天我们就分享两个js转码的常见案例的解决.

java编码规范

- - ITeye博客
   总结前期做的几个项目,个人认为代码的规范对团队的协作有着密切的关系. 现将一些常用的约束总结如下,以便今后参阅:. 1、所有的类、属性、方法都遵守以字母和数字为主,尽量不要参与特殊符号如下划线. 其次,除类名开头字母大写外,其他名字都要小写,然后第二个后的单词首字母大写,长度在30个字符以内.

oracle 编码规范

- - 操作系统 - ITeye博客
军规一:【恰当控制事务大小,commit不要过于频繁. 】 军规二:【在OLTP系统中一定要注意使用绑定变量. 】 军规三:【在OLTP系统中一定要注意复杂的多表关联不宜超过4个,关联十分复杂时,需要拆分成多个步骤,防止执行计划不正确. 】 军规四:【合理收集统计信息,固定住SQL的执行计划. 】 军规五:【尽量避免使用XA事务,在RAC环境中要避免XA事务跨节点操作.