04月 16, 2013

【名词解释】Currying:因为是美国数理逻辑学家哈斯凯尔·加里(Haskell Curry)发明了这种函数使用技巧,所以这样用法就以他的名字命名为Currying,中文翻译为“加里化”。

我感觉很多人都对函数加里化(Currying)和偏函数应用(Partial Application)之间的区别搞不清楚,尤其是在相似的上下文环境中它们同时出现的时候。

偏函数解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值。

几乎所有编程语言中都有非常明显的偏函数应用。在C语言中:

int foo(int a, int b, int c) {

return a + b + c;

}

int foo23(int a, int c) {

return foo(a, 23, c);

}

foo23函数实际上就是一个foo函数的偏函数应用,参数b的值被固定为23。

当然,像这样明显的偏函数并没有太大的用处;我们通常会希望编程语言能提供我们某些偏函数特征。

例如,在Python语言中,我们可以这样做:

from functools import partial

def foo(a,b,c):

return a + b + c

foo23 = partial(foo, b=23)

foo23(a = 1, c = 3) # => 27

函数加里化(Currying)明显解决的是一个完全不同的问题:如果我们有几个单参数函数,并且这是一种支持一等函数(first-class)的语言,如何去实现一个多参数函数?函数加里化是一种实现多参数函数的方法。

下面是一个单参数的Javascript函数:

var foo = function(a) {

return a * a;

}

如果我们受限只能写单参数函数,可以像下面这样模拟出一个多参数函数:

var foo = function(a) {

return function(b) {

return a * a + b * b;

}

}

通过这样调用它:(foo(3))(4),或直接 foo(3)(4)。

注意,函数加里化提供了一种非常自然的方式来实现某些偏函数应用。如果你希望函数foo的第一个参数值被固定成5,你需要做的就是var foo5 = foo(5)。这就OK了。函数foo5就是foo函数的偏函数。注意,尽管如此,我们没有很简单的方法对foo函数的第二个参数偏函数化(除非先偏函数化第一个参数)。

当然,Javascript是支持多参数函数的:

var bar = function(a, b) {

return a * a + b * b;

}

我们定义的bar函数并不是一个加里化的函数。调用bar(5)并不会返回一个可以输入12的函数。我们只能像bar(5,12)这样调用这个函数。

在一些其它语言里,比如 Haskell 和 OCaml,所有的多参数函数都是通过加里化实现的。

下面是一个把上面的foo函数用OCaml语言写成的例子:

let foo = fun a ->

fun b ->

a * a + b * b

下面是把上面的bar函数用OCaml语言写成的例子:

let bar = fun a b ->

a * a + b * b

头一个函数我们叫做“显式加里化”,第二个叫做“隐式加里化”。

跟Javascript不一样,在OCaml语言里,foo函数和bar函数是完全一样的。我们用完全一样的方式调用它们。

# foo 3 4;;

- : int = 25

# bar 3 4;;

- : int = 25

两个函数都能够通过提供一个参数值来创造一个偏函数:

# let foo5 = foo 5;;

val foo5 : int -> int =

# let bar5 = bar 5;;

val bar5 : int -> int =

# foo5 12;;

- : int = 169

# bar5 12;;

- : int = 169

事实上,我们可以把下面这个匿名函数:

fun arg1 arg2 … argN -> exp

当作是下面这个函数的简写:

fun arg1 -> fun arg2 -> … -> fun argN -> exp

函数加里化和偏函数应用的总结

偏函数应用是找一个函数,固定其中的几个参数值,从而得到一个新的函数。

函数加里化是一种使用匿名单参数函数来实现多参数函数的方法。

函数加里化能够让你轻松的实现某些偏函数应用。

有些语言(例如 Haskell, OCaml)所有的多参函数都是在内部通过函数加里化实现的。

[英文原文:Currying vs. Partial Application ]

作者:Aqee
____________________________________________________________________________________

Tags: ,,,.
04月 10, 2013

1. 做出个东西

找个东西/项目,直接开始做。

