开发项目需要关心什么

在开发过程中,怎样做好一个项目,是一个值得思考的问题。这里不是讨论做一个好项目,而是做好一个项目。在日常的开发中,我慢慢掌握了一些开发的套路,可以提高开发的效率和项目的质量,在这里分享出来。开发项目需要重点要去做的事情,是把握项目的整体质量,权衡利弊,取舍有度,使得项目合理化。我以完整、性能、成本为项目开发的三大提纲来开发业务,在开发过程中权衡三大纲领。在这三大提纲相冲突的时候,舍弃相对不重要的部分,使得项目的质量最大化。接下来详细解释三大要素。

完整:

1)可用性

可用性是开发的最低要求,这个不用去讨论。无论怎么讨论软件开发,这个都是放在第一位去考虑。我们有时会看到不堪入目的代码,但是它如果可用,那就有价值。如果有些代码精致到不可挑剔,将所有都考虑的面面俱到,但是如果不可用,那它连最烂的代码都不如,因为它不能体现出价值所在,不能盈利。

2)安全性

在项目开发中,安全问题是很重要的问题,按照粗略的划分,可以分为线程安全、代码安全、参数安全。对应的,在开发过程中要防止毒线程、毒代码、毒参数对项目的影响。

线程安全(可以理解为并发安全)需要了解线程知识和java基础,如静态变量全局变量局部变量的线程安全问题及应用、静态方法(工具类常用)是否存在线程安全问题、java并发与锁应用的权衡、事务、乐观锁与悲观锁、行级锁与表级锁等等。往往线程安全是指并发时,数据变量是否可以被并发的多个线程修改?如果可以是否符合逻辑?如果不符合将怎样处理。在线程安全并发安全的问题上,可能需要很多的论述才能表达清楚这个问题,在此概括为项目的线程安全问题。

代码安全是合理的设计代码,使得生产出来的数据达到预期目的。代码有的时候就像一个理想的机器,它可以制造出来我们想要的数据,然后将它持久化。但是有的时候会因为程序的设计问题,导致很多安全问题的出现。比如抛出异常、比如在某种合理的干预下生产的数据不符合需求的标准等等问题,这类问题可能是对于线程安全考虑不周或者本身代码设计不合理造成的。

参数安全是对参数提前做过滤,禁止有毒参数接触到代码。如远程调用的签名、防止缓存穿透进行简单的防护、防止注入式攻击等等。

注入式攻击造成的危害比较大,就拿这个举例。比如在用mybits技术开发时,${}表达式存在注入式攻击的风险,如果${}表达式的值是直接从外部传递的,那就会存在很大的安全隐患。所以,在使用${}表达式的时候,不要直接使用外部参数。如果需要用${}表达式,一定要评估参数是安全的。比如当sql语句中如表名等信息无法用#{}表达时,用${}。在一般的CRUD操作中最好做一个规范禁止使用${}表达式,优先用#{}。这样防止不知道的人误用${}表达式造成外部参数注入式攻击。仁慈一点的恶意攻击可能只是获取你的数据,要是故意捣乱的,把你的正式库数据表删掉,会対项目造成巨大的损失。

绝对的安全性并不一定是项目一定去追求的目标,这要看具体项目对于不安全因素的容忍程度到底有多大。有的项目的安全性要求没有底线,也有项目非常保密,这需要实际项目具体去判断。 在一般的情况下,项目的线程安全、代码安全、参数安全等问题需要重点关注,也有如权限粒度控制、数据暴露、数据丢失等业务安全问题,需要弹性把握。

性能:

1)执行性能

程序像是一个容器,将万事万物的需求都定格在这个容器中,如果这个容器给予事物足够的自由(扩展性),程序会走的更加长远。在项目框架搭建基本完毕、功能代码逻辑实现、关系型数据表建立之后,将这个容器塑造成型的时候,如果觉得不妥再去修改就为时已晚。也许你需要重新梳理表关系,数据迁移、程序修改都会很麻烦。所以,在前期需要认真的规划设计,特别是数据收集和统计的相关表。

