cgi.parase/FieldStorage

2011年9月13日 没有评论

发泄一下!
简而言之:代码很少,不打算动什么框架,手工处理请求参数而已
很想当然的用了这么一句

f = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)

客户端是 php(curl),post 字段大体是 foo = json_encode($foo), bar = json_encode($bar)
使用一段时间后发现偶尔(最可恨的就在偶尔!) 它的解析是错的,看起来最后一组(原生分段顺序) 的屁股擦不干净!大体上:

'bar':....":0,"ext0":0}\r\n------------------------------87493e42753d--',
# curl 的 post 字段是数组的时候会使用 "multipart/form-data"

cgi.parse 一样的问题

就在准备放弃,手工解析 body 字段的时候偶然看到了这么个写法

f = cgi.FieldStorage(fp=cStringIO.StringIO(environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))), environ=environ)

怀着死马碰运气的心情试了一通,居然 TMD 解析成功了!
蛋疼啊!

分类: 烂笔头 标签:

做个广告 – 招募 php 工程师数枚,欢迎举荐/自荐

2011年5月8日 1 条评论

简单地说,你将负责搜狐矩阵一些产品的研发,
我们期望你能
1. 在这一领域有活力,有兴趣
2. 对这几个关键字不只是仅仅了解那么简单,linux/memcache/mysql/php/html/javascript/css
3. 熟练地阅读英文技术文档,良好的学习习惯
以下内容为加分项
1. 有大型项目开发经验
2. 有较好的算法及数据结构基础,有c/cpp(当然是linux下的)或java、py等开发背景
3. 前端见长,对其开发与优化有感觉,有见解,有思路
4. 有个人技术博客或者一个活跃的技术社区账号
5. 重度*nix用户

欢迎有兴趣的朋友以各种途径联系我 –#
eg: leonguo#sohu-inc.com/g65537#gmail.com/g65537#live.cn(msn)/361683623(q) etc.

分类: ad 标签:

owa2010-notifier (chrome ext)

2011年2月9日 1 条评论

公司邮件系统升级至 Outlook Web App 2010 后,发现其 web ui 强大而惊艳,几分钟后就决定就抛弃了一直在使用的 Foxmail Client,
自然,all in web 也有它的缺陷,对我而言最严重的莫过于及时收件了,搜了一下暂时好像没有合适的解决方案,于是做了这个扩展,功能很少,但已经足够满足我的需求了。

设置
2 

未读邮件
1

即时桌面提醒
3

代码放在了 code.google 上,如果您有需要,欢迎试用,不过没做过多少测试,应该会有不少 bug,欢迎留言,当然最好附带解决方案,我很懒 -_-z
http://code.google.com/p/owa2010-notifier/

分类: 烂笔头 标签: , ,

html5 的几张 slide

2011年2月9日 2 条评论

去年十月的一组分享,本来打算做一个系列来着,结果一直在瞎忙,慢慢就搁置下来,
只有通信相关的几张了

分类: 烂笔头 标签:

技术文化和惨淡命运 — 中国雅虎

2010年11月28日 2 条评论

转自 Dreamer 大作
原文链接: http://www.zhuoqun.net/html/y2010/1535.html

很早就想写这么一篇文章了。我离开中国雅虎已经一年有余,在中国雅虎工作的那段时光是我最珍贵的回忆之一,和以前的同事吃饭聊天的时候也经常会怀念一下中国雅虎,怀念得多了,就觉得不如写篇文章好好回顾一下。很多事情虽然已经过去,但有些话不说出来,到底意难平。

从2008年7月份毕业之后加入了中国雅虎,到2009年9月份跟着中国雅虎工程技术部全体人员“被跳槽”到淘宝,我在中国雅虎只呆了一年多的时间。这个时间并不长,甚至可以说短得可怜,所以我或许不是写这篇文章的最佳人选。但是,中国雅虎给我的是人生第一份工作,凭着初生牛犊对社会的好奇心,我对公司的文化、技术、架构、流程包括产品设计等各个方面都有浓厚的兴趣和广泛的了解,从这个方面来说,由我来写这篇文章也是合适的。而且最重要是,我愿意把它们写出来。

在进入正文之前,先开诚布公地声明一下:众所周知,中国雅虎是阿里巴巴的一个子公司,所以文中我也不必遮遮掩掩地用“某电子商务公司”来代替。而且我对阿里巴巴这个公司有意见,不代表我对阿里巴巴的员工有意见,如果伤了某些人的感情,先说声抱歉,请您发扬一下风格,在这里也“拥抱变化”一下。

正文:

我在 2007 年底通过校园招聘拿到了中国雅虎的 offer ,但实际上在我2008年7月份入职的时候,中国雅虎的品牌虽然还在,公司却已经在7月9日和口碑网合并了,改名叫做“雅虎口碑”。尽管这样,到现在为止我还是厚着脸皮说自己原来是雅虎的,因为那里让我着迷和真心喜欢的东西全部都是紫色的,而不是橙色的。

雄厚的技术实力

中国雅虎最好的一个地方就是它和 Yahoo! 全球共享同一个技术平台,那是一个有十几年历史的技术平台。Yahoo! 的技术文化不如 Google 的工程师文化那么有名,但 Yahoo! 在相当长的一段时间内都是互联网的旗帜,吸引了全球大量的技术牛人加入,Yahoo! 的技术平台就是他们的知识、经验和心血日积月累的成果。尽管阿里巴巴收购了中国雅虎,但是在技术方面并没有对中国雅虎做出太大的改造(幸好没有改造),所以就工程师来说,每天更多接触到的还是 Yahoo! 的东西,而不是阿里巴巴的东西,对我影响最大的也正是这些东西。

