大道至简,系统设计和模块划分的实用经验之谈

一、系统设计

根据工程实践经验,系统设计总体来说可以精简提炼分为两个核心阶段,即总体设计和详细设计。

1、总体设计

总体设计的主要任务是把需求分析得到的结果转换为软件结构和数据结构,也就是确定软件的主体系统结构。

设计软件结构的具体任务是将一个复杂系统按功能进行模块划分、建立模块的层次结构及调用关系、确定模块间的接口和人机界面等。

概要设计方法的主要目标是根据特定维度确定各个子系统和模块的划分,将由一个或多个功能(或目标)密切相关或相似的应用程序所组成的程序集合抽象出来。根据经验概要设计方法主要包括模块化方法、功能分解方法、面向数据流和面向数据结构的设计方法。按照面向服务架构(SOA)或者比较时髦的观点,概要设计的主要工作就是提取和整合微服务及业务逻辑,按照领域抽取展示层,最终拆分出功能独立的子系统。举例来说,按照一般的模块化或者功能拆分方法,我们可以将一个完善的电商系统分解为商品、库管、订单、支付、财务、结算、配送、搜索、CRM、虚拟货币、优惠票券、短信、邮件、活动等子系统。而子系统可以再次按照模块或者功能细分,比如订单系统可以按商品品类或者活动类型或者线上线下等维度拆分;支付系统可以按照内外部支付方式、支付和风控策略、支付模式(如跳转或直连等)等不同维度进行划分。从SOA的角度看,不论子系统划分维度是什么,SOA都会对各种服务进行布局和整合,发布服务和数据契约,其最主要的目的就是对子系统服务进行复用。当然,SOA如何和子系统设计布局和整合联系起来这是另一个话题了,本文不展开讨论。

ArchDesign

2、详细设计

细节决定成败(Idea is cheap,detail is devil.),详细设计是实现系统模块的关键步骤。

程序=算法+数据结构,虽然我认为这个公式不完全正确,但是突出了算法和数据结构的重要性。

详细设计的主要任务就是根据总体设计中确定的业务子系统,设计每个子系统功能或模块的实现算法和数据结构,但根据一般的业务系统开发经验,详细设计涉及的具体内容可能还包括数据库设计、界面设计、子系统互联设计等。

DetailDesign

详细设计非常考验程序员的基本编程水平和经验。我认为任何详细设计的最终目标都是通过可编程的手段实现软件系统,所以,对于开发人员,代码是第一重要的作品,其次才是文档,手册,图表,再其次是PPT等等这些副产品。

在实现业务子系统的过程中,必然会涉及到各种方法论,比如面向过程,面向对象等等。那么通过哪种方法论如何实现一个可正常工作功能强大适应变化的子系统呢?

在系统具体实现这一块,我个人接触最多的是面向对象编程(OOP)。成功设计开发一个子系统,我的个人开发经验可以总结为如下几条:

a、分而治之,划分模块,子系统还可以拆分子系统,服务还可以拆分子服务,这里涉及到一个粒度的问题,非常考验开发者的水平和经验,否则很容易过度设计

b、分层,这个不用说了,如果你真正理解分层的含义,那么在很多情况下,N层不如经典三层,谁写谁知道

c、保证隔离,划清界限,不要过多假设,不要拖泥带水,任何模块或服务只做它该做的事情

d、实现隔离的最佳方法,就是针对接口,而不是对具体实现编程(Programming to an Interface, not an Implementation)

e、多态,多态,多态,如果一定要复用类,请优先使用对象的组合而非继承

f、提取变化剧烈的变化点,定期重构,核心业务逻辑必须单元测试

g、UI变化最大,其次业务逻辑,而且很多时候UI变化会直接影响后端业务逻辑,所以,你的接口设计要向UI和业务逻辑倾斜,反而是基础框架和基础服务非常稳定,不需要过度设计

做到上面这几点,绝大多数的开发问题都会迎刃而解,反正在我多年开发经历中屡试不爽。

当然,归根结底,成功的子系统的设计与开发还是看具体开发者的水平,如果逻辑和抽象能力差,或者不认真没有追求看上去就不那么让人放心,说什么都是白搭。

 

二、平台化设计

我们可以把以提供统一的公共服务为主要职责的软件或系统叫做平台软件。比如常见的框架基础平台、应用管理平台、工作平台(OA系统等)、MDM、运维平台、财务平台、结算平台、支付平台、配送平台、决策平台、客户管理平台、CTI平台、开放平台、云平台等等。

纵观软件发展历程,围绕着“复用”,各种方法论和工具层出不穷,比如:结构化开发中,函数和过程(表示一段代码)的复用;面向对象设计(OOP)中的类和对象的复用 ,COM和COM+中的组件标志着模块的复用;SOA架构中某个业务服务(子系统)的复用等等。

