在功能稳定後,你对程序码还有要求吗?
「没有最好的程序,只有更好的程序。
」在完成功能後 Code Review 是非常重要的事情;不只看自己的程序码,也要多观摩其他人的程序码,这个动作除了可以优化程序码品质
外,还可以帮助团队了解彼此的工作进度
。
人无完人,很多时候第一时间想到的解法未必是最好的;解决问题的方法不只一种
,可能有更简洁的写法或是更好的 Pattern 可以套用,只是开发者不具备这块的知识储备;此时 Code Review 就是提升团队程序水平
的方式。
找到需要改善的问题後,Refactoring(重构)
就是另一个开始;如果为了尽快完成功能而埋头狂写,容易导致日後维护以及交接的困难性;专案越大这个问题会越明显,所以在完成功能後对程序做 Refactoring 是必要的任务,它能提升你日後解决 Bug、需求变更时的工作效率
。
Code Review 会注意哪些事?会依照什麽原则对程序做 Refactoring?
回答问题所需具备的知识
衍伸问题
只要是软件工程师的职位,这题可以说是超级常见面试题
;因为它能问得很浅也能够问得很深,如果是相对资浅的职位,求职者只要能说出关键字并给出基本解释
就能过关;如果是资深的位置,除了关键字外,面试官会继续询问你在专案中是否有实践
。
我会先观察变数与函式的命名
是否符合团队规范、变数的宣告
是否合理(var/let/const 的使用时机);然後看程序在设计上是否有符合 SOLID 原则
;在功能完成後如果发现有合适的 Pattern 可以更好地解决问题
,就会再对程序做 Refactoring。
其他章节的知识,可能换一个时空背景就用不到了;但今天这个章节的内容,是每位开发人员都需要将其内化成为本能的
。
SOLID 是一个物件导向
的设计原则,核心目标是为了让程序码更乾净、易读、好维护,让程序朝着 Clean Code
(无瑕的程序码)的方向前进。
一次只做好一件事
;如果把系统比喻成乐高,那单一责任原则就是乐高的每一块积木。功能的扩充是新增程序,而非修改过去的程序
,这麽做可以维持原有程序的稳定性。完全继承父类别的功能
;实作时还需顾虑到单一责任原则,避免日後功能拆分或删减时的困扰
。版本从 1.0 ➞ 1.1 时行为是一致的,不会更新完旧功能就坏掉
。
子类别 Override 时要注意
- 不可改变父类别先决条件
假设篮球比赛的参与者年龄限制在 15~80 岁;里面可能区分为青年组、中年组、老年组,青年组的年龄「可以是 15~30」;但「不可以是 14~30」。- 子类别的後置条件不该被削弱
篮球的得分有「2」分球、「3」分球,都是数字;如果某个比赛改用「三分球」这个字串纪录得分就是不可以的。
不要让一个 API 可以做好多事情,但做每件事情时只用到其中几个参数
。子类别一定会依赖父类别
,这样单向的关系是乾净的;如果是双向的依赖就会导致程序码逻辑难以追踪。Pattern
是指在不同场景下的解释,包含 Context(情境叙述)、Problem(问题)、Solution(解决方案)。
而 Design Pattern
就是过去人们发现解决问题的套路;学习越多 Design Pattern 在遇到问题时可以有更多的思路,并缩短与其他工程师讨论的时间,因爲 Pattern 本身就包含了对问题的基础解决方案,可以省下说明的时间。
下面分享一些常见的 Design Pattern 帮大家建立基础概念,在看完後读者也许会恍然大悟,原来我一直都有在使用 Pattern!
Factory Method 工厂方法
简述:工厂负责生产客户需要的产品
假设今天有一个饮料工厂
,他会生产很多种类的产品
,像是「红茶、绿茶、乌龙茶」;也许这些饮料的制作过程很复杂,但对客户来讲只要说出自己想要什麽口味的饮料就好了。
Strategy 策略
简述:一个策略介面底下有很多灵活的方法供选择
把计算机的计算
当成一个介面,这个介面提供加减乘除
的方法;如果想加入次方、开根号
的功能也能够轻松扩充。
Factory Method 与 Strategy 混合运用
简述:有时解决方案是多个 Pattern 的组合
假设今天开一间饮料店,饮料会分成茶类、咖啡;每杯饮料又有冰量、甜度的选择,这里我们可以用 Factory Method
来建立产品;而饮料在贩售时,不同组合有对应的折扣,这里就可以用 Strategy
提供对应的方法来计算总金额。
Singleton 单例
简述:希望在程序每个位置都能呼叫统一的 Instance
在写程序时会希望某些资源可以重复利用
,并且在不同档案引用时这些资料是一致
的,像是共用的计时器、资料库等物件。
Decorator 装饰
简述:将需求独立,依据实际需求取得动态的结果
假设一间餐厅提供三种餐点
我们发现上面餐点是有叠加性的,所以可以用继承的方式来撰写餐点间的关系;但如果今天老板想要更换简餐的内容组合(ex:赠送水果),而不想改变套餐的内容,就会导致程序必须改写。
面对这个问题,我们可以用 Decorator
作为解决方案,将主餐、饮料、甜点、水果各自独立,依据商业午餐、简餐、套餐实际的内容来做组合;这样就能减少耦合性的问题。
Observer 观察者
简述:观察者要能掌握被观察者的状态改变,较常用於 GUI 的设计
像是 Vue.js 的 watch 就是用来监听一个「值」的变化去做一系列的事情(ex:UI 上的调整)。
Command 命令
简述:将请求的物件和执行的物件分开
路边摊的老板通常是一个人负责备料、点餐、料理、清洁…等到生意做起来有店面了,他才会考虑雇用一些人手来帮忙内场、外场,如果把这个解决方案用 Command 来举例:
Builder 建造者
简述:依照自己的需求客制化产品
一台笔电是由许多零件组装而成,你可以选择标配
也能够用选配
来客制化它;为了让选配的零件规格有弹性,Builder
就是一个很棒的解决方案;它让你先选完自己所需的零件後,再产生最後的产品。
备注:如果你熟悉的 Pattern 刚好能解决目前遇到的问题那是皆大欢喜;
万一没有合适的 Pattern 可以套用,千万不要为了设计而设计
;开发人员的目标应该是想透过 Pattern 解决问题,而不是从 Pattern 出发去设计问题。
除非是新创团队或是接案类型的公司;不然绝大多数新人入职後都要接手前人遗留的程序码(Legacy Code),如果求职者只有从零开始的经验,在一开始会有阵痛期。
考点:了解求职者是否接触过 Legacy Code、碰到时如何快速掌握
之前有因为专案扩编
而去支援的经验,因为当时有时程上的压力;所以我在加入团队後除了重点了解自己要负责的 Feature、团队的 Coding Style
外,会主动向定下这些需求的 PM 讨论
,以此了解因果关系并快速融入团队。
也曾接手过要维护及扩充的专案
,因为当时没有相关文件可以参考,为了快速掌握专案,我一边操作系统一边画心智图
帮助自己厘清功能;了解系统架构後再去找合作窗口确认需求
,避免实作方向与客户需求不同。
在修改 Legacy Code 时,我会特别注意前人是否有撰写测试案例
,在程序能有效测试的状态下才能安心的修改与扩充。
以正在运行的专案来说,我会希望建立团队 Code Review 机制
,让每个人熟悉彼此的程序、使用共同的 Coding Style,当知识共享与风格统一後,就能减少 Legacy Code 的产生
。
考点:是否有善用工具解决问题
我在 VSCode 有安装一个 Prettier 的外挂,靠它就能非常有效的将程序码格式化;不过有时为了保证团队的 Coding Style 会导入 ESLint 来统一风格,但 Prettier 与 ESLint 一起使用时会遇到冲突,所以我有再安装一个 Prettier ESLint 的外挂来解决这个问题;让程序不仅符合团队的 Coding Style,还可以透过快速键将程序码格式化。
写完这篇文章时,我的心里突然冒出一段话:「一开始我们在追求问题的解答;到後来,我们在学习解决问题的方法。」
感谢大家的阅读,如果喜欢我的文章可以订阅
接收通知;如果有帮助到你,按Like
可以让我更有写文的动力,我们明天见~
我在 Medium 平台 也分享了许多技术文章
❝ 主题涵盖「MIS & DEVOPS、资料库、前端、後端、MICROSFT 365、GOOGLE 云端应用、自我修炼」希望可以帮助遇到相同问题、想自我成长的人。❞
睡觉、运动、读书、写日记、呼吸冥想、跟久未联络的朋友联系,这些常被推崇的快乐生活指南,我这个月都实践...
本篇介绍JS插件pdf.js简易应用篇 今天介绍透过插件pdf.js在网页中直接浏览pdf 官网:...
前 11 天已经将常见的 concurrency patterns 介绍完毕,今天我们要介绍的不是 ...
首先很感谢it铁人赛给予我这个机会,让我做到平时连想不会想到的事。因为对於我而言,实在是没什麽能够说...
本篇是看 Go Concurrency Patterns 的心得 简报网址:https://talk...