如何有效地提高编程(特别是debug)能力?

提高编程能力,特别是调试能力,是每位新手程序员提升能力的重点。以下是一些高效提升debug技能的方法:

理解你的程序

高效 debug 的前提是充分理解你自己的程序。每段代码负责什么工作、有哪些 corner case 的处理、对输入有哪些假设,等等。如果你对你的程序非常熟悉并充分理解,那可能大部分 bug 你看到症状之后一眼就能猜出个大概位置,这可以极大提升你的 debug 效率。对于比较 “业务” 的代码来说这一点尤其重要。对于算法/数据结构类的代码,bug 可能相对不那么容易一眼看出来。但充分理解你的代码依然可以指导你进一步收集信息。

编程语言通常会对常见的错误场景提供各类警示。以月兔为例,月兔会给我们提供很多的检查,例如,如果我们声明了一个标识符应当为变量,那么月兔会检查这个变量是否被修改,因为一种出错的场景就是在写循环的时候可能忘记对计数器进行迭代。

在这里插入图片描述

月兔会检查我们的返回值是否和类型声明相同。即使我们的返回类型声明的是单值类型,我们也不会主动地舍弃这些运算结果,而是需要我们手动添加声明来做到这个也是为了避免我们可能会漏写返回类型的声明。

在这里插入图片描述

虽然并不是每一个警示都需要被清除,但是审视警示信息可以减少代码发生错误的可能性,避免踩进大家都掉过的坑中。

学会收集信息

当一眼瞪不出 bug 的可能来源时,就需要收集更多的信息来辅助判断了。这部分主要是技巧的积累,这里推荐几个小技巧:

  • 崩溃类的 bug 通过 stack trace 可以快速定位
  • 优秀的 debugger 可以帮助你非常轻松的检视程序的中间状态
  • 大不了用最原始的 print debugging,除了写起来麻烦一些同样是获取信息的合理手段

当程序涉及的数据总量不大时,往往调试运行一次,收集一些信息就能够判断 bug 的成因了。但当程序涉及的数据量很大,难以逐一确认时,就需要运用对程序的理解,来尝试从大量数据中挖掘出不对劲的地方了。这其中非常常用而重要的一种,就是利用程序的性质来 debug。一段程序在正确运行时,在程序的不同位置,各种数据往往需要满足各种各样的性质(例如:二叉搜索树的左子树的元素永远应当比父节点小)。在程序没有 bug 时,这些性质是一定会得到满足的,因此为了效率我们并不会写代码去检查它们。然而,当程序出错时,往往就会有某个地方的性质被破坏了。此时,不妨插入一些代码,在程序的各个位置显式检查各种性质是否得到满足。这样可以快速地缩小 bug 可能的范围。

学会使用调试器等工具

除了插入代码以外,最高效的方式便是通过调试器在代码中添加断点,在运行中查看程序状态并实时计算。为此需要熟练掌握所使用的语言的调试器。例如,C语言对应的gdb等。MoonBit在开发模式的构建下同样可以利用调试器。目前,该功能已支持源码映射、基于源码设置断点、输出sourcemap等,在浏览器中进行源码调试。对于那些熟悉或正在学习MoonBit的开发者来说,使用调试器能够提高调试效率并更深入地理解MoonBit代码的运行过程。

MoonBit 现已支持在浏览器中进行源码调试

使用调试器允许我们在运行中看到实时的运行数据,更好理解运行过程。

!https://pic4.zhimg.com/80/v2-dd745a186bab5900eaa18f3c725233ab_1440w.jpg

写单元测试

测试代码有很多种方式,但其中最对 debug 最有用的无疑是单元测试。根据程序应当满足的性质,在每一处小模块都加入一些单元测试,往往能在更早的阶段发现 bug。而且单元测试的天性使得,当一个单元测试失败时,你马上就能知道 bug 的成因在哪、是程序的哪些性质没有得到满足。例如下面是在 moonbit 里写的测试:

fn iter_range(from :Int, to :Int, f : (Int) ->Unit) ->Unit {
  let mut i = from
  while i < to {
    f(i)
    i = i + 1
  }
}

fn sum(from :Int, to :Int) ->Int {
  let mut n = 0
  iter_range(from, to, fn{ x => n = n + x })
  n
}

fn assert_equal[T:Eq +Show](actual:T, expected:T) {
  if actual != expected {
    abort("assert_equal, actual: \\(actual), expected: \\(expected)\\n")
  }
}

test "sum 1 to 100" {
  assert_equal(sum(1, 100), 5050)
}

从测试结果我们很容易就能发现实际值比预期值少了100,于是很快就能定位到是第三行的while i < to {应该改为while i <= to {。

➜  mytest git:(master) ✗ moon test
inline test main ... FAILED
assert_equal, actual: 4950, expected: 5050
error while executing at wasm backtrace:
    0:  0x8ad - <unknown>!<wasm function 39>
    1:  0x8c3 - <unknown>!<wasm function 40>

Caused by:
    wasm trap: wasm `unreachable` instruction executed

debugging in the large

除了 debug 自己写的程序,在协作开发时,可能还需要 debug 别人写的代码。此时需要用到一些其他的技巧,例如:

  • 使用 git blame和二分调试快速找到某段代码是什么时候、由谁、为了什么目的引入的
  • 如果怀疑调用的他人的代码出错了,可以运用上面的、基于程序需要满足的性质调试的思路。在每次调用他人的代码时,检查结果是否符合预期、满足 API 要求满足的性质

希望这些建议对你有所帮助!

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值