2008年11月23日星期日
Chinese Blogger Conference 2008
第一天去到会场,就见到了LEMONed和hidecloud,然后拿到了我的fail whale tee。接下来的session……其实我不知道session讲什么,我想大多数人都跟我一样不关心session讲什么,大家只是找个机会来聚会而已。中午跟Elliot Ng一起吃了午餐,并且拿了一件CNReviews的tee。下午的session也是不知道讲了什么,然后就是自助晚餐了和Punch Party了。
自助晚餐吃的是点心,虾饺和牛肉丸都不错,但是鸡翅就很难吃。接着Punch Party正是开始,第一位上台的是Carol,介绍什么是Punch Party。所谓的Punch Party,就是每位speaker有7分钟的时间,大概就是20个slide每个slide讲20秒的时间再多一点。当晚的Punch Party做得非常perfect,每一个人讲的话题都十分之吸引人,做到了Punch Party所强调的punch效果——让人感觉耳目一新。Carol作为第一个speaker,把全场的气氛都调动起来了。中间有介绍大陆吃喝玩乐之行有多艰险的工头坚,还有介绍胖卡如何把宅男配送到乡下的。最后一位导演先生,表演了7分钟的无声演讲——开头只说了一句,“由于接下来的内容都很晦涩,所以自动进行静音处理”,接着做了7分钟演讲的动作与口型,幻灯片翻了几页,但是没说过一个字。对于所有参加Punch Party的人来说,这样的结尾实在是太impressive了!
Punch Party的好处显而易见,能够在最短的时间内让你了解到一些你可能永远都接触不到的知识,同时给你无限的震撼感。不过我觉得Punch Party对speaker的要求也挺高,否则也不容易做好。而且作为organizer,一场Punch Party必须组合不同类型的speaker。
第二天的session稍微有趣一些,不过依然没怎么听,莫非年会的习俗就是把重点放在晚上?下午年会结束后大家就跟着Issac Mao到“友鸡会”吃了火锅,然后到北风的凸凹酒吧去聊天。我也不知道最后大家是什么时候才回家的,我快到凌晨时已经想睡觉了,于是就回家了。
2008年11月13日星期四
Live Mesh vs MobileMe
Live Mesh的好处是可以指定任何一个目录进行同步,而非指定一个同步目录然后要同步的东西必须放在里面,这方面就比MobileMe要好。而且Live Mesh的自动同步客户端同时兼容Windows和Mac,而MobileMe仅仅支持Mac同步。Live Mesh唯一不足就是没有版本控制,不过我想要是有版本控制占用的网络空间和流量开销就成倍增加了。
MobileMe给我印象最深刻的是,我重装了我的MacBook后一登录MobileMe帐号就帮我把整个System Preferences给恢复了。当然,联系人和日程信息也都恢复了,这是现在Live Mesh完全没覆盖到的功能。另外对iPhone的push服务也做得很好,更新什么信息都在Mac上进行就可以了,根本不用管它什么时候同步到iPhone上。
我觉得最好就是把这两种服务结合到一起,一个帐号一个服务就把这些都覆盖了,当然我不介意付费。在TechED MVP Dinner上,我和一位做Azure的Microsoft员工聊了一下,说最好Windows上的程序都遵守Vista的规范,把代码和数据分开存放,也就是数据都放到C:\ProgramData下面,这样Windows也就如同Linux一样能够轻松备份纯数据了。接着只要把数据同步到cloud上面,例如说是Azure上层的Live Mesh,重装机器后就能够把数据重新同步回来了,只要再装上应用程序就一切恢复原装了。
2008年11月9日星期日
开始翻译 Adobe AIR in Action
其实AIR出来之前我就想去学习,很多很多技术都如此,不过翻译算是一个很好的学习过程,因为它逼着你认认真真把一本书读懂。这次着手翻译Adobe AIR in Action,我想半年后我也会熟悉AIR相关的技术。虽然我一直以来都对Flash和Flex没什么深入了解,但我希望这些知识反过来也能用到Silverlight开发上,结合两派的模式从而进化出一种更好的实践方法。
另外我还介绍了身边的朋友去翻译Practical Prototype and Script.aculolus。Manning即将发布Silverlight 2 in Action,如果图灵引进这本书的话,我也去看看是否能够参与翻译。
2008年11月4日星期二
以服务器端为中心的 ASP.NET AJAX 模式 (Part 2 - Control)
在上一篇文章当中,也就是《以服务器端为中心的 ASP.NET AJAX 模式 (Part 1 - Behavior)》,我们探讨了较为易用的Behavior模式。之所以说它较为易用,是因为它不涉及和原有Page处理流程的交互,即使访问网络也是访问独立的Web Service(包括Page上的[WebMethod]),因此和Page处理流程的设计绝对是正交的。但有时候我们需要的就是与Page处理流程的交互,这时我们不得不使用与服务器端逻辑紧耦合的Control了,这正是本次文章要讨论的内容。
在基本的 ASP.NET AJAX框架下,我们有三种方法来做基于Control的Ajax操作,它们分别是UpdatePanel、ICallbackEventHandler 和IScriptControl,下面我们就分别看看它们的特点和使用场景。
UpdatePanel
UpdatePanel 是与服务器端逻辑进行交互的多种方案中最易用的一个,甚至就不能称之为交互——你根本就不需要触及任何客户端逻辑。一个服务器端操作,经过 UpdatePanel的“劫持”,变成了一个客户端操作,而这个客户端操作又直接调用对应的服务器端操作,就这么简单。
如果用UpdatePanel来做一个带分支的选择对话框,那应该如何设计?思路可别跑到客户端的confirm方法上去,那可太绕了,或者说太不 ASP.NET AJAX了。用UpdatePanel,就应该坚持它的理念,一切客户端操作都是幻象,所有操作其实都是在服务器端进行的,包括选择对话框。要按 ASP.NET的思路来做,我会做一个选择对话框控件,它的实质可能是一个浮动层模拟的对话框,这属于实现细节,我们不用太关注。重点是,这个选择对话框的分支逻辑是完全在服务器端进行的,Async PostBack之后服务器端根据提交回来的数据决定如何触发事件。这样做整个分支选择的逻辑就是内嵌在Page处理流程当中的,不需要通过 Cookies或者Session来做数据的中转媒介,避免了Page处理流程与更大作用域中的数据的紧耦合。
UpdatePanel 适用于逻辑完全在服务器端的开发,并且我建议使用UpdatePanel时也就把所有逻辑放在服务器端,不要去写一些混合服务器端逻辑与客户端逻辑的代码。有人会说,你看老赵就很喜欢去动那个 Sys.Net.WebRequestExecutor来改变UpdatePanel的行为啊,但其实这属于分层设计思想中的一部分,他去动那个东西改变的也就是一个分层内的逻辑,只要层与层之间的接口不变,具体实现是可以按需设计的。但如果你用了UpdatePanel,同时又用Cookies或者 Session来传值,这就跨越了n个层,增加了不少耦合度。
ICallbackEventHandler
关于ICallbackEventHandler,我已经说过无数次了,重点还是你必须用Page处理流程来思考,只要你理解了Page处理流程,你就明白为什么ICallbackEventHandler在.NET Framework 2.0 Beta2中只有一个方法,而到了RTM要分拆成两个方法。具体可以参考《ASP.NET 2.0 ClientScript Callback》,我就不再重复了。
如果用 ICallbackEventHandler实现一个带分支的选择对话框,又如何做?和使用UpdatePanel的做法类似,我还是会做一个选择对话框控件,并且这个控件继承自ICallbackEventHandler。为这个控件编写JavaScript并实现 ICallbackEventHandler接口时,我会确保JavaScript对Callback给出正确的调用参数,并在接口方法的实现中接收这些参数然后触发正确的事件,就这么简单。和UpdatePanel一样,不要偏离了ICallbackEventHandler的设计思想,它的处理流程必须是合并到Page处理流程中的,你的控件也就必须这样设计。
至于在什么情况下选择 ICallbackEventHandler?如果你有一个轻量级的Ajax操作,但使用UpdatePanel更新整个区域的HTML开销很大的话,那么你可以考虑使用ICallbackEventHandler。当然,前提是你懂得控件开发和JavaScript。
IScriptControl
这是最复杂的解决方案了,你需要实现一个Control的两个副本——一个服务器端的,一个客户端的。有一部分逻辑,是要在客户端和服务器端重复实现两次的,而另外一部分逻辑,只需要在客户端或服务器端之中的一个实现一次。IScriptControl的经典例子,当然是ASP.NET AJAX自带的Timer控件。它的计时器是纯粹的客户端逻辑,然而Tick事件却在服务器端触发,Async PostBack成为了两者之间的桥梁。当然,就Control本身而言,它并不在乎PostBack是不是异步的,Tick事件只因PostBack而触发。
如果用IScriptControl来实现带分支的选择对话框,那将会和 ICallbackEventHandler的版本十分相似,唯一不同的地方就是它在客户端的逻辑会被封装为一个Sys.UI.Control的派生类,而ICallbackEventHandler的客户端逻辑往往是不封装的。这样的好处显而易见,那就是代码更容易维护了,并且客户端的Control可以同样可以加入事件支持,并提供和服务器端一样的代码分支事件。要知道在CTP阶段的Timer控件,其客户端版本Sys.Timer(而非RTM的 Sys.UI._Timer)是拥有tick事件的,和服务器端的Tick事件对应,只不过RTM取消了此项功能,因为ASP.NET AJAX 1.0的侧重点完全就是服务器端功能,客户端功能都被砍掉了。
什么情况下选用IScriptControl?如果你认为你的客户端逻辑应该封装为Sys.UI.Control的派生类,那就选择IScriptControl吧。
小结
我们分别讨论了三种通过Control实现Ajax调用的方案,并且一再强调了设计必须基于Page处理流程,不要在此流程之外增加不必要的复杂度和耦合度。值得一提的是,有很多人质疑为什么要在Web上提供这样一个支持分支的选择对话框功能,我的看法是这样的:既然客户端软件的流程会有此功能,那么 Web应用也有此功能就实在是太正常了,你删除blog post的时候问你一下是否确认删除,难道会有人觉得这个功能是设计错误?可能不同的只是表现形式而已,到底是confirm还是弹出层,甚至是一个专用的过渡页面。然而从用户体验的角度来说,这其实并不是最优的方案,多数时候用户删除就是确认删除,并不需要再问一次是否确认之类的愚蠢问题,但开发人员觉得用户错手删除的后果应当由用户自己承担,所以就做了这样一个对话框来推卸责任。真正好的用户体验是不需要确认的删除,但用户一定能够恢复,最好是按一下 Ctrl+Z就可以了,然而对于开发人员来说还是有很多操作是无法做到可恢复的,这时候除了显示对话框也没有更好的解决方案了。
最后,如果你喜欢我的文章,可以通过订阅feed来及时获得更新:
2008年11月3日星期一
软件安装时到底是否应该让用户选择路径
到底不让用户选择安装目标好不好?我们认为用户分为三个层次:
- 入门用户 - 购买的是品牌机,可能就一个C:和一个用于一键恢复的D:。这时候有什么好选择的呢?当然是不选择最好了。
- 熟练用户 - 经受过文件难以搜索或者忘记及时备份误删文件的种种磨难,学会了分门别类存放文件,自己有计划地把硬盘分成C:, D:, E:, F:四个盘。这时候你不满足他分类存放文件的习惯,他就会觉得很不爽了。
- 高级用户 - 经过无数次备份与重装后又在返璞归真,只用一个C:,安装时多数选项都直接next,不选择安装路径。
事实上,我认为给用户那么多选择是没必要的,文件的搜索与备份应该通过其它手段来改进,而不是让用户手动归档。要求用户理解文件系统,就如同要求调用者理解API实现方式一样,其实是很不合理的。
对于现在的品牌机而言,只有一个C:,培养Windows用户好像Mac用户那样,什么都装到一个盘里面,这才是正确的发展道路。Mac有Spotlight,Windows Vista现在也有不错的磁盘索引与搜索系统,将来实现了WinFS或许能做得更好。
现在Windows缺的是一套好用的备份与迁移方案,问题来源于Windows软件都没有规范地把可执行代码与数据分离存放,所以没有一种统一的模式来备份软件数据。如果Windows上面的软件能够按照Vista的指引,把数据都存储到C:\ProgramData,那么接下来的事情就容易多了。况且我之前也说过了,这也是UAC的意义所在,有助于提高Windows的安全性。
2008年10月27日星期一
以服务器端为中心的 ASP.NET AJAX 模式 (Part 1 - Behavior)
早在ASP.NET AJAX从CTP转向Beta再转向RTM时,看着客户端的Control被逐步放弃,与此同时ASP.NET AJAX Control Toolkit越来越多地使用Behavior,我就想深入说说ASP.NET AJAX的模式。不过由于我比较懒,所以这个话题只在《理想的 ASP.NET AJAX (Part 2 - Server Centric)》中一笔带过,没有深入讨论。今天看到volnet的《我们究竟是否有在“Asp.net中模仿Winform的MessageBox ”的必要?》,决定写一个文章系列来说说ASP.NET AJAX的模式。
什么是Behavior?
什么是Behavior?Behavior与Control有什么不同?这是首先需要回答的问题。
在Windows开发当中,Behavior的概念是不存在的,有的只是Control。ASP开发连Control都没有的,到了ASP.NET才引入了Control的概念。为什么Ajax开发要引入Behavior这样的概念呢?因为Behavior意味着不需要改变原有的组件逻辑,而改变原有组件的逻辑在客户端往往是不可行的,至少是难以实现的。
举个最简单的例子,一个<input type=”text” />就是一个浏览器内部的对象,你无法扩展这个对象的类型,也无法为它加上新的属性与方法,至少并非所有浏览器都允许你在JavaScript中这样做。然而如果你想要让它加上auto-complete(或曰suggest)的功能,这是可以做到的,并且很多人都做过了,例如ASP.NET AJAX Control Toolkit的AutoComplete,或者是script.aculo.us的autocompleter。这些实现都基于同一种方式,就是尝试基于input已有的接口在它之外添加新功能,而非尝试继承input并在它之内添加功能。
类似的做法在Ajax开发中普遍存在。例如说拖放吧,现在离HTML5拖放的全面普及不知道还有多远,所以大家都只能基于现有的鼠标事件来开发拖放功能。又或者说带有验证功能的输入框,无论是input还是select,无论是客户端验证还是服务器端验证,也都是基于现有HTML元素的事件来完成的。这一切都是Behavior。
什么情况下使用Behavior?
简单归纳,就两个条件:
- 需要基于特定的一个组建进行扩展
- 组建本身所处的环境缺乏可扩展性
单看第1个条件,我们有丰富的选择。很多人的第一反应就是继承自该组件,把扩展功能做到子类里面。熟悉设计模式的话,可能还会想到decorator pattern。然而在浏览器的环境当中,受到第2个条件的限制,继承或者decorator pattern都是不可行的。这时候,我们就需要使用Behavior了。
在一定程度上,我们可以把Behavior看作一种折衷了的decorator pattern。在decorator pattern中,decorator也继承自组件,因此当一个组件使用decorator pattern后,我们就把decorator放在原组件所处的位置上,而原组件就成了decorator的一个子节点(基于树的角度来看的话)。如果再加一个decorator,原decorator就会如同一个普通组件那样再被封装一次。在多个decorator的情况下,decorator之间是串联的关系。Behavior本身不是一个浏览器内部的组件,它无法继承自input的基类,因此Behavior也不能串联。Behavior本身本也不会取代input在树中的位置,这使得Behavior可以并联起来——一个input可以有多个Behavior,例如一个是自动完成,另外一个是输入验证。
总之,如果你原来的工作就是和UI打交道,并且熟练使用decorator pattern,那么在进行Ajax开发时把decorator pattern换成Behavior就可以了。
小结
回过头来看文章开头所说的MessageBox(或曰confirm)的问题,如果这个功能不需要对服务器端进行反馈,完全可以使用Behavior实现。ASP.NET AJAX Control Toolkit就有ConfirmButton这样一个东西,在客户端叫Behavior,在服务器端叫Extender,其实Extender就是对Behavior在服务器端做一下封装而已。当然,ConfirmButton不能完全实现MessageBox的功能,它只能在用户选择“取消”时取消整个提交操作,但不能够执行另外一个服务器端的代码分支。这算是Behavior的一个限制,就是它只能在客户端添加额外的功能,但是它不能影响到与服务器端的交互。但很多时候,正是这种限制确保了我们开发的组件是与服务器端解耦的。
如果我真的需要一个与服务器端交互的客户端组件,例如支持调用服务器端代码分支的confirm,怎么办?这时候你就真的需要一个与服务器端Control对应的客户端Control了。请关注本系列的下一篇文章,《以服务器端为中心的 ASP.NET AJAX 模式 (Part 2 – Control)》。通过订阅feed,你可以及时获得文章更新:
P.S.既然提到了Behavior和Extender的一一对应关系,就不得不说一下,服务器端的Extender就是真正的decorator pattern。
2008年10月26日星期日
远离国内的 SNS
如果要详细解释这件事,就要从很久很久以前说起,就是海内刚刚开放注册的时候。在改为邀请注册之前,海内曾经开放注册过几天,让及时获得消息的geek们第一时间获得了帐号,那时候我还没有多少好友在上面,已有的好友没有多少活动,news feed自然不值得一看。
后来,海内上的好友逐渐多起来了,大家也更活跃了,这是我认为海内最好的一段时候了。虽然,这时候的news feed算法也不怎么样,例如不会把同类项合并了,也不会对信息按照重要程度进行过滤。我之前也说过,Facebook的真正价值就在于它的news feed,news feed的算法不行也就以为着海内能为用户带来的价值优先。
随后,海内开始把重心转移到游戏开发上来。买卖好友可以说是为了刺激用户数量的扩张,但越来越多的游戏上线让我觉得整个海内都变得以娱乐白领为首要目标了。我的个人观点是跟Bean和Awflasher差不多,虽然中国人口众多必然导致劳动力过剩,但让每个人都把自己过剩的劳动时间投入到游戏当中并不是好事情。当海内的news feed充斥着各类游戏相关的信息时,我就不再去看海内了。
说完了海内,国内的其他SNS我想也没必要一一列举了。海内曾经是国内最用心用力想称为白领SNS的一个了,国内其他成功SNS的目标从一开始就定为娱乐性SNS,短期内不可能得到比海内更有价值的结果。在这里我所说的价值不是指SNS本身的商业价值,而是指推动国内SNS用户素质提升的价值,是指创造SNS之外的商业价值的可能性。
2008年10月23日星期四
China MVP Open Day 2008
我是17号晚上和飞飞一起从中关村打的去汤山的。Bean则是当晚深夜飞过来,很可惜Bean不知道联合航空到北京的飞机是停南苑机场的,结果从南苑机场打的到汤山还费了他不少时间和金钱。Dflying早些时候就飞来北京了,不过不知道去哪里玩了,竟然18号晚上不到酒店让我一人独占房间。18号晚上去到后,人都散了,只是见到了Sisley、Eddie等人在筹备第二天的晚会,当然还有排舞的老葛等人。
由于晚上看Wanted看到凌晨两点,18号一起来就赶去吃早餐,接着就见到了Mango和Bean。由于我第一天晚上没有签到,吃完就马上赶去签到领衣服——没办法,早上的keynote规定大家要穿统一的衣服。keynote上讲了很多东西,还颁了奖——就是MVP每年一块的水晶座,今年是奥运年所以是火炬造型的水晶座——不过整个早上最让大家兴奋的应该就是那台Surface了。据说中国只有一台Surface,放在MSRA,估计就是那一台了,现在拿来向我们展示WPF如何开发Surface应用程序,keynote之间我们就都冲上台玩这台Surface顺便拍照。
中午的午餐组织得有点混乱,实际上整个MVP Open Day都组织得比较混乱,不知道是不是因为会务外包了给CSDN。据说因为会务很赚钱所以CSDN现在热衷于做这个,不过确实不太专业。
接着就是下午的一对breakout session了,不过没有哪个我特别感兴趣的——完全没有ASP.NET或者Silverlight的session嘛……我和Bean在户外找了个地方坐下来上上网聊聊天,后来俞晖也加入进来了,包包跑过来和我们照相,Dflying说公司有事要立即赶回上海(他还真没在酒店住过一晚)……整个下午我就没有专心听过一个session,都是周围跑去见别的MVP。
午餐按照技术特长来分组,晚餐就是按照地区来分组,俞晖和紫柔跑来我们广东桌装广东人,俞晖还是忘记不了说他喜欢吃螃蟹并且对于没有螃蟹感到可惜。我则一再要求紫柔把我从Web版主调回ASP.NET版主,因为当初无拉拉被分到Web版主实在让人郁闷,大部分IIS、IE之类的问题我都无法回答上来,也不确认其他人的回答是否正确。
晚餐之后就是晚会了,一个半小时其实不算长,不过留下更多时间给MVP交流也是对的,随后就是博客园的MVP聚会。在博客园上的大部分MVP都来了,没来的据包包统计大多都是上海的,例如Jeffery Zhao——我很好奇他所谓的减肥成功到底是什么效果,可写他就是不出现。博客园的聚会,就是大家各自自我介绍,然后分组讨论,晚上黎波来了——他虽然没有MVP连任成功,不过刚好也在北京为Microsoft的客户部署项目——我就和他聊了一下Sharepoint。回到房间之后,我叫了Bean过来聊天,不过没聊到什么他就回去睡觉了。
19号早上是拓展训练,就是盲人方阵和毕业墙两个项目,我们组做得还不错。中午吃饭后就是期待依旧的参观鸟巢了——其实我一直不认为鸟巢如何如何特别,不过倒还是个很值得拍照的地方。一群MVP搭大巴来到鸟巢,被告知水立方和玲珑塔都不对外开放了,于是只能进入鸟巢参观。整个广场确实很大,不过设计确实不怎么样,很多地方都很不人性化——鸟巢很多长长的楼梯,出去少数电梯后竟然没有扶梯,这叫来自发达国家习惯走到哪都是扶梯的人怎么适应呢?整个广场那么大,座位放了很多但就是不见洗手间,垃圾分类就不要期望了因为连垃圾桶都是那种很丑陋带轮子的。简单来说,看看鸟巢就知道典型的北京本地价值观了——很追求体积上的庞大,或者说是“排场”,但是不注重细节,也不懂得什么叫人性化。
参观完鸟巢后,拍了几张集体照就解散了,去机场的、去火车站的、直接回家的……基本上都涌进了地铁站,然后各自超自己的方向走。
2008年10月19日星期日
有空要做个 Theme Software Corp 的游戏
将来如果有时间做游戏,就做一款Theme Software Corp。市场是有各种奇怪的需求,然后要请PM来做研究并得出产品开发计划,再要请SDE来开发,之后还要请SDET来提高质量。为了保证这群人的满意度,和招聘到更加高级别的人员,必须购买各种设备来满足他们奇怪的生活需求,从咖啡机到按摩椅,还有Wii、XBox360或者PS3,甚至自己建移动大厦加一个游泳池。结果发现这些人每天来到就去拿咖啡或者可乐,然后开始看看feed,最后工作一会儿又闪出吃饭了。你想尽办法利用他们的才能,但是innovation的发挥却是很不稳定的,项目不停delay士气下降,你又要投资点什么来补救。
总之,这个游戏应该继承Theme Hospital的一些关键特性,游戏中的各种事件都是很无厘头的,同时你又要努力balance游戏中不同的指标——正如Dreaming in Code中说到的质量三角,时间、金钱、特性三者不可能都得到,在追求其中一个的时候必然削弱另外的两个。这样在有相当游戏难度的同时,又有娱乐性可言。
2008年10月9日星期四
最糟糕的一次飞行经历
在广州白云机场的B区登机,又是一层登机口,意味着肯定是搭摆渡车的。开头以为好像上次那样,飞机是国际航班转飞国内,所以停在A区空地了,结果还真是这样,而且还不是停在A区空地——是泊在A区登机桥边了!那天广州暴雨,如果飞机停在空地,登机专用车是有遮顶的,这样登机还不至于淋湿。但飞机泊在登机桥边了,就要从地面爬上登机桥(我终于知道登机桥边的楼梯有什么用了),楼梯是没有遮顶的,所有人都是淋雨之后才走进飞机的。
到了北京首都机场后,被告知地面在调整停机位,要重新分配机位后才能下机,然后飞机就停在了机场空地上足足等了30分钟!不知道乘客与空姐吵起来是否有推进作用,最后停机位并没有怎么“分配”法,飞机就在原地把我们放下,然后让摆渡车接我们走。浪费那么多时间才出摆渡车,一早这样做不就好咯,机场的调度真是差。
2008年10月3日星期五
什么时候才能在网上收到广州和香港的节目呢
在北京最郁闷的事情,暂时来说,就是无法接收到任何广州或者是香港的节目,无论是电视还是广播。试用过很多P2P的网络电视平台,暂时来说最满意的就是TVU收看凤凰卫视了,至于TVB——虽然有人转发到网络上,但是peers太少,从来没有成功看到过,就是见到list上面有TVB的名字。
关于接收TVB,Catfish总是建议我接收卫星信号,因为他以前在北大就是负责把信号送上卫星的。但是这个方案对我来说也太不现实了——我连电视机都没有呢!我从来只有电脑,电视对我来说是多余的,所以在北京租的房子自然不会买电视。
除此之外,还有别的办法吗?我不停地问身边的人这个问题,但一直没有找到有效的解决方案。
2008年9月21日星期日
Vista 为什么要引入 UAC
UNIX的命令行有sudo,Mac在GUI上也能够在需要sudo调用时弹出对话框要求输入密码,然而这两者的出现频率比Vista的UAC要低得多。为什么UAC的出现频率那么高呢,难道是Vista的用户体验设计得有问题?显然不是这样,Vista的UAC就是设计来不停地干扰用户的。
干扰用户随之而来的是什么?就是用户觉得这个软件很烦,然后逐步放弃使用这个软件,转而使用同类软件中不那么烦人的。这个过程会逐步把经常进行UAC调用的软件从是场中淘汰掉,如果你的软件不希望被市场淘汰,你就必须尽量减少UAC调用,也就是减少系统调用。
最终,市面上大量滥用系统调用的软件会逐步消失,要么自身改进,要么自然淘汰,从而提高了Windows的安全性。等一下,这跟Windows的安全性有什么关系?假若你的代码要执行系统调用,同时你的代码是有漏洞的,就可能由于你的程序漏洞而导致系统受到攻击。但如果你的软件本来就不需要做任何系统调用,就算有漏洞也不会连累Windows,Windows也就显得安全多了。
P.S.当然,还有一些非系统调用也需要UAC,例如对C:\Program Files的写入操作。这是因为Vista认为这也是个危险操作,而程序应该将数据存放到C:\ProgramData来实现可执行代码与数据的分离。
2008年9月18日星期四
强烈推荐 Spore 这个游戏
Spore有趣的地方在于,你在里面总能够碰到各种各样奇怪的事情。在cell stage,你会发现合理组合装备的重要性,刚刚开始有针刺的时候就可以把针刺装在前侧,然后刺体积比你大多了的生物。如果你发现不够灵敏,总是没把对方刺死就被吃掉了,那么你可以加高性能的运动器官,但前提是你又要先杀死一只有该器官的生物来获取它。到了creature stage,你可以看到举行的epic creature,这其实是其它space stage文明通过supersize工具制造的。在tribal stage,你可能会看到UFO──也就是其它文明在space stage的飞船,他们可能把地上的生物吸走。总之,在整个游戏过程中,你都会感觉到银河系中充满了各式各样的文明,在你还没觉醒的时候他们就来造访你所在的行星了,而且还会制造各种奇怪的事件,例如麦田怪圈。
暂时Spore只有英文版和繁体中文版,不知道什么时候才在内地上市,或许我会去买一套简体中文版,把它的cd-key用到英文版上,然后连上EA的服务器玩。Spore是我认为挺值得收藏的一个游戏。
2008年9月17日星期三
第一次开 OT 开到 1:30AM
2008年9月15日星期一
如果浏览器 geek 到能够随意换 kernel
在过去,浏览器总让人觉得是一个monolith般的东西,一个大整体,内部耦合度高,很难在一个浏览器中复用另外一个浏览器的组件。准确来说,浏览器按照内核分成了几族,族内的组件倒是通用的,但族外的就不通用了。但是在看到Google Chrome如此组装开源组件后,才发现其实浏览器也有可能发展到能够跨族相互融合的程度。例如Google Chrome是基于Webkit的,然而JavaScript引擎换了V8,所以执行效率比Safari高多了,而渲染引擎换了Skia,因此暂时看起来没Safari那么精致,支持的CSS3也没有Safari那么全面。
将来的浏览器,或许会像Linux一样按照distro(distribution)来划分。安装插件已经不能满足geek的需求,所以选用什么组件变得可以自定义。浏览器与浏览器之间的组件复用壁垒不会好像现在那么高,programmer已经可以轻易地从一个浏览器借用代码复用到另一个浏览器上,然后制作自己的distro。
2008年9月2日星期二
Firefox Ubiquity
装完之后,可以体验一下Ubiquity内置的command,地图搜索或者翻译之类的其实还是挺好用的,但我觉得重点还是在于可以自己写新的command。官方的Author Tutorial简单介绍了一些开发command的基础知识,如果要深入学习的话就要看看别人的command是怎么写的,以及看看Ubiquity的源代码。
由于我觉得Ubiquity实在太符合QuickSilver的用户习惯了,所以我以后做Web应用程序都会考虑加上Ubiquity的支持。
2008年8月30日星期六
如何动态加载 JavaScript 与 CSS
Omar AL Zabir这位MVP总是喜欢搞些稀奇古怪同时又很实用的小东西,并且还十分值得参考。最近他就做了一个叫做ensure的小工具用于动态加载JavaScript、CSS与HTML,而且IE、Firefox、Opera、Safari都支持了,那么我们就来看看ensure是如何做到动态加载JavaScript与CSS的。
在介绍ensure内部的实现之前,让我们先来看看其功能:
ensure({
html: "popup.html",
javascript: "popup.js",
css: "popup.css"
}, function() {
Popup.show("hello world");
}
);
在这段代码中,ensure首先会确保popup.html、popup.js、popup.css这3个文件的加载,如果都没加载过ensure就会动态加载它们;如果已经加载过了,ensure不会再次加载。在确保这3个文件都加载后,ensure会调用后面的匿名函数,也就是执行Popup.show("hello world");。
接下来,就让我们看看ensure是如何动态加载JavaScript与CSS的。
加载JavaScript
在ensure当中,加载JavaScript分两种情况来执行,也就是Safari与非Safari这两种情况。
在IE、Firefox、Opera中加载JavaScript
在这三款浏览器中加载JavaScript,其实只需要创建一个script元素,把src指向要加载的URL,最后把script元素追加到head元素上,那就搞掂了。此项工作是在HttpLibrary.createScriptTag()中完成的。不过我们不仅仅要加载JavaScript,同时还需要知道它什么时候完成加载,这可以通过script元素的onload事件或onreadystatechange事件来实现。
在Safari中加载JavaScript
因为Safari 2不支持onload或者onreadystatechange,所以只能手动通过XHR把URL读去过来,然后再手动eval这段代码,这就带来了一个限制──只能加载本域的JavaScript文件。在ensure当中,eval的工作是通过HttpLibrary.globalEval()来完成的。为了让JavaScript代码在全局(global)上下文中eval,ensure还是使用了创建script元素的方法,并将要eval的JavaScript置于其内,最后把script元素追加到head元素内。
细心的人肯定要问,为什么HttpLibrary.globalEval()要如此设计,而非直接window.eval或者eval.call。这是因为,window.eval和eval.call都无法在IE6中实现和script标签加载JavaScript代码一模一样的效果,这两种做法的eval在IE6下仍然不是在全局上下文中执行的。搜索一下你就会发现一些相关的讨论,例如jQuery就曾经使用window.execScript()来完成此项任务。不过最终大家都发现添加script元素才是最好的跨浏览器解决方案,所以现在的jQuery和ensure都是如此实现的了。
加载CSS
相对于加载JavaScript而言,加载CSS就简单多了,而且方法也是类似的:在head元素内直接加入link元素就可以了。这也正是loadCSS()所完成的工作。
实际上,ensure没有确保CSS完成加载后再执行下去。这估计是因为浏览器都能够在CSS加载完成后自动应用到页面上,因此Omar AL Zabir就认为CSS的加载顺序是无关紧要的,不过假如CSS加载速度实在太慢,其实还是会影响显示效果的。
在IE6中加载CSS
这次需要特别照顾的是IE6,而非Safari。IE6在往head元素添加link元素时,必须在window的上下文中完成,因此添加link的函数通过call调用切换了上下文。
总结
实际上动态加载JavaScript与CSS都并不难,在大多数情况下只需要向head元素追加对应的子元素就可以了,只有Safari2和IE6这两款古老的浏览器是需要特殊照顾的。
2008年8月29日星期五
开始使用 MarsEdit 写 blog
在MarsEdit的试用期过后,我又懒得写blog了。在忍受不写blog与购买MarsEdit之间,最终我选择了购买MarsEdit,这个价值$29.95还周围都找不到coupon的东西。作为一个shareware,它真的做得不错,但$29.95又实在太贵了,Speed Download那么强大的下载软件也就$25嘛。
在买MarsEdit时,发现可以用PayPal,想起之前注册PayPal时验证信用卡后有$1.95存在PayPal上面了,决定就用PayPal支付,把那$1.95余额花掉。接着在PayPal的页面看到,原来通过PayPal来购买外汇超级是超级贵的。根据今天Yahoo Finance公布的汇率,1CNY能够买入0.1459USD,但是PayPal说1CNY只能买入0.141154USD,实在相差太远了。幸好,PayPal允许你选择不用它来做购汇,用回VISA的购汇功能,只不过支付时无法确定最终购汇汇率。如果VISA的购汇汇率不至于那么离谱,还是VISA比较省钱。不过到底VISA购汇价格如何,我还真的没有留意过,以后要仔细研究一下帐单。
2008年8月20日星期三
MobileMe 真应该免费 beta 一年
对比起这样不断道歉和延长试用期的做法,Apple还不如学习一下Google,让服务免费beta,让更多用户来发现bug和汇报bug,等服务成熟了再开始收费。当然,这样做的坏处是Apple必须保留免费用户,否则全面转为收费的话,很多beta阶段的免费用户都会流失掉。
2008年7月29日星期二
北京地铁比广州地铁落后多少年?
据说以前北京1号线和2号线也是没有信号覆盖的,但是后来改进了。10号线作为全新开通的线路,应该在设计阶段就考虑到这个问题,然而现实却是正好相反。想想10年前广州1号线开通,就已经解决了这个问题,而北京现在开一条10号线,还要是迎奥运了,都解决不了这样一个问题,只能说北京地铁比广州地铁要落后10年。
北京地铁还有一个搞笑的地方,就是所谓的“自觉安检”,安检不是放在必经通道上,必经通道旁边,人少的时候安检人员还能认出谁的包包经过机检了,人多的时候根本分不清,只听到安检人员说“请自觉打开包包接受检查”,很多人根本就不理,直接走过去了。还有一个搞笑的地方是,Singzy说她早上赶去机场时,本来想坐机场线,结果地铁安检说他们的行李体积过大,不能带进地铁──竟然航空公司能够接受的行李体积,地铁安检不能接受,那么北京赶在奥运之前开通机场线又是为什么呢?貌似机场线还有一列迎宾专列,估计就是专门用来迎宾的吧。