一、Linux 和开源文化

之前一个中国雅虎的同事,他是工作了几年之后才来中国雅虎,有一次他说:“雅虎是我见过的最尊重 Linux 的一家公司”。什么叫做尊重 Linux 呢 ? 不是在服务器上装个 Linux 跑 Apache 就叫做尊重 Linux 。在雅虎很多同事日常都使用 Linux 操作系统办公,即使有一些人使用 Windows, 也都是使用 pietty 或者 Xshell 等工具远程连接到开发机器上使用 VIM 做开发。不只是日常工作,在雅虎全球的技术体系中,产品的上线和发布也都借鉴了 Linux 包管理的方式:所有的产品都会被打成包放在一个专门的服务器上,产品的部署和升级就变成了简单的装包操作,绝对不会出现最后上线的时候文件路径出错等低级问题。Yahoo! 的技术平台是深深扎根于 Linux 和开源文化的。

大型互联网公司一般都会使用开源的产品,同时也向社区贡献代码。Google 和 Facebook 经常将自己研发的成熟产品开源,Yahoo! 当然也不例外。而且 Yahoo! 不仅仅给社区贡献代码,它在设计方面也拥抱了开源文化,将多年研究总结的设计模式库共享了出来。在 Yahoo! 内部,很多代码都是存放在 CVS 里面的,并没有限制读的权限,任何员工都可以查看里面的代码,这对于那些小团队内部代码都不敢共享防员工如防贼的公司来说应该是非常不可思议的。另外, Yahoo! 的工程师也经常出现在各种技术会议上,分享自己项目的架构、流程和经验。虽然这些更多都是 Yahoo! 全球技术团队做的事情,但是对于他们那种开放共享的精神我们是非常认同并且向往的,你会觉得做一个工程师很自豪,而不会觉得自己是民工、做技术没前途。这种认同感和成就感乍看上去没什么,但实际上它决定了你对技术的追求和态度,也会影响你以后在职业上的选择。

二、浓厚的技术氛围

虽然2008年的时候中国雅虎已经被折腾得快不像样了(这点后面细说),不过那个时候还是有浓厚的技术氛围的。让我印象深刻的一件事情是 Google Chrome 浏览器刚发布的时候,大家都立刻下载下来使用,但由于公司内网的一些问题无法打开网页。当我正打算把 Chrome 卸载了的时候,忽然发现公司邮件列表里面已经有人发邮件给出了详细的解决方案。从这件小事可以看出公司大部分工程师都不是那种只知道完成工作的人,而是随时关注新技术和业界动态的人。当时中国雅虎还是有很多牛人没有离开,大家也喜欢在邮件列表里面谈论技术,经常能看到精彩的讨论和解答。最让我兴奋的是,无论我遇到什么技术问题都不用慌张,即使无法 Google 到答案也可以从同事那里获取到帮助,而且大家也愿意回答技术问题,这对于我这样一个基础很差技术又烂的菜鸟来说真是天大的福气。

中国雅虎还有做技术分享的文化,如果有哪位同事想要分享一下最近学习到的技术,就可以自己预订一个会议室然后向所有的工程师发送会议邀请,有时候还会有一系列非常系统的课程,我就参加过长达十几个课时的 UED 培训,完全改变了我对 Web Develop 的认识。很多公司应该都鼓励员工做技术分享,但在中国雅虎几乎每次技术分享都会把会议室坐的满满当当,可见大部分工程师都还是想要不断提高自己的技术能力。直到离开雅虎之后我才明白这种普遍的学习热情有多么难得。我想,业界之所以到处流传着“程序员做到30岁最好转管理”之类的忠告,应该就是因为大部分公司都缺乏这种良好的技术氛围吧。

三、庞大的知识库

入职的前几天,我每天的工作就是看文档,不是类似“PHP技术手册”那种文档,而是一些 Yahoo! 内部的工具手册。Yahoo! 内部的文档非常齐全和详细,光是 Yinst 这款工具的使用手册就长达几十页。Yahoo! 内部是用 Twiki 做知识管理的,这个知识库经过十多年的积累已经非常庞大,从入门到提高,从 PHP 到 C ,从前端到后端……应有尽有,而且几乎 Yahoo! 全球所有子公司的技术资料都是开放浏览的,没有任何乱七八糟的权限设置和保密限制。有这么一个宝藏在,再加上好的学习氛围,如果你想要提高自己的能力的话,总是可以提高。当初我想从 PHP 工程师转做 Web Developer 的时候,就先把 Twiki 上 UED 部门的所有资料看了一遍,受益匪浅。

国内大部分互联网公司都是没有太多技术积累的,因为大部分产品的开发都只追求开发速度,并不会特别追求技术上的极致,就更不要提文档这种东西了。也正因为如此,从中国雅虎出来看到其它公司的知识库的时候总有不过瘾的感觉,可能也只有像 Google, 微软和 Facebook 这样的公司才会有像 Yahoo! 那样的知识库吧。在和之前一些同事吃饭聊天的时候,大家也总是会怀念那个无所不包完全开放的 Twiki ,好像少了一个忠实的朋友一样。我们由衷地尊敬那些在完成工作之余还愿意总结项目经验并花时间写 Twiki 的工程师们。

四、完善的流程

