【翻译】再见, Clean Code!

news2024/11/23 20:20:30

鑫宝Code

🌈个人主页: 鑫宝Code
🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础
💫个人格言: "如无必要,勿增实体"


正文开始

文章目录

  • 【翻译】再见, Clean Code!
    • 正文
      • 那是一个深夜
      • 次日早晨
      • 这只是一个阶段

【翻译】再见, Clean Code!

这篇文章翻译于React核心开发者Dan的这篇博客。

原文链接:overreacted.io/goodbye-cle…

正文

那是一个深夜

我的同事刚刚提交了他们整个星期一直在编写的代码。我们正在开发一个图形编辑画布,他们实现了通过拖动矩形和椭圆等形状边缘的小手柄来调整其大小的功能。

代码能正常运行。

但显得很冗余。每个形状(如矩形或椭圆)拥有各自不同的手柄集合,而拖动手柄的不同方向会以不同的方式影响形状的位置和尺寸。如果用户按住 Shift 键,我们还需要在调整大小时保持形状的长宽比。涉及了大量的数学计算。

代码大致如下:

let Rectangle = {
  resizeTopLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeTopRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeBottomLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeBottomRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
};

let Oval = {
  resizeLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeTop(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeBottom(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
};

let Header = {
  resizeLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },  
}

let TextBlock = {
  resizeTopLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeTopRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeBottomLeft(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
  resizeBottomRight(position, size, preserveAspect, dx, dy) {
    // 10 repetitive lines of math
  },
};

那些重复的数学运算令我颇为烦恼。

代码不够整洁。

大部分重复出现在处理相似方向的函数之间。比如,Oval.resizeLeft()Header.resizeLeft() 就有相似之处,因为它们都涉及拖动左侧的手柄。

另一类相似性存在于处理相同形状的所有方法之间。例如,Oval.resizeLeft() 与其它 Oval类的其他方法也有共通之处,因为它们都是围绕椭圆进行操作。同样,RectangleHeaderTextBlock 之间也存在一些重复,因为文本块本质上就是矩形。

我有了一个想法。

我们可以这样对代码进行归类,从而消除所有重复:

let Directions = {
  top(...) {
    // 5 unique lines of math
  },
  left(...) {
    // 5 unique lines of math
  },
  bottom(...) {
    // 5 unique lines of math
  },
  right(...) {
    // 5 unique lines of math
  },
};
 
let Shapes = {
  Oval(...) {
    // 5 unique lines of math
  },
  Rectangle(...) {
    // 5 unique lines of math
  },
}

然后组成他们的行为

let {top, bottom, left, right} = Directions;
 
function createHandle(directions) {
  // 20 lines of code
}
 
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 lines of code
}
 
let Rectangle = createBox(Shapes.Rectangle, fourCorners);
let Oval = createBox(Shapes.Oval, fourSides);
let Header = createBox(Shapes.Rectangle, twoSides);
let TextBox = createBox(Shapes.Rectangle, fourCorners);

代码的总大小减半,重复的部分也完全消失了!如此整洁。如果我们想要改变某个特定方向或形状的行为,我们可以在一个地方进行修改,而不是到处更新方法。

已经是深夜了(我太投入了)。我将我的重构代码提交到了主分支然后去睡觉了,为自己解开了同事混乱的代码而感到骄傲。

次日早晨

……并未如我所料。

上司找我进行了一次单独交谈,委婉地要求我撤销那次修改。我惊愕不已。旧代码一团糟,而我的代码整洁明了!

尽管心有不甘,我还是照做了。然而,我花了好几年才意识到他们是对的。

这只是一个阶段

对“清洁代码”痴迷、热衷于消除重复,是我们许多人必经的一个阶段。当我们对自己的代码缺乏信心时,往往会将自己的自我价值感和职业自豪感寄托于那些可度量的事物上。一套严格的代码风格规则、一种命名方案、一种文件结构、对重复的零容忍……

虽然无法完全自动化地消除重复,但随着练习,这一过程会变得愈发容易。通常情况下,每次修改后,你都能判断出代码中的重复是增多了还是减少了。因此,消除重复仿佛是在提升代码某个客观指标,给人以成就感。更糟糕的是,它还会影响人们的自我认知:“我是那种编写清洁代码的人”。这种错觉具有极强的迷惑性。

一旦我们掌握了创建抽象的能力,就很容易对此上瘾,只要看到重复的代码,就会迫不及待地从中抽离出抽象。经过几年编程历练,我们会发现到处都是重复——而抽象化正是我们的新超能力。如果有人告诉我们抽象是一种美德,我们会欣然接受,并开始评判他人不崇尚“清洁”。

我现在明白,那次所谓的“重构”在两方面都是一场灾难:

  • 首先,我没有与原作者沟通。我在没有征得他们意见的情况下重写了代码并提交。即便这算是一种改进(我现在已不再这么认为),这种方式也极其糟糕。一个健康的工程团队始终在建立信任。未经讨论就擅自重写队友的代码,将严重损害你们在代码库上的协作效率。
  • 其次,没有什么是免费的。我的代码牺牲了应对需求变更的能力,换取了减少重复,但这并非一笔划算的交易。例如,后来我们需要为不同形状的不同手柄添加许多特例和行为。若沿用我的抽象设计,实现这些变更会复杂数倍;而若是采用原先“杂乱”的版本,这些改动则轻而易举。

那我是否在建议你应该编写“脏”代码呢?并非如此。我想强调的是,当你谈论“清洁”或“脏乱”时,应当深入思考其含义。这些词语会让你产生反感、正义感、美感或是优雅感吗?你能否确切指出这些品质所对应的工程成果?它们又是如何具体影响代码的编写与修改方式?

我当初的确未曾深入思考这些问题,只是过分关注代码的外观,却忽视了它在一个由充满变数的人类组成的团队中如何演变。

编程是一段旅程。想一想从写下第一条代码至今,你已走了多远。第一次体验到通过提取函数或重构类让复杂代码变得简洁,想必令你欣喜不已。如果你对自己的技艺引以为豪,追求代码清洁自然颇具吸引力。那么,就先这样做一段时间吧。

但切勿止步于此。不要成为清洁代码的狂热信徒。清洁代码并非目标,而是我们在面对系统无尽复杂性时试图理清头绪的一种手段,是在面对未知领域、不清楚某项改动会对代码库产生何种影响时的导航工具。

让清洁代码指引你,然后适时放下它。

个人感言:clean code固然重要,但不可过度封装🙅‍♂️。

End

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTF-SHOW SSRF

web351 存在一个flag.php页面,访问会返回不是本地用户的消息,那肯定是要让我们以本地用户去访问127.0.0.1/flag.php web352 代码中先判断是否为HTTP或https协议,之后判断我们传入的url中是否含有localhost和127.0.0,如果没有则…

JAVA集合ArrayList

目录 ArrayList概述 add(element) 用法 add(index, element)用法 remove(element)用法 remove(index)用法 get(index)用法 set(index,element) 练习 test1 定义一个集合,添加字符串,并进行遍历&…

【JavaWeb】Day42.MySQL概述——多表查询

介绍 多表查询:查询时从多张表中获取所需数据 单表查询的SQL语句:select 字段列表 from 表名; 如果要执行多表查询,只需要使用逗号分隔多张表即可,如: select 字段列表 from 表1, 表2; 例如:查询…

解决mac本git安装后找不到命令的问题

不熟悉mac配置,折腾了半天,记录一下。 1.问题描述2.解决方法 1.问题描述 从https://sourceforge.net/projects/git-osx-installer/files/下载的git安装包: 安装时提示: 这里的解决办法是按住control键再打开文件安装。 安装完…

数据分析案例(一):地区收入的PCA主成分分析

练习1 地区收入的PCA主成分分析 0.变量说明 1.导包操作 核心思路:导入基础数据操作库包,PCA、k-means 库包,数据可视化库包 import pandas as pd import numpy as np from sklearn.decomposition import PCA from sklearn.preprocessing i…

补体系统研究解决方案BioPorto补体抗体

靶点研究新热点:补体系统 21世纪以来,人们对补体的认识从基于血液的抗菌素系统逐步转变为免疫和组织稳态的全局调节器。近年,对补体激活机制、结构、功能方面的研究更是取得了显著的进展,令补体系统研究跻身热门研究主题之一。 补…

基于SSM新疆旅游管理系统的设计与实现(内附设计LW + PPT+ 源码下载)

摘 要 随着经济的飞速发展人们对于旅游的热衷度也日益提升,新疆因特殊的地理优势具备了天然的旅游资源,天山山脉将新疆的地理区域划分为了南疆和北疆,北疆因气候湿润且河流草场较多造就了得天独厚的自然旅游资源,南疆沙漠广布且…

图像JPEG压缩(附python代码)

JPEG压缩是一种有损压缩技术,常用于数字图像。它通过减少图像文件大小来实现压缩,但会造成一定程度的图像质量损失。 目录 一、JPEG压缩1.1 JPEG压缩原理1.2 JPEG压缩优点1.3 JPEG压缩缺点 二、图像退化中加入JPEG压缩2.1 优势2.1.1 更逼真的模拟2.1.2 提…

OceanMind海睿思助力企业“数据入表”经济利益流入与生命周期管理

通过多年信息系统的建设与应用,企业积累了大量的数据。同时随着时间的推进,数据规模正以加速度快速增长。从国家到企业,都越来越关注所拥有的数据资源及其蕴含的深厚价值。很多企业已经逐渐认知到数据是重要的战略资源,数据资产化…

Acwing.3999 最大公约数(gcd欧拉函数)

题解 给定两个正整数 a,m&#xff0c;其中 a<m。 请你计算&#xff0c;有多少个小于 m 的非负整数 x满足&#xff1a; gcd(a,m)gcd(ax,m) 输入格式 第一行包含整数 T &#xff0c;表示共有 T 组测试数据。 每组数据占一行&#xff0c;包含两个整数 a,m 。 输出格式 每…

2024年第十四届MathorCup数学应用挑战赛C题解析(更新中)

2024年第十四届MathorCup数学应用挑战赛C题解析&#xff08;更新中&#xff09; 题目题目解析(更新中&#xff09;问题一问题二问题三 题目 C题 物流网络分拣中心货量预测及人员排班电商物流网络在订单履约中由多个环节组成&#xff0c;图1是一个简化的物流 网络示意图。其中&a…

UI自动化测试案例

备注:本文为博主原创文章,未经博主允许禁止转载。如有问题,欢迎指正。 个人笔记(整理不易,有帮助,收藏+点赞+评论,爱你们!!!你的支持是我写作的动力) 笔记目录:笔记本~笔记目录_airtest和selenium那个好用-CSDN博客 个人随笔:工作总结随笔_8、以前工作中都接触过哪…

Ansys Zemax | 如何将光栅数据从Lumerical导入至OpticStudio(下)

附件下载 联系工作人员获取附件 本文介绍了一种使用Ansys Zemax OpticStudio和Lumerical RCWA在整个光学系统中精确仿真1D/2D光栅的静态工作流程。将首先简要介绍方法。然后解释有关如何建立系统的详细信息。 本篇内容将分为上下两部分&#xff0c;上部将首先简要介绍方法工作…

如何处理ubuntu22.04LTS安装过程中出现“Daemons using outdated libraries”提示

Ubuntu 22.04 LTS 中使用命令行升级软件或安装任何新软件时&#xff0c;您可能收到“Daemons using outdated libraries”&#xff0c;“Which services should be restarted?”的提示&#xff0c;提示下面列出备选的重启服务&#xff0c;如下。 使用以下命令&#xff0c;能够…

【C】动态规划 之 多维最大最小路径和

总结一下这类题型的思路&#xff1a; 每一步所求的最优解 上一步的最优解 这一步的情况 1.数字三角形 主要思路&#xff1a; 1.到达每一个位置的最大和等于前一步最大和加上这一位置的值&#xff0c;而前一步要么是从左上下来&#xff0c;要么是从右上下来&#xff0c;这样…

如何应对app应用程序或者网站常见的几种攻击类型

大家好&#xff0c;我是咕噜铁蛋&#xff01;今天&#xff0c;我想和大家聊聊一个我们日常生活中经常遇到的问题——如何应对app或者网站常见的几种攻击类型。随着互联网的普及&#xff0c;app和网站已经成为我们获取信息、交流互动的重要平台。然而&#xff0c;这些平台也时常…

障碍物识别技术赋能盲人独立出行:一场静默的科技革新

作为一名资深记者&#xff0c;我始终关注并报道那些科技如何助力特殊群体克服生活挑战的动人故事。近期&#xff0c;一款叫做蝙蝠避障的应用进入了我的视线&#xff0c;它搭载先进障碍物识别技术以其独特的优势&#xff0c;悄然为视障人士的独立出行带来了显著变革。 “障碍物识…

MXNet安装:专业指南与深度解析

一、引言 MXNet是一个高效且灵活的深度学习框架&#xff0c;它支持多种编程语言和平台&#xff0c;并提供了丰富的深度学习算法和工具。随着深度学习技术的广泛应用&#xff0c;MXNet因其出色的性能和易用性受到了越来越多开发者和研究人员的青睐。本文将详细介绍MXNet的安装过…

基于yolov9来训练人脸检测

YOLOv9是一个在目标检测领域内具有突破性进展的深度学习模型&#xff0c;尤其以其在实时性与准确性上的优秀表现而受到广泛关注。针对人脸检测这一特定任务&#xff0c;YOLOv9通过其架构创新和算法优化提供了强大的支持。 YOLOv9在继承了YOLO系列&#xff08;如YOLOv7、YOLOv8&…

【数据结构与算法】二分查找算法

目录 二分查找算法什么是二分查找算法整数二分法常用算法模板 二分查找算法例题例题一&#xff1a;分巧克力问题例题二&#xff1a;M次方根 二分查找算法 什么是二分查找算法 枚举查找即顺序查找*&#xff0c;实现原理是逐个比较数组 a[0:n-1] 中的元素&#xff0c;直到找到元…