无论多么棘手的项目,首先要做的是确立一个大局观,我们造一条船首先是考虑的事情是:我们要造远航船还是近海船,是商船还是战舰,或者混合补给舰。把控项目的边界、粒度、用户群体、数据量等因素,去做需求分析。同样的项目和同样的技术,项目边界、粒度、用户群体、数据量等因素不同,设计就不同。摸清要做的东西时,所做的技术应用和问题会一个个的展现和解决。不用牛刀杀鸡,也不用铅笔刀杀牛,以最合理的规划去完成项目,低成本高效才是最终目的。大局观建立才会有序进行,不然可能会这里将就那里将就,最后造成极大的维护成本和其他资源的浪费,项目的质量会大打折扣。

从大往小的规划,从小往大的开发。从大往小的的规划评估技术栈、定制可行性方案、技术调研、可能遇到的问题、可能要打的TODO。自小往大的开发,严格执行优先级次序,逐层展开工作,迭代有序。

对于执行性能的提高,需要把握三个方面:数据库表设计、代码设计优化与重构、合理利用项目资源。合理的关系型数据表,可以为CURD节省很多时间,也很利于项目的扩展;代码设计优化与重构可以明显提升代码质量、合理利用项目资源,比如缓存技术,对于性能提升有很大帮助。

在开发期间性能的优化空间很大,程序员大有可为。

2)扩展性能

项目的扩展性是可以兼容未来可能出现的需求,这是在项目设计时就要考虑的。接口的扩展性能是指某个设计通过简单的修改可以兼容其他需求,达到一个接口满足多处调用的目的,这样可以缩小代码的体积,或者说简化功能。一般情况下,前提是不能降低了执行性能,以及功能的完整性。

在编写接口时需要留意扩展性:有些业务需要调用接口解决问题,在设计的时候我们应该更加注重于解决此类问题,以此为前提设计,而并非只是解决当前问题;接口编写时,尽量以一个接口满足多出调用,或者多态的方式实现,利于维护和接口扩展。

成本:

1)开发成本

开发成本是在确定需求之后项目启动到上线的过程,不同项目要求不同,项目进度都非常重要。有些项目可能需要快速上线,在开发中只是简单的实现,后期来进行优化和重构,这样是为了商业上的需要。项目是按照需求,有目的有节奏的执行的过程,所以开发成本对于项目非常重要,有的时候为了符合需求和时间,会省略很多完善的细节和性能,这也是开发成本和进度决定的,它在某种程度上决定这项目该有什么不该有什么。

2)维护成本

按照我的理解,开发成本与需求有关,维护成本跟项目设计和技术有关。有的时候开发成本和维护成本是和谐相处的,但是在开发中可能会出现对于需求没有充分的把握和评估,导致后期做优化和重构的时候成本大幅提升,需要对功能进行重新梳理和重构。功能的不合理设计造成后期功能扩展和关联业迭代时费时费力,影响工作效率,也影响了项目的质量。维护成本也包括对于项目维护或扩展时,了解业务的时间和学习复杂度以及难度,这都算作是一种成本。比如代码的结构化和注释,可以有效的降低熟悉代码的时间,这就算降低了维护成本。

我理解的维护成本概念介绍完了,接下来举几个实际例子,对比项目开发中使用怎样的方式降低维护成本。

一、mybits与hibernate框架比较。Hibernate需要熟练的掌握学习成本很大,首先体现在需要掌握完整性约束和关联关系映射,需要学习在持久层这些知识的应用。这本是关系型数据库表设计应该关心的,现在转移到持久层框架之内,把实体和表要套上一层映射关系,还有一大堆的注解,有的时候为了熟悉持久层一大堆注解,还需要专门学习注解的文档。hibernate的知识点跨度比较大,比如需要掌握hql语句的同时也需要掌握sql语句,以便特殊情况使用;而在多条件动态查询时需要去在持久层用java逻辑进行组织语句,这显然也是需要成本。当我们学习hibernate持久层框架的时候需要学习多方面的知识,提高了学习的成本。而在实际应用中,初学者如果不太熟悉相关知识,会给项目造成极大的负担。比如查询一个业务对象列表,由于里面映射到很多的子对象,知识点的生疏会导致完整性约束上的节点对象全部被加载出来,造成数据传输上的极大负担。也许有人会说懒加载可以解决这个问题,但是当实体与数据库产生映射关系增加了数据结构的复杂度,你需要学习懒加载什么时候合适用,什么时候不合适用等一系列的知识和场景,这又得学习。

