前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >还债啦!认识技术债系列之如何避坑

还债啦!认识技术债系列之如何避坑

原创
作者头像
用户1086038
发布2023-09-25 22:55:31
1860
发布2023-09-25 22:55:31
举报

在实际开发过程中,很多人都常常将技术债与糟糕的代码等同看待,认为,只要我们编写出了足够好的代码,就不会产生技术债。这是一种误解!其实,在我们的日常工作中,技术债产生的原因五花八门,无处不在,让我们防不胜防。现总结出来,供大家参考,以免避坑。由于本人能力和经历有限,总结难免周全,也欢迎大家评论区查缺补漏。

1)UI设计阶段考虑不周全所留下的技术债。

经常遇到的场景是,我们在做UI样式还原的时候,为了开始开发比较方便,很多背景色,或者文字颜色都是写死的具体的颜色值。但是,等系统实际要上线的时候,产品突然告诉我们系统需要同时支持普通样式和暗黑模式的样式。写死的固定颜色值,如何同时支持普通模式和暗黑模式?傻眼了吧!还有的场景,就是,在进行客户端非native应用开发的时候,比如app中嵌套h5的应用,或者类似于hippy这样的离线包应用,刚开始是一个初始版本的样式。可是,随着时间的推移,需要进行皮肤样式的升级,更换另外一套皮肤。如果我们一开始,在应用中把所有的颜色样式都写死,这个时候麻烦又来了,因为我们在这类型的应用中,需要同时支持2种皮肤样式的:旧版本的app里面的应用需要仍然支持旧版皮肤,新版本的app应用才需要支持新版本的皮肤。简简单单一个皮肤样式的升级,由于一开始我们考虑不周而留下来的技术债,会使我们的样式开发大部分都得重新来过,损失不可谓不大。

那这种情况下,我们该如何避坑呢?一开始,我们在规划UI样式开发的时候,就需要引入变量而非写死固定值,如下图所示。我们在一开始就可以规划好,如需要支持2种样式,需要把不同的样式放到不同的文件中,或者把颜色值都放到对应的变量中,在UI样式还原的时候,尽量不要写死颜色值,可以用这种变量的形式。用变量还有一个好处,就是能够保证全局样式的统一,就是所有的一级标题颜色都用C1,所有的二级标题颜色都用C2。。。。。。依次类推。后续当我们需要全局更换一级标题颜色的时候,我们只需要修改变量的颜色值即可,不用整个系统查找颜色值来替换。

变量样式
变量样式

2)使用框架引起的技术债。

        我们在选择某种技术框架的时候,由于对框架的本身调研不够,或者对系统的长远发展思虑不周,导致选用某个技术框架,系统上线迭代一段时间后,突然发现这种框架由于某种技术限制,不能支持系统进一步的开发迭代,需要更换系统框架。这种情况下引起的技术债是非常严重的,最坏情况下可能需要重构整个系统。重构期间,既要重构新系统,又要支持旧系统功能的迭代,苦不堪言。我们曾经就遇到过这样的情况,旧框架完全没法继续下去了,最后只能重新选择新框架,用新框架重新全部重构系统。那么,我们要如何尽量避免框架带来的坑呢?

        首先,选择一个框架,我们需要考量框架的生命力,它是不是一个长期有技术团队支持的框架,有没有完善的文档和活跃的开发者社区。如果一个框架的生命力很短,没有技术团队维护,这样的框架后续一定会有坑。

        其次,从产品短期发展和5年后长期发展看,该框架是否满足产品需求。很多时候,我们选择一个框架的时候,往往只看眼前。但是,当一个产品功能模块很少,或者用户基数很小的时候,很多问题不容易爆发出来。比如框架的高并发处理能力,框架的性能问题,框架的内存消耗情况,是否存在OOM的问题等等。所以我们应该从5年,甚至10年这种长远的眼光来选择一个框架,应该三思而后行,因为一旦后续要更换框架,将会是要付出血的代价。

        最后,选择技术框架需要考量开发上手的成本。看看该框架所用的技术栈跟本团队的技术栈是否接近或者一致;看看该框架是否有完善的技术文档可供参考,遇到了棘手的问题,是否有技术支持可以帮忙,这些也很关键。

