我见过的最糟糕代码

2023-11-03

作者 | Mehdi Zed

在本文,将向读者展示一些作者见过的一些最糟糕的代码。除非你希望被同事和用户讨厌,否则这些“魔鬼”永远都不应该被放到人间。我们会发现,通过一些好的实践,其实很容易避免它们。

**

01”魔鬼代码“

需要改进的代码与所谓的“魔鬼代码”是不一样的。

不管使用的是哪种语言,“魔鬼代码”都是糟糕的代码,因为它会危及项目的稳定性和可维护性。告诉你,我见过很多“魔鬼代码”。

当它堆积如山时,你的项目很快就会变成十八层地狱的样貌。如果你喜欢到处捅娄子,那么团队领导看你的眼光也会越来越不一样。

**

02模棱两可和前后矛盾

很久很久以前,在一个遥远的星系中,我在一个清晨醒来,被世界末日般的景象吓得跳了一跳。

生产环境出了一个了不得的错误。生产中的所有系统票证莫名其妙地返回“null”。到处都乱成一团。所有人都像无头苍蝇一样到处乱跑。

我百米冲刺到我的工作站,第一个条件反射就是看 Kibana。没有日志,什么都没有。完蛋了,这可不是什么好的开始。
因此,我决定追溯票证的创建路径。

为此,我必须深入研究系统自盘古开天辟地以来创建的那些内部库。考古工作结束的时候,我找到了问题来源之一的一堆文件。

然后,我看到了这样的景象:

// use id and expire to get ticket
async function get_ticket(i, expire) {
  return CheckisNotExp(expire).then(async function() {
    var t = await GetTicketModel(i)
    if (t) {
      return t
    } else {
      logger.error(JSON.stringify(t))
      return null
    }
  }).catch(async function(e)  {
      logger.error(JSON.stringify(e))
      return null
})

}

真的有一个“i”变量吗?我们现在在哪?这是一个 id,对不对?它是整数还是 UUID?到底是什么到期了?是日期还是时间戳?为什么会有 camelCase、PascalCase 和 snake_case?带有 promise 的异步注解和又一个异步注解?如果失败,我们会返回 null?简直是魔鬼啊!

那时,每隔 5 分钟就有一半的公司同事向我发 Skype 消息,索取 ETA 修复。

所以首先,有人需要知道这里究竟发生了什么。

我很快意识到,该为此负责的不是一个人,而是三个人。很久以前,其中两个人离开了公司,而第三个人今天早上还没来。这真是经典场景。

根据 Git 的记录,这三个人碰这个文件的时间各自差了很久。因此他们留下了不一致的代码、不同的样式、不一样的 ECMAScript 版本和不同的 promise 处理方式。

不管怎样,在这段代码中,一切都是模棱两可的,一切都是不一致的。这是一个绝佳的反面案例,你应该尽一切可能避免这种情况。不用说,代码审查并没有覆盖到这里。

现在好了,我们必须快速重写它。

我得更改那些变量和函数的名称。不能再有歧义了。各处的 Async/Await 都要做成相同的方式。

我还要确保自己不会漏掉任何错误,结果再返回一个 null。如果出现了什么问题,这些错误肯定要破坏函数。异常应由上面的层来处理。

// hotfix
// @todo rewrite the ticket module entirely
async function getTicket(ticketUuid, ticketExpirationTimestamp) {
  await validTicketExpiration(ticketUuid, ticketExpirationTimestamp)
  const ticket = await getTicketByUuid(ticketUuid)

  return ticket
}

最好的解决方案是重写这个模块的一部分。这里的票证验证逻辑很糟糕。但这并不是最要紧的事情。

当务之急是找出并修复错误。

在更新代码后,真正的错误开始浮出水面。前一天所做的一个配置更改改变了票证创建行为。返回到先前的配置可以立即解决这个问题。

接下来的一周时间里,有问题的模块被完全重写。

**

03肉酱意面

