1.程序员的工作

很多时候,新手程序员对程序员工作的看法与经验丰富的程序员的看法完全不同。

初学者经常会说“程序可以运行,您还需要什么?”之类的话。有经验的程序员都知道,“能正常工作”只是对程序的要求之一,甚至还不是最重要的

代码可读性

最重要的是程序代码对其他程序员来说是可以理解的这比正确运行的程序更重要。多得多。

如果您的程序无法正常运行,您可以修复它。但是如果你有一个代码难以理解的程序,你就无法对它做任何事情。

只需将任何已编译的程序,如记事本,将其背景颜色更改为红色即可。你有一个可以工作的程序,但你没有可理解的源代码:不可能对这样的程序进行更改。

一个教科书示例是 Microsoft 开发人员从 Windows 中删除了 Pinball 游戏,因为他们无法将其移植到 64 位体系结构。他们甚至拥有它的源代码。他们根本无法理解代码是如何工作的

考虑每个用例

程序的第二个最重要的要求是考虑到每个场景。很多时候,事情比看起来要复杂一些。

新手程序员如何看待发送 SMS 消息:

一个正常工作的程序

专业程序员如何看待它:

一个正常工作的程序

“工作正常”的情况通常只是许多可能的情况之一。这就是为什么许多新手抱怨 CodeGym 的任务验证器:10 个场景中只有一个有效,新手程序员认为这就足够了。


2.异常情况

异常情况

任何程序的执行都可能出现异常情况。

例如,您决定保存文件但没有磁盘空间。或者程序正在尝试将数据写入内存,但可用内存不足。或者您从 Internet 下载图片,但在下载过程中连接断开。

对于每一种异常情况,程序员(程序的作者)必须 a)预见到它,b)决定程序应该如何处理它,以及 c)编写一个尽可能接近期望的解决方案。

这就是为什么程序在很长一段时间内都有非常简单的行为:如果程序中出现错误,程序就会终止。这是一个很好的方法。

假设您想将文档保存到磁盘,在保存过程中您发现磁盘空间不足。你最喜欢哪种行为:

  • 程序终止
  • 程序继续运行,但不保存文件。

新手程序员可能会认为第二种选择更好,因为程序仍在运行。但实际上并非如此。

想象一下,您在 Word 中输入了 3 个小时的文档,但在您编写过程的两分钟后,很明显该程序无法将文档保存到磁盘。损失两分钟或三个小时更好吗?

如果程序不能做它需要做的事情,最好让它关闭而不是继续假装一切正常。当程序遇到无法自行修复的故障时,它能做的最好的事情就是立即将问题报告给用户。


3.异常背景

程序并不是唯一面临异常情况的程序。它们也出现在程序内部——方法中。例如:

  • 一个方法想写一个文件到磁盘,但是没有空间。
  • 一个方法想要在一个变量上调用一个函数,但是这个变量等于 null。
  • 除以 0 发生在方法中。

在这种情况下,如果调用方法知道被调用方法中发生了什么样的问题,它可能会纠正这种情况(执行替代方案)。

如果我们试图将文件保存到磁盘并且这样的文件已经存在,我们可以简单地要求用户确认我们应该覆盖该文件。如果没有可用的磁盘空间,我们可以向用户显示一条消息并要求用户选择不同的磁盘。但是如果程序内存不足,它就会崩溃。

曾几何时,程序员思考这个问题并得出以下解决方案:所有方法/函数都必须返回一个错误代码,指示其执行结果。如果函数完美运行,它会返回0。如果不是,它返回错误代码(非零)。

使用这种处理错误的方法,在几乎每次函数调用之后,程序员都必须添加检查以查看函数是否以错误结束。代码的大小膨胀起来,看起来像这样:

没有错误处理的代码 带有错误处理的代码
File file = new File("ca:\\note.txt");
file.writeLine("Text");
file.close();
File file = new File("ca:\\note.txt");
int status = file.writeLine("Text");
if (status == 1)
{
   ...
}
else if (status == 2)
{
   ...
}
status = file.close();
if (status == 3)
{
   ...
}

更重要的是,发现错误发生的函数常常不知道如何处理它:调用者必须返回错误,而调用者的调用者将错误返回给调用者,等等。

在大型程序中,几十个函数调用链是常态:有时您甚至可以找到数百个函数的调用深度。现在您必须将错误代码从最底层传递到最顶层。如果在某个地方某个函数不处理退出代码,那么错误将丢失。

这种方法的另一个缺点是,如果函数返回错误代码,它们将无法再返回自己工作的结果。计算结果必须通过参考参数传递。这使得代码更加繁琐,并进一步增加了错误的数量。