而相比mybits就没有那么多的事情了,我们只需要在mybits配置中添加实体类的位置,和使用的mapper.xml文件。然后就是mapper.xml的具体用法。很简单,学会之后就可以应用mybits持久层框架了。Mybits持久层中实体类与数据库的关系类似前端json与实体类的关系一样,不像hibernate那样通过实体来控制数据库表。Mapper.xml实际是写sql的地方,而且支持if,for,等语句,使得sql有很大的灵活性,可以根据条件轻易的写出动态sql。操作都是sql语言和简单的语句来混合完成。并且可以引用片段,提高了sql代码的复用性。实体类在其中扮演的角色只是传递数据的搬运小哥,它不可能控制到数据库的表。用mybits查询有一个好处,在相似的业务中组织相同的查询字段写进片段之后共用,这些字段是业务真正需要的字段,用多少字段,拿多少字段。而hibernate数据传递数据基本都是打包带走,有的时候像是提起一串葡萄一样带走很多不需要的数据。综合这些可以看出来mybit学习成本低、复杂度低、灵活性高的特点。在一般项目应用中,它的维护成本比hibernate更低。

二、枚举与字典表的比较。我在网上找了一些枚举与字典表的对比和适用场景,很多时候会有这样的解释:在高并发中,枚举相对于字典数据,不需要从数据库查询数据,所有适用于高并发。其实我们可以应用缓存策略来弥补字典这方面的劣势,当枚举的的优势通过缓存策略对冲之后它还有什么优势呢?可能我暂时没有了get到。字典数据对于枚举有什么特点呢?1、统一管理,简单的字典数据,只需要一张表存储,而且数据量非常少。将零散的字典数据统一管理,便于快速了解和维护。查找时提出整张表,利用递归算法嵌套节点,存在缓存,定时刷新。枚举添加的是代码,字典添加的是数据。一个项目的简单字典数据,基本上写一个功能就可以一劳永逸。2、在使用枚举时,如果是手动sql完成CURD,往往需要手动去完成存储的枚举与服务端枚举的转换(数据库存储的可能是枚举的序号或者标识)。联合查询时最明显直观。而对于字典数据,只需要join字典表,取到对应想要的数据即可(如查询时只需要字典的名字作为显示,就只获取字典表一个字段即可。)3、当一个临时需求来的时候需要改动一下需求,字典数据的操作,只用在上线的项目中操作字典功能进行数据动态管理即可。而枚举就需要代码修改、测试、升级等一系列服务升级操作,这个期间会浪费大量的时间和资源去做一件微不足道的事情,或者延期处理,等待下一次升级附带提交改动的枚举版本。因此,在一般的项目中字典的维护成本会比枚举低,灵活性也高一点。

上述的两个例子只是在一般的场景中举例比较维护成本,理论知识用来做维护成本的例子,实际开发中需要看具体的场景需要什么,再进行选择。我们在实际的开发中可以看到很多相似的例子,维护成本的控制与功能设计、技术选择、开发规范都有关系。

讲到维护成本,不得不讲springboot,springboot的特点是约定大于配置。这在很大程度上解放了框架搭建的复杂度,降低了框架和技术配置的学习成本。当我们需要修改那些配置的时候,会搜集springboot配置属性来进行修改。它为项目搭建大开方便之门,并且引用依赖自动加载,快捷方便,降低了项目的维护成本。Springboot的出现给传统的ssh框架ssm框架带来了另一种搭建的可能,降低了搭建项目的复杂度和成本。在项目开发中,我们能感受到它的方便、快捷。但是这些理由不足以取代传统的方式,也许有些公司会利用springboot快速开发,减小成本。但是也会有公司不屑于染指它,反而喜欢配置的详细内容,认为这样看起来有结构有条理。在springboot上添加技术,我们只需要引入对应的依赖包,然后进行简单配置即可;而一般的项目需要进行很多复杂的操作,掌握细节,配置大于约定。但是谁又能说这一定不好呢?不过是耽误了一些时间而已,反而对于细节理解的更加直观。在传统的搭建模式上应该是各有特点。

