写点什么

把同事的代码重写得干净又整洁,老板却让我做回滚?

  • 2020-02-06
  • 本文字数:2847 字

    阅读完需:约 9 分钟

把同事的代码重写得干净又整洁,老板却让我做回滚?

夜深了。


我的同事把这周写的代码提交了。我们在开发一个图形编辑器画布,已经实现了形状调整功能,即通过拖拽形状边缘的手柄来调整形状(比如矩形和椭圆形)。


代码可以运行。


但重复代码有点多。每一种形状(比如矩形和椭圆形)有不同的手柄,往不同方向拖拽手柄对形状的位置和大小影响也不一样。如果用户同时按住 Shift 键,在改变大小的同时要保持比例不变。这里涉及了很多数学运算。


代码看起来像这样:


let Rectangle = {  resizeTopLeft(position, size, preserveAspect, dx, dy) {    // 10行重复的数学运算代码  },  resizeTopRight(position, size, preserveAspect, dx, dy) {    // 10行重复的数学运算代码  },  resizeBottomLeft(position, size, preserveAspect, dx, dy) {    // 10行重复的数学运算代码  },  resizeBottomRight(position, size, preserveAspect, dx, dy) {    // 10行重复的数学运算代码  },};
let Oval = { resizeLeft(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeRight(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeTop(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeBottom(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 },};
let Header = { resizeLeft(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeRight(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, }
let TextBlock = { resizeTopLeft(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeTopRight(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeBottomLeft(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 }, resizeBottomRight(position, size, preserveAspect, dx, dy) { // 10行重复的数学运算代码 },};
复制代码


这些重复代码看起来真的很碍眼。


这样的代码不够干净。


大部分重复是因为朝相同方向调整形状的代码都差不多,比如 Oval.resizeLeft()和 Header.resizeLeft()就很类似。


其他重复是因为同一种形状的方法之间很相像,比如 Oval.resizeLeft()和 Oval 其他的方法就很类似。另外,Rectangle、Header 和 TextBlock 之间也有重复的地方,因为文本框也是矩形。


我想到了一个办法。


我们可以给代码分组,把重复代码移除掉,比如像下面这样。


let Directions = {  top(...) {    // 5行不一样的数学运算代码  },  left(...) {    // 5行不一样的数学运算代码  },  bottom(...) {    // 5行不一样的数学运算代码  },  right(...) {    // 5行不一样的数学运算代码  },};
let Shapes = { Oval(...) { // 5行不一样的数学运算代码 }, Rectangle(...) { // 5行不一样的数学运算代码 },}
复制代码


然后,把它们的行为组合起来。


let {top, bottom, left, right} = Directions;
function createHandle(directions) { // 20行代码}
let fourCorners = [ createHandle([top, left]), createHandle([top, right]), createHandle([bottom, left]), createHandle([bottom, right]),];let fourSides = [ createHandle([top]), createHandle([left]), createHandle([right]), createHandle([bottom]),];let twoSides = [ createHandle([left]), createHandle([right]),];
function createBox(shape, handles) { // 20行代码}
let Rectangle = createBox(Shapes.Rectangle, fourCorners);let Oval = createBox(Shapes.Oval, fourSides);let Header = createBox(Shapes.Rectangle, twoSides);let TextBox = createBox(Shapes.Rectangle, fourCorners);
复制代码


代码量减少了一半,重复代码完全消失了!多么干净。如果要修改某个形状或方向的行为,只需要在一个地方做出改动,不需要修改所有的方法。


夜已深,我把改好的代码提交到 master 分支,然后上床睡觉。因为帮同事把杂乱的代码清理干净了,我心里还引以为豪。

第二天

事情并没有像我期待的那样发生。


老板找我谈话,他们希望我把代码回滚回去。我感到很惊讶,毕竟原先的代码简直就是一团乱麻,而我改得很干净啊!


我很不情愿地答应了,但几年之后,我才意识到他们其实是对的。

必经之路

痴迷于“干净代码”和删除重复代码是我们很多人都会经历的一个阶段。当我们对自己的代码不是很自信时,就很容易将自我价值感和职业自豪感与一些可以被衡量的东西联系在一起,比如严格的 lint 规则、命名模式、文件结构、不重复代码实践。


我们没办法自动去除重复代码,但可以自己动手做。每次修改代码之后,我们可以很容易地知道重复代码是少了还是多了。所以,去除重复代码感觉就像是在改进代码质量。更糟糕的是,它扰乱了人们的认同感,让他们觉得“我是那种编写干净代码的人”,但这其实无异于自我欺骗。


一旦学会了抽象,我们就很容易对这种能力产生很高的期望,每当看到有重复代码就会想要对它们进行抽象。在写了几年代码之后,我们发现重复代码到处都是,而抽象成了我们获得的一项超级能力。如果有人告诉我们说抽象是一种美德,那我们肯定会深信不疑,并且会因为别人不崇尚“干净代码”而对他们品头论足。


现在,我知道之前的代码重构就是一个灾难,原因如下。


  • 首先,我没有事先和写代码的人沟通。我直接修改了他们的代码并提交,没有和他们讨论。即使这是一种改进(但我现在不这么认为了),但我这样的行事方式并不值得称道。一个健康的工程团队应该以信任为基础,不经过讨论就修改他人的代码会对团队协作造成沉重的打击。

  • 其次,天下没有免费的午餐。我以牺牲灵活性为代价,以此来减少重复代码,这算不上是一个好的权衡。例如,后来我们要求不同形状的不同手柄具备一些特殊的行为,被我重构过的代码需要修改多次才能满足需求,而原先“杂乱”的代码却可以很容易实现这些需求。


那么,我的意思是我们应该尽量写“脏”代码吗?当然不是。我只是建议大家在考虑什么是“干净”或“脏”代码时进行深度思考。你当时有什么样的感觉?厌恶?正义?美丽?优雅?你可以肯定这些品质会带来实质性的工程成果吗?它们又是如何影响代码的编写和修改方式的?


我确实没有深入思考过这些事情。我只考虑到代码本身,但从来没有想过代码与团队之间的演化关系。


编码就像是一段旅程,想想你从写第一行代码到现在走了多远。当第一次通过提取函数或重构类让复杂的代码变简单,我觉得那是一种乐趣。如果你对自己的“杰作”感到自豪,那么就很容易掉入追求干净代码的旋涡。


但请不要止步于此,不要只做一个干净代码狂热者。写出干净的代码并不是我们的终极目标,我们只是通过这种方式尝试找到处理系统复杂性的方法。当你不确定代码改动会对代码库造成怎样的影响,在未知的海洋中需要灯塔的指引,那么这不失为一种防御机制。


写出干净的代码可以作为一种指引,但后面的路还是要自己走。

原文链接

Goodbye clean code!


2020-02-06 14:5213093
用户头像
小智 让所有人认同的文字称不上表达

发布了 408 篇内容, 共 398.1 次阅读, 收获喜欢 1984 次。

关注

评论 6 条评论

发布
用户头像
有道理,虽然代码目前看着一样,但是如果含义和应用场景不同的话,迟早要分化,不要一开始就瞎jb整在一起
2020-09-16 11:45
回复
用户头像
对于第二点原因不太认同。我的经验是,当工程达到一定规模,代码越多反而灵活性越差
2020-02-18 13:15
回复
用户头像
如果是技术leader的话,这件事是需要先跟下面人一起讨论如何去优化代码,而不是自己去做,这种行为就是一种自私不信任,不然下面的人来了是当摆设,来衬托自己很牛吗?如果是员工的话,只需要负责好自己的那部分代码就可以了,因为代码的整体执行方案还是需要技术leader去领导的,不然百花齐放,每个人心里都有自己的完美
2020-02-17 09:39
回复
用户头像
直接改是不太好,最好能提PR,讨论之后再合并,不然别人维护了一年的代码,被你随手改的妈妈都不认识了,换谁不一肚子火。
2020-02-15 23:54
回复
用户头像
这个理由有牵强得一笔。。。继承一个实现接口,使用装饰器不就好了
2020-02-09 09:55
回复
你读过人家的源码?
2020-02-11 16:17
回复
没有更多了
发现更多内容

第四朵“云”!全托管的时序数据云平台 TDengine Cloud 正式支持阿里云

TDengine

大数据 tdengine 阿里云 时序数据库 云服务

通通透透看无服务器计算:由来、场景和问题

天翼云开发者社区

PostgreSQL:psql 介绍

天翼云开发者社区

AI笔刷怎样导入?adobe ai笔刷安装教程

Rose

AI画笔 AI教程 Illustrator 2023 下载 AI中文版

追踪 Kubernetes 中的数据包

张晓辉

Kubernetes 网络

移动云发布操作系统迁移工具,助力全场景业务一站式迁移

openEuler

Linux centos 操作系统 虚拟化 openEuler

云计算搭上“双碳”,天翼云在绿色算力赛道加速跑

天翼云开发者社区

全球掀起AI热,天翼云智算能力已就绪!

天翼云开发者社区

盘活存储资源,天翼云HBlock助力企业绿色高效发展!

天翼云开发者社区

Ascend CL两种数据预处理的方式:AIPP和DVPP

华为云开发者联盟

人工智能 华为云 昇腾CANN 华为云开发者联盟 企业号 3 月 PK 榜

Linux进程学习【进程地址】

Yohifo

Linux 学习 运维 后端 进程

使用K8S进行蓝绿部署的简明实操指南

SEAL安全

k8s 企业号 3 月 PK 榜 蓝绿部署

大语言模型(LLMs)和新兴机器学习技术栈

Baihai IDP

人工智能 自然语言处理 NLP 大模型 大模型 白海科技

Stepn跑鞋GMT系统开发(NFT链游)

薇電13242772558

NFT链游

AntDB-M数据库锁分析,不要错过!

亚信AntDB数据库

数据库 AntDB 国产数据库 AntDB数据库 企业号 3 月 PK 榜

共铸国云智领未来| 以数字林草之“笔” 绘就塞上江南新图景

天翼云开发者社区

专场直播预约 | 邀您探讨KaiwuDB 离散制造业场景解决方案

墨天轮

数据库 解决方案 制造业 国产数据库 KaiwuDB

听说火山引擎推出的DataLeap,已经可以支持万级表的数据血缘图谱了!

字节跳动数据平台

大数据 数据治理 数据研发 企业号 3 月 PK 榜

深入理解关键字volatile

小小怪下士

Java 程序员 volatile 关键字

优秀的录屏软件:Record It Pro 直装激活版

真大的脸盆

Mac Mac 软件 录屏 屏幕录制 录屏软件

学完阿里P8面试官推荐的Java高并发核心编程文档后终拿蚂蚁offer

程序知音

Java 并发编程 编程语言 高并发 java架构

HTML5智慧农业大棚Web3D可视化系统

2D3D前端可视化开发

智慧大棚 智慧农业 数字农业 大棚三维可视化 数字孪生智慧大棚

开启一个A/B实验到底有多简单?

字节跳动数据平台

云服务 AB testing实战 ab测试 企业号 3 月 PK 榜

Dubbo + ZooKeeper|如何解决线上故障排查链路长的难题

云布道师

dubbo

ChatGPT4 高分通过数据库系统工程师(DBA)认证

NineData

数据库 dba GPT ChatGPT4 数据库系统工程师

大语言模型必将取代一切?暂时不会!

深数

人工智能 科技 AGI GPT LLM

把同事的代码重写得干净又整洁,老板却让我做回滚?_文化 & 方法_Dan Abramov_InfoQ精选文章