2007年6月21日星期四

Becoming More Spiritual

人生总有突然为某些事情顿悟的若干次,我不知道这次算不算,但我发现自己更加spiritual了。

关于如何确定人生目标的方法看过一些,不过我觉得没必要试,反正我是一个很清楚自己想要什么的人,不过现在发现那些我很清楚的人生目标都是比较material或者低层次的spiritual的。李开复的那本《做最好的自己》中提到确定人生目标的时候,提到了假如你剩余若干时间的生命的时候会做什么,以及你死了之后别人的评价会是如何。对于前一个问题,我还算清楚,其实我不觉得有什么很急迫的事情必须完成的,所以我会放松地去完成我觉得可以完成的事情,就算完成不了也没什么所谓。至于后面那个问题,在高中的时候我对它的想法是比较material而且tragedy的。

我之前认为,即使我拥有一家庞大的国际化企业,有一个健康的家庭,我死掉之后事情将被很sophisticated地处理掉——幻想一下我有个office,而且至少是在中信那样能称之为tower的建筑物的顶层,然后有一天我就从那个office跳下去了,这一跳纯粹是“好奇心能够杀死一只猫”的结果,也就是我想知道之后会发生什么事,假如我还有能力知道的话。在大型城市中,救护人员会快速赶到现场,我的意思是帮忙确定我的死亡,好让那些记者回去有东西可写。然而在记者把文章发表出来之前,董事会的各位已经在思考自己的下一步棋怎么走了,因为接下来可能有不少的因素会显著影响股价,持住一大堆股票的人当然要先想清楚自己该买还是该卖,然后选择正确的对外立场。与此同时,企业良好的管理机制开始运作,适当的人选自然会被放到适当的位置,用来弥补缺少我的作用力以后所造成的影响,生态环境过一段时间自然能够重新平衡。至于家庭,他们——也就是妻子和孩子——是否好像企业一样找个人来替补我的空缺就是他们的事情了,反正我也没有发言权,然而只要他们有相当的股票在手,并且上面的事情能够按照预期的平稳处理掉,那么他们的生活也能平稳过渡。总之,这些如此sophisticated的事情总有人能负责的,无论我是否希望有人负责。

反正呢,material的东西你是无法带走的,而这个社会现在已经能够非常高效地把你遗留下来的东西瓜分干净,之后也或许就不会有人想要去悼念你。因为说到material了,如果你真的有相当多的股票,即使你的所有器官都捐赠出来,和这些股票的价值相比也就是冰山一角,除非你能在股票上印上你的头像吧,否则这个注重效益最大化的社会真的没什么必要去惦记你。因此,你留下的material价值越多,你的身体或者是贴身物品的价值比例就越低,别人就越没有理由去想着这仅占一点点比例的价值,这就是所谓的tragedy了。

现在,我突然间感觉到spiritual的重要性了,因为这才是你真正能够带走的东西。你死掉后别人没办法从你的大脑里把你的思想挖出来瓜分掉,至少暂时没办法吧,那么人们就会真心地感觉到他们失去了你。如果你的spiritual有相当的价值,例如你是画家或者诗人之类的,那么这个社会就会感觉到它真的失去了巨大的财富了。因此,在考虑人生目标的时候,spiritual是一个很重要的衡量角度,忽视了这个角度就可能导致不那么理想的结局,我的意思是假如你在乎别人对你的评价,又或者你死掉以后还有能力去评价结局是否理想的话。

另外最近看到一篇名为Life After Death的文章,如果你之前有看过我那篇《小睡 / Polyphasic Sleep》的帖子,或者你有关注过“小睡”的概念,就肯定知道其作者Steve Pavlina。这家伙的文章貌似挺注重与生活质量的方面,例如之前介绍过小睡,最近又在写如何能做到早起床;同时也有关注精神领域的题材,例如如何发现你的人生目标。我们把话题回归Life After Death这篇文章上,它的中文翻译版本名为《死后的生活》,主要讲你死掉后可能的精神状态。对于死后的生活来说,最不幸的,或者对某些人来说是最幸运的,也就是你的精神和肉体一起byebye了,那么你也就没办法为死亡做什么准备了,好好享受现有的生活吧;另外一种情况就是你的精神仍然存在,或许被冻结了,或许能继续发展,无论是哪种情况,假如你在死掉之前积累了充分的spiritual,那都肯定是好事情。

因此,我开始感觉到积累自己spiritual方面的感悟是生活中总要的一部分,必须投放相当的时间与精力去修炼,以便将来无论发生什么事情都至少能spiritual的生存下去。最坏的情况下,不是直接死亡,而是被关进纳粹集中营那样肉体上名存实亡,有相当的spiritual生存能力或许还能让你的肉体坚持下去。

2007年6月18日星期一

从 Dynamic Data Control 回归普通的 Data Control

我尝试在自己的软件工程项目中使用DDC,希望它能带来一些比较敏捷的特性,虽然在那么正统的软件工程课程上搞敏捷貌似有些不妥,不过其实也没有几个小组是完全按照流程来做的,反正最终所有文档齐全了演示也能让老师觉得效果不错那就行了。事实上很多小组都是随便分析一下就开始写代码,东西做出来了再补文档,哈哈……

新建了一个ASP.NET Futures的网站后,我先尝试使用DynamicDataAuto控件,发现确实如demo显示的那样“功能齐全”——所有字段都能在GridView中列出来,支持图片的直接显示,也支持外键的直接链接,一个页面上集成了所有的CRUD操作。然后我开始想细致定义这个页面,发现这个scaffold不能好像RoR的scaffold那样自动分解为低级代码,于是就尝试手工转换。首先把DyanamicDataAuto删掉,按照我的需要换上特定的Dynamic Data Control,然后发现可定制性不强,继续换……最终,页面上的控件降级到GridView了,Dynamic Data Page的特性完全没有用上,于是干脆换回普通的Page。