想进入编程这一行业的人开始时总是试图先学会一门语言。这种方法是低效的。找一个项目或一个小功能软件去做,针对性的学习那些需要完成这个任务必须具备的知识技能。这种学法让你有了一个学习的环境和目标,逼迫你去具有创造力。有些最有价值的知识会来自解决那些之前没有人解决过的独特问题。这个过程是辛苦的,但要的就是你的坚持。

2. 传教

传教,这能激发你去深入研究某项知识技能,会让你发现自己在某些知识上其实很烂。

因为我想学习AngularJS,于是我就是做了一个Twitter游戏教程。传教能够让你帮助他人,同时满足你求知欲,并提升你的价值。

3. 结伴

结伴编程是最快的学习别人分享的知识的方法。你吸取他们的知识,工作方式,以及问题解决策略,无需费力用自己的亲身体验去获取它们。

通过和其他程序员一起编程,我的技能有了快速的提高,但你不能就此而止。通过做一些个人项目,你能扩展那些分享到的知识,并能给你的团队带来新鲜的思想。

作者:Aqee
____________________________________________________________________________________

Tags: ,.
02月 19, 2013

我认识很多人都声称在做敏捷开发,说自己是在钻研软件开发,等等。不幸的是,以我的经验,很显然,很多人口中是这么说,但未必真正的就这么做了。

形式主义,走过场,而不是真正的理解所做的事,这些都是毫无意义的行为。想把一件事情做好,唯一的途径就是不断反省,明白自己所做的事情,明白自己这样的做法能达到什么效果。

举一些例子:

你的团队里的成员知道每日站会的原因吗?站会中与会人员互相传达什么样的信息?还是10分钟里只是在听?

你的团队不愿意对任务估计时间吗?为什么?在每次迭代之后是否会回来重新审视工作量估计的是否正确?如果预估显示不能按时完成任务,是否会删减一部分功能?

你们的自动化测试真的好用吗?我曾看到过大量的毫无用处的测试代码,它们无助于代码重构,毫无效率,或简单的根本测不出任何问题。如果人们根本不明白为什么要写测试程序,你怎么能期望他们写出好的有用的呢?

你们的项目总结是否只是一个30分钟等待结束的会议,没有任何的实际内容,不对现状产生任何改变?

软件开发人员不喜欢这样的事情是有原因的,因为很多事情就需要这样一步一步来,有很多事情并不能从中看到能带来多大的益处,并不是做每个事情都有明确的逻辑原因。一定要让你的团队成员知道为什么他们要做这些事情,只有这样,工作才能做的更好。

作者:Aqee

Tags: ,.
02月 1, 2013

我有幸承担管理着这个实验室里大部分的团队,这些团队绝大部分都是由自诩为程序猿(并以此为自豪)的人组成。

目前,正如众所周知的现状,程序猿们和公司里的规章制度有时候走不到一起。然而,这些年来,我还是学到了不少关于如何管理程序猿的问题上的重要教训,我认为值得分享一下。

程序猿确实是人类!他们的大脑也许有些古怪、与常人不同,也有着奇怪的睡觉/工作作息规律,但基本上,他们跟我们是相同的,这一点很重要….

大体上,管理他们和管理其他人是一样的,“按你喜欢的被管理的方式去管理”这样的黄金法则对他们仍然适用。除此之外,你只需要更多的留心一下那些程序猿特别讨厌做的小事情。

在他们的工作中尽可能的省去那些官僚形式主义的东西,他们痛恨做这些,也不擅长做这些,他们往往会花大量的时间琢磨究竟是手工做这些事,还是做个小程序自动完成它们,这后者通常会比直接手工做它们花去更多的时间。所以,所以我宁愿自己根据他们的活动来总结出他们的工作周报,这意味着我每周要写15份周报,但这比跟在这15个人屁股后面催促他们写周报要省时的多,他们讨厌每周都写周报。

找一些有趣的,并且是非常有挑战性的事情让他们做,任务越有难度越好——特别是当他们被告知其他人也在研究这个东西但无法解决的时候,他们会更兴奋。

相比起其它的绝大部分“正常”的公司员工来说,程序猿们更关注公司业务上的一些动态,愿意知道更多宏观经济环境带来的影响。所以,尽可能多告诉他们公司业务上的信息,这也能促使他们在那些有挑战性的项目上找到更好的解决方案。