主流的软件开发模式中,复用成了系统设计的一个重要目标,平台化是复用软件产品的一套成熟解决方案,开发和运营的性价比也较高,而且相对有利于扩展。

为什么说平台化设计有利于扩展呢?下面的段落中我将讲一个发生在自己身上的真实案例。

 

三、多商户或多租户系统

两年前某司新扩张了业务,大致需求就是相当于注册一个新公司同时该新公司可以使用已有的很多系统,但某些核心业务(如财务等)需要独立运营,然后就涉及到我这里说讲的多商户或多租户的系统。

平台化的软件产品有多种多样,其中,又以多商户或多租户的系统设计与实现最为复杂,而且随着需求的变化,扩展性很容易成为瓶颈,多商户或多租户的系统数据存储我曾经有过简单总结。

具体到某司的系统扩展,我给出的是两种方案,方案一是可以为新公司独立部署一套应用实例然后修改配置搞定,方案二是可以通过增量增加代码重新实现一遍已有的功能。

从维持系统稳定的角度,两种方案在理论上而言都相对的不会改动原有系统的实现代码,第一种直接拷贝原有的部署结构重新实施改改数据库配置就行了,第二种则是不改动任何已有代码而是通过增加新代码实现功能(这种不改动任何已有代码仅限理论上,考虑到业务复杂性,可能还是需要对已有逻辑做些微调)。对于这两种实现方案,很显然会有人有不同意见,好了,我知道你们要说重复是魔鬼,不要重复你自己等等等等。要是在2010年之前,我一定也有类似的看法,我甚至还可能写篇博客之类的洋洋洒洒批驳一番,但是经过多年工作和编程实践考验,再碰到有人说重复我就呵呵对待了。

无数事实证明理论和实践不是一回事,歪果仁也流行说theory is ugly,idea is cheap,talk is very cheap...所以我们需要大胆实践,验证口头上的理论在现实环境下到底行不行得通。

如果团队人员充足,第一种简直是为了扩展性而量身定做的,看上去只是增加了部署实施和后续维护的成本而已。但是如果人员不足,或者变化剧烈系统未来走向依然不确定,从维护角度,个人倒是倾向选择第二种方案,因为通过数据共享和可扩展配置然后只维护一套系统,我实在想不到不使用这种方案更好的理由了。

最终我选择了第一种方案,一份代码配置成两套系统。^_^ Yes,it works.两个系统目前运行稳定。 

这是我两年多前近一个月的亲身实践,最大的收获是,系统实现要高度可配置可运维,而且后台管理工具要开发完备,一套系统按实例多次部署确实是很有效可行且实惠的解决方案。

 

四、通用架构基础服务

在概要设计和详细设计过程中,不论业务、方法论、工具或框架等外部条件怎么变化,从各个(不同)系统中总是可以抽象出公共的相对稳定的框架工具或服务,比如分布式缓存服务、消息队列服务、通用数据访问代理DAL(提供访问数据模型和后端数据服务API实现对数据库的一致性访问,如果分表分库了,也包括DBRoute功能,不能简单等同于ORM),企业服务总线(ESB)、分布式文件系统、通用日志服务等等。这些基础技术服务不同于业务系统,也不同于公共平台服务(架构基础服务可供公共服务调用),因为它们和多变的特定业务逻辑无关,相对偏重于底层技术,对技术要求较高,开发和运维这部分服务的都是水平较高的技术型选手为主。一般能独立造轮子出来的公司还是比较有技术含金量的,虽然我也碰到过只发明却不能用或者一用就有无数坑的团队。我认为如果没有这部分通用架构基础积累,各个子系统各自为战很可能会造成运营和管理上的难题。

 

总结

这是我个人从业10年的系统设计与开发经验的粗浅总结,B/S和C/S结构的开发都通用。在很多人看来可能更多偏重于方法论,我所知道的绝大多数开发人员更喜欢讨论技术细节的干货,比如几年前的自己,更多的偏重于“小节”,比如记录学习某某编程语言的语法糖,某某流行框架的实践,某某数据库操作的奇技淫巧,某某算法和数据结构的妙用或误用,某些新技术的使用经验之类。

但是,我个人认为,当你真正从专注细节的小兵成长为可以独当一面的大将后,你可能也会跳出这些“细枝末节”,从系统和架构的角度,把握全局,全面看问题。

难忘的2017即将过去,感谢志同道合的人,每一年,我们都要有收获和进步,低头沉默更坚定。Coding for fun.

祝大家新年快乐。

posted on 2017-12-31 20:36  JeffWong  阅读(10664)  评论(0编辑  收藏  举报