实际上现在的Dynamic Data Control一点都不好用,就如同ASP.NET AJAX的拖放支持一样——现成做好的控件限制太多,自定义需要实现的也太多,难以快速开发一个支持拖放特性的自定义控件。如果要使用Dynamic Data Page,那意味着Page本身为你提供了统一的Data Source,所以Page上面的Dynamic Data Control就不用设置Data Source了,然而这个特性并不能为传统Data Control所用,这就意味着一个Page上要么只用Dynamic Data Control要么只用传统Data Control。然而Dynamic Data Control的定制性实在有限,所以面对上述binary choice只能选择传统Data Control了。

暂时来说,我们也不能用Dynamic Data Control做些什么,只能等下一个版本的ASP.NET Futures看看是否有什么改善。现在的Dynamic Data Control就如同Atlas的第一个CTP那样(那时候还有<atlas:TextBox />这玩意儿),或许到最后整个模式都改掉了。

2007年6月13日星期三

慎用 XHTML 标签的自关闭写法

我们都知道XHTML里面的img标记应该这样写:<img alt="" src="" />,这种写法也就是所谓的自关闭,在XML中是完全合法的写法。如果你熟悉XML相关的开发,可能也就习惯于这种写法,想着XML中任何不含子节点的元素都可以这样写,那么XHTML中没有内容的标签也都可以这样写。XHTML中理论上当然允许任何标签以自关闭的方法来书写,然而浏览器兼容性却带来了新问题,那就是IE无法正确识别某些标签的自关闭写法。

请尝试输入以下XHTML代码并在IE中浏览:<p>hello <script type="text/javascript" /> world</p>,你会发现只能看到前面的hello而不见后面的world,这事情让人挺无法解释的吧。可能有不少人都曾经遇到过这个问题,并且花了几个小时在上面都找不到合理的解释。

解释源自另外一段类似的代码:<p>hello <textarea /> world</p>,你在IE中看看其显示效果,能够得到合理的解释了吗?我们能够看到前面的hello正常显示了,而后面的world则显示在textarea里面,这证明IE并没有正确识别textarea标签已经自关闭了,而是当它没有关闭,并将后面的内容识别为textarea内部的内容。

这时候我们就明白前面那段代码为什么看不到后面的world了,因为它被当作script的一部分来识别了。这就说明了,在我们使用XHTML时并不能好像XML那样随意的使用自关闭的写法,只有少数原本不需要关闭的标签可以用自关闭的写法,其他标签即使没有任何内容最好也用成对的关闭写法。

最后需要提醒大家的是,其实弱智的parser不仅仅IE有,很多地方都可能碰到由于parser不严谨而引起的问题,所以我们在书写XHTML的时候还是要迁就一些老HTML继承下来的习惯,不能好像真的XML那样自以为符合标准了就随意写。不信?那么再试一个吧:<p>hello <br></br> world</p>,留意IE与Opera中的显示效果。

Update: 有部分读者认为我举的例子是不符合XHTML规范的,那么请先阅读XHTML规范Empty Elements一节的中文翻译如下:“空元素必须要么有一个结束标记,要么以/>结束,例如<br/>或<hr></hr>。请参考HTML兼容性标准以获取关于确保向后兼容HTML4浏览器的信息。”可以看得到,规范中也给出了<hr></hr>这样的例子,说明<br></br>的写法是符合XHTML规范的,只是没有兼容HTML4标准。那么到底XHTML是否兼容HTML4呢?我们来看Compatibility Issues一节,中文翻译如下:“虽然并没有要求XHTML1.0文档兼容现有的浏览器,但在实践中这并不难做到。”因此,XHTML是没有规定文档必须向下兼容,我给出的例子都是合法的XHTML文档片断,当出现在完整的XHTML里面时也全部能通过W3C Markup Validation Service的验证。

Update again: 其实我写这篇文章的目的不是为了强调只符合XHTML规范就行了,也不是强调符合XHTML同时兼容HTML4就够了,而是应该考虑更多需要兼容的情况。例如你的CMS中允许用户提交HTML,提交的HTML经过SgmlReader或者其他方法格式化为XHTML,同时或许还做了其它XML处理,这时候就有可能将用户提交的<textarea></textarea>转换为<textarea />,这种情况下你需要通过跟踪调试找出问题并不容易,因为XML处理并没有违反任何规范,每一步的处理都是符合语义的。另外最好不要把<br />写成<br/>,因为确实有些弱智的parser仅仅因为少了一个空格就无法正确识别。

2007年6月12日星期二

探索 ASP.NET Futures (Part 3 - Client Diagnostics)

貌似ASP.NET 2.0新增的诊断相关服务没多少人关注,更没多少人用,不过对于正在使用此类服务分析站点的人来说,肯定非常期望ASP.NET AJAX中的客户端代码错误也能记录到诊断日志中,这样就能获取更丰富的数据来分析站点不稳定因素的来源。

ASP.NET Futures中已经引入了客户端诊断服务,在解释此服务之前不妨先思考一下假如你要自己写一个客户端诊断服务会怎么做。如果我来写一个客户端诊断服务,我会设计一个Web Service负责收集错误信息,然后记录到数据库中,然后写一个js负责拦截客户端异常并且发送到该Web Service。ASP.NET Futures (May CTP)中引入的客户端诊断服务也差不多就这样子,只不过设计得更加通用更具扩展性。