第一次参与项目开发的时候,我的 Leader 领了一个 MM 过来说:“这位是项目的 QA 负责人”,我当时愣了一下:“呃…… QA 是做什么的?” 尽管在大学里我也在实验室做过一些项目,但那些项目基本上都是我自己负责所有的事情,完全没有分工和流程的概念,所以也不知道 QA 是负责产品测试工作的。进入中国雅虎之后,我才第一次接触到商业产品的开发流程,不过由于那个时候中国雅虎已经半死不活,我也没有受到有关流程的入职培训,以至于在做了好几个项目之后才真正熟悉了完整的流程。

中国雅虎的开发流程沿袭了 Yahoo! 的开发流程,乍看之下很平常,对于已经熟悉的工程师来说还显得枯燥,但后来我特别留心了这套流程之后,非常惊奇于它的严谨和高效,所以这里要详细说明一下。Yahoo! 的内部生产线分为三个相互独立的环境:开发环境、测试环境和生产环境(即线上环境)。这三个环境虽然独立,但它们的配置都会尽量保持一致,这样就可以保证开发完成的产品不会因为环境不同而出现问题。在开发的时候,我们会在开发环境中搭建虚拟环境,开发完毕之后开发工程师会自己在虚拟环境里面测试,保证没有大的问题,然后就会把所有相关文件打包上传到雅虎全球统一放置产品包的地方。上传完毕之后,就会发邮件通知 QA 部门相关人员,邮件内容里面要写明产品在测试环境的部署步骤:需要安装哪些包、是否需要修改数据库等等。然后 QA 就会开始测试,如果发现 BUG 就会写到 Bugzilla 中,指派给相应的开发工程师,开发工程师就会在开发环境中定位BUG并修正,修正一些BUG之后就会再次打包升级产品的版本,然后QA 会将新的软件包部署到测试环境验证之前的 BUG 并报告新的 BUG 。整个测试过程中可能要发布好多个版本,直到所有 BUG 被修正为止。修正完毕所有的 BUG 之后,开发工程师就会填写上线申请,Ops 看到申请之后就会安排一个时间把产品部署到生产环境。一般来说,生产环境不止会有一台机器,所以 Ops 会先从生产环境摘下一台机器部署,部署完毕之后会告知 QA 和开发工程师,然后 QA 和开发工程师就会修改 Hosts 文件,配置域名指向那台机器进行线上的测试,如果测试没有问题,那么就会把软件包部署到生产环境中所有的机器上,完成上线;否则就进行回滚,取消这次上线,也不会影响到线上的用户。

整个流程大概就是这样,但是要特别注意的是以下几点:1. 开发工程师只能接触开发环境。他所能做的就是在开发环境中开发、改 BUG 和打包上传。如果他去测试环境中修改 BUG,就很有可能忘记修改开发环境中的相应代码,这可能会导致产品测试通过但是上线之后却发现大的问题。 2. 产品“封版”之后就不可以做任何改动,如果有改动,即使只改动了一点所有功能也要重新测试一遍。所有的 BUG 都修改完毕之后的那个版本就会进行“封版”,那就标志着这个产品随时可以准备上线了。如果真的发现了新的 BUG 要修改的话,那么修改之后就需要重新打包重新走一遍完整的测试流程,只有这样才能够保证就算修改代码过程中引入了新的 BUG 也不会被遗漏。 3. 上线手册要详细。开发工程师要详细写明每一个步骤,不只是说明性的文字,还要把具体的安装和修改命令完整地放上去,如果写得好的话,那么 Ops 的同事只需要把上线手册里面的命令逐行复制到服务器上运行就可以完成上线。

这样的流程有什么好处呢? 首先,它最大地降低了上线风险。因为开发工程师不能接触到测试环境,只能打包让QA测试,所以完整经过测试的产品上线之后基本不会有什么问题,况且上线的时候我们也要先部署到一台机器上进行测试之后才会决定是否上线,即使上线不成功也可以在不影响用户的情况下回滚。中国雅虎的上线极少会出现问题,很多时候我们上线到半夜只是因为那个时间段用户访问量最小,而不是说焦头烂额地忙活几个小时一直到半夜才上线成功。其次,它使得各个部门职责分明。开发工程师和 QA 通过 Bugzilla 沟通,和 Ops 通过上线手册沟通,因为沟通渠道唯一而且清晰,所以就可以完全责任到人,出了问题也很容易定位到具体环节。比如说,如果产品测试通过之后在上线的时候出现了问题,那么基本就可以确定是 Ops 操作失误或者上线手册没有写好。职责分明之后很多事情也变得有条理,大家就可以各司其职、专注本职工作并且合作愉快,开会的时候也可以明确知道需要哪些人参加。

完善、清晰的流程从根本上解决了一些问题,创建了一个非常好的环境,这样我们就可以把心思都放在如何开发和测试上面,而不用担心诸如“如何上线才能不出错”等琐碎的事情。所以尽管中国雅虎的高层那么不靠谱,我工作得还是很开心,因为这个流程保证了管理层再怎么乱开发也不会乱。记得那时候很喜欢改 BUG ,有时候改得兴起会把之前版本遗留的 miss BUG 一并改掉,加班也是颇有兴致,不是很能明白为什么网上大部分程序员讨厌加班讨厌得要死。现在我明白了。

五、自动化工具

工欲善其事,必先利其器。如果没有那么多好用的自动化工具,那么 Yahoo! 的流程就不可能如此完善。Yahoo! 内部有很多非常好用的工具,而且这些工具都有非常齐全的文档,也可以在 Twiki 上找到不少相关资料。这些工具之所以在 Yahoo! 会起到那么大的作用,是因为 Yahoo! 全球所有的技术团队都在使用它们,Yahoo! 所有的服务器上也是默认安装了这些工具。这些工具就形成了一套全球 Yahoo! 工程师通用的话语体系,可以想象它们帮助 Yahoo! 节省了多少沟通成本。