而在多模块、多节点、多服务的分布式项目中,一般的搭建方式与springboot就像步行与自行车的区别,短距离体现不出来自行车的优势,但是长途比赛中会展现自行车的优势。也许有的人会说不用springboot也照样可以呀,但是我们想一下,有几个人的身体素质强壮到可以完成50公里距离的长途比赛,ko掉骑自行车的人呢?即使有也是少数,而且总的成本来说仍然偏高。在分布式多服务的项目中springboot就像自行车一样快,快捷、简单、高效,所以在springcould技术解决方案上,它的作用非常大。我们想象一下如果一个项目几十个服务不是用springboot搭建的,那光是在配置上的阅读和优化都需要很多的时间,更不用说其他方面了。这样我们的精力都消耗在了技术和框架上,而在多模块、多节点、多服务的分布式项目中,功能业务和更复杂的分布式技术解决方案,会让我们工作量大幅提升。因此,对于面向服务的分布式项目中,springboot会大大降低维护的成本,解放生产力。使得我们有更多的精力,去关心业务实现和分布式技术解决方案。Springboot和springcould的出现为普及分布式多服务技术做了很大的推动作用,也会使得社会的信息化更具有深度。

三大提纲介绍完了,接下来就是在项目中的应用问题。有的时候功能或者项目的完整、性能、成本会产生冲突,比如功能可用了,但是要想安全,就要浪费性能。或者要想提升性能,就要提升很大的维护成本。这些情况下可能大家都会为了安全而去牺牲性能,为了性能而去牺牲维护成本。当我们经常这样操作的时候,就会默认出一个优先级,即:完整>性能>成本

当有这样一个基本的标准之后,我们就会在满足同一个优先级的条件下,加入下一个优先级比较。比如,我们对代码或者技术做比较时,在安全性相同的条件下比较性能,比较扩展性。在性能差不多的技术或者代码中比较其扩展性和维护成本。舍末求本。

比如在适合springcloud的场景用这套解决方案是最好的决定,一般小项目最好不要用,因为它虽然可以大大的提高项目的吞吐量和性能,但是也增加了大量的开发成本和维护成本,当我们并不需要那么高的吞吐量和性能时,就要考虑成本问题,并不是所有的项目都适合用它。

三纲以及优先级是一个理论,实际上项目三大提纲的优先级是根据实际开发情况去做取舍的。比如一个内部低并发项目,可以容忍等待和多次操作的情况下,你可以忽略性能,忽略后台代码优化,忽略后台会链接数据库多少次,忽略数据库表设计有多么的不合理多么的浪费性能。只要尽可能的实现可用这个最低标准即可,况且现在的硬件软件这么方便,你只要按照常规开发去做,一个简单的项目不用考虑太多。

在实际项目开发中,确实会存在搁置安全、性能和维护成本,只要尽快实现可用性就行。即便我们真的这样做了,但是我们应该把性能放在心上。它是一个方向,是一个正确的方向。尽管三大提纲对于有的项目可能真的是个摆设,根本用不着,但是这并不妨碍它理论的方向性。它就像一座灯塔,也许你为了躲避前面的岩石而迂回前进,看起来没有朝向灯塔。但是你最终还是要靠近灯塔才不至于在海上迷失方向。这个理论性的东西就是我在开发中一个参照物,也许已进入深海,但是只要记住灯塔的位置就不会迷茫,最终还是会找到返航的路。

网上有大量具体的技术和代码,对于开发人员来说是很大的帮助。正是因为有互联网上很多问题的解决办法使得开发人员成长速度加快。结合开发的提纲,是为了判断开发时的解决方案是否合理,让功能变得更加的高效。

我所说的是参考方向,作为程序员,一定要以需求和进度为第一位。你可能开始没有实现功能理论上的那么完善,但是后期可以优化,可以重构。一次性的做好程序反而是不可取的,因为项目的初期开发和市场需求有一定的磨合期,做的完善做的精致而经不起市场的检验,就是在做无用功。况且如果误了开发进度,项目要是黄了就得不偿失的。并不是每一个项目都要非常完善完美,所以要严格执行需求设计和进度进行开发,不能书生气,去一味的追求理论的正确性,达到自己的欲望和目的。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181105G21FW800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券