程序员为什么要一直写bug ,不能一次性写好吗?

news2024/11/18 9:36:50

文章目录

      • 一、前言
      • 二、为什么要写bug
        • 1、程序员的疑问?
        • 2、bug产生的原因
        • 3、减少bug的措施
        • 4、程序员不是机器
      • 三、写代码的好习惯,减少80%的bug
        • 1、修改完代码,记得自测一下
        • 2、方法入参尽量都检验
        • 3、修改老接口的时候,思考接口的兼容性
        • 4、对于复杂的代码逻辑,添加清楚的注释
        • 5、使用完IO资源流,需要关闭
        • 6、代码采取措施避免运行时错误
        • 7、获取对象的属性,先判断对象是否为空
        • 8、手动写完代码业务的SQL,先拿去数据库跑一下,同时也explain看下执行计划
        • 9、调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点
        • 10、接口需要考虑幂等性
        • 11、多线程情况下,考虑线性安全问题
        • 12、主从延迟问题考虑
        • 13、使用缓存的时候,考虑缓存跟DB的一致性,还有(缓存穿透、缓存雪崩和缓存击穿)

一、前言

55年前,人类第一次的探月之旅“阿波罗”计划的成功,背后是超过30万名技术人员的努力、八年间耗资 250 亿美元的付出,更有 14.5 万行代码的运转支撑。人类每一次科技探索,几乎都始于一行行代码。

人类日常生活的运转,也离不开一行行代码,它在我们订外卖、线上挂号问诊、交通出行、上网冲浪获取信息的每时每刻。

在1996年,欧洲运载火箭Ariane 5在发射37秒后当场爆炸,一瞬间,70亿美元的开发费用、5亿美元的设备原地蒸发。这一切都由一个bug引起。

生活中用到的应用程序APP,可能会因为bug造成系统崩溃。而在诸如电力、交通、金融等关键基础设施领域,一旦出现“bug”,可能导致断电断水,我们日常出行、办公、生活都将受到影响。

一个项目运转通常包含成千上万行代码,涉及多个相互依赖的模块和子系统,往往“牵一发而动全身”。
在这里插入图片描述

二、为什么要写bug

1、程序员的疑问?

1.打高尔夫球为什么要打好几杆,不能一杆入洞吗?

在程序员眼里,
打高尔夫球简直是个超简单任务,
需求是明确的,
洞的位置是确定不变的,
资源是充足的,
球也有,
杆也有,
评价指标也是明确的,
进了或者没进。

2.为什么图纸经常会改,而盖好的楼几乎从来不改?

如果修改BUG像拆一栋楼一样代价高昂,
就不会出现经常改bug的现象了。

3.为什么写论文要反复修改,而不是一次写好?

其实这个反复修改本来就是写作的一部分。

正因为软件修改起来代价相对低,
所以改BUG本身就成为了写程序的一部分。
如果修改的代价过于高昂,
那要么会在动手之前投入大量的精力去反复讨论验证,
要么写成什么样都忍了。

在这里插入图片描述

软件开发是一个复杂且动态的过程,涉及到众多变量和不确定性。
尽管程序员努力编写高质量的代码,但bug是不可避免的。

2、bug产生的原因
  • 软件复杂性:随着软件系统变得越来越复杂,确保所有潜在交互都被考虑到变得更加困难。
  • 需求变化:项目需求的不断变化可能导致代码需要频繁更新,增加了引入bug的风险。
  • 时间压力:紧迫的截止日期可能迫使程序员在没有充分测试的情况下发布代码。
  • 人为因素:程序员可能会犯错误,这是人类活动的自然部分。
  • 技术限制:现有的工具和技术可能无法完全满足项目的需求。
  • 测试覆盖不足:没有足够的测试用例来覆盖所有使用场景。

在这里插入图片描述

3、减少bug的措施
  • 强化需求分析:确保需求被充分理解和文档化。
  • 代码复用:重用经过测试的代码模块。
  • 单元测试和自动化测试:为代码编写测试用例,并使用自动化测试来捕捉回归问题。
  • 代码审查:通过同事之间的代码审查来识别潜在的错误。
  • 持续集成/持续部署(CI/CD):自动化测试和构建流程,确保代码质量。
  • 性能测试:在不同的负载和压力下测试软件。
  • 用户验收测试:让最终用户参与测试,确保软件满足他们的需求。
  • 错误日志和监控:使用工具来快速发现和修复问题。
  • 培训和教育:提高程序员的技能和最佳实践的知识。