由于考虑到服务器的安全问题,Yahoo! 的这些工具的使用方法是对外保密的,这里我只简单说一下 Yinst 这款工具的强大。假如要把软件包 example_1_1_0.tar.gz 部署到 a1.yahoo.com ~ a10.yahoo.com ,那么只需要下面这样一行命令:

yinst install example_1_1_0.tar.gz -h a[1-10].yahoo.com

就可以完成整个上线过程。由于好奇的缘故,在上线的时候我比较喜欢跑到 Ops 那边看他们是如何操作的,然后发现其实他们在上线过程中执行的命令很少。因为工具好用,所以产品极少因为 Ops 这个环节出现问题,上线就变成一件比较轻松的事情。

中国雅虎的产品和业务确实不好,搜索不如百度,新闻不如三大门户,“雅虎助手”是人人皆知的流氓软件,邮箱也出过丑闻,而且被 Gmail 和 QQ 邮箱远远抛在后面。中国雅虎最广为人知的也都是这些不光彩的事情,但这里我想让很多人知道,对于一个对技术还有追求的工程师来说,当时的中国雅虎真的是一个很好的工作环境。至少对于我自己来讲,我从 Yahoo! 学到了太多太多的好东西,而且这些东西还只是 Yahoo! 精华中的一小部分,如果不是阿里巴巴集团战略调整,我一定会在中国雅虎多呆两年。

中国雅虎之死

有个同事曾经说过:中国雅虎就是中国互联网的黄埔军校。虽然别的老牌互联网公司也为行业培养了不少人才,但是没有一个公司像中国雅虎这么悲情。很多中国雅虎的员工离职不是自己想走,而是不得不走,看着原来好好的一个公司变得完全没有前途,只好选择离开。

关注互联网的人应该都知道,在 2005 年的时候,阿里巴巴收购了中国雅虎的全部资产,并享有雅虎品牌及技术在中国的独家使用权。中国雅虎尽管之前也一直水土不服,但被阿里巴巴收购之后悲惨命运才刚刚开始。

关于中国雅虎的折腾史,大家可以去看一下这篇文章,里面说的已经很详细。从网站的变化就可以看出中国雅虎的摇摆不定,在阿里巴巴入主的这 4 年来,中国雅虎就换了 5 任总裁,每位新官上任后都会颁布新的战略,网站也会随之大变脸。“治大国若烹小鲜”,这么简单的道理我相信阿里巴巴的高层不可能不明白,就算大象可以跳舞,中国雅虎的舞姿是不是也太难看了点?由此可见,中国雅虎在阿里巴巴集团内部就是一个鸡肋,一个可有可无的品牌。

有一件事情完全可以说明马云对中国雅虎的态度。约在 2007 年前后,马云对雅虎中国资产进行了大幅度调整。在此期间,雅虎相册宣布关闭,从发出通知到服务关闭,前后不到 20 天。这种缺乏对用户起码的尊重的行为,导致相当一部分中国用户失去了存储其中的照片。而且它引发的用户对雅虎品牌的失望和不信任,对雅虎来说更是难以挽回的损失。大家都知道,“客户第一”一直都是阿里巴巴宣扬的核心价值观,难道雅虎相册的用户就不是客户?到底是马云铁了心要把雅虎品牌搞砸呢还是所谓的价值观只是口号?或者是两者皆有?

这几年中国雅虎的历史就是逐渐被瓜分的历史:搜索团队被调走,于是有了后来的淘宝网搜索引擎;IM 团队被独立出去,于是有了后来的阿里旺旺(有人提醒我说阿里旺旺早就有了,这点我没有查证,十分抱歉,我是摘自这篇文章:“随后,雅虎的搜索和IM技术团队流入阿里,并为后者孵化出淘宝网搜索引擎以及阿里旺旺两个产品。”);挖走了广告搜索团队,于是有了后来的阿里妈妈;口碑网发展得不好,于是中国雅虎和口碑网合并,利用中国雅虎的品牌和技术支持口碑网;最后,中国雅虎的整个工程技术部都注入淘宝,原来的主要业务“雅虎关系”直接关闭并且推荐用户使用淘宝网的“淘江湖”。时至今日,中国雅虎已经气息奄奄,再无回天之力了。

我经常觉得,恩,马总在下一盘很大的棋,我们这些普通员工是不明白的。不然为什么“搞死中国雅虎”这个庞大的项目规划和施行得这么好?还是阿里巴巴一直在用实际行动考验中国雅虎员工的价值观呢?而且颇具讽刺意味的是,尽管马云费尽心思拿到了中国雅虎的搜索资源,最近却又和微软的 Bing 合作推出了 Etao 搜索,当初的那些搜索资源都用来做什么了呢?

还有一点不得不提的是中国雅虎和阿里巴巴之间的文化冲突。阿里巴巴一直都不能算一个真正的互联网公司,它只是以互联网作为工具,大部分业务的进行还是靠线下的销售。阿里巴巴最重视的是销售部门,整体的文化是销售文化,它所取得的成功也都只是商业上的成功,这也就从根本上决定了它不可能像 Google, Yahoo! 和 Facebook 等这些真正的互联网公司具有理想主义色彩,也不可能成为优秀工程师向往的地方。马云自己也经常放言说要“超越沃尔玛”,从来没有说过要超越 Google 之类的话,因为根本不在同一个领域,阿里巴巴更像一个传统的商业公司。我并不是说做电子商务的公司就不算互联网公司,同样是做电子商务,Amazon 就是互联网行业的领头羊,它非常重视技术,还是最早提供云计算服务的公司,它就是一家真正的“IT公司”。