使用客户端诊断时你首先要在页面上放置一个Diagnostics控件,它负责的就是向客户段输出一段js以便拦截客户端异常。熟悉ASP.NET AJAX控件设计的人应该能猜到Diagnostics控件肯定是一个ScriptControl,不熟悉ASP.NET AJAX控件设计的话也可以通过这个例子了解到,如果你有一个客户端组件要以控件方式在Page上部署那就应该考虑继承自IScriptControl接口了。

接下来我们要部署接收诊断信息的web service了。新建一个名为DiagnosticsService.asmx的web service,更改其code-behind声明如下:
<%@ WebService Language="C#" Class="Microsoft.Web.Preview.Diagnostics.DiagnosticsService,Microsoft.Web.Preview" %>
这样做的意思是,此web service不是使用你写的code-behind代码,它的code-behind类直接使用上述的DiagnosticsService类,所需的函数都在里面了,你不需要再写任何代码。那么我们到底在哪写代码记录客户段发送来的诊断信息?先别急,接下来我会解释此事。需要说明的是,ASP.NET Futures现在这个做法的风格和原来的ASP.NET AJAX有点格格不入,因为它没有直接采用HttpHandler的方式直接暴露此web service,而必须要开发者自己部属一个asmx文件,将来此做法可能改变,届时将不再需要手动部署asmx文件。

仔细留意DiagnosticsService,你会发现它有一个OnClientException的事件,这才是你真正需要关注的地方。为了确保将所有客户端异常都记录下来,你可以在Global.asax的Application_Start中绑定此事件,在HttpModule中绑定也是可以的。在事件的处理函数中,你将通过EventArgs获取到一个ExceptionServerInfo的类型,在里面将会记录如下一些与客户端异常有关的属性:

  • Data
  • FileName
  • LineNumber
  • Message
  • IpAddress
  • Timestamp
  • UserAgent

你可以直接访问这些属性,以你喜欢的方式进行日志记录,例如记录到你自己的数据库,或者是ASP.NET 2.0的health monitor。

好了,这样就解释完如何使用客户端诊断服务了。嗯……等等……还要一样重要的事情没有说,那就是在web.config中启用此项服务。首先要声明config section:
<configSections>
  <sectionGroup name="microsoft.web.preview" type="Microsoft.Web.Preview.Configuration.PreviewSectionGroup, Microsoft.Web.Preview">
    <section name="diagnostics" type="Microsoft.Web.Preview.Configuration.DiagnosticsSection, Microsoft.Web.Preview"/>
  </sectionGroup>
</configSections>

然后声明启用此服务:
<microsoft.web.preview>
  <diagnostics enabled="true"/>
</microsoft.web.preview>

最后,如果你有兴趣继续关注有关ASP.NET Futures新功能的介绍,可以考虑订阅我的博客:

2007年6月11日星期一

Apple 发布 Safari 的 Windows 版了

以前一直因为没有Windows平台上的Safari,所以设计CSS Template的时候就没办法测试对Safari的兼容性,或者只能使用browsershots.org这样的服务来查看CSS Template在Safari中的视觉效果。现在Apple最新发布的Safari 3 Public Beta已经有Windows版本了,那就能很方便的测试CSS Template的兼容性了。

Safari的Windows版本有一个重要的战略意义,那就是让你可以测试你的应用是否能在iPhone上面跑起来,包括AJAX应用。由于iPhone暂时还不会有任何第三方软件,所以它上面能够有什么第三方服务就依赖于Web了,而Safari对AJAX的支持则成为了亮点。如果你是服务提供商,并且希望你的应用将来能被iPhone用户所使用,那么使用PC上的Safari将能让你提早进入网站兼容性测试的环节。

探索 ASP.NET Futures (Part 2 - Search Enabled)

在本系列的上一篇文章中,我们探索了ASP.NET Futures (May CTP)的SearchSiteMap功能,说明了如何将ASP.NET的SiteMap影射为符合Sitemaps协议的XML以便搜索引擎更好的抓取我们的站点。然而让搜索引擎更好的抓取我们的站点了,这部分的优化却仅仅对来自于搜索引擎的访客有用,这是否有点浪费?我们是否可以选择站内的搜索也通过Internet搜索引擎(例如Google)来实现,从而避免开发自己的站内搜索引擎?从ASP.NET Futures (May CTP)开始,这也便得可能了,需要使用的仅仅是SearchDataSource控件以及简单的几句配置。

首先说说SearchDataSource是干什么的吧,它其实是一个ObjectDataSource的派生类,只不过设置了基类的TypeName为"Microsoft.Web.Preview.Search.SearchService",而SelectMethod则是"Search"。事实上你放置一个普通的ObjectDataSource然后设置这两个属性也就可以获得SearchDataSource的效果。之后你就可以像使用普通DataSource控件那样使用搜索返回的数据,绑定到Repeater或者GridView,又或者绑定到你自己的数据控件都是可以的。

SearchDataSource返回的貌似是一个IEnumerable,而事实上是一个List<SearchResult>,通过Reflector阅读SearchService.Search方法的代码就知道了。然后我们来看看SearchResult类型包含什么属性。它拥有3个string属性,分别是:Url、Title、Description。在使用SearchDataSource的时候,数据控件绑定这3个属性就够了。那么之后我们还需要做什么呢?接下来就是配置provider了,因为SearchService.Search方法正是通过轮询各SearchProviderBase派生类来获取搜索结果的。

