“Keras之父”亲传,一个软件工程师的成长自查清单

创造了Keras的 Francois Chollet近期在博客上分享了他个人的提醒清单,老司机带我们少走弯路。

在开发过程中

代码不仅仅是为了被执行的,也是一种团队内共同交流的方式。我们可以使用代码来向别人描述问题的解决方案。代码的可读性包括清晰的分段,易懂的变量名,以及描述隐含内容的注释。可读性并不是锦上添花,而是写代码必备的属性。

不要去想这次工作对自己下一次升值有什么帮助,而要去努力思考可以为自己产品的用户和社区做些什么。不惜一切代价避免“显眼的贡献”。不是真正对产品有帮助的功能,就不要添加。

个人品味也会反映在代码上。品味是一种约束-在简单性的渴望将这种可约束性满足的品味变得系统化。请保持对简单性的不懈追求。

味道也适用于代码。品味是一种约束-对于过程的满足感和对于代码简约的欲望之间的平衡。请保持你对简约的倾向。

学会拒绝。如果有人要求给代码添加新的功能,我们有权利拒绝。实际上,每个功能的成本都超出了最初的设想:维护成本,文档成本和用户的认知成本。每当被要求添加代码功能的时候,记得问问自己:我们真的应该这样做吗?通常来说,答案是否定的。

当你决定为产品添加新的用例,需要注意的是,如果你按照用户请求的字面意思去添加内容,这样反而达不到最佳效果。用户专注于他们自己的特定用例,而你必须从项目的整体和原则来考虑。通常,我们应该扩展现有功能而不是增加一个非常零碎的模块。

以持续集成和全面的代码单元测试为目标做出投资。始终确保自己处于一个能够自信地编码的环境中;如果不能够拥有靠谱的环境,首先要去建立合适的基础设施。

你可以不用事事都提前做好准备。有时候可以先尝试一下,看看结果如何,然后尽早更改错误的尝试。确保你建立了一个可以执行上述一切的环境。

好的软件让事情变得简单。虽然问题看起来很困难,但是这并不意味着解决方案必须复杂或难以使用。很多时候,我们有一个更容易并且并那么耀眼的办法,工程师却会选择使用更加复杂的有副作用的解决方案(画外音:“让我们使用机器学习吧”!“让我们构建一个应用!”“让我们添加区块链!”)在编写任何代码之前,请确保自己选择的解决方案是最简单的。从简单第一的原则着手,给出解决方案。

避免一切隐含规则。如果你发现自己开发的代码中有一些隐含规则,请用注释注明并与他人共享或自动化。每当你发现一个可重复的,类似于算法的工作流程时,应该设法将其文档化,以便其他团队成员从你的发现中受益。此外,你还应该设法在软件中自动化该工作流程的任何部分(例如正确性检查)。

从整个产品的设计过程去考虑你代码改动将会带来的影响,而不仅仅是关注你想要的部分-例如收入或增长。除了你正在监控的特定指标之外,您的软件对全球用户的总体影响是什么?是否存在任何副作用?在保留软件实用性的同时,你可以做些什么来解决这些问题?

关于API(应用程序接口)设计

你的API拥有用户,因此涉及到用户体验。在你做出的每一个决定中,始终牢记用户。请设身处地去理解你的用户,无论他们是初学者还是经验丰富的开发人员。

尽量减少用户在使用API时的认知负担。自动化可自动化的内容,最大限度地减少用户所需的操作和选择量,不要暴露不重要的选项,设计简单一致的工作流程,以反映简单一致的心智模型。

把简单的功能保持简单,让复杂的功能变成可能。不要为了实现某个特定功能而增加常用功能的认知成本。

如果工作流的认知成本足够低,那么用户应该可以在完成一次或两次之后就可以记住(而无需再次查看教程或文档)。

寻求与领域专家和从业者的心智模型相匹配的API。有领域经验但没有API经验的人应该能够使用最少的文档来直观地理解你的API。他们主要会查看代码示例,可用对象及其签名。

即使没有关于底层实现的任何材料,参数的含义也应该是容易被理解的。而由用户指定的参数应该与用户对问题的心智模型有关,而不是与代码中的实现细节有关。API只和它解决的问题相关,而与软件如何在后台运行无关。

