好产品往往是用很烂的代码写出来的
“好产品往往是用很烂的代码写出来的”
忘记最早是在哪里看到的这句话的,最近深有感悟。
在开发的过程中,我们总是无可避免地会遇到需要在“代码质量”和“产品质量”之间做权衡的时候。作为一个程序员,我们往往会追求代码本身的美感,而忘记这个程序能够产生的价值。从用户的角度来说,除非他脑子进水了或者是一个geek,不然用户永远不会管你服务器用的是Linux系统还是万恶的Windows,服务器端的代码用的是php还是高贵的RoR,你是用Ctrl+C & Ctrl+V从网上到处抄来的代码,复用了别人已经开发好的系统,还是用尽了各种设计模式和PEAA中学来的各种架构模式、绞尽脑汁严格控制代码中空格和tab的区别以及行末是否有多余空格等亲手一行一行敲出代码来。
用户关注的是你这个产品能不能满足他的需求,是不是有很好的用户体验。
这让我想起了Chrome里处理ed2k链接的方式。Chrome现在是我最喜欢的浏览器,但是每次我要到verycd.com上面去找一张专辑或者一部电影(我承认我侵犯版权了,我忏悔……),我都会很不爽。
为什么?因为在找到一个资源之后,我要么需要在页面空白位置点击右键,然后查看源代码或者“检视页面元素”,手动找到这个链接,复制这个链接,填到eMule里;或者我要打开我万不得已才打开的IE,或者我要打开我臃肿的做开发的时候才用到的Firefox。在这个支付宝和建行都已经支持Chrome的年代,这种事情实在让我很难以接受。
为什么?因为Chrome不认ed2k的链接。
为什么?很明显,ed2k的链接对待”|”这个符号不太符合标准,由于Chrome的代码用一种通用并且优雅的方式对待所有URL Scheme,而正好ed2k链接是一个比较尴尬的特例,于是它的“|”符号被转义了。
去读那个issue里面的用户评论吧,我基本上笑死了:)有用户在问这不就是一个if语句么,而马上开发者就说这样很脏,开始讨论是不是有一种通用的方式去对待这一类特殊的URL Scheme。然后有人说貌似只有ed2k链接比较变态啊,不存在一类特殊的URL Scheme,而是只有一个。这下尴尬了,不存在从代码角度来说很“优雅”的解决方案,至少短时间内找不到。而这时一个看起来比较senior的开发者就出来讲了一大堆Chrome内部对URL的处理方式,试图解释为什么这个bug还没有被修掉。后来又有用户出来说了:
Comment by NoamNelke, Oct 30, 2009
I'm all against special-casing in general, but at least until a better solution
is found or agreed upon - please, just do it...
Google code上的Chromium项目已经有了超过29000个Issue,这个Issue的Id是160,是一个在Chrome 0.2时代就存在的bug。
这个Issue在Google code上的chromium项目里的优先级是P3,就算Chrome的用户只有极少数会像我这样去点击ed2k链接,但是
至于么?不就是一条if语句么?
看来Google的APM/PM还不够多呀。
———————————————————–
另外一件事情是,Windows里有一个名字叫abc的数据结构 ,而且还是一个API。
我就想,负责这块代码的工程师们得有多大的毅力和自制力去维护它,并且在MSDN上搞出这么专业的文档。
虽然我很想笑,但是我真的要向你们致敬。
———————————————————–
说到这里,大家应该满清楚了。其实问题就在于,我们写代码是为了满足别人的真实存在的需求,还是自己内心充满寂寞的成就感。
在我精神分裂了一年之后,我不太灵光的脑子终于把这个问题想清楚了:)
当然,这不是意味着,在饿了么产品质量是P1,代码质量是P2。在饿了么,代码质量绝对是P1,而产品质量则是P0。你可以先用dirty hack的方式满足产品的需求,但是回头还是得尽快用重构的方式,避免给将来带来太大的麻烦。
当然,饿了么这个产品现在还远远没有达到及格线的标准。如果满分是100分,现在最多只有30分。
不过幸好目前许多工作正在幕后默默地进行着,预计近期能够越过这条线:)
———————————————————–
Raymond童鞋加入之后,我代码写得越来越少,也逐渐有了许多时间处理各种其他事情,和进行思考。在经历了身兼PM+dev lead,磕磕碰碰惹下无数麻烦,带来无数问题,体质变差精神分裂的一年之后,我终于逐渐开始洗手不写代码了。希望从此大家能重拾对我的信心:)
作为一个*nix programmer(虽然SC和PW童鞋还不赞同),我最近很信奉Unix的一条哲学:do one thing and do it well. 或许真的有人可以很好的身兼PM和Dev Lead的角色,但是我还是太嫩了,并且或许这辈子都不可能做到。
但是这未必就不是一件好事,赫赫。
写了这么多,回头看看自己的网站还是那么的不尽如人意,实在是丢脸啊。我做不成一个好PM+dev,那我就努力至少成为一个好PM吧。
![]()
阿猫 阿狗 和 foosball
我住的南洋博士新居楼下有一只黄色大肥猫,每次我经过它的时候它总是眯着眼睛看着我,貌似很大牌的样子。有一天我试着去摸摸它的头,它居然很温顺地低头不动了。
————————–
今天早上出门的时候,天上下着蒙蒙细雨。刚上车没多久,一只超可爱的黄色小狗跟在我自行车后面跑,屁颠屁颠地几次差点撞到我的后轮胎。我怕撞伤它,赶快停了下来,结果它马上开始舔我穿着拖鞋的脚= =
看来这条狗没有人养的样子,正考虑要不要抱回去养着,结果阿康骑着电瓶车过来了,它马上就把我抛弃了屁颠屁颠地跟着阿康跑了……
————————–
ELEME DevDiv Office V3基本完工,灰常感谢阿康和他的富婆。今天早上我们一帮人把foosball桌子装了起来,玩得巨high,右手臂现在有点酸。
傍富婆真好。
————————–
Project Pearl Wave 1 (codename Arsenal) 于今天正式开始了。希望一切顺利:)
饿了么产品组招聘软件开发工程师
饿了么产品组招聘软件开发工程师,全职也可,兼职也可,“实习”也成。要求很高,待遇不差:)
饿了么是什么?
饿了么创办于2008年9月,目标是帮助中国餐饮业提供信息化解决方案,完成整体产业升级。目前为交大闵行校区,紫竹科学园区和周边住宅区提供网上订餐和代购业务,运营状况健康,发展势头迅猛,预计将在半年内扩张到周边区域,一年内业务遍布全上海。现今因短时间内业务快速扩张的需要,产品部门需要新鲜血液加入。
饿了么的创始人均为上海交大校友,其中两人已经休学,一人已在今年本科毕业后全职加入。产品组办公地点在地铁剑川路站附近,距离交大北门10分钟自行车车程。
不就是个订餐网站么……
对,从用户的角度来看,的确是这样。从某种意义上来说,iPod也就是一个mp3播放器,kindle也不过是一个电子书阅览器而已。我们不想成为一个只会吸引用户注意力,浪费用户宝贵时间的网站,我们希望能够做出一个真正有价值的工具,一个真正能够给用户带来便利,给餐厅提高效率,带来收益的工具。日本的出前馆做出了这样的一个工具,美国的OpenTable做出了这样的一个工具,他们都上市了。淘宝、阿里巴巴、百度和Google从某种意义上来说,也都只是工具而已。
我们正在着力打造的是:
- 一个针对用户的足够简单足够强大的订餐工具;
- 一个针对餐厅的真正提高效率带来收益的软件即服务(SAAS)产品;
- 一个基业长青,百年不倒的伟大公司。
为什么我要选择饿了么?
在这里,你将获得和大型软件公司完全不同的体验:你面对的不会是业界最难的问题,你也不会困死在长达一年的项目周期里。有的只是敏捷开发,敏捷项目管理。你要关注的是getting things done.
你将体验大多数人一辈子都无法经历的最刺激的创业过程,你将感受和整个公司一起飞速成长的快感。在饿了么,每天都有新变化。在饿了么,我们互相学习,共同成长。在饿了么,我们 work hard, play harder.
我需要具备怎么样的能力?
我们需要真正卓越的人才,至少,你要有追求卓越的决心和毅力。
我们希望你有扎实的技术功底,踏实的作风。
最重要的,是有快速学习的能力,和学习的热情。Smart and get things done.
至于你具体会什么技术,不会什么技术都完全没有关系,我们相信只要你够聪明并且喜欢解决各种难题,你总会在团队里找到自己的位置。
我们目前用到的各种技术有(仅列出部分):
C(餐厅出单机驱动),CSS/XHTML/Javascript/JSON(网站前端),PHP(网站后端),shell脚本(各种自动化脚本),python(Google App Engine脚本),Java(数据挖掘和机器学习)和Linux自定义发行版(餐厅终端机所用的系统)。
同时,我们有完善的版本控制,逐步进入正轨的项目管理和产品发布机制。
看,饿了么不仅仅是一个简单的订餐网站吧?:)
我来了能做什么?
参与网站的开发,参与网站的测试,参与网站的设计,参与网站的运作。只有想不到,没有做不到。
饿了么能给我提供什么?
绝对有竞争力的待遇,绝对有竞争力的学习机会,绝对有竞争力的表现自己的舞台,最刺激的创业体验。
工作地点在哪里?
地铁剑川路站附近,距离交大北门10分钟自行车车程。
时间上有什么要求么?
为了保证有效的沟通,所以每周能够过来的时间越多越好,毕竟团队还很小,我们承担不起太高的沟通成本。原则上工作时间不少于每周3天,不过这个时间你可以比较灵活地进行安排。
如何加入?
发邮件给阿福 forrest dot ye at ele dot me,请附上简历。
我们不是最有经验的,但是我们是最有热情的。相信我,加入饿了么并且用心去做,这份经历会成为你这辈子最宝贵的财富之一。
Stay hungry, stay foolish. 你饿了么?
[译文] symfony 参考指南 – 配置文件原则
原文:the symfony Reference Book, http://www.symfony-project.org/reference/1_2/en/03-Configuration-Files-Principles
翻译:ELEME Dev Team
symfony 所有的的配置文件都基于一套共同的原则,并使用一些公共属性。本节将详细地介绍这些原则和属性,并且可为后面几个关于YAML配置文件的章节提供参考。
缓存
symfony 的配置处理类会将所有的配置文件缓存为 PHP 文件。当 is_debug 属性设置为 false 时 (例如在 prod 环境中,即生产环境),symfony 仅会在首次请求中对配置文件进行缓存处理,而在这之后的所有请求都将访问相应的 PHP 缓存文件。对 YAML 文件的解析是一个较“重”的处理过程,缓存机制使得这个过程只执行一次。
在
dev环境(即开发环境)下,is_debug属性默认设置为true,symfony 将在每一次配置变化后重新分析处理缓存(symfony 会检查文件的修改时间)。
可以通过 config_handler.yml 文件来配置解析和处理配置文件所需的配置处理类(configuration handler class)。
在以下各节中,我们称 symfony 将 YAML 文件转化为 PHP 文件并存储在缓存中的这一过程为“编译”。
要强制清空配置缓存可以使用
cache:clear命令:$ php symfony cache:clear --type=config
常量
配置文件 : core_compile.yml , factories.yml , generator.yml , databases.yml , filters.yml , view.yml , autoload.yml
一些配置文件允许使用预先定义的常量。symfony 通过占位符来使用常量,即在大写的常量名两侧加上“%”符号,类似于“%XXX%”。当配置文件被编译时,symfony 会用常量的实值去替换掉所有相应的占位符。
使用配置文件中的常量
settings.yml 中定义的任何设置都可以作为常量来使用。其占位符为大写的设置名称并在开头加上 SF_:
logging: %SF_LOGGING_ENABLED%
当 symfony 编译配置文件时,它会从 settings.yml 文件中读取常量的值并替换掉占位符。在上面的例子中,symfony 会在 settings.yml 中查找 logging_enabled 这一设置,并用其值来替换占位符 SF_LOGGING_ENABLED。
使用应用程序设置文件中的常量
与使用 settings.yml 文件中的常量类似,可以通过添加 APP_ 的前缀来使用 app.yml 中的设置。
特殊常量
默认情况下, symfony 根据当前的前端控制器定义了四个常量:
| 常量 | 描述 | 配置方法 |
|---|---|---|
SF_APP |
当前应用程序名称 | getApplication() |
SF_ENVIRONMENT |
当前环境名称 | getEnvironment() |
SF_DEBUG |
是否启用调试 | isDebug() |
SF_SYMFONY_LIB_DIR |
symfony 库目录 | getSymfonyLibDir() |
文件和目录
当你需要引用一个文件或目录地址时,使用常量而不是硬编码是个很不错的主意。symfony 已经为一些公共目录定义了对应的常量。
SF_ROOT_DIR 对应于 symfony 目录树中的根目录,其余所有目录变量都通过这一变量产生。
项目目录结构的常量定义如下:
| 常量 | 默认值 |
|---|---|
SF_APPS_DIR |
SF_ROOT_DIR/apps |
SF_CONFIG_DIR |
SF_ROOT_DIR/config |
SF_CACHE_DIR |
SF_ROOT_DIR/cache |
SF_DATA_DIR |
SF_ROOT_DIR/data |
SF_DOC_DIR |
SF_ROOT_DIR/doc |
SF_LIB_DIR |
SF_ROOT_DIR/lib |
SF_LOG_DIR |
SF_ROOT_DIR/log |
SF_PLUGINS_DIR |
SF_ROOT_DIR/plugins |
SF_TEST_DIR |
SF_ROOT_DIR/test |
SF_WEB_DIR |
SF_ROOT_DIR/web |
SF_UPLOAD_DIR |
SF_WEB_DIR/uploads |
应用程序目录结构是根据 SF_APPS_DIR/APP_NAME 所定义的:
| 常量 | 默认值 |
|---|---|
SF_APP_CONFIG_DIR |
SF_APP_DIR/config |
SF_APP_LIB_DIR |
SF_APP_DIR/lib |
SF_APP_MODULE_DIR |
SF_APP_DIR/modules |
SF_APP_TEMPLATE_DIR |
SF_APP_DIR/templates |
SF_APP_I18N_DIR |
SF_APP_DIR/i18n |
最后,应用程序的缓存目录结构定义如下:
| 常量 | 默认值 |
|---|---|
SF_APP_BASE_CACHE_DIR |
SF_CACHE_DIR/APP_NAME |
SF_APP_CACHE_DIR |
SF_CACHE_DIR/APP_NAME/ENV_NAME |
SF_TEMPLATE_CACHE_DIR |
SF_APP_CACHE_DIR/template |
SF_I18N_CACHE_DIR |
SF_APP_CACHE_DIR/i18n |
SF_CONFIG_CACHE_DIR |
SF_APP_CACHE_DIR/config |
SF_TEST_CACHE_DIR |
SF_APP_CACHE_DIR/test |
SF_MODULE_CACHE_DIR |
SF_APP_CACHE_DIR/modules |
环境
配置文件 : settings.yml , factories.yml , databases.yml , app.yml
某些配置文件与 symfony 的当前环境有关。这些文件通过划分不同的区段,为每个环境设置不同的配置。当创建一个新的应用时,symfony 会创建三个默认的环境:prod(生产环境),test(测试环境),和 dev(开发环境):
prod: # `prod` 环境的配置 test: # `test` 环境的配置 dev: # `dev` 环境的配置 all: # 所有环境公用的默认配置
all 区段为所有的环境提供默认设置。当 symfony 从配置文件中读取一个设置时,它会优先使用相应环境区段中的配置,若当前环境区段中没有提供该设置,则 symfony 会在 all 区段去寻找它。
配置的级联
配置文件 : core_compile.yml , autoload.yml , settings.yml , factories.yml , databases.yml , security.yml , cache.yml , app.yml , filters.yml , view.yml
有时候,同一个配置文件可以在几个不同的 config 目录多次出现,symfony 会按照目录结构合并它们。
symfony 在编译配置文件的时候,会根据以下顺序先后合并多个文件中的配置信息:
- 模块配置(
PROJECT_ROOT_DIR/apps/APP_NAME/modules/MODULE_NAME/config/XXX.yml) - 应用程序配置(
PROJECT_ROOT_DIR/apps/APP_NAME/config/XXX.yml) - 项目配置(
PROJECT_ROOT_DIR/config/XXX.yml) - 插件配置(
PROJECT_ROOT_DIR/plugins/*/config/XXX.yml) - symfony 库配置(
SF_LIB_DIR/config/XXX.yml)
例如,在一个应用程序目录中定义的 settings.yml 将默认继承这个应用程序所在项目的 config 目录中 settings.yml 的配置信息,而项目的 settings.yml 又是继承自 symfony 框架的默认 settings.yml 配置文件中的配置信息(lib/config/config/settings.yml)。
当一个配置文件与环境相关,并在多个目录中,那么则按照下面给出的优先级来合并配置:
- 模块
- 应用程序
- 项目
- 特定环境
- 所有环境
- 默认值
上周ELEME Dev Team工作总结
经过一周的辛勤工作,我们很开心地发布了一个新版本,主要包含以下内容:
1. 做了许多工作,大大提高了网站的安全性
具体细节不谈:)
2. 修改密码功能完成(终于……)
在登录后的页面右上方,可以看到一个修改密码的链接:
![]()
点击此链接即跳转到修改密码页面

3. 更改密码时需要输入原始密码,那么如果忘记密码了怎么办?找回密码!

输入注册时候的邮箱,饿了么会自动给您发送一封找回密码的邮件



为了您的安全考虑,您在饿了么的密码是经过单向哈希处理的,所以我们也不知道您的原始密码是什么。不过你可以重设密码:)
4. 可以用注册时候使用的Email登录饿了么了!
大家可能已经发现,刚刚这个图上有一点不一样的地方:

有时候,阿福经常会忘记自己在一个网站上的用户名是什么,所以有些网站在有找回密码功能的同时,还需要另一个功能,叫找回用户名……
所以,为了大家更方便地使用饿了么,现在你也可以用Email地址登录饿了么啦:)很简单,填入Email地址,填入密码,提交!
5. 咦,我刚刚下的订单哪里去了?
饿了么是支持不注册不登录直接下匿名订单的,但是之前存在一个这样的一个情况:
你下了一个匿名订单,然后在订单中心看到了这个订单。然后你注册,然后登录,然后到订单中心,发现订单不见了……
不用担心,现在这个问题已经没有了:)现在,在你登录之后,饿了么会帮你之前下的匿名订单转化成你的订单,再也不用担心订单不见的问题了!

这是刚刚下的匿名订单

成功认领匿名订单!
6. 更多……
还有,我们修复了灰常多的bug,做了灰常多的代码优化。饿了么每天都在成长:)
饿了么大大扫除
昨天,我们进行了一场大大大大扫除,整理出一个房间,饿了么DevDiv(Developer Division)终于有独立办公室了:)
废话不多说,上图:
浏览更多,请到
http://www.flickr.com/photos/forresty/sets/72157619862472826/
或者阿福校内:
http://photo.xiaonei.com/getalbum.do?id=309803401&owner=229030294&ref=minifeed
或者
http://cid-6fa2b93b87c3068f.skydrive.live.com/browse.aspx/2009-06-17%20ELEME%20DevDiv%20Office%20V2









最近评论