三十年软件开发之路:老码农的自我修养!
声明:本文来自于微信公众号 CSDN(ID:CSDNnews),作者:Julio Biason,授权站长之家转载发布。
【CSDN编者按】“千帆过尽仍少年”,对于程序员来说,保留技术初心、不断提升实力是夯实自己的不二法则。而本文的作者,作为一名有着三十多年开发经验的“老”程序员,就在本文中详细总结了自己这些年踩过的坑和实践得出的真理,谈到了包括软件开发、团队工作、个人成长等方方面面。相信阅读本文后,会帮助你成为更优秀的程序员。
声明:本文已获作者 Julio Biason 翻译授权。
译者 | 王艳妮,责编 | 郭芮
以下为译文:
这是我 30 年来从事软件开发过程中所学到的一些实际经验,可能有些听起来愤世嫉俗,但都是我的切身经验之谈。
再次强调,有些内容真的是愤世嫉俗,有些则是对不同工作岗位的长期观察。
软件开发
先明确问题,再开始写代码
如果你不知道你想要解决的问题是什么,那你肯定就不知道要写些什么代码。在编写任何代码之前,先明确地把应用程序是如何工作的写下来。
“如果没有需求或设计,编程就是向空文本文件不断增加bug的艺术。”——Louis Srygley
有时,即使只是“电梯演讲”(指短时间内表述结果内容)那么长——用仅仅两个自然段来描述这个应用程序的功能——也足够了。
有时候我看着自己的代码发呆,不知道下一步该怎么做,其实往往是因为下一步本来就还没有被定义出来。一般出现这种情况,就意味着是时候停下来,与同事们讨论一下了——或者重新考虑解决方案。
将步骤写为注释
如果你不知道如何开始,请先用自然语言、英语或你的母语描述应用程序的流程,然后用代码填充注释之间的空白。比这更好的做法是:将每个注释视为一个函数,然后编写出能完全实现其功能的代码。
Gherkin是帮助你了解期望(expectation)的好帮手
Gherkin是一种测试描述格式,它指出“鉴于系统处于特定状态,当发生某些事情时,这是预期的后果”。即使你不使用任何能读取Gherkin的测试工具,它也会让你很好地理解应用程序的预期效果。
单元测试很好,集成测试更好
在我目前的工作中,我们只测试模块和类(例如,我们只为视图层编写测试,然后仅测试控制器层,依此类推)。它能让我们了解到某一部分有没有出错,但缺乏对整体的观察——而集成测试测试了整个系统的行为,在这方面会表现得更好。
测试可以让API更好
我们在不同层次中编码:有一个存储层,应该使我们的数据永久存储;有一个处理层,应该对存储的数据进行一些转换;有一个视图层,它有关于数据必须如何被展示出来的信息......等等。
正如我所提到的,集成测试感觉更好,但是单独测试不同层可以让你更好地了解其API。然后你可以更好地了解如何调用东西:API是否太复杂了?是否需要保留大量数据才能进行一次调用?
做你知道如何在命令行上运行的测试
也不是说命令行对于任何项目都很重要,但是当你知道运行测试的命令时,你就知道如何让测试的执行自动化起来,然后你可以在一个连续的集成工具中使用这些测试。
时刻准备好扔掉你的代码
很多人在刚开始使用TDD(测试驱动开发,Test-Driven Development)时,一旦被告知他们可能不得不重写很多东西,就会变得很生气。
TDD“旨在”扔掉代码:越了解你的问题,那么你就会越明白,无论你写了什么,从长远来看都无法解决问题。
所以你不应该担心这个。你的代码不是一面墙:如果你必须永远抛弃它,那也不是白白浪费了材料。当然这意味着你编写代码的时间一去不复返了,但是你现在对这个问题有了更好的理解。
好的语言生来带有综合测试
可以肯定的是,如果一种语言在其标准库中自带一个测试框架——即使小得不能再小——那么与没有测试框架的语言相比,它周围的生态系统仍将拥有更好的测试,无论该语言的外部测试框架有多好。
未来思路是垃圾思路
当开发人员试图解决问题时,他们有时会试图找到一种方法来一下解决所有问题,包括未来可能出现的问题。
但现实就是这样:未来的问题永远不会到来,你最终要么必须维护一堆永远不会被完全使用的庞大代码,要么得整个重新写,因为有一大堆屁用没有的东西......
解决你现在遇到的问题,然后解决下一个,然后再下一个。直到有一天,你会发现这些解决方案中显现出了一种固定的模式,然后你才能真正地“一次性解决所有问题”。
文档是写给未来自己的情书
我们都知道,为函数、类(class)和模块编写该死的文档是一个痛苦的过程。但是以后当你看到文档就能回想起来当时你编写函数时的思路,你就会明白将来文档能在关键时刻救你一命。
功能文档是份合同
当你以编写文档作为自己编程工作的起始点时,你实际上是在签订合同(可能是跟未来的自己):我说了这个函数要做这件事情,那么它就必须做这件事情。如果稍后你发现代码与文档不匹配,那你就是代码出了问题,而不是文档出了问题。
如果一个函数的描述包含“和”,这就是不对的
一个函数应该且仅应该做一件事,真的。当你编写函数文档并发现你写了“和”这个字的时候,这意味着该函数不仅仅是做一件事。那么就需要将该函数分解为两个独立函数并删除“和”。
不要使用布尔型变量作为参数
当你设计一个函数时,你可能会想要添加一个flag——不要这样做。
现在,让我给你举个栗子:假设你有一个消息传递系统,并且有一个函数可以将所有消息返回给用户,称为getUserMessages。但有一种情况是需要返回每条消息的摘要(例如,第一段)或完整消息,因此,你添加一个名为retrieveFullMessage的flag/布尔参数。
再说一次,不要这样做。
因为任何读你代码的人都会看到getUserMessage(userId,true)并想知道这里的true到底是个什么意思。
你可以将函数重命名为getUserMessageSummaries并使用另一个getUserMessagesFull或类似的东西,但每个函数只调用原始的getUserMessage为true或false——但是类/模块外部的接口仍然是清晰的。
但是一定“不要”在函数中添加flags / Boolean作为参数。
注意界面的变化
在上面几点中,我提到了重新命名函数的问题,如果你能控制使用该函数的整个源头,那就不算是问题,只需要搜索和替换即可。
但是,如果该函数实际上是由库公开的,那么你不能随便地更改函数名称。这将打破你无法控制的许多其他应用程序,并惹恼其他人。
你可以通过文档或某些代码功能创建新函数并将当前函数标记为已弃用,然后,经过几次释放后,你终于可以Kill掉原来的函数了。
(你可以做的一个有些混蛋的举动是创建新函数,将当前函数标记为已弃用,并在函数开头添加一个休眠,这样一来使用旧函数的人会被迫更新。)
好的语言自带集成的文档
如果语言有自己的方式来记录函数、类、模块或其他,而且带有一个哪怕最简单的文档生成器,你就可以确切知道所有的函数、类、模块、库、框架都具有良好的文档了(不是说一定特别好,但至少是比较好的)。
大多数情况下,没有集成文档的语言,文档方面做得都不怎么样。
一门语言绝不仅仅是一门语言而已
编程语言就是你写的、而且能做事情的东西,但在特殊关键词以外它还有很多别的东西:它有一个构建系统,它有一个依赖控制系统,它有一种使工具/库/框架互动的方式,它有一个社区,它有一种与人打交道的方式。
不要仅仅因为一种语言容易使用就选择它。永远记住,你可能因为一种语言的语法很简明而支持这种语言,但是与此同时你也是在支持维护人员对待这个社区的方式。
著作权归作者所有。
<