高级开发人员可以向初学者学习什么

发布于:2020-12-30 14:36:13

0

135

0

高级开发人员 初学者 学习

在过去的几年中,我与很多初学者一起工作并指导他们。虽然我显然见证了我在编程方面的不二之选,但是事情并没有看起来那么黑白。我在整个初学者中都一贯看到了几种模式和行为。尽管其中一些行为被误导和有害,但许多行为为高级开发人员提供了学习机会。与普遍的看法相反,有很多经验教训的人可以从经验较少的人那里学到,因为他们的观点是无偏见的(初学者的想法)。 

条件反转

我与初学者见过的最常见的反模式之一是我喜欢称之为“条件反转”的东西(它可能已经以更好的名字存在了)。使用分支语句控制或限制代码流时,可能会发生条件反转。以下是反码的示例:

function atleastOneOdd(potentialOdds) {   if (potentialOdds !== undefined) {      if (potentialOdds.length) {          return potentialOdds.some((num) => num & 1);     }   }   return false;  }

如果您认为上述代码对于完成这样一个简单的任务而言过于复杂,那么您并不孤单。感觉到的复杂性是嵌套的结果,因为嵌套极大地促进了代码的“感知到的复杂性”。这是功能上等效但可读性更高的实现:

function atLeastOneOdd(potentialOdds) {     if (potentialOdds === undefined) {       return false;   }   if (!potentialOdds.length) {       return false;   }   return potentialOdds.some((num) => num & 1); }

通常,更少的嵌套使代码更易于阅读和维护。与所有规则一样,总是有例外,因此请确保在做出决定之前先了解上下文。

知道什么时候看

重要的是要记住,不仅仅是初学者知道“更少”,还在于他们还没有对应该期望的东西产生直觉。经过一段时间的编码(不是字面意思),您对标准库和软件包中期望的逻辑粒度有了敏锐的认识。一个很好的例子就是我女友的情况。我的女友是计算机科学专业的学生,最近我就她为C ++作业编写的代码提供了一些反馈。作为作业的一部分,她需要检查给定的输入内容char 是否为字母。这大致是她的实现:

bool isLetter(const char someChar) {     const char letters [] = {     ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’,     ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’   };   int i = 0;     for (i = 0; i < 26; ++i) {         if (letters[i] === someChar) {            return true;     }   }   return false; }

我甚至不生气。这是一种直接而逻辑的实现。但是作为一名经验丰富的开发人员,本能告诉您,必须解决这一普遍存在的问题。实际上,我的直觉是利用c字符的数字性质,然后简单地检查输入字符是否在特定的ASCII az范围内。但是由于我的“编程直觉”,我怀疑对于这样一个普遍的问题,这仍然有很多工作要做。我告诉她Google是否可以检查char是否是字母。原来是isalpha-我可能已经使用了一百次,但是却不记得(在足够的编程中会发生的事情-您无法记住所有事情)。

对是否已经存在可以解决您的问题的事物形成直觉,对于成功作为开发人员至关重要。不论好与坏,增强直觉的唯一方法是用多种语言和范例编写更多的代码。

寻找最直接的解决方案

初学者在找到问题的直接或字面解决方案时绝对令人赞叹。仅以上isLetter 一节中的示例为例。虽然我女友的解决方案绝对不是最有效的解决方案(内存或计算明智的解决方案),但它非常干净,可以完成工作。尽管倾向于使用最强力解决方案的代价可能很高,但在大多数情况下,这实际上并不重要。我并不是说您应该把性能抛在脑后,而只能依靠蛮力解决方案,但是这里有个教训需要学习。要了解这一课,重要的是要了解初学者和专家之间的主要区别之一:他们想要达到的目标。 

初学者通常是通过编程来学习如何编程,而经验丰富的开发人员通常是通过编程来达到最终目的(工作,个人项目等)。在大学里,计算机科学老师很少给出有绩效要求的作业。这导致学生在学习编程时没有考虑到性能。刚开始时,这似乎在我们教人们编程的方式上有很大的不足,但是我实际上认为这是高等教育正确完成的少数事情之一。担心性能通常是一种非常致命的疾病的症状,这种疾病被称为“过早优化”。根据我的观察,一旦程序员开始担心性能,他们就很难停止。 

如果针对性能进行的优化不需要花费额外的时间,但是这确实不是问题。结合性能几乎无关紧要的事实(这是来自低级C / x86程序员)的事实,很清楚为什么总是针对性能进行优化是有问题的。这种效果是如此强大,以至于我实际上已经看到初学者比一个有能力和经验丰富的开发人员能够更快地找到一个可行的解决方案,这仅仅是因为初学者只关心使其能够正常工作,而高级开发人员则认为它必须表现良好。具有讽刺意味的是,即使大四学生完成了“表演者”解决方案,您也无法分辨他们与初学者之间的区别。