这听上去很复杂的样子哦,远超过了放置一个SearchDataSource的难度。其实不是的,ASP.NET Futures (May CTP)中已经包含一个SearchProviderBase派生类了,那就是WindowsLiveSearchProvider。此provider的配置方法如下:
<microsoft.web.preview>
  <search enabled="true">
    <providers>
      <add name="WindowsLiveSearchProvider"
        type="Microsoft.Web.Preview.Search.WindowsLiveSearchProvider, Microsoft.Web.Preview"
        appID=""
        siteDomainName="" />
    </providers>
  </search>
</microsoft.web.preview>

其中的appID是你在Windows Live Search申请的Application ID,还没有Application ID的话可以到Windows Live Search的Developer站点申请一个。siteDomainName就是你的网站的域名,例如我的网站就是CatChen.biz。另外,你还要确认Windows Live Search已经抓取了你的网站的页面,通过大部分搜索引擎都支持的site:指令你就可以知道一个搜索引擎对你的网站的抓取情况,例如我可以通过site:CatChen.biz搜索来了解Windows Live Search对我的网站的抓取情况。完整配置并且确保搜索引擎对你的站点的抓取后,你就可以通过SearchDataSource获得期望的搜索结果了。

如果你不满足于WindowsLiveSearchProvider提供的功能,你可以实现自己的SearchProviderBase派生类。在官方文档中Enabling Search页上,最后一个例子提供了两个自定义的provider,一个是用于Yahoo的,另一个是用于Index Server的。另外不要把目光局限于某个特定的搜索引擎,如果你觉得Google、Yahoo、Windows Live都不够好,那么你可以考虑做一个自己的meta-search(源搜索)引擎。所谓的meta-search是指通过调用若干个不同的搜索引擎,根据它们的返回结果再次进行信息的分析与提取,最后生成自己的搜索结果。

在你实现了自己的SearchProviderBase派生类后,有一点需要注意的,那就是SearchService是不知道返回结果的排名的。一般我们都会认为搜索结果越靠前的,当然应该是越匹配的,这在配置一个provider时是没什么问题的。然而配置多个provider后,SearchService仅仅是将多个provider的结果拼接成一个更大的List<SearchResult>,这时候就毫无排序而言了。因此,如果你需要使用多个provider,我还是建议直接写一个SearchProviderBase派生类,使用meta-search的方式自己去合并以及重排结果。

最后,如果你有兴趣继续关注有关ASP.NET Futures新功能的介绍,可以考虑订阅我的博客:

2007年6月7日星期四

Languages Differentiate Thinking?

其实很早的时候我就意识到可能使用中文思考相对于使用英文思考来说,对思考者某些特定领域的思维能力会带来一定的正面或负面影响,不过我不很确定有什么例子能论证这个话题,也不知道哪个领域的思维能力造成的影响可能是最明显的,所以也就没有继续想它。

上个星期新东方有个老师说,使用英语思考能够让人的逻辑思维能力更加严谨,因为没有哪一个在中国的华人能够拿到诺贝尔奖,然而华人在美国改用英语思考就能拿到诺贝尔奖了。或者这根本不是一个有价值的例证,反正新东方老师上课吹水是必须的,然而这却让我重新感到问题本身确实值得思考。

首先我们来看看程序设计语言而不是自然语言之间的区别。我最近阅读到一篇文章讨论了程序设计语言与解决方案之间的关系:On Semantic Distance and Computer Languages。文章中认为,使用的程序设计语言的语义和解决方案的距离越近,实现起来就越容易,因为所谓的实现就是搭桥跨越程序设计语言以及描述解决方案的语言。然而文章最后说道,世界上有5000种语言(包括方言),你是不可能找到一个等价语义集合的,因此也就不存在一种语言总是最贴近任何一个解决方案,那意味着也不可能存在所谓的最好的程序设计语言。

可能这样说比较空泛,那么我们通过一些实际的例子来说明计算机语言与描述解决方案的语言之前的距离为何可以相去甚远,当然后者暂时指代的就是英语为主的描述性语言。假如你需要取一个值,它代表当前时间的20分钟前的时间,用Java写的话代码如下:
new Date(new Date().getTime() - 20 * 60 * 1000)
然而用Ruby写的话代码如下:
20.minutes.ago
上述例子来自Sometimes less is more,阅读该篇文章你可以看到更多这种Java和Ruby的比较。在此我无心说Java与Ruby之间哪个更好,我只是想找一个例子证明不同语言与解决方案语言间的距离是可以有很大差别的。

解释完程序设计语言有关的事情,那么我们可否直接拿上例来推导,并由此得出一个类似的结论,那就是不存在一种自然语言总是最贴近任何一种思维模式。正如如果你想写一段代码获取代表20分钟前的时间值有两种思维方式以分别适应Java与Ruby一样,中文与英文也有描述一件事情的两种不同思维方式,而随着你使用特定一种语言的时间积累,这种方式将反过来对你的某些领域的思维能力造成影响。

然而到底中文与英文训练人的思维能力的结果如何呢?我也不敢乱下什么结论,但从表象上看来,貌似英文适合逻辑推理而中文适合艺术创作。然而到底事实是如何的,我们可否遮盖其他文化因素的影响单纯探讨使用一种特定语言对人的思维能力的影响,这就是我能力范围之外的事情了,应该由社会学家以及语言学家来解决。

2007年6月3日星期日

Broaden Choices before Making Decision

继续发展《还有新鲜感吗?》那次的话题……最近真的在考虑MacBook哦,漂亮的MacOS为什么不能成为选择呢,反正Vista也是在模仿它的。