不要过高的抬举他们!对待他们只有稍微的与“正常”员工不同就行了,目标是让整个团队都感觉出受优待。

有规律的和他们私下里一对一谈心,定期的团队会议,但要寻找一种适合你的团队的风格,这周我和他们的面对面谈心变成了品茶日!

他们的事业发展是对你的挑战,但要开诚布公的和他们谈论什么样的发展道路适合他们。今天团队里的这些面孔如果还能和一年前一样,那是很少见的。提前做好思想准备。准备一个好的招募新兵的途径。通常最好的方法是由熟悉的人推荐。

管好程序猿能给你带来丰厚的回报,只要你的方式能多留一点灵活度。

如果你在找一些能够真正带来启发的关于如何管理程序猿的视频演讲,或如何指导大型团队的演讲,下面就是极好的一个。

作者:Aqee

Tags: ,,.
01月 25, 2013

这是关于一个具有极高智商但却极端个人主义的程序员的故事,这种类型的程序员我们都知道,也都不喜欢。我们可以不用这样的人吗?

有一些我曾经共事过的程序员,他们极其的聪明,但也极端的古怪离奇。

“古怪离奇”也许用来形容一个事件或一个观点更合适。也许称这类型的人为书呆子更合适。但不管怎样,我的印象中,大多数时候,他们并不会带来太大的麻烦。

并不是他们的脑瓜不灵。很多时候,这些“优秀”的程序员往往是团队中最有能力的。他们的智商和解决问题的能力都是其他人无法企及的。

很多时候,他们是公司里能够解决那些将会让公司损失百万美元问题的唯一的人。当然,大多数情况是因为最初他们参与了开发设计或给了最初的指导。

如果是他们自己故意制造了这将要到来的灾难,我一定都不会吃惊,这样一来他们就能成为救世的英雄。

不幸的是,在众多的IT企业文化中,英雄崇拜是普遍现象。一个明显不合群的程序员但却会被经理们高捧在众人之上。

管理者们需要在意这样的程序员吗?我曾在以前的文章里谈到过这样恃才放旷的程序员,比如Tyler——无视规定,破坏团队建设。是的,我相信管理者绝对应该重视他们,因为他们会影响到团队其他人员,影响到整个团队,他们会给团队带来长久的不确定的风险。

可问题是,管理者们喜欢依赖于这样的有才华的程序员,把他们当作中流砥柱。

我以前也这样过,现在想起来内心有愧。你很容易陷入这种境地,你会因此悔断肠子,因为他们会让你丢掉工作。

这些年来,我曾和很多种这样极富挑战型性格的人共事过。我这里选一个有代表性的例子:我向你保证,乔希绝对是一个真实存在的人;但我给他起了另外一个名,以免他发癫到我家来找我。

我第一次见到他是在我新上任第一天处理一个危机的时候。乔希在我之前很多年就来了这个公司。我们的团队的任务是解决公司的软件产品中的各种问题。

我们当时都在会议室里,免提电话里传来客户的咆哮。他已经受够我们的产品环境中的一个迟迟不能解决的问题,威胁要取消订单。

于是我把乔希叫了进来,他就是产生这个问题的程序的开发者——更像是个主谋。一般情况下,没有人会把乔希带到客户面前,因为他的外表,怎么说呢,让人想起Charlie Brown卡通中邋遢的Pigpen。

我知道这不是可视电话(也不会传导气味),所以应该没问题。而且毫无意外,乔希一个小时内就解决了这个问题。客户得到了安抚,我也松了口气,避免了在我的管理下丢失客户。

我问技术支持小组的技术负责人,问什么乔希一个小时解决了这个问题,而我们的团队花了两天时间都解决不了?回答让我震惊。

他说“我昨天问了乔希,向他求助,但他笑我。他说如果我们没有能力解决这个问题,那我就不配待在这里。”

我的这个技术负责人继续解释说,尽管他翻遍了所有产生错误的程序代码,问题实在让人费解,他查不出问题出在哪。我问程序的文档在哪,他转着眼珠,不自然的傻笑,“什么文档?”

先对乔希的背景做一下介绍。他有时会穿印有挑衅性标语的T恤。上班时你有时会找不到他,甚至好几天。