在这里插入图片描述

虽然完全消除bug是不现实的,但通过持续的质量改进和采用最佳实践,程序员可以显著减少bug的数量,并提高软件的整体质量。这需要程序员、团队和组织的共同努力,以及对技术和流程的不断投资和优化。

4、程序员不是机器

在这里插入图片描述
写bug、改bug、查bug贯穿程序员的整个职业生涯,消耗了开发工作中大量的时间精力,甚至还有金钱。

程序员是人,不是机器,人做事是主观判断性去做的,再加上“禀赋效应”:心里头自动地给自己写的代码添一层滤镜,觉得自己写的代码没有问题,所以程序员总找不出自己的Bug。

这导致程序员日常的第四件事是:挖坑填坑。有人大手一挥,一大段代码不写注释,或业务方法不用公共定义,不拆分类,一个方法写了一千行,从此没人敢动这些烂代码。也有人默默地“感谢”前任给他有活干,一点点地将坑填上。

还有对开发流程的漠视也是导致系统Bug多的原因。有开发心想“我只是改了两行代码,不影响业务流程”,心想提给测试太麻烦了,便自顾上线了。

结果线上就出Bug了。

所以公司才设定各种软件开发规范来减少Bug的产生,例如提测前开发之间的Code Review和需经过测试人员的测试才能上线。

程序不是一蹴而就地做出来的,Bug也不是一时半会能改完的。毕竟“写程序不像是造一座桥,而是造一座城。”

三、写代码的好习惯,减少80%的bug

在这里插入图片描述

1、修改完代码,记得自测一下

「改完代码,自测一下」 是每位程序员必备的基本素养。尤其不要抱有这种侥幸「心理:我只是改了一个变量或者我只改了一行配置代码,不用自测了」。改完代码,尽量要求自己都去测试一下哈,可以规避很多不必要bug的。

2、方法入参尽量都检验

入参校验也是每个程序员必备的基本素养。你的方法处理,「必须先校验参数」。比如入参是否允许为空,入参长度是否符合你的预期长度。这个尽量养成习惯吧,很多「低级bug」都是「不校验参数」导致的。

如果你的数据库字段设置为varchar(16),对方传了一个32位的字符串过来,你不校验参数,「插入数据库直接异常」了。

3、修改老接口的时候,思考接口的兼容性

很多bug都是因为修改了对外老接口,但是却「不做兼容导致」的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~

所以,如果你的需求是在原来接口上修改,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。

4、对于复杂的代码逻辑,添加清楚的注释

写代码的时候,是没有必要写太多的注释的,好的方法变量命名就是最好的注释。但是,如果是「业务逻辑很复杂的代码」,真的非常有必要写「清楚注释」。清楚的注释,更有利于后面的维护。

5、使用完IO资源流,需要关闭

应该大家都有过这样的经历,windows系统桌面如果「打开太多文件」或者系统软件,就会觉得电脑很卡。当然,我们linux服务器也一样,平时操作文件,或者数据库连接,IO资源流如果没关闭,那么这个IO资源就会被它占着,这样别人就没有办法用了,这就造成「资源浪费」。

6、代码采取措施避免运行时错误

(如数组边界溢出,被零除等)

日常开发中,我们需要采取措施规避「数组边界溢出,被零整除,空指针」等运行时错误。

7、获取对象的属性,先判断对象是否为空

因为平时空指针异常太常见了,一个手抖不注意,就导致空指针报到生产环境去了。

所以,你要获取对象的属性时,尽量不要相信「理论上不为空」,我们顺手养成习惯判断一下是否为空,再获取对象的属性。

8、手动写完代码业务的SQL,先拿去数据库跑一下,同时也explain看下执行计划

手动写完业务代码的SQL,可以先把它拿到数据库跑一下,看看有没有语法错误嘛。有些小伙伴不好的习惯就是,写完就把代码打包上去测试服务器,其实把SQL放到数据库执行一下,可以规避很多错误的。

同时呢,也用「explain看下你Sql的执行计划」,尤其走不走索引这一块。

9、调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点

调用第三方服务,或者分布式远程服务的的话,需要考虑:

异常处理(比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败);
超时(没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口);
重试次数(你的接口调失败,需不需要重试,需要站在业务上角度思考这个问题)。
简单一个例子,你一个http请求别人的服务,需要考虑设置connect-time,和retry次数。

