我的知乎:井方哥
前言
知识大纲
- 一、萌芽
-
二、初识架构
- 1、阅读《架构之美》之论架构
- 2、分析行业内各个APP的架构演进
- (1)架构为什么需要演进
- (2)他们是怎么演进的
- (3)带来的好处
- 3、Google搜索关键字:架构设计
- (1)知识概要
- (2)个人小结
-
三、架构的定义
-
四、产品
- 1、产品设计
- (1)、用户群体(什么人用)
- (2)、核心理念(要做什么)
- 2、迭代计划(计划怎么做)
- 3、开发资源(用什么做)
- (1)、开发团队配置(人)
- (2)、数据内容配置(物)
- (3)、开发投入预算(钱)
- (4)、第三方资源
- 4、产品质量(做的怎么样)
- (1)、用户体验
- (2)、软件性能
- (3)、产品安全
- (4)、质量评测
- 5、风险规避
- (1)、人力变动风险
- (2)、上层决策风险
- (3)、项目延期风险
- (4)、软件缺陷风险
- (5)、人为失误风险
- 6、产品交付
- (1)、测试版本
- (2)、灰度机制
- (3)、版本管理
- 1、产品设计
-
五、技术开发
- 1、技术选型
- (1)、 开发平台
- (2)、 开发工具
- (3)、 开发语言
- (4)、 开发模式
- (5)、 开源框架
- (6)、 新兴技术
- 2、业务拆分
- (1)、常用基础业务
- (2)、通用技术业务
- (3)、特定功能业务
- 3、架构设计
- (1)、核心概念
- (2)、设计思维
- (3)、设计原则
- (4)、设计方案
- 4、开发实现
- (1)、项目分包
- (2)、抽象接口
- (3)、数据存储
- (4)、性能管理
- (5)、特殊处理
- (6)、Log打印
- (7)、软件重构
- (8)、兼容适配
- 5、软件测试
- 6、开发规范
- (1)、设计一致
- (2)、编码清晰
- (3)、文档有效
- 7、日常工作
- 1、技术选型
-
六、统筹规划
- 1、开发驱动
- 2、敏捷开发
- 3、达成共识
- 七、总结
- 八、参考文献
一、萌芽
作为一只编程经验并不怎么丰富的程序猿来讲,我一直觉得架构师是一个比较神秘的职业,架构设计就更加的高大上了。经过今年的几个项目,之前曾发文叙述我的从MVC到MVP项目重构实战经验,也曾说过我准备对目前手底下的项目进行重构。但是,前段时间,我改变了我的想法。开发模式的重构,仅仅只是换了一个套路,也许在重构的过程中对业务的逻辑进行了一次梳理,也是在基于前人的代码设计上进行了一些优化。但是,这远远还不够,这不是我理想中的开发场景。在项目开发的过程中,也发现存在许多的问题,但是都是一些零散的问题,我很多时候希望能够改变现状,更加优雅地编程,然后实际的情况却是陷入了迭代功能开发和bug修复的死循环。现在回过头来想想,我理想中应该是开发应该是一种由规划和设计指导的开发,那么架构设计就显的尤为重要了。
二、初识架构
1、阅读《架构之美》之论架构
仅看完了《架构之美》的第一部分:论架构,对架构有了一个大概的认识。下图是这部分的知识点概要:
(2)个人小结
架构分为三个阶段:规划、设计、构建,每个阶段架构的设计有不同职能。在规划阶段,考虑的是产品的需求、质量的需求,技术的可行性分析以及预研。在设计阶段,考虑的如果将一个复杂的系统拆分,并设计如何进行组织这些拆分的模块。在构建阶段,考虑的就是具体的实施问题,并且要保证一定的伸缩扩展性,因为架构是不断演进的。文中引用了《软件架构设计》一书的一个模型图,我觉得有必要在此贴出来。最近也在思考软件模块化的设计,模块化的设计也许各有理解,在此先不做讨论。如下图:
模型分解
根据实践开发中个人的理解,我将此图再次进行了简化如下:
如上图所示,通过上述横向分块、纵向分层、接口通信这三大步骤之后,我们可以将一个系统进行了很好的分解,并得到一个理想模型。当然,这是一个理想的模型。在我们的实际开发中可能无法避免一些交叉等特殊情况,我们还需要从实际情况出发。但是有一点,我们可以保证接口的分离,已达到更低的耦合度的目的。
统一管理
统一管理,是对于我们的设计中有一些东西是需要统一管理起来的。通过上述原则,我们将一个复杂的系统进行了拆解,已达到架构设计中将关注点分离的目的。然而在实际的开发中,我们除了要进行业务的分拆,也需要对某些业务进行统一的管理。比如说一些模式的开关管理,比如说我们在进行 络请求时需要在测试环境和正式环境之间的切换,我们可以将这些模式切换的开关放到一个地方,方便我们进行管理,而不要去到各个地方去修改。再比如说我们的请求url地址,是否可以写到一起进行统一的管理。还有在某些应用中会通过一个中间人来进行统一管理数据的流通、页面的跳转,这也是一个可以尝试的方案,详细请看苏宁易购移动端的架构优化实践文中提到的模块管理器、Url跳转管理器。统一管理的意思就是将分拆的某一类小的模块某一些特性放到某一处进行统一的管理。但是这样会存在一个问题,比如前面举例说到的统一开关管理,这造成了开关耦合,如何去避免呢觉得可以将开关默认写到自己的模块里边,并公开出修改的接口,方便上层进行统一的修改,以达到统一管理的目的。这样的话,即使这个模块拆离出来,也不会受到影响。但是,这样的话,其安全性受到了一定的影响。架构设计总是这样,你总需要选择一个折中适合自己的方案。
我们通过上述横向分块、纵向分层的方法将一个系统切成不同的小块,这些小块负责某一单一的职责,然后通过接口将块与块之间进行了间接性的连接,依赖的是接口而不是实例,以弱化这种模块间通信造成的耦合。当然,上述模型仅仅只是一个理想状态的模型,如果是一个非常复杂的系统,那么层级之间也能拆分出更多的层级。比如,在数据层,我们在MVP模式的开发下使用Model来完成,当Model层的业务变得非常复杂时,有部分人会考虑拆分出Data层放在最底层,最为最基础的数据操作等。最后,为了方便我们对模块进行组合并进行管理,我们可以考虑在小模块中开放出接口,供上层进行统一的控制管理。最后,我想说的时,我们在进行业务分离拆解时可以考虑按照上述的方案来做,最终还得根据实际情况来进行设计。
4、开发实现
当完成我们的设计工作后,我们进入了开发编码阶段,在这个阶段主要表达我们的设计,并最终取得实实在在的成果。当进入这个阶段之前,我们的设计不能仅仅是一份文档,而应该是开发人员和架构设计者达成的某种共识。再好的设计,也需要获得良好的表达和实现。下面主要谈一谈在实现过程中需要考虑的问题。
(1)、项目分包
项目的分包结构体现一个软件的架构,我们在进行分包的时候总有一种困惑。因为我们存在多种分法,比如我们可以分为根据类的功能分为activity、fragment、adapter、util等,有的时候,我们又根据功能模块分,比如一键搜中有查单词模块、有搜题模块,同时又存在 络请求,软件升级等小的外围通用功能模块。存在的问题就是模块之间又存在一些可以复用的东西,那么我们进行拆分明显出现了代码的冗余。如果按照两种方案同时分,那就肯定存在了架构的混乱。我们该如何达到这两种的平衡认为,这个也需要更加项目的大小而来,如果是非常小的项目,也不存业务扩展的可能,我们就可以采用上述的第一种方案,简单的分类就好。但是,对于较大的项目,我建议使用第二种方案。下面,我简单列一个模型仅供参考:
(2)、抽象接口
如果说在架构设计中抽象很重要,你可能有些迷糊,但是如果要你先写interface或者abstract class 而不是class时,你就可能感觉得到抽象的意义。我们将一个系统分解成几个大的模块,一个模块查分成不同的层级,每个层级再次拆分成不同的细节业务。最后,我们很清晰的知道我们要完成某一项功能需要做哪些事的,做哪些事就就是一个个接口,我们在编码时先写接口再写实现有利于帮助我们对业务进行拆分和抽象。我们都知道做一件事情一般情况都需要提供一些条件,做完了会有返回结果。这些都可以在接口的设计中完成。我们需要注意是一个接口只做一件事情,如果有两件事非常相似也要尽量拆分而不是合并。在接口命名方面做到见名知意,怎么去评判,就是如果你的接口没有注释也同样能让人知道你的接口是做什么的就好。
(3)、数据存储
数据存储常用的有SQLite、SharedPreference、文件等,缓存是否也可以算是一种。这里想强调的就是要注意数据存储的规范性以及安全性,如果是数据库还有必要考虑其扩展性,如果不满足需求将会需要进行升级。
(4)、性能管理
这里源自于对性能优化的一点体会,对于服务端的开发我们很珍惜服务器资源,应该是看的见的需要银子买的。然而,对于客户端的开发我们常常忽略了这一点。虽然手机设备现在拥有大内存,但是如何写出一个优秀的程序,性能也是一个非常重要的指标。性能优化处理,那是我们在更正错误,那么之后应该是少犯错误。性能体验不够好,无非就是对机器设备的内存、CPU、GPU资源无节制的使用,造成资源的浪费,当机器设备无法承受时就会应用就会出现卡段、死机、异常等不良反应,严重影响了应用的体验。我们要做的就是要有很强的性能管理意识,对于内存、CPU、GPU等资源按需借用,并做到有借有还,即用完后记得释放资源。
(5)、特殊处理
我们在开发的过程中,总有那么多问题并不是按照正常思路出牌的,这些得归功于我们强大的测试团队。不同的手法,就能得到不同的结果,然后就给了我们一堆的bug。所以,我们在软件的开发中需要特别注意一些特殊情况的处理,这些最终往往还是逻辑上的死角。以下简单总结了一些:
- 功能冲突
功能冲突可以分为两种,一个是应用内部的功能冲突,二是应用之间的功能冲突。应用内冲突比如A功能和B功能都使用了某资源文件,如果在同时使用就会出现问题,我们通常加同步锁来防止这种冲突。应用外的冲突有很多,比如多媒体、闹钟、日历、铃声、电话等都肯能引起这些冲突,比如你正在播放一段视频,这个时候来了一个电话,那我该优先哪一个呢有当闹钟响起的时候,弹出一个界面是竖屏的,那么他就会强制将当前的界面变为竖屏,而如果你这个时候如果是横屏的话该怎么办呢似于这类还有很多,以后再细细总结。
- 极限操作
我们的测试人员喜欢对着某一个按钮狂点、或者在机器上安装无数的应用使内存爆满,或者在磁盘里边塞满各种文件。这些场景虽然并不是理性的用户所出现的,但实际也是程序的缺陷。所以,我们要注意对这些问题进行处理。
- 络问题
不可用的 络,信 很弱的 络, 路在wifi和流量之间切换,2G 络和4G 络, 络请求超时等都需要我们针对实际情况进行处理,比如切回到流量的时候进行下载是否有提醒用户。这些处理也算是各个应用的标配了,就不再多说了。
- 为null处理
这应该是最常见的问题了,我们平时改bug或者从后台异常抓取的大多数都是空指针异常。首先,我们得搞清楚为null的原因是什么后我们需要进行为null的判断,并警告。
(6)、Log打印
这里把Log打印单独拿出来是应为我觉得很需要重视。Log是用来干嘛的显然是用来帮助我们查找问题的,然后我们大多数的情况下是问题来了再去加打印,并且TAG五花八门的,是有错误的地方用Log.d,而只是查看信息却是用的Log.e,我们查问题的时候要去阅读很多的代码逻辑,最后再定位到位置。我们在修复bug的时候花了大量的时候再阅读代码,这个太影响工作效率了。如果我们在编码之初就对Log有了很好的规范设计,有异常的地方就用Log.e,可能出现问题的地方就用Log.w等等,关键点的信息用Log.i,临时调试的用Log.d这样区分不是很好吗们在控制台一样就能够分辨自己需要的信息。我们应该充分应用这个工具,帮助我们快速定位问题。
(7)、软件重构
重构是因为业务的需要,也是因为对代码更高的质量要求,重构无处不在。我们不要为了重构而重构,也不要一直停滞不前,该重构时不重构,欠下太多的技术债务。重构有小到一个方法的重构,也有大到整个系统架构的重构。重构是软件迭代升级的一个必要过程,也是我们能够满足当前需要,并且能够适应未来的发展,获得良好的扩展性的必要手段。重构并不难,也不是什么大事,重点在于重构背后的目的、思想、设计是否清晰。
(8)、兼容适配
兼容适配的问题是我们开发一个头疼的问题,Android设备无法八门的屏幕尺寸、层次不齐的Android系统版本。除了进行针对性的处理,还得提醒产品设计人员在设计之初就得考虑兼容性问题。
5、软件测试
软件测试是我们开发中非常重要的一到工序,除了能够客观的感应我们所开发的软件质量水平,最终目的还是在于帮助开发人员修复软件缺陷,提高软件的质量。除了开发人员提交测试之前的自测,我们需要专业的测试人员来进行测试。人工测试的效率相对较低,所以我们应该考虑通过技术手段完成自动化的测试,如单元测试等。这样有利于软件的稳定,也同样的有助于开发人员提高代码质量。
6、开发规范
(1)、设计一致
什么样的设计才是有规范的设计呢个人认为一个项目保持一致的设计思想就是有规范的设计。我们可以这样去理解,在某一类的情况下,我们按照某一类似的方案来解决这一类问题。面对复杂的系统,我们一种设计思想也许无法满足架构的需求,但是我们只需要明白,这种事情这么干,那种事情那么干,相互之间灵活的组合却也不存在交叉,给人设计思路清晰的感觉。
(2)、编码清晰
什么样的代码才是高质量的代码觉得结构简单,逻辑清晰,一看就懂的代码就是一份高质量的代码。所以,我们可以抛开那些编码规范、命名规范等等,重新去审视自己的代码,看看读起来是不是很舒服。如果来了一个新同事,对你对项目一无所知,是否能够很快速的理解你的思维后几点有必要提出,一是慎用设计模式,二是尽量少写文档注释,三是遵循Java的面向对象六大设计原则。我想这三点就是编码的原则,遵守这些原则,形成一种习惯,自然而然就是一种规范。
(3)、文档有效
什么样的文档才是有效的文档,我认为能说明核心问题的文档就是有效的文档。作为软件开发人员,我们没有耐心去阅读一份复杂啰嗦的文档。文档只需要给我们呈现代码无法说明的问题,帮助我们快速理解项目结构,备忘重点问题,追溯历史记录。文档的形式又很多,比如我们git的提交记录、tag,项目结构图、核心功能流程图等。总之,文档是给人看的,以尽量少的文档来说明核心问题就好。
7、日常工作
作为一名合格的软件开发人员,我们有许多的日常工作,如Bug修复、异常处理、Monkey、性能优化、代码质量改善等待。这些事情并一定要求你每天都要做,但是每天都得关注,做到心中有数。如此,才能够培养一个很好的编程习惯,写出优秀的代码,优秀的程序。
六、统筹规划
1、开发驱动
一个项目的正常运转一定是由某一方主导项目的进行,不断的提出产品需求,并组织项目成员分工合作,完成产品的开发交付,以下是两种驱动开发模型。
- TDD:测试驱动开发(Test-Driven Development)
测试驱动开发指的是由测试主导开发的工作,从产品的使用出发,对产品的功能提出测试要求,组织项目中各个角色完成开发任务。
- BDD:行为驱动开发(Behavior Driven Development)
敏捷开发便是行为驱动的开发,更加强调产品的设计,鼓励项目中各个角色提出自己对项目开发的观点,已获得更优秀的产品功能,完成产品的开发。
2、敏捷开发
下图引自 络上的一张关于敏捷开发的图片,目前我们团队基本也是根据这个模型进行敏捷开发的。我觉得在敏捷开发中更加强调的各个角色之间的随时沟通和快速响应,我们并不对整个系统进行一份完整而详细的设计,而是进行阶段的设计开发工作,并谋求不断的迭代更新。在敏捷开发的过程中,普遍存在的问题就是沟通不及时、产品变动大,所以如何动态的进行统筹管理变的非常重要。我们通过需求评审、交互评审、视觉评审、Bug评审等由各个有关角色的人员参加评审会议,共同完成决策,以保证软件开发的顺利进行。不得不说,这个过程中还是存在许多的问题,沟通的问题,产品变动的问题,产品功能细节开发过程的中流程性的问题等等,在此不详细说了,后期有时间再进行总结。
推荐阅读
- 《架构之美》
- 《软件架构设计》
- 《人件》
- 《人月神话》
- 《简单法则》 John Maeda 著
- 《Coding Dojo Handbook》
【掘金年度征文】https://gold.xitu.io/post/587f0e7a5c497d0058bcabd7
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!