其实在有充足的选项之前,干什么那么早选定一个固定的方向呢,提前缩窄搜索范围,这在遗传算法里面叫做“早熟”哦。这个所谓的“早熟”会导致之后都搜索都限制在这个小范围内,即使让你求得了这个小范围内最优解,在全局范围内也不一定怎么优。所以遗传算法通常要避免“早熟”,在开始的时候要确保搜索解集尽可能在全局里分散。当然,还有一些更高级的方法避免类聚,然而这部在我们的讨论范围之内。

另外一种要防止出现的情况是不收敛,或者叫做“迟熟”,假如你一定要找一个和“早熟”对应的说法的话。不收敛意味着你在一个很广泛的范围内搜索来搜索去,貌似搜索了很多的解,但是你所能得到的最优解看起来总合全局最优解有一定的距离。

不过对我现在的情况而言,应该控制好避免“早熟”,过早收敛是不好的。找mm这事情也一样,如果不想“早熟”或者“迟熟”就应该做好范围控制,不能让它过早收敛,但又要避免不收敛的情况。

2007年6月2日星期六

Google 的赞助商链接在搜索结果之上!

Google向来声称广告在右边,明确标出,不会打扰用户看搜索结果,搜索结果放的位置才使人视觉焦点的主要位置。只有相关度本身就非常高的广告能够出现在搜索结果之上,并且也会标明为广告。

这个声明在PC上是成立的,即使把CSS给禁用掉仍然成立。CSS禁用掉不是两栏布局就变成一栏了吗?哦……别就只知道CSS布局,我们还有原始的table布局呢,Google的搜索结果页就通过使用table确保广告再右侧。

那么什么情况下广告会跑到上面了呢?在用Opera Mini的时候,因为Opera的服务器会对页面进行优化后再发送给客户端的Opera Mini进行呈现,这过程中不知道什么优化规则就让广告显示到前面了。不过先说明,这样的结果是必然的,因为在HTML中广告出现在搜索结果之前,Opera对内容按顺序进行分段并且优化时先处理广告自然先输出广告。

我觉得这种特殊情况对于Google来说是非常讽刺的,Google一直大力宣称搜索结果上层的位置你无法买到,然而在Opera Mini上显示时显然就是买的结果先出现。并且因为Opera Mini上面能显示的字体只有一种,所以“赞助商链接”这几个字就不那么明显,不留意看你就以为第一条广告是第一条结果。即使你知道那些使广告,要寻觅哪条才是第一条结果也许要费些时间仔细看。

2007年5月30日星期三

Microsoft Surface 发布啦!

非常cool的Microsoft Surface技术终于发布了,之前在YouTube上看过一些demo显示这是Microsoft正在研究的技术,以为要多少年之后才能变为实用,因为实在太Sci-Fi了。

值得注意的是,Microsoft Surface官方网站演示中所用到的UI技术正是WPF以及其基于的.NET Framework,这在ScottGu的blog中有所提及

另外,Microsoft考虑优先将这台售价五千到一万美元的机器卖给商业合作伙伴,例如高档的餐厅、赌场、影院等,并且可能将于2007年底就开始投入使用,所以这东西是一点都不Sci-Fi的。

Popular Mechanics有另外一段视频深入解释了一些技术细节,可以在这篇名为Microsoft Surface: Behind-the-Scenes First Look的文章里看到。

Less Coke and Chocolate

昨天去补了很多只牙,估计都是可乐和朱古力惹的祸。平时经常吃完甜食,没有清理口腔的习惯,所以糖分就留在牙上面导致蛀牙了,而且这次还蛀得很深了,哎……

另外感觉省口腔医院很废,看上去设施和服务态度一流,不过总是治不好就是了。大半年前我已经开始有一点牙肉痛了,但中间去过几次省口腔医院他们都没告诉我有蛀牙,搞到拖了那么久。

2007年5月28日星期一

探索 ASP.NET Futures (Part 1 - Search & Sitemaps)

如果你在使用ASP.NET站点,同时又希望它Search Engine Friendly一些,很可能你就希望它有一个Sitemaps。在这里我们说的不是ASP.NET的SiteMap,而是Sitemaps.org定义的基于XML的Sitemaps协议,注意这两个名字的大小写以及单复数,之后我都会这样区分它们。Sitemaps协议有点类似RSS或者Atom,只不过它描述的不是最近的内容更新,而是整个站点的地图,主要用来描述特定URL的重要程度、更新时间及频率等。搜索引擎如Google是支持Sitemaps的,通过Google Webmaster Tools(以前叫做Google Sitemaps)你可以提交你的站点的Sitemaps,以便Google更好地索引你的网站。

简单调用

在ASP.NET Futures (May CTP)之前,如果你想要为你的ASP.NET站点增加Sitemaps支持,恐怕必须自己实现一个特殊的页面(或者HttpHandler)用于读取ASP.NET SiteMap并输出为Sitemaps协议。而现在这工作可以交给ASP.NET Futures的AspNetSiteMapSearchSiteMapProvider来做了,你需要做的仅仅是在web.config中写上几句。由于这个功能属于ASP.NET Futures中SearchSiteMap这个类别,所以需要在web.config中对该节进行配置:
<microsoft.web.preview>
  <searchSiteMap enabled="true">
    <providers>
      <add name="Navigation" type="Microsoft.Web.Preview.Search.AspNetSiteMapSearchSiteMapProvider, Microsoft.Web.Preview"/>
    </providers>
  </searchSiteMap>
</microsoft.web.preview>

在这个配置里面,我们启用了SearchSiteMap,然后配置了一个名为"Navigation"的Provider,此Provider使用AspNetSiteMapSearchSiteMapProvider类,就这么简单,和配置任何其他Provider的形式完全一致。之后你还需要确保一下有关的HttpHandler配置好了,如果你新建网站时使用的模板是ASP.NET Futures的,那么HttpHandler就应该配置好的了,配置信息如下:
<add verb="*" path="SearchSiteMaps.axd" type="Microsoft.Web.Preview.Search.SearchSiteMapHandler" validate="True"/>