10、接口需要考虑幂等性

接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是「用户连着点击两次」,你的接口有没有hold住。

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

一般「幂等技术方案」有这几种:

  • 查询操作;
  • 唯一索引;
  • token机制,防止重复提交;
  • 数据库的delete删除操作;
  • 乐观锁;
  • 悲观锁;
  • Redis、zookeeper 分布式锁(以前抢红包需求,用了Redis分布式锁);
  • 状态机幂等。
11、多线程情况下,考虑线性安全问题

在「高并发」情况下,HashMap可能会出现死循环。因为它是非线性安全的,可以考虑使用ConcurrentHashMap。所以这个也尽量养成习惯,不要上来反手就是一个new HashMap();

Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的;
Vector、Hashtable、ConcurrentHashMap等都是线性安全的。

12、主从延迟问题考虑

先插入,接着就去查询,这类代码逻辑比较常见,这「可能」会有问题的。一般数据库都是有主库,从库的。写入的话是写主库,读一般是读从库。如果发生主从延迟,很可能出现你插入成功了,但是却查询不到的情况。

如果是重要业务,需要考虑是否强制读主库,还是再修改设计方案;
但是呢,有些业务场景是可以接受主从稍微延迟一点的,但是这个习惯还是要有吧;
写完操作数据库的代码,想下是否存在主从延迟问题。

13、使用缓存的时候,考虑缓存跟DB的一致性,还有(缓存穿透、缓存雪崩和缓存击穿)

通俗点说,我们使用缓存就是为了「查得快,接口耗时小」。但是呢,用到缓存,就需要「注意缓存与数据库的一致性」问题。同时,还需要规避缓存穿透、缓存雪崩和缓存击穿三大问题。

  • 缓存雪崩:指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
  • 缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。
  • 缓存击穿:指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。

在这里插入图片描述

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

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

相关文章

SpringBoot3核心特性-快速入门

目录 传送门前言一、简介1、前置知识2、 环境要求3、SpringBoot是什么 二、快速体验1、开发流程2、特性小结3、Spring Initializr 创建向导 三、应用分析1、依赖管理机制2、自动配置机制2.1、初步理解2.2、完整流程2.3、如何学好SpringBoot 四、核心技能1、常用注解1.1、组件注…

Spring Boot的自动装配机制?(Spring Boot怎么完成自动装配的?)----面试常问