不止一次我身边的女同事说他在她们面前说脏话。然而,他仍然在这个公司里,而且是拿的薪水最高的程序员。

我决定跟乔希聊一聊。当走进他的办公室时(他是唯一一个有私人办公室的程序员),我感觉需要拿着一个手电筒,因为太黑了。更像是个洞穴,而不是办公室。

宁愿找个衣服夹夹住我的鼻子。

我记不清确切的说了哪些话,但过程大概是这样的。

“你好,乔希”,我说,声音尽量轻松高兴。

静悄悄。

乔希依旧狂暴的敲着他的键盘。我继续说,“嗯,乔希,我能占用你一分钟时间谈谈客户发现的那个问题吗?”

他没有停下来,嘴动了一下,“你说。”

“我想说的是谢谢你解决了那个问题,但我也知道,昨天我的团队向你求助时,你不肯帮他们。”

乔希,注意力并没有从键盘上移开,支吾了一句“怎了?”

“我想知道,你为什么不肯帮他们?”

“我很忙,”他爱理不理的说。

“我知道,但如果你能帮一下….”

他打断我,语气中带着轻蔑的说“帮他,让我去向那个白痴去解释如何做他的工作?我写我的代码。我的代码好用。over。”

我不知道这次谈话怎么结束的,而且,这不太像是一次谈话。我决定找乔希的经理谈一谈。

我一提起这个话题,他的经理噌的站起来去关上了她办公室的门。

她说,“小心,你应该放弃这个念头。这是乔希。他喜怒无常,如果我不全力支持他,他随时都会拍屁股走人。他写代码的速度比团队里任何一个人都快。”

我试图向她解释,乔希应该融进团队中,写的程序也应该有文档。她的回答是,有能力的程序员都不需要文档。

代码”就是文档。她根本无视整个“团队”的抱怨。

随后她笑了,说,“我直说吧,如果没了乔希,我们就不能按时完成下一次的发布,我也就不能坐在这里了。over。”

一天内两次“over”。可是,这事儿没这么就over了。当有更多的客户方面的问题出现后,CEO出面并强行解决了这个问题。

你猜在CEO和乔希的谈话后发生了什么?第二天他没来上班。他走时甚至没有拿走留在办公室里的东西。

他就这样….失踪了。

跟着他走的还有他掌握的对那些复杂(杰出)的代码的理解。一大群优秀的和“水平一般”的程序员最终把这留下的烂摊子整理清楚,但公司为此耗费了大量的时间和金钱。

我们可以称乔希这样的程序员为怪胎,疯子,或蛮不讲理,可毫无疑问,他们的智商是高人一等的。但是,如果你一直任着他们这样下去,他们迟早会成为你公司,团队或事业上的定时炸弹。

Tags: ,,,.
01月 24, 2013

如果说最近的Java暴露出来的安全缺陷能给我带来什么警示,那就是现在是到了Oracle公司重写这种语言的时候了。

这是杀毒软件Bitdefender的缔造者、资深软件威胁分析师、罗马尼亚人Bogdan Botezatu做出的结论,由于本周发现的最新的java缺陷,他估计会导致多于1亿台计算机暴露在黑客攻击的危险之中。

按Botezatu的说法,Oracle的Java代码已经处于失控之中,这就是为什么严重的安全问题不断的出现在这种语言软件中的原因。

“Oracle需要整理出Java的一些核心组件,彻底重写它们,”在一次访谈中他这样说。

一些成熟的产品,比如Java或Adobe公司的几款软件,在过去的很长的时间里已经被无数人的手动过。“这些产品变得如此庞大,被如此多的程序员 维护过,导致这些软件的出品人基本上对这些软件里应该有的东西失去了控制。”Botezatu说。

与软件缺陷的战争

Oracle最近在对Java漏洞进行修补的结果证实了这位罗马尼亚安全专家的分析。

例如,2012年8月份在新版的java7修订版7中,Oracle修补了3个安全漏洞。就在这些补丁包发布的几个小时后,波兰安全专家、Security Explorations公司的创始人和CEO——Adam Gowdiak发现了一个由这些补丁程序造成的安全漏洞。一些安全专家认为,Java现在是年老多病,很多功能器官都要依赖其它技术手段来维持工作。

