鄙人是一个职业程序员,职位不过前端开发,学历不过本科而已。虽然我能力一般,但近十年的工作经验是实实在在的,对于软件开发工作,我自认为还是比较有发言权的。那么接下来我要讲述一些多年来代码工作中的经验教训。
一、设计
1.框架选型
1.1避免先吃螃蟹
这里不是说不要使用新兴的框架,而是不要在大型的、重要的项目里使用新兴的、前途不明朗的框架,否则就是给自己埋雷,隐患极大。
1.2流行程度
在绝大多数中小型企业场景中,不建议自己开发复杂的框架,应遵守降本增效的原则,选用流行的、较成熟的开源的三方框架;反之如果是大型企业,强烈推荐建立属于自己的强有力的技术团队,自行开发代码框架,以规避法务问题。主要通过观察社区活跃度、技术支持团队信息以判断该框架的前景。应尽量避免使用个人开发者开发的组件,除非是公司员工。
1.3性能情况
可查看该框架的网络风评、已使用该框架的三方买家做粗略判断,但主要还是要自己上手试用后才能给出明确评估,避免人云亦云。
1.4技术前瞻
思考当前框架有多少平行的可替换方案、未来将会出现的可替换方案、未来将会出现的对接方案、潜在大坑。
2.样式风格
2.1早期不设计,仅使用默认样式
别着急设计UI样式,没用。应先出功能,后再调理样式,因为先出的功能会在之后任何时候突然大改甚至消失,导致过早的UI设计成为无用功。
2.2后期再调整,应基于三方库
当功能趋近成熟,此时意味着系统接近完善,不会再有需求大改存在,此时再设计样式调整代码事半功倍。且应基于使用的框架,不要做过猛的调整。何谓过猛的调整?就是指形状、尺寸与默认样式差距过大。例如,框架中一个输入框是矩形的,你要改成三角形、心形的,这就属于是过猛的调整。不是不能实现,而是容易让人产生视觉误解,日后维护麻烦,且不见得有多少收益。
2.3应避免布局大改
同一视觉组件在不同风格时展现的位置、出现/消失的形式、尺寸差异大就可认为是布局大改。布局改动巨大往往意味着无法使用同一套代码实现,仅为了一些炫酷的视效而添加大量的臃肿代码可不是个明智的选择,这意味着将来维护的工作量将成倍增长。
开发
文件夹结构
抽离控制箱
一定要在最外层放一个集中式的控制箱。即抽离一个文件(以前端为例:appConfig.js)。该文件里面仅放置控制键,如果有必要的话甚至需要调整打包配置,使该文件于程序打包后仍处在外层文件夹目录处。此时如果客户服务器地址换了,或者要求做一些统一性的修改(例如要求接口超时时间从8秒修改为12秒),你只需在该文件中修改一下即可应用于整个系统软件,便捷易懂。
按类型放置文件
同类型的文件应避免分散于各个位置,例如,图片、样式文件、字体文件等。放在一块儿有利于将来维护时可迅速找到该文件并覆盖以替换资源。
代码命名
命名不应该极尽简短,而应该尽量用较少的词汇描述名词意思或动作意义。名词不应超过三个单词,动作也应该使用动宾短语,同样不宜超过三个单词。命名过长不利于阅读和编写。如果实在是不长不足以描述其效用,则可适当采取缩写,但一定要给该变量添加解释性的文字注释。
有必要做一些开发前的约定,例如一般变量使用驼峰式;局部变量使用下划线标记或包裹;静态常量使用纯大写加下划线拼接。
变量决定
全局变量
慎之又慎,除非万不得已,否则应避免使用全作用域的全局变量,如window.xxxx。这种可污染全局的变量会在多框架协作时产生意外的、很难被排查出的错误。
静态数据
静态数据也叫常量,或者说是“写死的数据”。应将这类数据集中管理,他们在本质上和数据库的作用是相同的,在前后端分离的现代不应该混杂在具体的页面文件中。
局部变量
这种变量是用的最多的,注意命名时可带有一些通用性,这样方便在添加一个类似页面时复制粘贴。
函数功能
我们一般崇尚“纯函数”,也就是说一个变量进入到一个函数被处理加工后输出一个结果量,但是原变量也是丝毫不被影响地抛了回来。也就是说,一个不改变输入的,有输出的函数称为纯函数。如果一个函数每运行一次函数都会对原变量做一次修改,那么当程序因出现逻辑bug时运行了两次,结果就会和预期不一样,而且光从阅读代码上很难想到问题出在哪里,降低开发效率。
组件封装
应避免过度封装
我个人建议前期不封装组件,除非某功能或视图频繁出现。组件的封装应该是随着项目进度而被推进着逐步进行的,而不是你看着某个部分感觉能封装就封装一下的。因为某些功能甚至仅只出现一次,那么封装就先显得毫无意义且徒增工作量。开发时发现某个功能或视图常常出现时,这才意味着该部分有必要封装一下,所以封装工作应该在中后期进行。
原本就是一个组件内容,但是还是要一个组件嵌套着另一个组件这样地出现,当嵌套层数大于等于3时即可认为是过度封装。开发的时候你觉得很爽,很有成就感,等过几年回头再维护时你就会知道什么是地狱了。
共用部分有必要封装组件
封装的意义就在于让开发者开箱即用,当某功能重用次数大于等于3时就可认为该部分有必要封装。封装的好处一是创造开箱即用的黑盒模式,二是当发生修改、调整时可做到改一处而处处生效。
写代码
先写注释、多写注释,后写代码
钱多不咬手,技多不压身。同样地注释也不怕多写。怕的是不写注释,多年后回来再看那才叫折磨。我看过这么一段话,大意是“写注释就是跟未来的自己对话,经过时间的冲刷,现在的你和未来的你对这个程序的理解是大不一样的,如果你留下了足够的注释,无疑像是给迷失在森林里的自己插上了路标。”直到前两年,我才深深地体会到这段话的意义。
保持易读性、整洁性、一致性
很多经验都介绍写代码的时候要保持简洁易懂,但代码就像作文一样,也有风格一说,其一致性同样重要。例如将变量在函数之初就做声明,就比临用之前再声明更容易理解;当调用某种方法时是那样写的,那么其他位置调用该方法也都沿用同一种写法就很容易理解。
避免过早优化
先不着急优化,把软件逻辑做对了才最重要。
逻辑正确性最优先,性能优化最后做
性能优化是个有意思的事情,这件事非必要完全可不予理会。
交互反应时长、等待/状态提示语
很多程序做出来容易没有交互时的状态提醒,例如点击之后实际已经调用了某接口,但并没有告知用户或画面没有任何变化,使用户不知所措,产生困惑;应该时刻提示用户“加载中”、“加载成功”、“加载失败”之类的明确状态提示,避免使用户困惑。另外加载中的过程不宜过短/过长,某位置加载过快可能会使页面闪烁或突然数据变化,此时若另一个部位因处理数据繁琐而响应时间较长,就像是在暗示用户系统出错的意思,降低用户体验。可设置一个最快响应时间(300ms),使用户在交互过程中有一个“节奏”的存在。
错误信息提醒
应使用用户可以理解的术语描述,避免出现乱码提示,避免语言中带有指责色彩。
维护
评价标准
到了这个阶段,才能看的出来哪些框架是优秀的、哪些代码写的非常好,哪些反之。可以断言,时隔几个月或几年后,仍然容易阅读理解的代码才是优秀的,仍然容易修改逻辑的代码才是优秀的,仍然可以避免牵一发而动全身的设计才是优秀的。
关于代码退化
清华6版的《软件工程》里有这么一句话“软件在未来会出现‘退化’”,当时我无法理解,代码就放在那里,一成不变,不会进化就是了,怎么还能退化呢?后来我才明白,多年后技术生态早已更迭,出现了许多新的技术方案,代码甚至也出现了新的语法,再回头来看那些旧代码,才明白为何会发生退化。其实不能与时俱进就是退化的表现。但即便如此,只要写的代码逻辑清晰易懂,再怎么退化也不可怕;反之,一坨坨不知所云的,调用混乱的、连一行注释都没有的代码那叫一个恶心。用退化一词形容简直是太贴切了,像是西装革履的绅士进入了原始社会跟野人争抢食物一般,可悲又可笑。
实施原则
维护时千万不要做过度处理,只要程序是正确可用的,就别动。做好必要的调整后就撤离,应避免强迫症发作或不必要的优化。
驳回要求
有时候客户提出的要求是不合理的,是离谱的,这时就要耐心解释并驳回其无理要求。