这时候,如果你的网站已经正常启用ASP.NET自身的SiteMap功能,例如使用静态的Web.sitemap,那么访问SearchSiteMap.axd就应该能看到按照Sitemaps协议输出的结果。这时候或许你会很奇怪,为什么结果只有一条记录呢?这就是Sitemaps的递归调用了,这个主Sitemaps仅仅声名了我们之前配置的那个名为"Navigation"的Sitemaps的地址,也就是SearchSiteMaps.axd?sitemap=Navigation。打开这个地址,你会发现仍然是一个Sitemaps,它里面包含的就是ASP.NET SiteMap提供的数据了。

深入看看

接下来,我们用Reflector来看看Microsoft.Web.Preview.Search下面的一些类的实现方式。我不准备详细分析代码了,因为代码都很简单,直接说说看完的结果吧。如果你之前浏览根据SiteMap生成的Sitemaps时发现少了些东西,在这里你就知道如何把这些项目补充上去了。Sitemaps协议中关于一个URL能够包括以下几样信息:

  • 地址:也就是URL本身
  • 最后更新时间
  • 更新频率:此URL的内容多久更新一次
  • 重要程度:一个0到1的值,默认值为0.5,搜索引擎并不一定根据这个值来判断URL的真正重要程度

然而自动生成的Sitemaps仅仅包括前两项信息,如果我们需要后两项信息就需要手动增加。怎样手动增加呢?因为SiteMapNode类似于字典,能够访问this [string key],所以只要SiteMapNode[]存在"lastModified"/"changeFrequency"/"priority"这几个值就能自动输出到Sitemaps中,而且"lastModified"会覆盖对应Page的aspx文件的真实最后更新时间。

简单举例说明这功能怎么用,假设你使用的是静态的Web.sitemap,我们已经习惯这样定义一个SiteMapNode:
<siteMapNode url="Default.aspx" title="Welcome" description="" />

而增加特定的属性只需要这样定义:
<siteMapNode url="Default.aspx" title="Welcome" description="" changeFrequency="daily" priority="0.8" />

支持Dynamic Data

上面说了那么多,也就仅仅能做到支持系统自带的SiteMap,而实际上SearchSiteMap还能够对Dynamic Data提供特殊的支持。Dynamic Data简单易用,好像Ruby on Rails那样支持scaffolding,预览了ASP.NET将来在敏捷方面的发展。有关Dynamic Data Control的详细信息,请参考Dflying的文章,我们这里仅讨论SearchSiteMap的支持:

需要支持Dynamic Data的话,首先你要实现自己的DynamicDataSearchSiteMapProvider。大家不要一看到要继承自系统类实现自己的类就觉得是非常复杂的事情,其实这里我们仅需要override掉一个函数,也就是DynamicDataSearchSiteMapProvider.DataQuery()。在这个函数中,我们需要返回一个IEnumerable,其中的元素需要具有主键列名属性以及以下属性:

  • SiteMapLastModified
  • SiteMapChangeFrequency
  • SiteMapPriority

你很可能会问,为什么要是不确定类型的IEnumerable而不是确定类型的List<>呢?想想.NET Framework的什么部分用IEnumerable用得最多吧,那就是LINQ。如果你在QueryData()中直接使用LINQ来筛选数据,你就不需要创建自定义类型并且自己填充IEnumerable了。况且,主键列名也不是确定的,如果用一个属性记录其名称用另外一个属性记录其值那就很麻烦了,所以ASP.NET Futures选择了上述充分发挥LINQ优势的做法。

最后,我个人感觉SearchSiteMapProviderBase的设计有点问题,它作为AspNetSiteMapSearchSiteMapProvider与DynamicDataSearchSiteMapProvider的基类,其中包括QueryData()方法,然而此方法只有DynamicDataSearchSiteMapProvider用到,很显然就应该将它放置到DynamicDataSearchSiteMapProvider里面。

2007年5月24日星期四

被急 call 去参加 Google 面试

早上起来后,本来是计划帮一位老师把他的个人网站的模板设计好的,10:30突然收到电话通知叫我去面试。

开头我说大学城出市区起码一个多小时,很难赶上,但对方没有改时间的意思,说“那就只能另外约时间了”。这时候我当然不会选择让电话挂掉然后等下一次通知啦,所以马上问她下午是否可以,这时候才知道原来下午的时间都排满了,才一定要我上午去,然后我就答应上午赶过去咯,她说超过12:00到也没问题。

跑到大学城北部枢纽的时候,发现刚刚走了一部3线,而且最近的司机都很守规则离站了就不开门,所以想着可能还要很久才开下一班车,结果发现10分钟左右就有下一部3线准备开出了。出市区用了我半个小时,然后打的去东方宾馆又用了半个小时,去到刚刚过了12:00。

至于面试,就是签了NDA再进行的,所以就没什么好说的啦,自我感觉不怎么样,没有很突出的表现。之前听说Google的面试都是一个早上几轮面试一起来的,如果你被通知可以走了然后就没消息了,那么你也不知道是在哪一轮面试被刷下来的。不过今天我面试完临走时问了一下,才知道过了的话会有二面通知,希望自己能顺利提供第一轮面试吧。

2007年5月22日星期二

Google SE 笔试通不过