根据Gowdiak所说,这种编程语言里最近发现的一个还没有相关补丁包的安全漏洞也同样被认为是2012年10月份的那次安全升级的补丁包引入的。这些安全补丁包本身就不安全,它们打开了大门让自己暴露在黑客攻击下。

现在是一个很好的重写Java的时机,以此来消除bug,而不是一层一层的打补丁。”Botezatu说。

然而,Botezatu知道这是不可能的。“Oracle不可能去做一些大的动作,因为这样会影响现有市场上的众多程序,”他补充道。

目前Oracle所面对的Java开发上的问题是一个所有软件生产商都在面对的问题:如何在不破坏对以前版本兼容性的前提下改进软件。

“你可以看一下Windows Vista,看看它是如何因为一些客户的在Windows XP上的应用不能在Vista里运行而不被用户接受的。”Botezatu解释说。

不管怎样,一些迹象显示,Oracle真正努力解决Botezatu所说的这些问题。在周五,Oracle宣布,从9月份的Java8开始,新的版本将以两年一次的频度发布。

鉴于目前安全形势,美国国土安全部建议禁掉浏览器里的Java,可以通过Oracle公司提供的以下这些步骤实现。

Tags: ,,,.
01月 11, 2013

在我任职于雅虎期间(大约2001-2007),我学会了做很多事情,但同等重要的,我还学会了如何避免做某些事情。对于后者,主要就是如何避免不公的对待技术人员。雅虎,尽管做出了很多善意的努力和明显的例外举措,仍然没有在公司内带来技术人员地位的提高。尽管我们这些技术人员创造了大量的价值,可管理层永远都是非技术人员。不可避免的,大量优秀的人才注意到了这些,忍无可忍,愤而离开。

在2007年离开雅虎后,我和别人合作创立的Polyvore,从这时开始,我的一个人生主要目标就是,要建立一个高度重视技术人员、将他们作为一等公民对待的公司/社会环境。我毫不动摇的坚信,建立这样的环境能带来各种各样大量的好处。

此后我一直在思考一个问题,相对于很多的社会上能创造出巨大价值的传统职业角色,为什么软件技术人员的价值会被整体的低估?我总结出三个社会学上的原因:

一个有形,一个抽象。人们倾向于更认可他们能看得见摸得着的有形的东西。

一栋办公大楼,坐满了在办公桌前办公的人。人们能看见这些,很自然的会认识到大楼的价值。人们面对一栋高耸如云的建筑物,会欣赏它的规模和设计。人们会习惯的认为,不管是谁在负责创造这些东西,他一定是极具价值的人。与之形成对应,人们却看不见和摸不着一个运行起来能等价于50个人工作的软件或一个用来设计大厦的软件。软件和其它抽象的智力劳动是因为人们不可见,所以被社会性的低估。

缺乏测量方法。在缺乏好的方法来测量和评估一个东西的真正价值时,人们倾向于用他们的偏好来评判。人们倾向于认为大型团队=更重要。对于我们这些曾经在“大企业”工作过的人来说,这是显而易见的,一些大型公司的管理者通过组建更大的团队来扩大他们的权利机构。更多的人=更多权力&报酬。

要公平还是要平均?人们都渴望公平。但有趣的是,人们的这种渴望却无法应用到像软件工程师这样一个人产出会比另一个人高出几个数量级的生产力异类上。一个技术人员能让一个操作过程自动化,于是50个人的活儿现在只需要5个人。人们很难接受这样的事实:一个人的报酬应该比其它人高出几个数量级,这种悬殊看起来不公平。

还有一些实际操作上的原因。例如,用一个经理来管理一个大组织,这是必不可少的,因为少了他们事情会很快变得一团糟。这种必不可少成了他们讨价还价的资本。而相对照的,优秀的程序员总是使得自己看起来是多余的,他们能让系统在缺少他们的情况下仍能不停的工作、生产有价值的东西。只有最开明的公司老板才能真正认识到这种人的真正价值。

如果你在做的工作正是这种创造可扩展且复杂、抽象的智力工作,很有可能你正是不被人看重并且因此被低估。