3)产品需求变更引发的技术债。

        在敏捷开发模型下,产品负责人为了快速验证产品是否能够被用户所接受,会快速的验证多个功能,频繁的变更需求,从而会引发以下两种类型的技术债:

        第一种类型:某些功能之间是互斥的,导致选用的技术框架也是不同的。比如针对用户反馈模块,在初期版本,产品负责人想要实时聊天类型的反馈功能,主打一个实时性,这个时候,开发团队需要选用一个实时通信的技术架构来支持,应用程序的部署也是不同的;可是等该功能上线后,发现用户的使用率并不高,而且需要特别大的运营人力来支持,很不合适;于是,在下一个迭代周期,废弃了实时聊天的反馈功能,修改为列表展示用户的反馈问题,线下来回复的形式。那么原来的技术架构都需要作废,都需要重新设计,从而带来了额外的技术债。针对这种情况,我们应该跟产品负责人多沟通,多问问产品的长远规划,从长远规划来进行技术选型,避免过度的浪费而引入技术债;

        第二种类型:产品负责人在开发过程中,发现了某个紧急情况,需要修改需求文档。该需求文档是经过需求评审的,并且估算了耗时和上线日期。如果在开发过程中修改需求文档,就会增加开发人员的工作量,在开发日期不变的压力下,开发人员会走偏激路线,采用错误的开发模式来赶进度,从而引发大量的技术债。针对这种情况,我们应该杜绝在开发过程中随意修复需求文档,一定要学会说“不”,把新的调整作为一个新的高优PBI参与下期的迭代开发,而不是在本期开发过程中来实现。

4)使用组件引起的技术债。

        该类技术债主要分为两大类:

        其一,是偷懒使用组件而引起的技术债。通常我们只需要组件中的一小部分,或者某一个功能函数,但是却往往引入了整个组件库,这样会带来很多的潜在风险:一方面会增加我们应用打包的体积,或者js文件的大小,影响系统的速度;另外一方面风险更隐蔽,由于组件的升级迭代,某个没有被我们用到的部分由于技术升级,与本系统的技术栈不兼容了,导致该组件安装不上,增加了组件引入的维护成本。举个例子,特别常见的是:import * from lodash; 但是,lodash里面包含的函数功能非常多,并不是每一个都是我们需要的,应该需要用到哪一个具体的函数,就引入哪个函数,比如:import get from 'lodash/get'; import filter from 'lodash/filter';

        其二,是组件本身的更新迭代带来的技术债。组件本身会经常进行升级迭代,在升级迭代中可能会引入新的功能,需要被迫升级某些底层的依赖库,比如需要升级nodejs的版本。但是,为了这个组件去升级nodejs版本,却给整个系统带来了其它的问题,从而需要修复这些问题,这就是间接引入的技术债。所以,组件的升级,需要提前预告,提前沟通,杜绝“先斩后奏”!