只有一个依赖项

很久很久以前,在一个遥远的星系中,我正在做一个代码干净整齐的产品。

作为优质产品,一切都在内部做好了优化。功能是用尽可能少的代码开发的。代码高度重视可读性。由注重整洁代码的工程师管理的代码审查流程确保了产品严格遵循所有最佳实践。

SOLID、DRY、KISS、YAGNI 和你可以想到的其他首字母缩写词,这里都能见得到。

即使做到这个地步,这个产品的某个特殊部分也会间歇性地崩溃。在一个冲刺期间,我终于设法安排出了时间来调查这件事。

很快,我意识到问题不在于产品。那些错误只有一个共同点:一个依赖项。那是一个通过内部工件处理的内部依赖项。

它由另一个团队管理,而且——令人惊讶的是——这段代码不是免费提供的。你必须先获得许可才能看到它。因此,我请求了访问权限来了解到底发生了什么事情。

然后我收到了一条 slack 消息,问我为什么要访问源码。

“你好!为什么你需要访问这个存储库?”

“你是什么意思?你知道我在这里工作吗?等等,我在路上。”

我突然出现在他面前后,终于拿到了访问该项目的权限。

我在其中看到一个文件,大小为 300KB。300KB 的文本,竟然有那么大。它已经有好几年没人碰过了。上次碰过它的那个人,我完全不认识。

简直是最可怕的魔鬼。

那是我一生中见过的规模最大的意大利面条代码。篇幅所限,我并没有把所有代码都放在这里。下面的代码只是我看到的那一坨东西的冰山一角。

小心阅读,它读起来扎眼。


// Thousands of lines of spaghetti codes

if (global.Builder)
{
    module.exports.buildPgs = function(pgs, options, limitNodes = 0)
{
        var config = options.config || {};
        var builded = [];
        pgs.each(function(pg)
{
            var supported = pg.prop('tagName') == "INPUT"
                            && pr.attr['name'] == "file"
                            && options.pgs.rel.active == ""
                            && global.FileReader;
            if (!supported || !pg.f || pg.f.length == 0)
                return;

            for (var i = 0; i < pg.f.length; i++)
            {
                builded.push({
                    file: pg.f[i],
                    instanceConfig: _.extend({}, config)
                });

                if (isFunction(options.before))
                {
                    var returned = options.before(pg.f.path);
                    if (typeof returned === 'object' && global.status.in_progress)
                    {
                        if (returned.action == "skip")
                        {
                            var needsSkip = (typeof global.status.in_progress === 'boolean' && global.status.in_progress)
                                            || _.hasAny("cancel", Global._quotes.BAD_DELIMITERS)
                                            || str.indexOf(Global._delimiter) > -1;

                            if(needsSkip) return;
                        }
                        else if (typeof returned.config === 'object')
                        {
                            var LOCAL_BUILDER = new global.Builder("/builder/" + options.module + "/" + options.module + );

                            for(var s=p,a=p.matchIndex(o),shift=0,i=0;i<a.length;i++){
                                var deepcopyfile = JSON.parse(JSON.stringify(pg.f[i].getRawValue()));
                                LOCAL_BUILDER.build(deepcopyfile)
                                LOCAL_BUILDER.onmessage = global.Notification("buildPg", deepcopyfile);
                            }
                        }
                    }
                }
            }
        });
    }
}

// Thousands of lines of spaghetti codes

我甚至都没有尝试去碰这个恶魔之子。

在这里插入图片描述
在这类情况下,解决方案不是从代码中找出来的。我召开了一次小组会议,向他们解释具体情况。我的计划也很简单。

我们用一个已经可用的开源模块替掉了这个撒旦般的依赖项。与往常一样,这是一个大问题。必须做一些准备工作才能正确插入新的依赖项。

一开始的快速调查已经演变成持续几天的一项艰巨任务。