怎么办?

要杰出。并不是因为你是程序员,你就能创造出无数的价值。你能让你的团队的工作效率翻翻吗?你能让你开发的项目具有很好的扩展性吗?

会讲故事/沟通。让一个复杂抽象的题目变得易于理解和欣赏的好方法就是给人们讲故事。用一种其他人能听懂的方式解释为什么你正在研究的工作很重要。一旦人们理解了其中的原因,他们也就找到了欣赏你的工作的理由。

用合适的度量手段。采用人们易于接受的度量方法能让抽象的事物变得有具体,能够很好的让人们理解你创造的价值。如果你说你调整了图像压缩比,使得每个图像的体积减少了4.5KB,很少人能理解你说的是什么。而当你解释说这些压缩能使得用户界面的加载速度提高15%,那大部分人都能明白。如果你解释说页面加载延迟减少10ms意味着收入会增加10%,这就更好了。每个人都理解收入是什么。

加入正确的公司团队。最后一点,你也许应该寻找一个开明的公司,一个能按人的实际贡献、而不是按老旧的社会标准来评价人的公司,加入他们。选择的方法可以看看这个公司是不是由技术人员创立/管理的,看看这个公司是否大量的使用各种方法评价人。去看看他们都有哪些评价标准!

你认为呢?还有什么其它原因导致程序员的价值被低估吗?你对如何选择一个正确的公司有什么好的建议?

Tags: ,,.
01月 9, 2013

在过去的25年里,编程世界发生了巨大的变化,如今,我们有大量的有用的、灵活的数据类型可以使用,但在25年前,你需要花大量的额外时间自己去构造这些类型。

C和Pascal语言——当时的标准语言——提供了少量的面向机器的数据类型:数字,指针,数组,形式上的字符串,以及把多种数据组合到一起的结构体或record。重要的是,以这些基本的类型为基石,我们可以构造出更多有趣的类型,例如栈,树,链接表,哈希表,可变数组等。

在Perl或Python,或Erlang语言里,我不需要考虑这些东西。我在使用list、string或array时,根本不关心它们能容纳多少元素,或放在内存的什么地方。最常使用的还有字典,同样,根本不担心它的容量或哈希冲突是如何避免的细节内容。

除此外,我仍然需要一些新的数据类型,但它们更多的是现有类型的一种变换,而不是重新构造。任意维度的vector实际就是array。一个RGB颜色值实际上一个3元tuple。一个多项式既可以是一个tuple,也可以说list。我惊奇于这些array,tuple,list,dictionary等数据类型大大的消除了我在大学课程里学到的那些基本数据类型上的不便。在实现一个平衡二叉树时,你的注意力放在如何让二叉树平衡,而不是痛苦的纠结于乱如麻的指针操作。

将已有的小方块搭建成一个新的建筑,这将会引起比小方块出现带来的更大的变化。这些小方块是如何出现的已经不是人们关心的重点。在很多的编程课程和教材中,本来很好的教学中突然出现了一批新词汇:对象,构造器,抽象基础类,以及私有方法。于是,下一次作业中,用简单的三元tuple来表达的RGB颜色值变成了由一个具有get、set方法,多高构造器的类来代替,更要命的,出现了大量的代码。

这就是为什么有人会不停的呼吁、解释为什么面向对象不是个好东西、会使编程失去乐趣的原因。但很少奏效。

并不是面向对象不好,或含有什么缺陷。而是面向对象不是计算机编程的基本原子,它们不是人们想象的天生就存在的。不设门槛的任意使用面向对象来解决问题会让代码变得臃肿和过度技术化,然而,很多人还是坚持锲而不舍的用对象来解决所有问题。这非常糟糕,因为这样做让人们辨不清面向对象风格的做法是否真的产生了使问题简化并易于理解的效果。

Tags: ,,.
01月 8, 2013