4)编写代码过程中所引入的技术债。

        这类型的技术债占比非常高。主要有以下场景:

        其一,是技术编码不规范所导致的技术债。例如对象的引用,没有判断是否为空,就直接去用它里面的属性,在正常情况下可能没有问题,但是在某些特殊情况下,该对象一旦为空,则整个程序会报错引发功能异常。例如: this.data.user.salary,data和user对象都可能为空,引用前,做好是否为空的判断可以避免后续的异常;还有,就是文件夹的命名规范,文件的命名规范,函数的命名规范等,如果不认真对待,都会引入技术债。针对代码规范引入的技术债,大家可以去好好学习各类语言的技术规范,这里不一一列举;

        其二,是我们偷懒引入的技术债。我们在编码过程中,经常爱偷懒写死一些常量值,特别是中文字符,比如: alert('密码输入错误'); 一般情况下,这么做没有什么问题。但是,如果系统需要支持国际化,这下你可惨啦,修改的代价将会很大。所以,常量建议要放到对应的常量文件里,通过枚举类型来引用;

        其三,代码中太多的 // todo,这些都是我们的技术债。我们在开发过程中,由于跟上下游同事有依赖,需要的东西暂时不能提供,于是,就在代码中写了// todo 作为提示。但是,时间一长,我们早就忘记了这样的 // todo, 从而造成了潜在的系统风险,增加了我们的技术债;所以,每一个// todo需要作为一个需求单记录下来,放入需求列表中,时时刻刻提醒我们,以免遗忘;

        最后,是由于经验不足,在不经意间引入的技术债。例如:

        if (getCookie('uid')) {

        // todo some login logic        

        }

        在正常情况下,用户登陆后,都会在cookie里面种下uid,退出,会把cookie里面的uid删除,看起来一切都没有问题。但是,如果系统接入了企业微信登陆,企业微信登陆并不会在cookie里面种下uid,从而导致系统的登陆异常。如果系统各处的鉴权判断都是引用上面的方式,那么系统的改造工作量可不小!针对这种不稳定的因果关系可能导致程序变得难以修改甚至引入bug,我们在编码时,需要养成良好的编码习惯,所有的技术细节需要进行函数的封装,例如:我们可以把getCookie('uid')这种技术细节,封装到一个isLogin的函数中,通过引用isLogin函数来判断用户的登录与否。后续一旦要修改登录逻辑,也只需要修改isLogin这一个函数,不用维护整个系统。

        if (isLogin()) { // todo some login logic }

        function isLogin() { return getCookie('uid') || getCookie('uin')}

        针对这类型的技术债,我们还需要做好代码的code review,找更高级别的同事帮忙review 代码,尽早找出代码中的异常,将损失减小到最小。

5) 由于误用数据从而引发的技术债。

        这种场景常常发生在app系统开发中,一个系统数据的输出,直接是另外一个系统数据的输入,没有做任何版本的隔离限制。例如,我们在进行“明星意图”模块的迭代开发,开始用播放量作为二级标题;后来由于某种管制,不允许外露播放量,于是去掉了播放量字段,替换为来源字段。如果不做任何版本的隔离限制,直接发出去,旧版本的用户在前端还是用播放量字段作为二级标题,但是现在该字段已经在后端删除了,将会引发程序的功能异常。所以,在进行app功能模块迭代的时候,尽量做好版本的隔离限制,避免引入技术债。

6)由于数据库的设计不合理从而引发的技术债。

        在应用开发早期,由于数据库的设计或者规划不合理,从而引发的技术债,非常常见。场景有:

        其一,某些字段的类型定义错误了,比如把数字类型定义为了字符串类型,或者没有考虑到系统的发展,少定义了字段,需要进行更多字段的添加,从而造成了技术债;

        其二,分库分表设计的不合理,从而造成技术债。分库分表对与数据库的设计异常关键,设计不好,会造成很多问题,比如,分页,排序,跨节点联合查询的问题;事务的一致性问题;全局唯一关键字的问题;历史数据的迁移问题等等。所以,数据库的分库分表设计最好采用比较成熟的架构模式来进行,减小不必要的技术债;

        其三,由于sql语句引发的技术债。常见的在sql语句中写死很多字段值,查询值等,或者关联更新和删除等,都会引发系统后续的潜在问题;

7)由第三方系统引入的技术债。

        我们在应用开发过程中,无可避免会使用很多第三方的系统,比如CI/CD系统,比如监控系统,比如日志系统等等。正常情况下,我们开发流畅,相谈甚欢。但是,突然有一天,某个CI/CD系统突然告诉我们说某某日,我们的系统由于降本增效,人力不足,不能再维护了,需要下线,那么系统必须要增加工作量迁移到别的CI/CD系统中去,将会给系统增加艺术债。

--

本文从日常开发的角度,给大家总结了技术债在日常开发过程中经常出现的场景,希望能够给大家起到抛砖引玉的作用,让大家尽早把容易引起技术债的因素扼杀在摇篮之中。

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
TAPD 敏捷项目管理
TAPD(Tencent Agile Product Development)是源自于腾讯的敏捷研发协作平台,提供贯穿敏捷研发生命周期的一站式服务。覆盖从产品概念形成、产品规划、需求分析、项目规划和跟踪、质量测试到构建发布、用户反馈跟踪的产品研发全生命周期,提供了灵活的可定制化应用和强大的集成能力,帮助研发团队有效地管理需求、资源、进度和质量,规范和改进产品研发过程,提高研发效率和产品质量。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档