在会议桌那头,Scrum 主管很生气。讨论得越多,我越觉得想要不碰到该死的东西会非常困难。当我展示我们的处境后,讨论结束了,答案是不行。

“你只需要稍微动一动这个模块,把它修好就行了,然后我们会继续原本的工作。”

于是乎,我做了开发人员为代码质量和项目的可持续性应该做的额外工作。我说不行。我甚至走得更远。这是我职业生涯中的第一次,也是唯一一次,如果我被迫要辞职,我已经做好辞职的准备。

他们显然问了其他开发人员。大家都拒绝了。

由于这个问题的严重性,我争取到替换这个模块所需的时间。我为开源依赖项开发了一个小型适配器。然后我摆脱了那个被诅咒的依赖项。

此后,那个产品一切顺利,运行正常。

开发人员经常会抱怨意大利面条代码,这是有充分理由的。这是你能见过的最糟糕的代码。但无需大量投资即可确保你避免这种情况。

**

04驱魔

一开始,本文想写的是一个最佳实践的列表。

“作为开发人员,为什么以及如何应用最佳实践。”

不过上面这个标题很容易像大剂量安眠药一般令人昏昏欲睡,此外我出于两个原因更改了计划。

首先,对于我,特别是对你来说,先谈论后果会有趣很多。对开发人员来说,这很重要,因为这就是魔鬼代码的起源。此外,如果你可以为我的遭遇会心一笑,那也很好。

其次,互联网上已经有很多关于这个主题的文章。它们都有一个共同点,就是它们的内容都是从两本书中摘出来的。这两本书培养了几代开发人员。——罗伯特·马丁的《代码整洁之道》、史蒂夫·麦康奈尔的《代码大全》

你是否真的要缩短代码审查时间,并且再也不想搞出什么魔鬼代码?直接看原始资料就行,花点时间好好看完这两本书。

我发现《代码大全》的方法更易读、更实用。但是,尽管《代码整洁之道》非常复杂,但它教给我的知识不亚于甚至超过了《代码大全》。前者里面使用的代码是 Java 和 C++,但是谁在乎具体的语言呢?你在这本书里学到的是规则和编程理念。

用代码审查来验证代码是好事情。但是,如果你不确定为什么它是好的代码,那么到头来还是会出来你经历过的魔鬼代码。

                     —END—