而中国雅虎的技术资产全部来自美国 Yahoo! ,工程技术部也继承了 Yahoo! 的“技术文化”。“技术文化”偏重简单实用、冷静思考和解决问题;而“销售文化”则重视加油鼓劲,更喜欢喊口号,越热闹越好。我承认这两种文化都有它们的合理之处,但是强迫工程师接受那种“销售文化”就会有很多矛盾出现。阿里巴巴内部有时候玩得还比较过火,跳钢管舞倒也算了,但很多时候做游戏会直接让一个同事站到前面,然后轮流问他诸如“第一次用了多长时间”之类的问题。并不是所有人都喜欢这么玩儿的,“贱文化”和“骚文化” 的最大一个弊端就是很容易引起一些人的反感让他们觉得被侮辱,而公司不是经常倡导要对人才各尽其用么?为什么要用这样的文化把一些“思想保守”的人驱逐出去呢?我就听说过一些非常优秀的工程师因为这些东西而坚决不去参加公司的培训和集体活动,中国雅虎的很多人应该也是因为无法适应这种“销售文化”而出走的。

另外,当年和我一起通过校园招聘来到雅虎本来有不少人,在 2008 年 3 月份的时候我们还曾一起在北京参加了一个叫做“集结号”的新人培训。不过在我入职之后发现,有几个人直接被调动到了阿里巴巴在杭州的其它子公司,还有几个做搜索的同学虽然人在北京,签的却不是雅虎,而是什么“阿里巴巴集团搜索事业部”——当时雅虎的搜索部门已经被独立出去了。之后我也和那些最终没有来雅虎的同事聊过,他们都表示很郁闷,表示自己并不是很情愿去其它公司。这件事情让我感到很气愤,明明大家都是冲着中国雅虎来应聘的,为什么在发放 offer 之后又进行调动呢?当然,阿里巴巴肯定是做了一些说服工作让那些同事“自愿”服从调动的,但是那个刚好出现了金融危机工作比较难找,其它公司的招聘也早已结束,而且大家都是初出茅庐的学生,能不服从么? 那几个同事也实在是太光荣了,刚入职就完美表现了自己“拥抱变化”的价值观,KPI 应该给五分。

不只是新入职的员工,因为中国雅虎的业务变化频繁,平时也经常会出现内部调动,而中国雅虎在北京,调动的话就很有可能需要去杭州,这对于很多已经在北京安家的同事来说并不是一件小事。但不服从调动,就是价值观有问题。五十六种语言,汇成一句话:拥抱变化拥抱变化拥抱——变化。

在写这篇文章的时候,我不断提醒自己:我的目的是要让大家了解一下中国雅虎,千万不要写成针对阿里巴巴的檄文。但真实情况确实是那个样子,很多事情也是人人皆知,无法绕过去不说。相信很多人都还记得中国雅虎首页的那次糟糕的改版,把原来清爽干净的页面改成了屎黄色,据说这是当时的 CEO 金同学坐在设计师旁边亲自指导的结果。如果一个乡镇企业的老板非要外包公司的设计师把网页做成他想要的也罢了,但作为一个缺乏审美能力的 CEO 居然连“把设计的工作交给设计师”的觉悟都没有,实在让人觉得不可思议。就算是一心想要“去雅虎化”,也没有必要这么羞辱设计师们吧?

不知道为什么,有些东西不用每天灌输也深得大家认同,怎么折腾都无法斩草除根。我在雅虎的时候从来没有任何一个人和我们说“你们要热爱雅虎,要以雅虎为荣”之类的话,但是每次公司给员工发放印有雅虎 LOGO 的杯子或者背包的时候,大家总是一哄而上,疯抢干净。在中国雅虎和口碑网合并之后,因为担心以后再也领不到雅虎 LOGO 的笔记本等文具,不少同学都开始申请办公用品留作纪念。由这些事情就可以看出工程师们认同的到底是哪一种文化,大家自然会用脚投票。这些事情甚至让中国雅虎的一些非工程师同事也觉得难以理解。这种生命力强劲的外来文化可能也是阿里巴巴一直不满中国雅虎的原因。

真正的开放应该是同事之间开诚布公、乐于分享和坦然接受批评,而不是不分场合地讲荤段子,不是让别人站到前面然后问别人“第一次用的是什么姿势”;真正的“员工第二”是站在员工立场上考虑问题、虚心听取员工提出的问题,而不是在员工有意见的时候首先进行价值观教育,不是强迫员工拥抱不可理喻的变化;真正的对“用户体验”的重视是尊重用户、切身考虑用户感受,不是在年会上把某个子公司的总裁骂哭,不是为了巨额广告费用而在首页做弹窗,不是让员工为了 KPI 每隔几个月就想着改版;真正的“幸福感”是来自于发自内心的对公司的认同、对公司产品的成就感,而不是来自于整齐划一的口号和对某个人的崇拜,也不是来自于被灌输的“换个角度看世界”。脱离了原本的初衷,就算宣传得再好口号喊得再响亮,也不过是看上去很美的空洞的形式主义,这样的公司有什么底气去做“百年公司”呢?

技术的悲哀

