在过去的7年半时间里,我指导了十几个软件实习生,看了上百个学生和研究生档案。我发现他们需要学习的东西很多。也许你会说,我这不是在讲具体的技术、算法、数学或者其他具体形式的知识吗?是的,这确实是需要学习的东西,但不是最重要的。他们最需要学习的是“自我调节”。这些规范是:尽可能编写最简洁的代码;如果后面的改动导致代码变得凌乱,就得重构;尝试删除无用的代码并添加注释。我花了很多时间督促这些实习生学习这些东西。我经常问他们如何成为一名优秀的程序员,他们通常回答说代码应该清晰易懂和易于维护。这正是我想听到的,但很少有年轻的程序员能够真正始终如一地做到这一点。请牢记这一点,理解“自我调节”,一旦代码“起作用”就不要忘记它。如果所有的变量都命名错误,但代码仍然完美运行,那代码绝对是乱七八糟的,不堪入目。将功能代码改进为干净的代码可能不会在短期内得到回报:代码已经可以工作,并且在清理后仍然可以工作。这就是为什么你需要“自我调节”的步骤。这就是实习工作如此必要的原因:一个好老板是非常有代码意识的(即使每个程序员对“好代码”的定义都不一样),从而迫使实习生和初级程序员不得不反复修改。下面是新手程序员在编写代码时经常出现的一些例子:函数/变量/类的命名错误这些函数、类和变量实际上与它们的名字所表达的意思不符。片面看名字是对的,但从实际来看,有些甚至是无关紧要的。比如我上一个实习生写了两个类:EditorGUI和EditorObjectCreatorGUI。处理编辑界面的代码。让我哭笑不得的是,EditorGUI是用来创建新对象的,而EditorObjectCreatorGUI只能通过处理不同的对象来导航。两者的意思其实是完全相反的!尽管代码相对简单,但我花了很长时间才理解它,因为一开始我是在完全相反的假设下做的。这种情况的解决方法很简单:将EditorObjectCreatorGUI重命名为EditorObjectNavigationGUI即可,这样更容易理解。我见过很多这种情况。发生这种情况是因为代码在工作过程中不断演变。起名字的时候可能还没错,但是一写代码,名字就名不副实了。关键是记住术语。你必须了解你添加的东西是否仍然匹配函数和类名。杂乱的类另一个问题是类是杂乱的:类做很多不相关的事情。添加新功能很简单,但是慢慢地,你会发现你的代码变得臃肿,各种无关紧要的功能随处可见。有时膨胀与类大小无关:一个类可能只有几百行长,但仍然包含不属于它的代码。为什么会这样?举个例子:假设出于某种原因,一些GUI类需要分析可用的纹理(可能有选择纹理的按钮)。如果此GUI类是唯一需要此分析结果的类,那么在GUI类中执行此操作是有意义的。然而,出于某种原因,完全不相关的游戏类也需要此信息。因此,您需要将这些纹理查找信息从GUI类传递到游戏类。这个时候,其实这个GUI类已经变大了:因为它实际上包含了TextureAnalyser类。解决方案也很简单:将TextureAnalyser类拆分为一个单独的类,供GUI类和游戏类使用。许多人质疑这个经验法则:如果我添加的功能仍然符合原始类名怎么办?如果不合适,我是否必须重命名它,或者将其拆分为一个单独的类,或者将其编码为一个不同的类?如果你不能为你的班级想出一个合适的名字,它会让人感到不舒服。如果你不能在它的名字中描述一个类的用途,它看起来会很乱。有时我们还需要将一个臃肿的类分成几个部分,并给每个部分起一个合适的名字。过大的类这有点类似于前面的一点——杂乱的类:很多东西被一点一点地添加到类中,然后它不可避免地变得臃肿。在这种情况下,这样的类仍然有意义,但太大了。如此庞然大物,不仅笨重,而且容易出bug,因为操作同一个私有成员变量需要使用大量的代码,所以我们很容易忽略一些细节。拆分一个已经长大的班级实际上非常乏味。如果类中的代码高度交织在一起,这也会成为一个挑战。此外,它已经在工作,并且在修复期间不能添加新功能,所以我不得不说拆分一个太大而无法严格自我调节的类是不可行的。根据Ronimo的一般经验,将类保持在500行代码以下,将函数保持在50行代码以下是最合适的。然而,有时这样做既不可行也不明智。但一般来说,一旦一个类或函数超出了那个边界,我们就可以想办法重构它,将它拆分成更小、更易于管理的部分。关于代码注释几乎所有示例代码都会包含注释代码片段,但不会解释原因。此代码是否需要修复?旧代码是否已被替换?为什么这些代码写在那里?大家都知道,没有注释的代码往往不知道该说些什么,但不知为何,很多人却忘记了对自己的代码进行注释。并行逻辑和代码重复的另一个问题是我经常在几个代码段中看到类似的逻辑。例如,我们可以从纹理的名称中知道它大概的目标对象,比如“TreeBackground.dds”。要知道纹理是否可用于树,我们检查文件名以查看它是否以“树”开头。也许使用SDK我们可以通过filename.beginsWith("tree")快速检测到它。只是这段代码太短了,我们经常选择需要的地方,直接复制粘贴即可。当然这是重复代码,大家都知道应该避免重复代码,但是如果复制的代码太短,我们往往会忘记这一点,直接复制。我们这里面临的问题也很明显:也许我们检查某个纹理是否适合树的方式稍后会改变,然后我们必须执行“shotgun修改”(即到处修改)策略,一个一个地面修复。这里的一般规则是,如果它是非常具体的代码,请不要复制它。即使原代码超短,调用一个函数比直接写代码需要更多的代码,还是应该封装成一个函数。上面讨论的内容已经解释的很透彻了。你甚至在大学里学到了很多内容。但现在的挑战是,你需要一步步养成习惯,从被动遵从到主动背诵。这也是为什么在Ronimo实习生最重要的不是学习知识,而是学习自我调节。