最强大的心智模型是模块化和层次化的:总体很简洁,当你查看细节时又很精确。同样,一个好的API也是模块化和分层的:易于着手,但具有表现力。在更少对象上使用复杂签名,和在更多对象上使用简单签名之间存在一个平衡。一个好的API具有合理数量的对象,而且具有合理简单的签名。

你的API不可避免地反映了你的实现选择,特别是你选择的数据结构。要实现直观的API,你必须选择自然适合该领域的数据结构。这与该领域专家的心智模型相匹配。

深思熟虑地去设计从始到终的工作流程,而不仅仅是一系列原子功能。大多数开发人员去开发API的时候,会通过询问“应该提供哪些功能?让我们为他们配置选项。”而不是,请问“这个工具有什么使用场景?对于每个使用场景,用户操作的最佳顺序是什么?什么是最简单的API可以支持这个工作流程?”API中的原子选项应该满足高级工作流程中出现的明确需求。“因为有人可能需要它”,并不是添加理由。

错误消息,以及通常在与API交互过程中向用户提供的任何反馈,都是API的一部分。交互性和反馈是用户体验不可或缺的一部分。设计API的错误消息请深思熟虑。

因为代码是为了交流,所以命名很重要-无论是命名项目还是变量。名称反映了你对问题的看法。避免过于通用的名称(例如“x,变量,参数”),避免过度长和特定的命名,避免可能产生不必要纠纷的术语(例如“奴隶主/奴隶”),并确保在命名选择中保持一致。命名一致性意味着内部命名一致性(例如,不要命名“轴”的时候既用“dim”又用“axis”),以及与问题域已建立约定的一致性。在确定名称之前,请确保查找域专家(或其他API)使用的现有名称。

文档是API用户体验的核心。它不是附加组件。花时间去撰写高质量的文件,相较于花时间在其他的功能上,你会看到更高的回报。

用"展示"代替"叙述":你的文档不应该谈论软件如何工作,它应该展示如何使用它。展示从头到尾工作流程的代码示例;显示API的每个常见用例和关键功能的代码示例。

给软件工程师职业生涯的建议

职业进步并不是你管理的人数,而是你所产生的影响:你的工作是否为世界带来改变。

软件开发是团队合作,人际关系和技术能力同样重要。做个优秀的队友。当你走在职业道路上时,记得与他人保持联系。

技术永远不会中立。如果你的工作对世界有任何影响,那么这种影响就有道德方向。我们在软件产品中看似无害的技术选择调整了技术获取的条件,技术的使用激励,谁将受益以及谁将受到影响:技术选择也是道德选择。因此,始终谨慎而明确地表达你想通过选择支持的价值观。为道德而设计并将你的价值观融入到你的创作中。永远不要想“我只是在建立这种功能,这本身就是中立的“:它不是,因为你构建它的方式决定了它的使用方式。

建立世界需要的东西,而不仅仅是你希望拥有的东西。很多时候,技术人员过着远离常人的生活,专注于满足自身特定需求的产品。寻求扩大生活体验的机会,让你更好地了解世界需求。

在做出有着长期影响的任何选择时,将你的价值观置于短期的自身利益和情绪之上,例如贪婪或恐惧。了解你的价值观是什么,并让它们指导你。

当我们发现自己陷入冲突时,暂停一下,承认我们的共同价值观和共同目标是个好主意,并提醒自己,我们几乎肯定是站在同一边。

生产力归结为高速决策和行动偏见。这需要:1.)来自经验的良好直觉,以便在给出部分信息的情况下做出大体正确的决定;2.)敏锐地意识到何时更谨慎地行事并等待更多信息,因为错误决策比延迟决策的成本更高。在不同环境中,最佳速度/质量的决策权衡可以有很大差异。

更快地做出决定意味着你在职业生涯中做出更多决策,这将使你对可能选项的正确性有更强的直觉。经验是提高生产力的关键,更高的生产力将为您提供更多的经验。这是一个良性循环。

在你意识到缺乏直觉的情况下,坚持抽象的原则。在整个职业生涯中建立可靠且正确的原则列表:原则是形式化的直觉,和原始模式识别(需要直接和广泛的类似情境经验)相比,可以推广到更广泛的情境。

标签: none