更多精彩内容欢迎关注百度开发者中心公众号。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我见过的最糟糕代码 的相关文章

  • 一篇史上最全面的 Vue 代码风格指南,建议收藏

    作者 卡喵妹 https juejin cn post 6987349513836953607 一 命名规范 市面上常用的命名规范 camelCase 小驼峰式命名法 首字母小写 PascalCase 大驼峰式命名法 首字母大写 kebab
  • vscode配置setting.json文件实现eslint自动格式代码

    一 ESlint Vetur 实现ESlint代码规范 二 重点 旧版本 旧版本配置在setting json 会出现警告 eslint autoFixOnSave true eslint validate javascript langu
  • Source Insight (SI) 变量、函数、宏定义变成黑色,无法快速查看调用的几种解决方法

    Source Insight 变量 函数 宏定义变成黑色 无法快速查看调用的几种解决方法 方法一 同步SI与本地的代码 方法二 重构SI工程 其他解决方法 在source insight中 一般即使鼠标点在函数或者变量处 context w
  • 【python基础知识】15.编码基础知识

    编码基础知识 前言 编码 二进制 编码表 encode 和decode 前言 在你的网络冲浪生涯里 我想你或多或少有这样的疑问 为什么传说中只能读懂0和1的计算机能显示如此五花八门的内容 为什么明明办的100兆的宽带 撑死就只有10几兆的下
  • 《战狼》演习中到底是靠什么代码攻破对方的指挥系统?

    战狼 演习中到底是靠什么代码攻破对方的指挥系统 红蓝双方正在进行军事演习 开局 红方发动了手速buff 仅用时3秒 便成功入侵了对方了指挥网络 旗开得胜 接下来让我们好好学习一下这段代码 敲黑板 啊 这 C语言的气息 通过红框标注的prin
  • 【Java代码规范】阿里编码规约 VS CheckStyle

    全文速览 1 关于代码编码质量 2 如何小成本有效管理企业内的编码规范 2 1 阿里编码规约IDE插件 2 2 CheckStyle IDE插件 3 如何在代码提交中检验规范 3 1 阿里编码规约配置git precommit check
  • 代码质量(单元测试+代码审查)

    代码质量 1 单元测试 2 代码审查 1 单元测试 单元测试的目的 尽早在尽量小的范围内暴露错误 错误率恒定定律 一定量的代码 必然会产生一定量的BUG a 刚写完一个方法就发现BUG 修改只要几分钟 方法提供给其他人使用后 再发现BUG
  • Google Cloud API设计指南

    目录 一 基于资源的设计 什么是 REST API 设计流程 资源 方法 示例 Gmail API Cloud Pub Sub API Cloud Spanner API 二 资源名称 完整资源名称 相对资源名称 资源 ID 集合 ID 资
  • Sonar代码扫描常见规则总结

    Sonar代码扫描常见规则 最近公司项目交付 交付前集成 功能 性能 安全种种测试工作就来了 由于测试离职 被抓壮丁 兼职起测试修改工作 小公司 平时敲 ctrl c 代码 ctrl v 时 同事也不在意一些代码规范 以及一些常见的规约要求
  • 我接手前同事写的烂Java代码,不小心搞出了一个内存泄露事故

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 目录 String 字符串在内存里是如何存储的 String intern 方法 String 字符串是如何引发内存泄漏呢 总结 今天给大家聊聊咱们平时写代码的时候
  • PhpStorm添加PHP代码规范检查CodeSniffer(phpcs)和PHP代码静态分析工具Mess Detector(phpmd)

    首先需要了解一下这些工具是用来干什么 PHPCS 是 PHP Code Sniffer 一款代码规范检查工具 可以根据你的设置来检查代码规范性问题 PHPCBF 是PHPCS 内置的代码规范修复工具 大部分的代码规范问题它都可以自动修掉 P
  • PlatformIO - 静态代码分析(Static Code Analysis)

    关于 静态代码分析 相信大部分的嵌入式开发者或多或少在日常的开发中都有所了解 但可能在实际的开发中我们使用的并不多也不习惯通过工具对我们编写的代码进行静态扫描而是完全依赖于在开发板上运行然后基于运行结果来判断自己所编写的代码的好坏 是否有b
  • Python 乱码原理及其解决办法

    最近在爬虫过程中爬下来的HTML文件中出现了不认识的字符 也就是 乱码 之前也遇到了系统之间文件显示 乱码 的问题 花了点时间学习Python编码相关的问题 主要参考了以下几位的文章 Unicode编码底层描述 Python二进制数据 Py
  • 一个“程序员的自我修养”是什么?

    在 喜剧之王 中 周星驰扮演的尹天仇 一直梦想成为一名演员 而他不管是在扮演跑龙套 或者在街坊中开设演员训练班 亦或成为主角时 他对待演员的态度 始终是认真 热爱而又投入的 而那一本他随身携带的书 演员的自我修养 尽管不知道里面具体写的是什
  • 知识中台,驱动产业智能化升级

    随着人工智能技术的进步 智能化成为产业转型升级的关键抓手 但企业在提升数字化和智能化水平的实践过程中 面临多种挑战 如 移动应用的普及 带来异构数据呈几何级数增长 企业需要深度挖掘数据价值以赋能业务 以及传统 IT 系统缺乏智能化的技术手段
  • SonarQube 9.x集成阿里p3c代码规范检测java代码;

    文章目录 前言 一 下载p3c pmd插件 二 sonarqube配置使用p3c规则检测 1 新建质量配置 2 将创建好的p3c检测规则设置为默认质量配置 注1 注2 前言 因为我们公司后端主用的是java语言 在进行sonar代码检测的时
  • git 服务端钩子做代码检查

    需求分析 在代码修改后可以对代码进行检查 比如代码规范检查 代码构建 单元测试等 我们需要禁止成员推送不符合规范的代码到服务端 Git 钩子能在特定的重要动作发生时触发自定义脚本 钩子分为客户端和服务器端两类 使用客服端钩子可以在commi
  • 容器安全最佳实践入门

    作者 Cloudberry 译者 王者 策划 万佳 保证容器安全是一项复杂的任务 这个问题域很广 面对大量的检查清单和最佳实践 你很难确定采用哪个解决方案 所以 如果你要实现容器安全策略 应该从哪里开始呢 我建议从最基本的开始 理解容器安全
  • Java中的魔法值和解决方法

    目录 一 什么是魔法值 二 解决方法 一 什么是魔法值 魔法数值 魔法数字 魔法值 这是一个东西 不同的叫法 所谓魔法值 是指在代码中直接出现的数值 只有在这个数值记述的那部分代码中才能明确了解其含义 数字意义必须通过阅读其他代码才能推断出
  • 后台-husky提交代码规范使用

    husky是一个git hook工具 可以帮助我们触发git提交的各个阶段 pre commit commit msg pre push 1 如何使用husky呢 npx husky init npm install Windows安装不成