一切都必须是一堂课

我一直在初学者中看到的更令人沮丧的行为之一是无法在类范式之外进行编码。我将此归咎于每所只向学生介绍计算机科学程序Java的学院。我通常与语言无关,但是我总是发现“一切都必须是一个类”的要求是Java特别愚蠢的方面。我们明白了,Sun的某个人真的很喜欢OOP。这种迷恋的代价是20年后,Java仍在尝试将其自身重新组装成人们真正想要使用的语言。

要理解为什么这是一个实际问题,而不仅仅是对Java的抱怨,我们必须考虑初学者如何学习。初学者倾向于以呈现的粒度将概念内在化。因此,当他们使用诸如Java之类的语言来强制执行类范式时,他们倾向于理解最小的代码单元是一个类,并且期望每个变量都像一个对象。使用另一种面向对象的语言(例如C ++)将很快证明,最小的代码单元不必是一个类-为原始和无状态的逻辑编写整个类通常过于费力且麻烦。别误会,在现实生活中有很多情况需要这些语义和保证,实际上,这就是Java是最普遍使用的语言之一的原因。

问题在于,这些语义为初学者提供了误导性的描述。缩小Java世界时,您会注意到很少有编程语言是面向对象的。这就是为什么仅使用一种语言学习编程如此危险的原因。您不会最终学习编程,而是最终学习语言。 

当我与其他开发人员讨论了这种信念时,他们经常争辩说这些弊端实际上是弊端,因为Java避免让初学者冒充自己。对于那些需要雇用许多不受信任的程序员的《财富》 100强公司来说,这可能是一个很好的理由,但我们不应该向这样的初学者介绍编程。

强大的语法和结构

初学者往往比经验丰富的开发人员更依赖一致的语法和结构。考虑到人类是模式驱动的,并且代码语法和语义是模式最明确的示例之一,因此,一旦想到这一点,这实际上很有意义。对于有经验的开发人员,了解函数的功能(及其操作方式)通常是去定义其功能并阅读源代码。似乎无法想象不以这种方式运行,但是我几乎保证即使是最好的开发人员也不会以这种方式开始。模式匹配对人类的学习方式至关重要,以至于它远远超出了编程的范围。例如,众所周知,英语是最难学习的语言之一。

当我最近在帮助一个初学者编写一个内部状态相对复杂的C ++类时,就发生了一个实际的编程示例。根据类的目标/用途,使某些方法直接改变状态而其他方法返回副本是有意义的。在一起编写了很多方法之后,我离开了初学者自己编写其余方法。当我稍后返回时,我的学生没有取得太大进步,并告知他们被卡住了。具体来说,他们对于哪些方法正在改变状态而哪些方法没有使状态感到困惑。在这种情况下,有经验的开发人员不会遇到这种情况,因为他们只会查看方法的内部逻辑并确定状态是否正在发生突变。但是,初学者还不够流利,无法快速解析相同的逻辑(即使他们以前曾编写过),而是依靠代码的语法和结构。审查代码后,我意识到他们的挣扎部分是我的错。

当我们一起实现初始方法时,我确保可变性和不变性很好地结合在一起。我还没有意识到,这些方法给初学者带来了一种误导性模式。具体来说,每个可变方法都是void函数,每个不可变方法都具有返回类型。 

class MyType {  void addElem(int elem);    MyType createCopy();  ... };

我无意间教了我的学生一种在实践中显然不正确的模式。因此,在他们需要实现可变bool removeElem(int elem) 或不变的那一刻void printElems(),事情就崩溃了。我说这是我的错,因为在一天结束时,我很懒。作为一个经验丰富的开发人员,我对语法和结构的依赖不如我实际实现的逻辑要多。这很愚蠢,因为可以改进我编写的代码,以使初学者保持零歧义,并以几乎为零的成本消除潜在的错误。我是如何做到的?通过使用const关键字,这使我可以明确指出方法是否有可能改变状态:

class MyType {   void addElem(int elem);     bool removeElem(int elem);     void printElems() const;     MyType createCopy() const; };

忘记他人如何解释您编写的代码确实很容易。保持一致并利用语言功能,使您能够编写可消化的显式代码。 

结论

当您被介绍给更有效和可维护的解决方案时,您所接受和采用的许多初始模式都会被淘汰。话虽如此,我希望本文能够说明,有时即使是最有经验的开发人员也可以从一点“学习”中受益。虽然初学者可能对高级功能和语言特质不太满意,但是有时候当工作需要完成时,这是天赋。