为什么不能一次性写好代码,而需要改bug?

3,876 阅读5分钟

小姐姐: 你上班一般做些什么?

程序员: 我上班一般写 bug...

虽然程序员自嘲自己是写 bug 的,大家都是希望自己程序无bug 的。

首先来看看 Bug 的由来,

"Bug" 一词最早可以追溯到计算机科学的早期。1947 年,美国计算机科学家格蕾丝·霍普(Grace Hopper)在哈佛大学的 Mark II 计算机中发现了一只飞蛾卡在继电器中,导致计算机无法正常工作。她将这只飞蛾贴在日志本上,并写道:“First actual case of bug being found”(首次发现实际的 Bug)。从此,"Bug" 一词被广泛用于描述计算机系统中的错误。

"Bug" 通常指软件、硬件或系统中的错误、缺陷或故障。它的来源一般有复杂性问题、编程错误、设计缺陷、需求误解、环境问题、时间压力等。

一、技术篇

1.1、软件开发并不简单

软件开发本身就是一个非常复杂的过程。一个软件系统可能包含成千上万行代码,涉及多个模块和功能。

下图是历史上最庞大的代码库代码行数,排在最下面的是 Google:

  • Google 全家桶代码行数大概在:20亿左右
  • 微软 Windows11 代码行数在:1亿左右

即使是最有经验的程序员,也很难在第一次写代码时就考虑到所有可能的情况。比如,用户可能会输入一些奇怪的数据,或者在某些极端情况下系统会崩溃,这些都需要在开发过程中逐步发现和修复。

假如一个简单的计算器代码,也就是加、减、乘、除的功能,以下的代码感觉已经比较完善了。

def calculator():
    print("欢迎使用简单计算器!")
    
    # 获取用户输入
    num1 = float(input("请输入第一个数字: "))
    num2 = float(input("请输入第二个数字: "))
    operation = input("请选择操作 (+, -, *, /): ")
    
    # 执行操作
    if operation == '+':
        result = num1 + num2
    elif operation == '-':
        result = num1 - num2
    elif operation == '*':
        result = num1 * num2
    elif operation == '/':
        result = num1 / num2
    else:
        result = "无效的操作"
    
    # 输出结果
    print("结果是:", result)

# 调用计算器函数
calculator()

但是如何用户输入

  • 用户输入非数字:如果用户输入的不是数字,程序会崩溃。
  • 除以零:如果用户选择除法并且第二个数字是零,程序会崩溃。

这时就会产生 bug,就需要修改 bug 了。以下是修改后的 代码:

def calculator():
    print("欢迎使用简单计算器!")
    
    try:
        # 获取用户输入
        num1 = float(input("请输入第一个数字: "))
        num2 = float(input("请输入第二个数字: "))
        operation = input("请选择操作 (+, -, *, /): ")
        
        # 执行操作
        if operation == '+':
            result = num1 + num2
        elif operation == '-':
            result = num1 - num2
        elif operation == '*':
            result = num1 * num2
        elif operation == '/':
            if num2 == 0:
                result = "错误: 除以零"
            else:
                result = num1 / num2
        else:
            result = "无效的操作"
        
        # 输出结果
        print("结果是:", result)
    
    except ValueError:
        print("错误: 请输入有效的数字")
    except Exception as e:
        print("发生了一个错误:", e)

# 调用计算器函数
calculator()

即使修复了上述问题,程序仍然可能存在其他潜在的 bug或边界情况。比如输入超长数值、输入负数(当前程序员有考虑到负数)等等。

除了软件本身存在的复杂度来说,还有另外一些因素。

1.2、软件需求不完善或误解

软件需求根据产品人员、业务复杂度相关,随着项目的深入和产品的熟悉,认知加深,会发现需求不完善的问题,此时需求需要完善。这就意味着程序员需要不断地调整代码,以满足这些变化。即使需求没有变,开发者对用户需求的理解有误,导致开发的功能与用户期望不符。

1.3、Bug 发现者

一般来说发现 bug 最多的应该就是测试。虽然测试是发现Bug的重要手段,但测试覆盖率永远不可能达到100%。程序中有无数的分支也就是无数的可能性,开发自己单元测试都可能无法覆盖 100%。再加上用户硬件、系统、网络及数据都会有差异这个覆盖 100%就更难了。随着经验的积累,自动化测试和手动测试只能覆盖一部分场景,很多Bug只有在实际使用中才会暴露出来。所以,即使测试通过了,也不代表代码就没有问题。

1.4、代码质量

代码质量也是一个问题。为了赶进度,程序员可能会写一些“临时性”代码,这些代码可能在短期内有效,但随着项目的扩展,可能会引发新的Bug。这就需要程序员在后续的开发中逐步优化和修复。

另外如在并发的业务中开发人员使用了 Java HashMap 在多线程环境下是非线程安全的,如果多个线程同时修改同一个 HashMap,可能会导致数据不一致 使业务异常。这种 Bug 与开发者的经验与能力都有关联。

1.5、 编程语言Bug

某些编程语言本身的设计可能存在缺陷,导致某些操作的行为不符合预期。所以程序语言也在不断的升级和更新。


二、白话篇

如果你不是程序员,可能不太理解为什么写代码这么麻烦。其实,我们可以用一些生活中的例子来解释。

比如软件开发就像盖房子。即使你设计得再好,房子建成后,你可能会发现某些地方需要调整,比如水管漏水、电线布局不合理,或者房间的采光不够好。软件开发也是一样,即使程序员设计得再完美,总会有一些小问题需要修复。

软件是由成千上万行代码组成的,就像一张巨大的拼图。即使拼图的每一块都正确,拼在一起时也可能出现缝隙。Bug就是这些缝隙,程序员的工作就是找到并修复它们。让它不断更新和改进,随着技术的进步和用户需求的变化,软件也需要不断升级,修复Bug并添加新功能。

我是栈江湖,如果你喜欢此文章,不要忘记点赞+关注