Spring Boot的自动装配机制?(Spring Boot怎么完成自动装配的?) 目录 一、概念版(重要) 二、实操版 1. 依赖管理 (pom.xml导坐标) 2. 自动配置类 2.1 SpringBootApplication 注解 2.2 EnableAutoConfiguration 2.3 Import({AutoCon…

基于node.js的宠物寄存管理系统,基于express的宠物寄存系统

摘 要 伴随着社会以及科学技术的发展,互联网已经渗透在人们的身边,网络慢慢的变成了人们的生活必不可少的一部分,紧接着网络飞速的发展,系统管理这一名词已不陌生,越来越多的宠物店等机构都会定制一款属于自己个性化…

2.8销毁窗口

目录 1.实验原理 2.实验代码 3.运行结果 1.实验原理 销毁某一个指定名称的窗口 destoryWindow 函数原型 Destroys a window.void destroyWindow(const string& winname);含义 功能: 销毁指定名称的窗口。 参数: const string& winname: 一个字符串&am…

香港租云服务器多少钱一台?

香港租云服务器多少钱一台?香港云服务器的租用价格因配置、带宽、服务等级等因素而异,从数百元到数千元不等。例如,入门级服务器的价格在数百元至一千元之间,适用于个人网站、小型博客等低流量应用。标准型服务器的价格在一千元至…

电商人必看!4招拿捏消费者心理,没有卖不出去的产品

在竞争激烈的电商领域,产品如何脱颖而出,成为消费者心中的首选,不仅依赖于产品的质量与性价比,更在于如何精准把握并巧妙运用消费者心理。今天,我们就来探讨4个关键策略,结合选品建议,帮助电商人…

欠债还钱 天经地义李秘书专业写作:这是一篇涉借款纠纷的民事起诉状

欠债还钱 天经地义 李秘书专业写作:这是一篇涉借款纠纷的民事起诉状 (精品范文) 民 事 诉 状 原告:李某军,男,现年46岁,无业,现住黑龙江省大兴安岭地区漠河市汉东路阳和门。 被告…

儿童可以用挖耳勺吗?六大挑选妙招需掌握!

耳垢会随着人体的运动量增加,1岁以下的儿童运动量较小,可以不用经常掏耳朵,但随着年龄增长,耳垢也会增多,这时可以适当地给儿童掏耳勺。但掏耳朵的工具要选对,目前市面上不少宣称是儿童专用的掏耳工具&…

汇凯金业:清洗黄金首饰的方法

黄金首饰,作为我们日常生活中常见的饰品,不仅能够提升我们的穿着品味,更彰显了我们的经济实力。然而,黄金首饰戴久了,难免会出现一些污渍,甚至失去原有的光泽。这时候,很多人会选择去专业的珠宝…

【MySQL】SQL语句执行流程

目录 一、连接器 二、 查缓存 三、分析器 四、优化器 五、执行器 一、连接器 学习 MySQL 的过程中,除了安装,我们要做的第一步就是连接上 MySQL 在一开始我们都是先使用命令行连接 MySQL mysql -h localhost -u root -p 你的密码 使用这个命令…

Qt (9)【Qt窗口 —— 如何在窗口中创建菜单栏和工具栏】

阅读导航 引言一、Qt窗口简介二、如何在窗口中创建菜单栏1. 创建菜单栏2. 在菜单栏中添加菜单3. 创建菜单项4. 在菜单项之间添加分割线 三、如何在窗口中创建工具栏1. 创建工具栏2. 设置停靠位置3. 设置浮动属性4. 设置移动属性 引言 在上一篇文章中,我们深入探讨了…

掌握 BM25:深入了解算法及其在 Milvus 中的应用

我们可以通过 Milvus 轻松实现 BM25 算法,将文档和查询转化为稀疏向量。然后,这些稀疏向量可用于向量搜索,根据特定查询找到最相关的文档。 信息检索算法在搜索引擎中非常重要,可确保搜索结果与用户的查询相关。 想象一下&#…

Vue2中watch与Vue3中watch对比和踩坑

上一节说到了 computed计算属性对比 ,虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时&#…

conda环境下在pycharm中调试scrapy项目

前提条件 已经创建好了conda环境已经安装好了scrapy框架项目初始化完成 编写一个爬虫脚本 import scrapyclass StackOverflowSpider(scrapy.Spider):name stackoverflowstart_urls [http://stackoverflow.com/questions?sortvotes]def parse(self, response):print("…

阿一网络安全实战演练之利用 REST URL 中的服务器端参数污染

所需知识 要解决这个实验室问题,您需要了解以下内容: 如何确定用户输入是否包含在服务器端的 URL 路径或查询字符串中。如何使用路径遍历序列尝试更改服务器端请求。如何查找 API 文档。 这些内容在我们的 API 测试学院主题中有涵盖。 进入实验室 研…

终极解决CondaValueError: Malformed version string ‘~’: invalid character(s)问题

conda 创建环境时出现: Solving environment: failed CondaValueError: Malformed version string ‘~’: invalid character(s)以下两种方法都不行时: 原因一: 添加的镜像源中,清华镜像源是https(错误)&a…

软件测试 - 测试分类(静态测试、动态测试、白盒测试、黑盒测试、灰盒测试、单元测试、集成测试、系统测试、验收测试等)

一、为什么要对软件测试进⾏分类? 软件测试是软件⽣命周期中的⼀个重要环节,具有较⾼的复杂性,对于软件测试,可以从不同的⻆度 加以分类,使开发者在软件开发过程中的不同层次、不同阶段对测试⼯作进⾏更好的执⾏和管理…

R语言管道操作详解-高效编程

引言 R语言是一种广泛应用于统计分析和图形表示的编程语言和软件环境。随着数据分析和数据科学的发展,R语言的管道操作符已经成为提高代码可读性和效率的重要工具。本文将详细介绍R语言中的管道操作符,包括它们的用途、语法和一些实用的示例。 目录 引…

手写签名怎么变成电子签名?

教大家一个快速生成有效电子签名的方法!(有效电子签名即通过正轨平台绑定了CA数字证书、防伪防盗的签名) 1.登录【微签】,点击【自己签】。 2.点【添加文件】,上传需要签名的电子文件(格式不限)…

一起学习LeetCode热题100道(46/100)

46.二叉树展开为链表(学习) 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历…