三年前,当我还在YouTube做一名web程序员时,有一位资深的工程师发了一通牢骚,说播放视频的页面体积太大。这个页面体积已经膨胀到了高达1.2MB,包含有数十次的请求。这个工程师公开的宣称说,“如果他们Quake能在100KB的体积下克隆出我们的页面,我们没有理由达不到这个体积!”因为我同意他的观点,并且我正在找新的任务,于是就决定接受这个挑战,让YouTube的视频播放页面的体积减到100KB以下。那天晚上从旧金山回家的火车上,我编写了一个基本的原型。我决定限制页面上的功能数,只保留一个标题,一个视频播放器,五个相关视频,一个分享按钮,一个插旗工具和十条评论——是通过AJAX加载的。我把这个任务命名为“羽毛”。

即使这样一个有限的功能,页面的体积仍然达到250KB。我深入代码查看,发现我们的优化工具(比如闭包编译工具)无法清理这个页面上实际没有使用的代码(也许不该责备这些工具,这种情况下任何工具都做不到)。想进一步减少代码,唯一的方法就是手工优化CSS,JavaScript和图片。经过辛苦的三天努力,我已经把页面做到了相当的精瘦,但仍然没有低于100KB。因为我刚刚写完了一个HTML5视频播放器,我决定用它来替换体积笨重的Flash播放器。砰!98KB,只有14个请求。对这个页面设置了一些基本监视后,我们对一小部分人开放了这个页面。

经过了一周数据的收集,数据有了,但它们却让我困惑。羽毛版下的页面的总体平均延迟时间实际上是增加的。我减少了总的页面体积,减少了页面请求的次数,但数据显示在加载羽毛视频播放页却花了更长的时间。这是不可能的事情。深入挖掘数据,经过在浏览器上的反复试验,没有任何结果。我基本上要放弃这个版本了,我的信仰几乎被完全击溃,正在此时,一个同事发现了其中的奥秘:地理因素。

当我们标注了数据的地理信息,把所有信息按区域划分进行对比,我们看到了地区,比如东南亚,南美,非洲,甚至西伯利亚等地在流量上呈现的不对称增加。进一步调查揭示,在这些地区,羽毛版的页面的平均加载时间超过2分钟!这意味着,一个普通的视频,大概1兆左右,会需要20分钟来加载!人们为了等待这个页面就如此痛苦,更别提视频了。可纵观这些地区,他们之前根本无法观看YouTube,因为等了很久也看不到什么。而在羽毛版下,尽管要等2分钟才能看到视频的第一帧,但不管怎样,事实上是可以看到了。在过去的一周里,羽毛版在这个地区很受欢迎,所以我们的数据被他们弄的完全不平均了。大量以前不能观看YouTube的人现在突然可以了。

通过开发羽毛,我学到了一个关于世界其它地方网络状况的很有价值的认识。我们很多人有幸能生活在一个有高速宽带的地方,但实际上仍然有很大的区域不是这样。通过让客户端的代码变少变轻,你就能完全开启一个新的市场。

Tags: ,,,.
12月 28, 2012

这篇文章要介绍的,是我作为专业程序员这些年来学到的能真正提高我的代码质量和整体工作效率的10件事情。

1. 永远不要复制代码

不惜任何代价避免重复的代码。如果一个常用的代码片段出现在了程序中的几个不同地方,重构它,把它放到一个自己的函数里。重复的代码会导致你的同事在读你的代码时产生困惑。而重复的代码如果在一个地方修改,在另外一个地方忘记修改,就会产生到处是bug,它还会使你的代码体积变得臃肿。现代的编程语言提供了很好的方法来解决这些问题,例如,下面这个问题在以前很难解决,而如今使用lambdas却很好实现:

///

/// 一些函数含有部分重复代码

///

void OriginalA()

{

DoThingsA();

// unique code

DoThingsB();

}

///

/// 另外一个含有部分重复代码的函数

///

void OriginalB()

{

DoThingsA();

// 没有重复的代码

DoThingsB();

}

现在我们重构含有部分相同代码的函数,用delegate模式重写它们:

///

/// Encapsulate shared functionality

///

/// User defined action

void UniqueWrapper(Action action)

{

DoThingsA();

action();

DoThingsB();

}

///

/// New implmentation of A

///

void NewA()

{

UniqueWrapper(() =>

{

// unique code

});

}

///

/// New implementation of B

///

void NewB()

{

UniqueWrapper(() =>

{

// unique code

});

}