有着世界级的研发实力却不得不悲惨收场,我想再没有人比中国雅虎的工程师更能强烈地意识到技术所能决定的事情实在是太少太少。在中国,互联网只是一个营销工具,“技术改变世界”也不过是一个笑话。那些商人们从来不相信“一个优秀的程序员抵得上一百个平庸的程序员”,却虚伪地把“我不懂技术但是尊重技术”挂在嘴边;他们整日想的不是创造价值,而是如何赚更多钱;他们更相信“廉价劳动力”所带来的成本优势,也总能把“技术密集型”的公司做成“劳动密集型”,以至于国内的互联网公司不是山寨就是血汗工厂,雇佣着大批大批会写代码的高级民工。这样的环境和氛围,暂且不说 Google 和 Apple 这样伟大的公司,什么时候我们才能有产生像 37Signals 和 The Omni Group 那样的小公司的土壤呢?

文章的最后,还是那句老话:他日江湖相逢,再当杯酒言欢。

各位雅虎人,多保重了。

分类: uncategorized 标签:

狗日的 MSIE

2010年8月25日 4 条评论

昨天写社区广告的 js 渲染器,结果又和 ie 杠上了, 几点总结:

1. 问题源自自定义标签,看起来挺好,纠结也源自这里,还是要有选择的折腾。
2. 非 ie 下的 jquery 提交(POST/GET) 都可以直接仍数组:{‘places[]‘:arr_places}, 狗日的 ie 不行,需要完全手工拼接。
3. jQuery.param 看起来挺好,也不支持数组。
4. 狗日的 ie 会将自定义标签处理为 HTMLUnknownElement,而且如 <ad place=”….”></ad> 会被凶残的处理为 <ad place=”….” /> </ad /> 两个元素,继而无法正常使用 innerHTML/$.html()、$.replaceWith() 等方法
5. jQuery(“ad”) 取不到元素,jQuery(“ad:xx”) 居然可以(甚至 xx 可以毫无意义), jq1.3
6. 带名称空间的 jq 选择方法 jQuery(“club\\:ad”) // <html … xmlns:club=”http://club.sohu.com”> , xhtml
7. 几乎不会用到的尾标签 jQ 选择方法:jQuery(“\\/ad”); (也有 5 的问题).
8. 别把 $.replaceWith/outerHTML 遗忘.
9. 工具还是必不可少的 firebug (for ie/oprea etc.)

分类: 烂笔头 标签: ,

一分钱一分货, 极度悔恨中.

2010年6月20日 1 条评论


连续头脑发热,连续贪便宜,结果连续弄了两个废品,微软那个太 mini,完全没感觉,罗技这个倒是够大,外观也尚可一看,谁知握到手里粗糙不说性能极差,mac 下几乎拖不动的感觉,尤其是在M555b的对比之下,极度悔恨中..

分类: xbox 标签:

bloom filter 备忘(2)

2010年5月10日 没有评论

Bloom 过滤器(以下称 Bloom Filter 或 BF) 采用位数组表示数据集合并有效支持集合元素的成员查询,由于其能显著节省存储空间,在对错误率不敏感的领域(如字典查询、数据库),Bloom Filter 有着广泛的应用。
随着网络及数据流处理技术的飞速发展使 Bloom Filter 焕发了新的活力,数据流等新应用场景也推动了 Bloom Filter 理论的发展,产生了计数型 Bloom 过滤器(Counting Bloom Filter, CBF) 、光谱 Bloom 过 滤 器 (Spectral Bloom Filter, SBF)和动态计数过滤器(Dynamic Counting Filter, DCF)等多种 Bloom Filter。

标准 Bloom Filter:
前文已经示例了一个 bloom filter 的 Toy Demo 实现. 并简要介绍了 bf 的基本原理.
参考文档:Bloom Filter概念和原理
数 学之美系列 - 布隆过滤器

标准 Bloom Filter 不支持从集合中删除元素,如果删除元素时把相应的位置为 0,而别的元素也哈希到这一位,那么 Bloom Filter 就不再正确地反映集合中的所有元素,而产生假阴性。同时也不能完成计数等功能,于是一些变种出现了。

计数型 Bloom Filter (CBF)
Counting Bloom Filter的出现解决了这个问题,它将标准Bloom Filter位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的k(k为哈希函数个数)个Counter的值分别加1,删除元素时给对应的k个Counter的值分别减1。Counting Bloom Filter通过多占用几倍的存储空间的代价,给Bloom Filter增加了删除操作。
基本结构:


参考文档:Counting Bloom Filter

光谱Bloom过滤器(SBF)
标准 Bloom Filter 和 CBF 解决了元素与集合的成员查询问题。在最近涌现的数据流应用中,用户不仅关注元素的成员归属,而且关注多个元素出现的频数。SBF扩展了CBF,利用 CBF的计数器支持计数查询。
基本结构:


参考文档:Counting Bloom Filter

动态计数过滤器(DBF)
SBF解决了由于计数器大小变动带来的动态存储问题,但是引入了复杂的索引结构,每个计数器的访问变得复杂而耗时,元素频数出现剧烈变化时的索引重建也十分耗时。于是 DCF 出现了,DCF支持元素出现频数查询,结构又相对简单。
基本结构:


参考文档:Dynamic Count Filter

计数型 Bloom Filter 的简单比较

计数器大小 内存占用 访问速度 重建率 计数器溢出
CBF 固定
SBF 动态 较多 最终会
DCF 动态 较多 不会

可以看出,CBF虽然内存占用少、访问速度快、无重建操作,但是存在无法解决的计数器溢出问题。SBF与DCF相比,在内存占用方面,由于DCF中计数器的最大值决定了整个DCF所占的空间,因此在元素分布比较均匀、增删
操作相对平均的情况下,计数器的值相差不大,而且DCF不用维护复杂的索引结构,占用空间比SBF少。如果少数计数器的值显著大于其他计数器,SBF在空间使用方面会占据优势;在计数器的存取时间方面,DCF占有绝对的优势,它仅比标准CBF多了一次内存访问,而SBF的访问相对复杂;在处理数据抖动方面,SBF和DCF都不够理想,前者需要数据访问索引的重建,后者可能面临开销巨大的OFV数组重建工作。如何设计和维护计数器的结构也是CBF一个重要的研究方向。

