【翻译】再见, Clean Code!


鑫宝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.mzph.cn/news/819394.shtml

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

相关文章

var cannot be resolved to a type

var cannot be resolved to a type var 是JDK10的产物吧。真的是够懒的人,一个var自动转换类型。 高版本的功能又要放到低版本的平台系统中,【集成】,向下兼容天天改这些。

2024年山东三支一扶考试报名照片要求

2024年山东三支一扶考试报名照片要求

[大模型]internLM-Chat-7B FastApi 部署调用

internLM-Chat-7B FastApi 部署调用 环境准备 在autodl平台中租一个3090等24G显存的显卡机器,如下图所示镜像选择PyTorch–>1.11.0–>3.8(ubuntu20.04)–>11.3 接下来打开刚刚租用服务器的JupyterLab,并且打开其中的终端开始环境配置、模型下…

Github 2024-04-16Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10TypeScript项目1Vue项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次…

[spring] Spring Boot REST API - 项目实现

Spring Boot REST API - 项目实现 书接上文 Spring Boot REST API - CRUD 操作,一些和数据库相关联的注解在 [spring] spring jpa - hibernate CRUD 主要的 layer 如下: #mermaid-svg-QE1PR1gyrkz4XIT0 {font-family:"trebuchet ms",verdana…

[Linux][基础IO][二][缓冲区][理解文件系统]详细解读

目录 1.缓冲区0.缓冲区的刷新策略1.何为缓冲区?2.总结 2.理解文件系统0.文件元数据1.了解文件系统 --> 理解inode2.软硬链接 1.缓冲区 0.缓冲区的刷新策略 一般情况 立即刷新行刷新(行缓冲)满刷新(全缓冲) 特殊情况 用户强制刷新(fflush)进程退出 所有的设备&a…

conda配置多版本python

安装conda 以下任选下载 Anaconda Miniconda 配置conda环境变量 比如windows,在配置我的电脑中的环境变量,在系统变量的Path中新增下面内容 需要根据实际目录进行更改 D:\soft\miniconda3 D:\soft\miniconda3\Scripts D:\soft\miniconda3\Library\bi…

Java的Future机制详解

Java的Future机制详解 一、为什么出现Future机制二、Future的相关类图2.1 Future 接口2.2 FutureTask 类 三、FutureTask的使用方法四、FutureTask源码分析4.1 state字段4.2 其他变量4.4 构造函数4.5 run方法及其他 一、为什么出现Future机制 常见的两种创建线程的方式。一种是…

Python进阶编程 --- 2.MySQL、pymysql、PySpark

文章目录 第一章:SQL基础入门1.1 数据库数据库如何存储数据 1.2 数据库和SQL的关系1.3 MySQL版本1.4 命令提示符内使用MySQL1.5 SQL概述1.5.1 SQL语言分类1.5.2 SQL语言特性 1.6 DDL库管理表管理 1.7 DML - 数据操作1.8 DQL - 查询和计算数据1.8.1 基础数据查询1.8.…

HDFS Lease详解

本文主要介绍hdfs lease的设计以及实现。 写在前面 https://www.cnblogs.com/jhcelue/p/6783076.html https://blog.csdn.net/yexiguafu/article/details/118890014 https://www.jianshu.com/p/33e1a5a2b876 https://blog.csdn.net/breakout_alex/article/details/1014569…

行业模板|DataEase批发零售大屏模板推荐

DataEase开源数据可视化分析平台于2022年6月发布模板市场(https://templates-de.fit2cloud.com),并于2024年1月新增适用于DataEase v2版本的模板分类。模板市场旨在为DataEase用户提供专业、美观、拿来即用的大屏模板,方便用户根据…

【Canvas与艺术】绘制斜置黄色三角biohazard标志

【关键点】 径向渐变色和文字按角度偏转。 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>使用Html5/Canvas绘制…

spring-cloud微服务gateway

核心部分&#xff1a;routes(路由)&#xff0c; predicates(断言)&#xff0c;filters(过滤器) id&#xff1a;可以理解为是这组配置的一个id值&#xff0c;请保证他的唯一的&#xff0c;可以设置为和服务名一致 uri&#xff1a;可以理解为是通过条件匹配之后需要路由到&…

2024 CKA 基础操作教程(十二)

题目内容 考点相关内容分析 Pods Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。 Pod 是 Kubernetes 中的原子单元&#xff0c;用于封装应用程序的一个或多个容器、存储资源、唯一的网络 IP&#xff0c;以及有关如何运行容器的选项。Pod 提供了一个共享的…

一些实用的工具网站

200 css渐变底色 https://webgradients.com/ 200动画效果复制 https://css-loaders.com/classic/ 二次贝塞尔曲线 https://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html 三次贝塞尔曲线 https://blogs.sitepointstatic.com/examples/tech/c…

Day92:系统攻防-WindowsLinux远程探针本地自检任意执行权限提升入口点

目录 操作系统-远程漏扫-Nessus&Nexpose&Goby Nessus Nexpose 知识点&#xff1a; 1、远程漏扫-Nessus&Nexpose&Goby 2、本地漏扫-Wesng&Tiquan&Suggester 3、利用场景-远程利用&本地利用&利用条件 操作系统-远程漏扫-Nessus&Nexpose&a…

Python——详细解析目标检测xml格式标注转换为txt格式

本文简述了目标检测xml格式标注的内容&#xff0c;以及yolo系列模型所需的txt格式标注的内容。并提供了一个简单的&#xff0c;可以将xml格式标注文件转换为txt格式标注文件的python脚本。 1. xml格式文件内容 <size>标签下为图片信息&#xff0c;包括 <width> …

​​​​​​​iOS配置隐私清单文件App Privacy Configuration

推送到TestFlight后邮件收到警告信息如下&#xff0c;主要关于新的隐私政策需要补充&#xff1a; Hello, We noticed one or more issues with a recent submission for TestFlight review for the following app: AABBCC Version 10.10.10 Build 10 Although submission for …

servlet的三个重要的类(httpServlet 、httpServletRequst、 httpServletResponse)

一、httpServlet 写一个servlet代码一般都是要继承httpServlet 这个类&#xff0c;然后重写里面的方法 但是它有一个特点&#xff0c;根据之前写的代码&#xff0c;我们发现好像没有写main方法也能正常执行。 原因是&#xff1a;这个代码不是直接运行的&#xff0c;而是放到…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《应用图论建模输电网的电力现货市场出清模型》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…