草庐IT

浅谈研发实践的技术债与效能提升

shanxihualu 2023-03-28 原文

在软件研发过程中,往往随着为了快速满足业务要求的压力,用户需求的变更,软件代码的增多,以及版本的迭代,团队成员的变化等等因素,导致一个软件项目随着时间推移,欠的技术债会越积越多,用户使用容易出错,部署流程也变得复杂。

技术债务不及时还掉,就会产生“利息”,进而导致软件复杂度呈指数级增长。代码行越多,逻辑越复杂,技术债务就会欠的越来越多,最终到了某个临界点的特定时刻,软件代码就会变得失控,没人知道里面改动会带来什么后果。每一次的需求修改调整,引发即使很小的代码修改,可能由于软件复杂度变高,都会带来新的问题,轻则导致软件无法正常使用,重则导致出现严重的问题,甚至系统崩溃无法正常使用等问题。随着时间的累积,导致问题处理和修复耗费大量时间。

而这种失控,在实际软件开发过程中,是一个普遍的现象。熵增定律告诉我们,孤立系统总是趋向于熵增,最终达到熵的最大状态,也就是系统的最混乱无序状态。熵是无序的混乱程度,也就是说世界上一切事物发展的自然倾向都是从井然有序走向混乱无序。软件也不例外,如果不进行适度控制和优化,也必然朝着混乱的方向行进。

在实践中,团队技术人员通过多种办法来提高软件研发效能,调整软件研发模式,以流程、方法等方式持续提高软件质量,最终提升软件可用性,以及用户体验。从笔者的过往实践来看,比较常见的有:

1.从需求分析与输入端控制

2.从软件架构与设计方面提升

3. 从团队协作与组织方面提升

4. 从软件代码质量与测试方面提升

5.从研发模式与工作流程方面

6.软件项目管理与部署发布

这篇文章,下面就以个人粗浅的理解,概要式的进行一些初步的分析,后续我们针对具体的每个方向的主题,逐步再进行详细的探讨。

需求分析与输入端控制

需求输入端的重要性毋庸置疑。软件要解决用户的什么痛点,用户会在什么场景下使用,做什么样的操作,来达到什么样的效果,解决了什么样的问题,这些要做一款软件需要考虑的首要问题。

而对用户真实需求的分析,做出符合产品定位并满足用户使用的解决方案,其中需要有很多的思考和分析,如何以高效且低成本方式做好,是值得长期研究和实践的话题。

ToC类软件和toB类软件的用户属性不同,需求侧重点不同,在做需求分析时候,做好需求分析,需求挖掘,以及需求的验证等也都不同。

在实践中,往往也会存在很多的伪需求,以及被忽略的隐含需求。功能性需求只是一方面,但决定软件成败的,往往是隐含的非功能性需求。

在进行软件需求分析时候,需要对于功能的完整性、功能前后一致性,以及逻辑合理性等进行论证,也需要考虑到需求是否可落地实施等。

需求分析和输入端的分析和控制,对软件的研发时间方向起着至关重要的作用。往往多一个需求,或者一个功能流程的变化,就足以使得后续的一系列软件流程随之改变。在软件需求阶段,做好需求分析,需求确认,以及需求评审,是很重要的一个环节。

软件架构与设计方面

当需求确定之后,就需要进行软件设计了。软件规模的大小,用户的使用场景差异,就决定着软件的设计方式,就一般的普通软件系统而言,采用单体软件、前后端分离、分布式云架构方式,采取公有云、混合云、或者私有云模式部署,都对整体软件设计影响很大。

软件整体架构的选择,不仅仅需要考虑功能方面,也需要对系统的可用性、性能、可扩展性、文件存储、消息处理、接口协议、通信方式等进行考虑,从基础模式上做好设计。

一般而言,常见的软件系统由前端UI展示层、服务应用层、业务逻辑层、数据持久化层组成。不论是单体应用,还是分布式应用,以及微服务架构,乃至一些大的云厂商设计的Serverless架构,都在解决给用户界面呈现,业务逻辑处理,与数据持久化的问题。只是在每一层里面,有更详细的架构设计;以及由于业务属性或者项目某方面的特点需要,导致做了一些特殊型的架构设计。如何巧妙地让前后端协调起来,通过完整、准确、高质量的代码实现,从而输出一个稳定高效的软件,是在设计方面值得下功夫去做的事情,并且值得持续演进和更新。架构设计是一个不断演进的过程,也是一个产品长期演进和迭代过程中绕不开的必由之路。

实践工作中,我们做的业务软件系统,也需要随着用户需求的驱动,不断进行技术选型的修改,软件架构设计的优化,持续不断地优化和调整。我们学习一些业界开源的经典软件架构设计,会有一定帮助。比如下面这几个:

Linux系统架构:

(上图参考:https://retrage.github.io/img/lkl-architecture.png)

Openstack架构设计:

(上图参考:https://object-storage-ca-ymq-1.vexxhost.net/swift/v1/6e4619c416ff4bd19e1c087f27a43eea/www-assets-prod/openstack-map/openstack-map-v20221001.jpg)

Kubernetes架构设计: 

(上图参考:https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.2/docs/design/architecture.png)

一些开源的经典软件设计很巧妙,在实际的软件设计中,可以给我们很多启发,在实践中可以参考学习借鉴,以便少走很多弯路。

团队协作与组织模式

当需求与软件基本设计确定之后,团队的协同与组织模型就进行相关协作与工作开展,基于一些常用的协作工具,如Jira、Redmine、Tapd、Worktile、Teambition、禅道、飞书之类进行产品需求、工作事务、项目进度、task、bug与软件质量等的管理与跟踪。大部分的工具现在都提供了对于任务优先级设定,人员、时间等的。可以根据自己团队的时间选择取用。各种工具皆有自己的优劣势,选取一种作为团队的标准化工具,再逐步优化和改善,目标是能够实现信息共享与同步,方便团队协同,提高效率就可以。

软件代码质量与测试

在人月神话中提到,软件开发工作没有银弹,不为系统测试安排足够的时间简直就是一场灾难。由于软件工程在实际中的复杂性,需要做好合理的时间规划,并且需要注意风险。在实际的项目开活动中,前期未为测试分配足够的时间,就会导致大多数项目在后期长期维护修复,反复挣扎,导致实际上测试花费了进度中超过一半的时间。软件工程中进度计划方面,典型的经验是为1/3计划、1/6编码、1/4部件测试以及1/4系统测试。

在项目实践中,许多项目在系统测试之前还能保持进度。在进入系统测试之后,就会陷入泥潭,时间不可控。因为项目为测试预留时间较少,测试介入较晚,在项目快完成的时候才开始启动测试,直到项目的发布日期,人们才会发现进度上存在问题,还有很多复杂的问题没有处理完成。给测试预留的时间不足,就会在项目快完成接近发布日的时候面临延期的窘境。就软件而言,实际往往需要经过数轮测试,才能使得一个软件能够功能可用,而要达到好用,更是需要持续地精雕细琢,经历更漫长的测试,多轮的实践。所以业界也有说法,好的软件是不断测试之后才优化打磨出来的。所谓“不经一番寒彻骨,怎得梅花扑鼻香”,只有持续的深入细节测试和优化,不断打磨,才能使得软件能用,直到最终好用、易用。

研发模式与工作流程

所谓”工欲善其事必先利其器”,选择合适的开发工具与模式,会对实际的效率提升有很大帮助。首先建议团队之间采用相同的标准SDK版本,相同的IDE版本,相同的项目管理工具与构建工具,节省一些由于版本差异导致的转换等成本。其次,敏捷开发模式已经盛行多年,基于敏捷模式的快速迭代工作,采取小步快跑,小版本迭代,快速发布,循序渐进的模式,这种主流普遍的研发模式,团队之间快速协作,更早的验证软件小功能,每一个Sprint都有对应的输出,迭代式、增量交付,能够让团队整体实现更高效的协作,以及最高效的交付。

项目管理与部署交付

在实际项目运行中,即使采取敏捷方式,基本的需求分析,编码与单元测试,集成与系统验收测试等关键环节也是必不可少的。而项目管理方面,就需要做好内外部的资源与时间等各方面的协调工作,控制好风险,确保团队的进度满足,整体进展与原计划之间是匹配的。

软件的部署与交付,是整体相对靠后的一个重要环节。通过持续集成结合持续交付与持续部署的方式,让一切自动化起来,让开发、测试人员专注与业务的实现与测试,让代码构建到发布的过程自动运行。采取流水线式自动部署,让项目从代码提交,代码质量扫描、单元测试、build构建,自动化测试,自动化发布,并完成自动化部署,代码提交即可触发构建到发布的过程,实现全程无人值守即可完成。

把能固化的流程性工作交给工具,降低人工操作,可以减少错误,也可以提高效率。用程序测试程序,用程序调用程序,用程序管理程序,从而提升整个发布与研发的运转效率。

总体而言,软件的研发、交付,也是个系统性的工程,只有快速地响应变化,持续提高效率,才能实现更好的结果。一些GTD工具、好的项目管理工具,一个小脚本,也会带来效能方面的提升。培养好的习惯,养成良好的规范化标准对工程师而言很重要。

小结

本文很简要地从几个方面讨论了一些效能提升的要点,在软件研发实践中,效能提升也不止上面几点,而且以上提到的几个方面也有更深入的细节,后续我们继续分享交流。

有关浅谈研发实践的技术债与效能提升的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  3. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  4. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  5. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  6. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  7. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  8. Ruby 最佳实践 : working with classes - 2

    参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin

  9. ruby-on-rails - 用于门户的 Ruby 技术 - 2

    我刚刚看到whitehouse.gov正在使用drupal作为CMS和门户技术。drupal的优点之一似乎是很容易添加插件,而且编程最少,即重新发明轮子最少。这实际上正是Ruby-on-Rails的DRY理念。所以:drupal的缺点是什么?Rails或其他基于Ruby的技术有哪些不符合whitehouse.org(或其他CMS门户)门户技术的资格? 最佳答案 Whatarethedrawbacksofdrupal?对于Ruby和Rails,这确实是一个相当主观的问题。Drupal是一个可靠的内容管理选项,非常适合面向社区的站点。它

  10. ruby - 存储外部 API 的密码 - 最佳实践 - 2

    如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。

随机推荐