随机推荐

  • Rabbitmq的消息转换器

    Spring会把你发送的消息序列化为字节发送给MQ 接收消息的时候 还会把字节反序列化为Java对象 只不过 默认情况下Spring采用的序列化方式是JDK序列化 众所周知 JDK序列化存在下列问题 数据体积过大 有安全漏洞 可读性差 默认
  • 微信公众号H5页面(vue)跳转至微信小程序页面方案总结

    微信公众号H5跳转微信小程序方案总结 1 需求背景 最近由于发挥小程序的性能与用户体验优势 决定将微信公众号的部分功能跳转至小程序相关模块 解决方案 注意开放对象如下 已认证的服务号 服务号绑定 JS接口安全域名 下的网页可跳转任意合法合规
  • 使用腾讯云轻量服务器Matomo应用模板建网站流量统计系统

    腾讯云百科分享使用腾讯云轻量应用服务器Matomo应用模板搭建网站流量统计系统 Matomo 是一款开源的网站数据统计软件 可以用于跟踪 分析您的网站的流量 同时充分保障数据安全性 隐私性 该镜像基于 CentOS 7 6 64位操作系统
  • 【性能】Android中的内存溢出(Out Of Memory,OOM)

    性能 Android中的内存溢出 Out Of Memory OOM 1 JVM内存区域介绍 2 OOM形成的原因 3 造成OOM的有哪些 3 1 从JVM的角度 3 2 从具体使用角度 3 2 1 内存泄漏导致的内存溢出 3 2 2 资源
  • 【设计】低压差稳压器(LDO)的设计分析

    本简短教程介绍了一些常用的LDO 相关术语 以及一些基本概念 如压差 裕量电压 静态电流 接地电流 关断电流 效率 直流输入电压和负载调整率 输入电压和负载瞬态响应 电源抑制比 PSRR 输出噪声和精度 同时 为了方便理解 文中采用了示例和
  • WebStorm 初步使用 & HTML5 学习报告

    WebStorm 初步使用 WebStorm介绍 WebStorm是Jetbrains公司旗下的一款JavaScript开发工具 因其界面简洁 操作方便 被广大国内JS开发者誉为 Web前端开发神器 WebStorm具有智能代码补全 代码格
  • 宝塔面板部署Java项目

    宝塔面板部署Java项目 使用宝塔面板里面的 Java 项目管理器来进行部署 首先注意 1 tomcat7 8 9使用的端口依次是8081 8082 8083 安装的那个版本Tomcat就 开启对应的端口 2 该管理器项目不是部署在tomc
  • 【JMeter】RSA加密传参处理方法

    问题 登录请求参数中输入了正确的账号密码 响应结果报错 用户名或密码错误 原因分析 密码需要以RSA加密的方式传参 不能明文 解决方法 在该登录接口下新增一个 B e a n
  • UDP的抓包和网络协议

    背景 一直都在wireshar抓包 但是经常看的都是应用的报文 没有关注到udp的本身传输协议 所以花了一点时间查看了一下UDP的传输协议是什么样的 报文 这个是之前抓包的udp 的协议报文然后对应协议的字段进行协议 目前查看的话还是比较清
  • [编程题] 等差数列

    如果一个数列S满足对于所有的合法的i 都有S i 1 S i d 这里的d也可以是负数和零 我们就称数列S为等差数列 小易现在有一个长度为n的数列x 小易想把x变为一个等差数列 小易允许在数列上做交换任意两个位置的数值的操作 并且交换操作允
  • linux下使用socat

    其实网络协议比较简单 一般都是一个固定的套路 传 输 包 传 输 的 数
  • MES系统各部门评估建议

    生产部 如果期望通过项目推动来解决库存和交期的问题 需要首先针对我们最大的短板和痛点 供应商交期和品质 有针对性的改善 否则系统上了后也会因短板没有解决 无法实现最终目的 如果是为了解决目前制造部各单元计划协同性及准确性问题 以及针对急单插
  • Linux网络文件共享服务(一)存储类型和文件传输协议FTP

    成功不易 加倍努力 网络文件共享服务 本章总目录 1 存储类型 1 1 DAS存储 1 2 NAS存储 1 3 SAN存储 1 4 三种存储比较 2 文件传输协议 FTP 2 1 FTP工作原理介绍 2 2 常见 FTP 相关软件 2 3
  • 谈谈To B业务的难点

    最近有个说法 中国互联网的新增长点是 To B业务 而一个经常被提及的事实是 中美互联网巨头对比 在To C业务上的收益和市值近乎并驾齐驱 虽有差距 但至少是可以相提并论的 而在To B业务上 美国巨头的市场规模 比起中国的同类公司 高两个
  • STM32CubeMX之emWin移植

    前面两章介绍了SDRAM和LTDC的使用 本篇文章将介绍emWin移植到STM32 硬件环境 STM32F429IGT6 软件环境 STM32CubeMX v5 5 0 HAL库版本 STM32CubeF4 Firmware Package
  • 什么叫泛型?有什么作用?

    作者 Java3y 链接 https www zhihu com question 272185241 answer 366129174 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 一 什么是泛型 Jav
  • MySQL的B+树索引和hash索引的区别

    简述一下索引 索引是数据库表中一列或多列的值进行排序的一种数据结构 索引分为聚集索引和非聚集索引 聚集索引查询类似书的目录 快速定位查找的数据 非聚集索引查询一般需要再次回表查询一次 如果不使用索引就会进行全表扫描 还有可以进行多字段组成联
  • svn历史版本操作说明

    svn历史操作简写说明 操作的字母缩写为R 一般我们常见的操作为 A D M R A add 新增 C conflict 冲突 D delete 删除 M modify 本地已经修改 G modify and merGed 本地文件修改并且
  • centos安装gcc时出现问题:Delta RPMs disabled because /usr/bin/applydeltarpm not installed.

    解决办法 此问题安装Deltarpm包 增量 RPM 套件 即可解决 当然您也可以先使用一下命令 查看是哪个包提供applydeltarpm yum provides applydeltarpm yum install deltarpm y
  • 我见过的最糟糕代码

    作者 Mehdi Zed 在本文 将向读者展示一些作者见过的一些最糟糕的代码 除非你希望被同事和用户讨厌 否则这些 魔鬼 永远都不应该被放到人间 我们会发现 通过一些好的实践 其实很容易避免它们 01 魔鬼代码 需要改进的代码与所谓的 魔鬼