之前浪费了那么多时间wandering,该报应的时间终于来了,Google SE笔试通不过,收不到面试通知。总结出来就两点:

  1. 改拓展与利用人脉的时候一定要利用好。人脉一方面要拓展,另一方面更要利用,就如钱一样花得值了的才是你真正得到的。其实早些时候就有人大家帮我做Google的推荐,当时一心想着去申ID,就不怎么重视SE笔试,也就没在这之前作推荐,笔势完才发现原来身边那么多人是找人做了推荐的,也就是说他们来参加笔试只是玩下,有推荐可以直接进入面试的。
  2. 该做好的事情一定要全方面重视。其实对于SE笔试我也是很认真的,提前咨询了别的学校举行笔试的方式等等,然而却疏忽了推荐着一个重要的项目。

Move on. Next Target. 继续努力,由于最近对Product Manager的职位比较花痴,所以决定目标是早日有足够的能力获得一个PM职位。

Keywords: cnblogs, profit, future and more

上个星期六下午参加完博客园广州的聚会,讨论议题是博客园的盈利与发展,那么我也来说说这事情。

您为什么愿意使用博客园

要探讨这件事,我觉得首要问题应该是“您为什么愿意使用博客园”,这个问题决定了博客园当前的价值曲线何在,然后你才能确定博客园是否应该迁移到新的价值曲线上面去。如果你问我为什么愿意使用博客园的话,我的回答会很简单:因为用它来写blog简单易用咯。

看到这个答案,你是不是已经笑到肚子痛了?好,那么你先捂着肚子,回想1999年Blogger刚刚创立时候的样子。那时候还没有免费的Blog*Spot,如果你是Blogger的用户你必须有自己的空间,而且要是支持FTP上传的,Blogger所负责的仅仅是根据你设计的HTML模板套用你保存在他们数据库中的数据,然后生成静态HTML并且上传到你的FTP。免费的域名和空间?没有,你自己想办法买去。漂亮的模板?没有,除非你自己精通设计与HTML。看到这里我想你的痛症已经从腹部转移到头部了,这么辛苦才能弄一个blog难道不是一件非常头痛的事情?

我们再来看一个例子,VeryCD与传统的ed2k network有什么不同?理论上整个ed2k network是连通的,资源是完全共享的,当然有些客户端mod设计为同类mod之间优先传输,不过我们暂时忽略掉这类情况。VeryCD的成功就在于它让资源下载变成了非常便利的事情,甚至不仅仅是资源下载,而应该说资源的消费(consume),包括搜索、预览、下载、使用全过程。很早很早之前就在Dash的blog看到一张brain storm的图,画着用户现在消费VeryCD资源时都会遇到什么障碍,其中包括例如播放DVDRip需要安装codec和字幕插件,不是专业用户不知道什么是codec更不知道codec存在版本冲突等问题。之后VeryCD是有致力于解决这些问题的,例如通过制作Storm Player来方便用户播放DVDRip,并且保证此播放器是无捆绑的,这就让用户摆脱了既想装codec又害怕惹上捆绑软件的困境。

总结一下,是否简单易用对产品能否进入大众市场起到关键作用。相信博客园不是想做1999年的Blogger那样的高端用户服务平台,所以易用性就成为了关键。星期六的讨论有人说到了开源项目,有人说到了出书,这些好主意最终能否让大众受惠也就看是否便利(convenience)了。

什么是便利

那么到底便利是什么?我们拿开源项目来说说吧。如果一个开源项目必须要你下载源代码后自行配置和编译,你会不会用?如果好像Community Server那样下载后就是一个Installer可以直接安装使用,你又会不会用?无论对于开源项目的开发者还是使用者来说,是否便利都是很重要的一个因素。例如我想参与到博客园主持的一个开源项目吧,我该如何做呢?先装个SVN吧,这谁不知道,说起来可真简单。但对于没经验的人来说,选择什么SVN客户端,装完之后如何用,这就是个大问题。先说说题外话,知道什么方法能够最有效增加你的feed订阅量吗?那就是在订阅链接旁边加上一个帮助链接,用户打开后能看到一篇文章详细解释什么是feed以及如何使用feed订阅。因此,如果想要有更多人参与到开源项目中来,第一件事应该是普及SVN的使用方法,这就减少了用户自己摸索恰当的SVN使用方式所需要的时间成本。

事实上,我觉得4C理论可以合并为3C,因为convenience也就是cost,不过不是你的cost,而是你的服务对象的cost。星期六讨论时大家的思维方向都是如何能让博客园的写作者能够从写作本身受惠,从而增加粘滞度以及吸引新人。实际上我们可以尝试反过来思考,就是如何降低写作者的成本,从而达到同样的效果。这种成本可以是任何东西,而不仅限于便利性。而且这种策略还可以推广到写作者以外的群体,例如读者、广告商,甚至其他潜在客户。

价值与成本的问题

服务业本身就不在于创造实物商品,而在于创造服务,如果你多观察美国的Web2.0网站创业模式,你就会发现他们有时候会用到一种思维——“如果我能够帮你减少一百万的成本,你肯定乐意从这一百万中分一部分给我”。然而中国人的思维不是这样的,中国人就想着“我如何能赚一百万”。这样想的话,第一条答案肯定是去银行抢,第二条答案可能是坑别人一百二十万扣除成本自己获利一百万,这种思维再想下去就肯定都是和“假冒伪劣”有关的事情,做出来的结果肯定是零和博弈——你所有的收益都基于其他人的损失。因此,如果你很诚实,你想要一个双赢(win-win)的盈利方案,你必须优先考虑如何帮别人赚一百万,而不是自己赚到一百万。