分类: xbox 标签: ,

完美哈希函数(Perfect Hash Function)

2010年5月9日 没有评论

转自:http://blog.csdn.net/chixinmuzi/archive/2007/08/05/1727195.aspx

什么是 完美哈希函数
完美 哈希函数(Perfect Hash Function,简称PHF)就 是没有冲突的哈希函数,也就是,函数 H 将 N 个 KEY 值映射到 M 个整数上,这里 M>=N ,而且,对于任意的 KEY1 ,KEY2 ,H( KEY1 ) != H( KEY2 ) ,并且,如果 M = = N ,则 H 是最小完美哈希函数(Minimal Perfect Hash Function,简称MPHF

什么时 候使用PHFMPHF
通常情况下,PHF或MPHF是针对静态集合的。也就是,在使用PHF或MPHF时,所有的 KEY 值是事先已知并且固定的。不过,这里有 针对动态集合的一个算法。

使用PHFMPHF的一般流程
1.  (准备阶 段)将已知的所有的 KEY 值传给PHF或MPHF生成算法,生成PHF或MPHF以及相应的数据;
2.  (使用阶 段)调用已有的PHF或MPHF以及相应的数据快速计算哈希值并进行相应的操作。
其实在实际使用中我们只关心步骤2,但步骤1的生成算法却是PHF或MPHF的关键。

PHFMPHF生成程序库
GNU的完美哈希函数生成程序,可以生成PHF和MPHF,生成MPHF时和输入数据以及参数设置的关系比较大。使用的应该是比较简单的算法, 生成的效率不高,当数据量大时,程序就没什么反应了。生成的结果是代码(里面包含有数据,直接组织在代码里),移植性非常好。很多编译器对保留字的处理都 采用gperf来建立完美哈希函数。Windows版的可执行文件可以从这里下 载,源代码可以从这里下 载,一篇介绍论文在这里, 说明书在这 里,说明书中文翻译在这里
易用性:5
稳定性:5
移植性:5
效率 : 2
MPHF: 2
巴西的这个哥们Fabiano C. Botelho发了很多MPHF方面的论文。CMPH应该他和其他几个人开发的开源的生成MPHF的程序库。 这里面封装了4个算法,而且设计了一个程序框架(搞不懂他们为什么要设计这样一个框架,用MPHF的人不会 像他们做研究那样会一次使用那么多个算法的,而这样一个框架明显增加了使用的难度)。里面有几个算法是针对大数据量的,但简单试了试,发现并不像他们论文 里宣称的那样高效,而且由于是一个框架,生成的MPHF并不能直接脱离他们的环境来使用。这里是他们在SourceForge上的链接。
易用性:3
稳定性:2
移植性:2
效率   : 2
MPHF:5
又一个牛人写的生成MPHF的算法,注 意了,他写这个纯粹是为了好玩,考!
简单试了试,可以直接生成代码,但不是很好用,针 对大数据量效率也不行。
易用性:3
稳定性:3
移植性:4
效率 : 3
MPHF:5
又又一个牛人写的生成MPHF的算法,比 较好用,可以处理大数据量的集合,而且比较有特色的是关键字不仅仅可以是字符串,还可以是整数等。
易用性:5
稳定性:5
移植性:4
效率 : 5
MPHF:5
以上都是用C/C++来实现的PHF或MPHF生成程序 考,这是一个用Python实现的MPHF生成程序。还是比较好用的,遗憾的是对大数据量效率不行。
易用性:5
稳定性:5
移植性:4
效率 :3
MPHF:5

PHFMPHF生成算法
我一贯坚持的是拿来主义(只要不存在法律和道德风 险),所以对PHF和MPHF的生成算法我只是浅尝辄止,不敢在这里唧唧歪歪。下面给出一些链接,想研究这些算法好好看这些论文 吧。论文按大概时间顺序排列,最新的在最前面。

分类: xbox 标签:

贝叶斯分类实现

2010年5月9日 3 条评论

最近做的一公司笔试题里的一道题:

背景:搜索引擎会根据用户搜索的关键字提供对应的广告,一般是通过统计学习实现(不限方法)。
脚本要求:附件articles.tar.bz2中的文本文件已经分好类了,请从每个类别中随机挑选90%文件做为训练集,然后将剩余文件分类并输出分类的正确率。

常用的文本分类有基于统计的方法(bayes)、决策树、神经网络等,实际使用时往往要以具体情况判断或组装。其中,朴素贝叶斯算法是这类应用中的重要一支,由于其实现简单、运算速度快、在良好训练的前提下往往有较高的精度而被广泛使用。

之前用 java 写过,这次要 python 实现,稍改了下,而且由于样本是英文的,中文分词也省下了,不过这样看起来更清晰一点 –//

【chap1】bayes 简述

Pr(A|B) = Pr(B|A)Pr(A)/Pr(B)

如果你看到一个人总是做一些好事,则那个人多半会是一个好人。这就是说,当你不能准确知悉一个事物的本质时,你可以依靠与事物特定本质相关的事件出现的多少去判断其本质属性的概率。用数学语言表达就是:支持某项属性的事件发生得愈多,则该属性成立的可能性就愈大。

贝叶斯法则又被称为贝叶斯定理、贝叶斯规则,指的是当分析样本大到接近总体数时,样本中事件发生的概率将接近于总体中事件发生的概率。是概率统计中的应用所观察到的现象对有关概率分布的主观判断(即先验概率)进行修正的标准方法。

关于基础理论就不多赘述了,标记几个链接,google 也可以得到数以顿记的结果。

基于朴素贝叶斯分类器的文本分类算法(上)
基于朴素贝叶斯分类器的文本分类算法(下)
朴素bayes公式分类器
bayes factor
经典算法之朴素贝叶斯分类

【chap2】demo 实现
tokenizer.py
#stem 使用了 stemming 组件(http://pypi.python.org/pypi/stemming/1.0)
#easy_install stemming

#coding:utf-8
import re
from stemming.porter2 import stem

class tokenizer:
    """ 切词器(EN) """

    def __init__(self):
        self.__stopWords = set(["0", "1", "2", "3", "4", "5", "6", "7",
                                "8", "9", "about", "after", "all", "also",
                                "an", "and", "another", "any", "are", "as",
                                "at", "be", "because", "been", "before",
                                "being", "between", "both", "but", "by",
                                "came", "can", "come", "could", "did", "do",
                                "does", "each", "else", "for", "from", "get",
                                "got", "has", "had", "he", "have", "her",
                                "here", "him", "himself", "his", "how", "if",
                                "in", "into", "is", "it", "its", "just", "like",
                                "make", "many", "me", "might", "more", "most",
                                "much", "must", "my", "never", "now", "of",
                                "on", "only", "or", "other", "our", "out",
                                "over", "re", "said", "same", "see", "should",
                                "since", "so", "some", "still", "such", "take",
                                "than", "that", "the", "their", "them", "then",
                                "there", "these", "they", "this", "those",
                                "through", "to", "too", "under", "up", "use",
                                "very", "want", "was", "way", "we", "well",
                                "were", "what", "when", "where", "which", "while",
                                "who", "will", "with", "would", "you", "your",
                                "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", ""])

    def parse(self, text):
        """ 获取词干/清理停用词

            @param text 待处理文本
            @return 有效文本
        """
        sentence = []
        for word in re.split("\W", stem(text).lower()):
            if word not in self.__stopWords:
                sentence.append(word)

        return sentence

bayesclassifier.py

#coding:utf-8

import os
import math
import tokenizer

class bayesClassifier:
    """ 贝叶斯分类器 """

    __trainingdata = {}                     # 存储训练数据
    __tokenizer = tokenizer.tokenizer()     # 切词器

    def __count(self, cls, lst):
        """ 计算指定文本隶属指定分类的概率

            @param cls 假定分类
            @param lst 待分析文档切词列表
            @return 结果预测
        """

        total = len(self.__trainingdata[cls])
        res = 1

        for s in lst:
            if s not in self.__trainingdata[cls]:
                # 避免乘积累积降低精度,改用对数相加
                # 规避语料未经"训练"的情况,也就是p(di/m)=0,做拉普拉斯校准,即令每一个切词基数+1
                res += math.log(float(1) / total)
                #res *= float(1) / total
            else:
                res += math.log(float(self.__trainingdata[cls][s] + 1) / total)
                #res *= float(self.__trainingdata[cls][s] + 1) / total

        return res

    def train(self, cls, text):
        """ 样本训练

            @param cls  样本所属分类
            @param text 样本内容
        """

        if cls not in self.__trainingdata:
            self.__trainingdata[cls] = {}

        # 统计各分类单词出现次数
        for word in self.__tokenizer.parse(text):
            if word not in self.__trainingdata[cls]:
                self.__trainingdata[cls][word]  = 1
            else:
                self.__trainingdata[cls][word] += 1

    def classify(self, text):
        """ 获取分类结果

            @param text 待测数据
        """

        t = -1 << 32
        res = "unkown"

        for cls in self.__trainingdata.keys():
            c = self.__count(cls, self.__tokenizer.parse(text))
            if c > t:
                res = cls
                t = c

        return res

StartUp.py

#!/usr/bin/env python
#coding:utf-8

"""
使用朴素贝叶斯算法对邮件归类 demo
@auth g 2010-05
"""

import os
import bayesClassifier

# 样本数据路经
articles = r"./articles"
# 分类器
classfier = bayesClassifier.bayesClassifier()

if __name__ == "__main__":
    # 训练
    print "#train.."

    for cls in os.listdir(articles):
        for f in os.listdir(os.path.join(articles, cls)):
            # 抽取文件名末位非0的文本为训练数据
            if int(f.rstrip(".txt")) % 10 != 0:
                classfier.train(cls, open(os.path.join(articles, cls, f)).read())

    # 测试
    print "#test.."

    # 标记测试总数/失败数
    totality = 0
    failed = 0

    for cls in os.listdir(articles):
        for f in os.listdir(os.path.join(articles, cls)):
            # 抽取文件名末位非0的文本为训练数据
            if int(f.rstrip(".txt")) % 10 == 0:

                expect = cls
                effect = classfier.classify(open(os.path.join(articles, cls, f)).read())

                if effect != expect:
                    failed += 1
                totality += 1

                print "%s\t@%s" % ("".join([cls, "/", f]), effect)

    # 结论
    print "#mark:"
    print "total %d tested." % totality
    print "failed: %d" % failed
    print "hit rate: %f" % (1 - float(failed) / totality)

实际测试中,取测试样本中末位不为0的文本为训练素材,其余为测试数据,正确率接近97%,表现出了较好的精度。

#mark:
total 394 tested.
failed: 12
hit rate: 0.969543

附样本数据:articles

分类: 烂笔头 标签: , , ,