2. 留意你开始分心的时候

当你发现自己在浏览facebook或微博、而不是在解决问题,这通常是一种你需要短暂休息的信号。离开办公桌,去喝一杯咖啡,或去跟同事聊5分钟。尽管这样做看起来有点反直觉,但长久去看,它会提高你的工作效率。

3. 不要匆忙赶任务而放弃原则

当带着压力去解决一个问题或修改一个bug,你很容易失去自制,发现自己匆匆忙忙,甚至完全忘了一直坚持的重要的测试过程。这通常会导致更多的问题,会让你在老板或同事眼里显得很不专业。

4. 测试你完成的代码

你知道你的代码能做什么,而且试了一下,它确实好用,但你实际上需要充分的验证它。分析所有可能的边界情况,测试在所有可能的条件下它都能如期的工作。如果有参数,传递一些预期范围外的值。传递一个null值。如果可能,让同事看看你的代码,问他们能否弄坏它。单元测试是到达这种目的的常规方法。

5. 代码审查

提交你的代码之前,找个同事一起坐下来,向他解释你做了哪些修改。通常,这样做的过程中你就能发现代码中的错误,而不需要同事说一句话。这比自己审查自己的代码要有效的多得多。

6. 让代码更少

如果你发现写了大量的代码来解决一个简单的问题,你很可能做错了。下面的boolean用法是一个很好的例子:

if (numMines > 0)

{

enabled=true;

}

else

{

enabled=false;

}

这时你应该写成这样:

enabled = numMines > 0;

代码越少越好。这会使bug更少,重构可能性更小,出错的几率更小。要适度。可读性同等重要,你可不能这样做而使代码丧失可读性。

7. 为优雅的代码而努力

优雅的代码非常的易读,只用手边很少的代码、让机器做很少的运算就能解决问题。在各种环境中都做到代码优雅是很难的,但经过一段时间的编程,你会对优雅的代码是个什么样子有个初步的感觉。优雅的代码不会通过重构来获得。当你看到优雅的代码是会很高兴。你会为它自豪。例如,下面就是一个我认为是优雅的方式来计算多边形面积的方法:

static public double GetConvexPolygonArea(Vector2[] vertices)

{

double area = 0;

for (int i = 0; i < vertices.Length; i++)

{

Vector2 P0 = vertices[i];

Vector2 P1 = vertices[(i + 1) % vertices.Length];

area += P0.Wedge(P1);

}

return area / 2;

}

8. 编写不言自明的代码

勿庸置疑,注释是编程中很重要的一部分,但能够不言自明的代码跟胜一筹,因为它能让你在看代码时就能理解它。函数名变量名要慎重选择,好的变量/方法名字放到语言语义环境中时,不懂编程的人都能看懂。例如:

void DamagePlayer(Player player, int damageAmount)

{

if (!player.m_IsInvincible && !player.m_IsDead)

{

player.InflictDamage( damageAmount );

}

}

能自我说明的代码不能代替注释。注释是用来解释“为什么”的,而自我说明的代码是来描述“是什么”的。

9. 不要使用纯数字

直接把数字嵌入代码中是一种恶习,因为无法说明它们是代表什么的。当有重复时更糟糕——相同的数字在代码的多个地方出现。如果只修改了一个,而忘记了其它的。这就导致bug。一定要用一个命名常量来代表你要表达的数字,即使它在代码里只出现一次。

10. 不要做手工劳动

当做一系列动作时,人类总是喜欢犯错误。如果你在做部署工作,并且不是一步能完成的,那你就是在做错事。尽量的让工作能自动化的完成,减少人为错误。当做工作量很大的任务时,这尤其重要。

11. 避免过早优化

当你要去优化一个已经好用的功能代码时,你很有可能会改坏它。优化只能发生在有性能分析报告指示需要优化的时候,通常是在一个项目开发的最后阶段。性能分析之前的优化活动纯属浪费时间,并且会导致bug出现。

好吧,我说是10个,但你却得到了额外赠送的一个!

这些就是我要说的,我希望它们能帮助你改进编程开发过程。

下次再见!祝快乐!

Cheers, Paul.

Tags: ,,,.