博客园要盈利,思维的重点就不应该在于自身如何盈利上面,而应该在于当前客户甚至是潜在客户如何盈利的问题上面。因此,我们无论讨论出书还是悬赏求技术求人才都好,第一个关注点是客户而不是博客园本身。例如悬赏求技术吧,想着别人一个题目悬赏¥1000那么博客园能收益多少是没有任何意义的,正确的思维应该是想想客户乐意为一个问题悬赏多少钱。例如一个问题,客户估计要自己解决的话要¥1000的成本,那么他的悬赏肯定在¥1000以下,例如他估计来竞标的人肯定不少,那么悬赏可能就是¥900,这时候我们就去思考博客园是否可能使用不超过¥900的成本找到一个合适的人把这个问题解决掉。

总结起来,就是以下步骤:

  1. 博客园能够为客户提供什么样的价值
  2. 博客园能否在特定的成本下完成该价值

产品化——前方200米处

是不是两步就能完事呢?实际上这和最终产品化还有一定距离。

我们来说说出书的事情,其实现在我们都知道有博客园出书团队,但到底找博客园出书的途径是如何的呢,对比其他出书途径有什么pros&cons呢,这些暂时都无法在方便的在博客园或者出书团队的首页上找到,使用搜索引擎也找不到,这就让出书看起来更像是一个内测(private beta)的服务。这时候我觉得博客园就需要一位PM(Product Manager)来把出书服务变为正式版了,至少是公测(public beta)吧,这样才能让更多的人接触到这项服务。虽然出书的人仍然只占一个非常小的比例,但完善的服务总能给需要出书的人一个更好的体验,同时对于读者来说也更有影响力。

因此,最终我们还要加上第三个步骤,从而变成:

  1. 能够为客户提供什么样的价值
  2. 能否在特定的成本下完成该价值
  3. 是否有人能负责产品化

最后,还是照例推介一下我自己的blog,喜欢的话可以进行订阅哦:

2007年5月21日星期一

Google Recruiting Event

今晚去听了宣讲会、交了简历、做了笔试。如果成功获得面试机会的话,明天下午就会有通知,紧张的等待中……

题目当然如传说中的那么基础,但是和其他学校考过的题你全无关系,甚至你不可能通过一份题考的技术范围来猜另外一份题考的技术范围。做完之后,也不知道自己到底算是怎样,大家都是大部分做对了然后错了一点点吧,但到底哪题是关键,错了就死定了,那是不知道的。所以现在除了等,也没办法预测什么,或者作出什么抉择。

比较奇怪的一件事情是,实习职位列表上竟然没有Interactive Design Intern一项,然而网站和海报上是有的,难道因为招的人少而且不属于需要笔试的职位所以在宣讲中以及笔试的职位列表上都去掉了?另外一件事情就是,我越来越觉得Associate Produt Manager职位有吸引力了,可惜Intern不要本科的,Full-Time才收本科毕业生。APM职位给我的良好印象是它什么领域都能接触到,Technology、Design、Marketing、Legal等等,而且Google招收毕业生为APM后两年就能转为PM,其他企业的PM一般都是SE(Software Engineer)凭借多年经验晋升而来的。如果真的有机会进入Google,就一定要试试自己是否有足够的实力获得APM的位置。

2007年5月17日星期四

Cat2 模板系列开始预览啦!

什么是Cat2

Cat2 = Cat * Cat,两位Cat合作的意思,也就是我Cat Chen猫窝猫影组成的小团队。

什么是Cat2模板?

这是一个XHTML+CSS+JavaScript的模板系列,暂时只包括blog模板,并且优先提供Blogger与WordPress立即可用的模板,同时也会考虑为其他常见的blog平台(例如DotText)提供立即可用的模板。

如何获取Cat2模板?

我们的模板存放在Google CodeProject Hosting,地址为:http://code.google.com/p/cat2/。您可以直接在Cat2的SVN上下载模板,或者预览模板的效果。暂时我们仅提供SilverBlack两个模板的预览,这两个模板都还没有100%完成XHTML+CSS的设计,大家可以根据预览的效果为这两个模板提出一些建议。

如何使用Cat2模板?

在我们的模板正式发布之后,您可以将我们的模板直接应用于您当前使用的blog,也可以修改后应用于您的blog或者其他形式的网站。Cat2模板使用的许可是MIT License

2007年5月16日星期三

What turns me on?

CC说我是一个非常清楚自己想要什么的人,这应该和我小时候经常努力争取到一样东西然后发现并非真正想要有关。现在我无论决定要获取什么,我都必须先确定我是真的想要,不是一时刺激让我对此有占有欲而已。

不过对于what turns me on这个问题呢,我却没有任何确认的答案,或许因为还没有足够多的like/dislike test呱,所以暂时处于untrained状态,无法预知我对一样东西最终的态度是like还是dislike,也就无法确认what turns me on。

2007年5月15日星期二

更新了 Blog Roll

大家如果看到“榜上有名”的话,可以考虑在你的blog上也增加我的链接哦。如果发现自己“下榜”了,则可能是因为你的blog已经长期没更新了,所以我就把链接给去掉了。

花了一整天终于把 Universal Resume 呕出来了

参考着几份不同人的简历,从去年8月份那份Google Camp简历上面把信息复制到新简历上来,同时又做了一些增删,最终做好了一份最新版本的通用型简历。另外还完成了简历翻译工作,现在有中英对照两个版本,要感谢的是Google Translate,很多时候不知道怎么翻译好的时候就参考它给出的翻译,能够获得很好的灵感的哦。

然后开始要做portfolio,因为申请designer类的职位都要portfolio啦,而且就算申请engineer类职位有个portfolio也没什么坏处。