(给
伯乐在线
加星标,看经典文章
)
来源:伯乐在线 - 周昌鸿
作者是Rails/Angular开发者,企业家& YC alum。早先创建了Clickpass.com网站并出售。目前担任Brojure.com的OTO(唯一O(only)TO),兼职entrepreneur first。
免责声明:这是一篇非常长的文章,比我通常会写的主题要长得多。我编辑文章并发给朋友评审,直到他们都觉得文章没有一字需要删改的。我希望你也这么认为。
如果有一件事是开发者都关心的,那就是成为更优秀的开发者。那你应该从哪里开始呢?你是否应该积累一些附加的卖点:比如专研Node知识和no-sequel?或者你应该死记硬背专业的网关问题答案,并能按要求立即写出冒泡排序算法和短连接算法吗?或者有其他更基本和关键的东西更值得你投入?
我相信,作为一个程序员的资历和价值并不是以你所知道的东西来衡量的,而是通过你做出多少成就来衡量的。这两者是相关的,但又有本质的不同。你的价值是你如何推动项目前进,如何鼓励你的团队也这样做。在我十五年的开发生涯中,我从来没有需要实现一个冒泡排序算法和短链算法。不过,我花费了成千小时来编写和重构账户管理工具,编辑套件,缓存逻辑,邮件接口,测试套件,部署脚本,JavaScript分层,分析架构和文档。这些都是有价值的事情,完成了这些事情推动了我们的前进。
那些微小的组件是构建项目的砖瓦和沙砾,需要成百上千小时的辛劳工作来组建。尽管它们被用来组装复杂系统,它们本身却不应该是复杂的。你应该将简化这些组件作为目标。多年来,我学会简单可以通过假以时日的不断工作和重构来达到,而这比纯粹“灵感一闪”的思考更容易得多。
简单和卓越通过一些事情或者任何可以让工作完成并从回头重新审视这样的过程来不断完善,这是最可靠的路径。这也是那些公司和MVP试图深入我们意识观念的真谛,软件也是如此。从一些可工作但丑陋的解决方案开始,你不断应用这个丑陋和怪异的方案,不断重构它为最简单的形式。简单从工作中比“灵光一闪”来得更为可靠。通过写代码比费力思索更加可预期。简单来自努力。
衡量一个开发人员的价值,不是通过你能达到的某个点的高度值,而是在于你表现线下的面积值。— Peter Nixey (@peternixey) April 22, 2014
对于聪明的懒人来说,他们可以轻易展现自己的卓越才华,亮瞎同龄人的双眼,然而公司却不能建立在这些人之上,产品也无法落实在那些“卓越的才华”上。公司是由那些每天进出办公室,提交良好的代码,并且也让其他人也干同样的事情的团队和个人。伟大的产品由勤奋的驭马驱动,而不是由那些盛装的舞步马推动的。
多年之前,Joel创造了“明星程序员”这个词多,它依赖公司对需要这样缺乏合作的极客来完成所有事情的误解。的确存在拥有这样特质的人,但是人数不多。你发现他们的聪明缺乏规律——让他们感兴趣的事情表现得惊人的聪明,然而在和其他人协作或与团队无缝合作时,又显得无法抱有期望。
他们的成果是无法预期的,但是他们的成就又让人艳羡,而且更具传染性。他们的傲慢可能伤及到团队的其他人员。它大声而且响亮地释放这样的信号:如果你够聪明,你可以选择你何时工作和你干什么。你成为了一个“Developer in Residence”。你不但吸取了薪水,也扭曲了你周围工作人员的价值。
所以现实是,你和你的团队更可能依靠或者说应该依靠于那些值得依靠并可靠工作的人,而不是那些自认为是“明星程序员”或者“编程忍者”的人。
卓越的开发者不是那些上手就可以写出冒泡排序或者短链接算法的人。他们是你一旦将其安排在项目中工作,就会不停推动和鼓舞周围每一个人来做到一样的人。让明星程序员滚蛋,雇佣那些可以驾驭的驭马(Fuck Rockstars. Hire workhorses),下面一些方法值得借鉴:
为你的函数和变量取个好名字(编写见名知意的代码)
这是一个难以置信的简单开始,但是我认为它是编程中最重要的技巧之一。函数命名是问题定义直接表现,坦白的说,是编程最难的部分。(编注:ITWorld 在2013年发起的一个投票,结果显示:《程序员最头疼的事:命名》)
名字是你代码的的边界条件,命名是你应该解决的首要问题。
如果你的命名是正确的,也解决了边界条件,使用这样的名称,你几乎不可避免编写出了高功能的代码。
考虑这样的函数:
def
process_text string
…
end
它几乎没有透露它准备做什么或者是怎么实现的,但是:
def
safe_convert_to_html string
...
end
它告知了接下来会发生什么,通过这个函数你可以预期它会完成什么,并且你可以多大程度重载这个函数。
开发者可能会很高兴重构一个“process_text”函数,同时将字符串转换为HTML标签并自动嵌入视频。不过,这在一些使用这些函数地方时可能是完全不期望的。一旦你改动了它,你就制造了bug。一个清晰的名称,不但保住函数会做什么,也表明了它不会做什么。
函数名称为函数和调用它们的代码之间创建了契约关系。好的命名定义了好的架构。http://t.co/6JMyGvGuzl
— Peter Nixey (@peternixey) April 22, 2014
一个好的函数,承诺了它会交付什么并如期望地交付了。好的函数和变量名称,不但使得代码更加清晰易读,也为你纵横交错的代码库建立了成千上万的约束。草率的命名意味着草率的约束,缺陷,甚至建立在它们之上更加草率的契约。
不仅仅是函数命名可以衡量你的代码质量,变量命名也应该加强。有时为了简化,值得创建一个变量名来自注释代码逻辑。
以下面的内容为例:
if
(
u2
.
made
10.minutes.ago
)
&& !
u2
.
tkn
&&
(
u2
.
made
==
u2
.
l_edit
)
...
糟糕的变量名称使得你很难弄清楚到底正在发生,甚至哪怕你这样做了(成功了),你也难以保证100%清楚原作者意图是做什么。它什么也没告诉你。
“and not”声明经常让人困惑(请永远不要编写“and not”与名称结尾的代码),如果你的工作是重构这样的代码,你不得不做一些复杂的猜测来推断它原始的含义。
不过:
if
(
new_user
.
created_at
10.minutes.ago
)
&& !
new_user
.
invitation_token
&&
(
new_user
.
created_at
==
new_user
.
updated_at
)
我们将这些变量修改为一些更有意义的名字,代码的含义立马就变得更清晰了:
user_is_recently_created
=
user
.
created_at
10.minutes.ago
invitation_is_unsent
= !
user
.
invitation_token
user_has_not_yet_edited_profile
=
(
user
.
created_at
==
user
.
updated_at
)
if
user_is_recently_created
&&
invitation_is_unsent
&&
user_has_not_yet_edited
_
profile
...
我们还可以进一步要求对 if 语句声明中的每一部分进行分离,命名组件并做文档注释。
需要一些勇气来写像“user_is_recently_created”的变量名,因为这样的命名逻辑模糊。不过我们时不时这样做了,并且承认这告知了代码阅读者你做了什么假设。
注意,这些方法比使用注释要更加有效。一旦你改变了代码逻辑就会要求你改变变量的命名,而使用注释却无法强制这一点。我很认同DHH,注释是危险的并且容易腐朽——最好是编写自注释的代码。
代码自注释越充分,其他人就更可能按照其初始的意图来实现它,代码也会有更好的质量。记住,在计算机科学中只有两类问题最难:缓存失效、命名和off-by-one错误。(我怀疑作者是写错了,这是三个…)。
“如果你想成为一个伟大的开发者,请确保你写的代码让人见名知意:也就是说代码精确地完成了它名字告诉的东西” http://t.co/6JMyGvGuzl
— Peter Nixey (@peternixey) April 22, 2014
在学习广泛之前先精深某一方面——从里到外学习你选择的技术栈。