2006年4月5日星期三

监视你的用户

正如之前的StealthMeter或者GamePlaysMan一样,我时不时都利用流行的技术和设计想出一些坏东西来,这次轮到Keep Your Visitors Under Surveillance了,咔咔……为什么那么多个词不用,偏要用Surveillance,因为我就想做到好像闭路电视监视网一样的效果,能够在中央控制室同时监视多个用户,而且要是实时的。

Analytics和MeasureMap出来了都还没有机会用上,就又听说有一个新的更强的站点分析平台能够分析用户鼠标在页面不同部位停留的时间长度,然后用不同的颜色把鼠标停留时间的梯度显示出来,虽然实际效果如何还不知道(该平台还在Alpha阶段),不过通过用户鼠标停留时间应该能够看出用户的阅读方式(还是有不少人习惯用鼠标跟随目光的),以及用户对页面的哪些链接感兴趣(即使没有点击)。另外最近也看了Sliver(1993),觉得在监控室中对着满墙的监视屏幕看着不同房间的人在做不同的事会挺有趣,于是就产生了监视Web用户这个想法。

首先,要实现一种ClientViewState,也就是客户端的ViewState。和ASP.NET的服务器端ViewState用于保持页面生命周期间View的状态不同,ClientViewState就是显示反映客户端浏览器当前的状态,例如页面滚动到何处,用户鼠标停留在哪里。这个ClientViewState要是实时更新的,也就是客户端的所有操作相应都实时更新ClientViewState,对于好像鼠标移动这样的事情ClientViewState会产生Frame,而对于点击这样的更新产生KeyFrame,Frame和KeyFrame会使用Ajax模式直接传输到服务器以更新服务器端存储的ClientViewState,再传输时KeyFrame拥有更高的优先级,一旦产生KeyFrame则KeyFrame之前产生但未传输完的Frame就丢弃,仅当没有连续KeyFrame时才传送Frame。

然后,监视页面从服务器下载ClientViewState下来(使用Comet模式),把每一个ClientViewState释放到一个对应的IFrame,在该IFrame还原对应的被监视用户的当前ClientViewState,通过IE的DOM的按百分比缩小显示功能把IFrame内的内容缩小,这时候监视者就可以在监视页面看到用户实际操作的情况了。

实现ClientViewState不是难事,现在的DOM足以应付,然后把ClientViewState串行话传导服务器端然后再传到另一个客户端并还原也不难,关键就是传输途中用的Comet模式是否有效率。所谓Comet模式就是现在Talk in GMail和Meebo等WebIM采用的Ajax模式,和普通Ajax唯一不同的就是Comet使用keep-alive的HTTP连接从而实现服务器端主动Push数据到客户端,但到底这样的长连接能够应付多大的负载我实在还不知道,不过应该应付串行话的ClientViewState传输还是绝对没问题的。

至于实时监视有没有什么意义,这个我暂时不知道,对于成熟的站点来说可能没什么意义,但是对于Beta阶段需要知道用户使用方式的站点来说或许有用,正如软件易用性测试可以用走廊测试一样(在走廊上随机拦几个人来试用你的软件然后看他们的操作方式),你可以通过监视用户如何使用你的站点从而知道易用性方面是否有问题,同时也无需让用户填一堆关于使用方式的调查问卷。

2006年4月3日星期一

LoadPostData 最多只有两次

在很多MSDN的一般文档中,都回避了LoadPostData这个问题,直接就说Page由Init到Load然后就是控件事件了。而根据我的实验,在Load的前后会出现两次的LoadPostData,而最后在MSDN也找到了独立的文章证实了这个流程。

一般的HTML中静态声明的控件初始化应该发生在Init,Init之后这些控件也就初始化完成。然后此时会有一次LoadPostData,这是面向仅使用HTML静态声明控件的情况,这样在Load的时候这些静态声明的控件就已经成功加载了数据,可以直接访问这些数据做一些事情了(例如根据这些数据动态创建控件)。在Load之后,如果确实有动态创建了控件,那么第二次LoadPostData就会被调用,用于为这些动态创建的控件加载数据,如果在上一次页面生命周期这些控件也有被动态创建,那么此时它们的数据就得以加载到本次页面生命周期的对应控件实例。再之后就是控件事件阶段了,所有控件都根据自己加载回来的数据判断是否要引发什么事件。

动态创建控件的最迟不能晚于第二次LoadPostData,否则创建的控件在下一个生命周期就算再次创建同样的控件也不能成功加载数据,这就确定了动态创建控件不能放到控件事件中进行,因为控件事件发生在LoadPostData后。(理论上页面生命周期可以设计为递归型的,也就是每次引发控件事件后再检查是否有添加新控件,有的话再LoadPostData,LoadPostData后再检查这些控件是否需要引发事件,不过实际上页面生命周期没有这样设计。)基本上动态创建控件必须在Load前后完成,例如开发复合控件或者模板控件时常在CreateChildControls和DataBinding中做此项工作。

如果涉及复杂的控件创建,这些控件创建必须依赖于事件改怎么办?这就只有一个办法,把动态创建变成创建所有并动态隐藏。例如制作一个有很复杂规则的调查问卷,根据答题者不同的选择转跳来转跳去(这时候你可能首先会想到ASP.NET 2.0的Wizard控件或者CrossPagePostBack,但这样每次仅显示当前的一个问题),先在页面上创建所有题目并且在Load时根据当前答题情况隐藏不应该出现的问题就是一个解决方案。这里隐藏的关键,就在于隐藏的控件不呈现到HTML上(或呈现到HTML但隐藏),但它们的ViewState却照样保存,这就使得所有的题目实际上都能够跨越页面生命周期而存在并且实现数据持久。

不过Page级别的隐藏方法好像不那么美观,所以我们应该这些逻辑封装到一个WebControl里。既然封装到WebControl里,也就没必要让各个隐藏状态的控件自行保存ViewState,直接把它们的属性统一集中到父控件并保存到其ViewState就行了。此时所有子控件的数据加载变成了由父控件统一控制,当一个子控件不需要出现时就不再需要先创建再隐藏而根本就不用创建,因为父WebControl会继续负责此子控件数据的持久。

其实ASP.NET 2.0的Wizard可能也是用类似的方式实现。在ASP.NET 1.1时我就提出过Wizard,觉得这是一个非常容易实现的控件(就按照上面的父控件统一实现子控件数据持久的方法),而且也很有价值,就是奇怪为什么各大WebControl开发商不做一个出来,结果到ASP.NET 2.0官方就做了一个出来了。至于CrossPagePostBack,用的也就是没有控件但ViewState保留的做法,每次CrossPagePostBack都把PreviousPage的整个ViewState保留下来,不过唯一问题就是如果连续用很多个CrossPagePostBack实现一个Wizard那么多个ViewState堆叠下来占用的传输带宽也一定不少。

所以说,在ASP.NET里面用好ViewState很关键(这个下次详细说),如果还是没ViewState的思想,还是按照其它动态页面语言的思路去做,那是用不好ASP.NET的控件模型的。

2006年3月31日星期五

Cassini其实不是新东西,早在2000年就有离线ASP宿主

详细可以参考这两篇文章:
http://msdn.microsoft.com/msdnmag/issues/0900/cutting/default.aspx
http://msdn.microsoft.com/msdnmag/issues/1000/cutting/default.aspx

那时候,设计的目标是为了做Demo CD,而作为Demo CD不能够要求客户机上必须装有IIS,所以就需要设计一个轻量级的离线的ASP Host。在2000年,这两篇文章归到Cutting Edge去了,不过这样的技术在当时来说确实非常Cutting Edge了,一般Demo CD最多内附一个PWS(Personal Web Server)让Win9x也能装上看看ASP的效果,基本上没有人会想到要实现自己的ASP Host。这不仅仅是技术问题,而且还是思想问题,RIA还没有提出,用HTML或者Flash做Windows应用还是非常罕见,没有人有理由要实现一个随处可运行的展示给localhost看的Web Host。

现在Cassini来了,靠的主要是System.Web.Hosting这个namespace下面的东西。其实要实现ASP.NET Host关键就是要把Request流的内容倒入HttpWorkerRequest,之后HttpWorkerRequest配合HttpRuntime就是你所要的一切输入了,而且是完整封装好和普通ASP.NET无异的了。至于输出,Cassini同样是需要实现原本HttpResponse直接让IIS实现的功能,自行把Response流的各种Header写入,然后写Response流的主体。

System.Web.Hosting其实是ASP.NET 1.x就有的东西,看来MS一早就准备了要让ASP.NET可以脱离IIS运行。如果非Windows平台上的.NET Framework能够弄出来,就能够轻易地把ASP.NET迁移过去。现在也有人在搞.NET Compact Framework上的ASP.NET Hosting(因为.NET CF没有System.Web.Hosting),那么ASP.NET就能够成为全平台的Web应用了哦,既能在线也能离线。

Macro CSS, CSS Script or Xml CSS?

继续上次那篇Programmable CSS,我现在有三个实现方案:

1.Macro CSS

用Macro来实现简单的CSS编程,既然CSS是纯文本输出,那么可以考虑仿照ASM/C++的Macro那样,定义一些简单的文本输出Macro,例如Coo所谓的自定义颜色常量就完全可以好像C++定义常量那样定义。页面就引用一个.mcss文件,这个后缀在服务器端关联一个HttpHandler(假设在.NET环境,其他语言环境自行变通),专门负责处理.mcss文件里面的Macro输出标准css。

这样做需要对Macro CSS用正则表达式进行分析,提取指令,还要做变量存储,我觉得这是比较麻烦的事情。例如变量存储,我上次说了要实现子元素可以设定padding为父元素padding的加上1px,这就需要允许在Macro里面定义变量,然后Macro运行时这些变量是无类型的,或者说是动态类型的,要支持各种运算,烦死,简直就是要自己写一个Macro Engine。

不写Macro Engine的方法有没有?也还是有的,就是把Macro转换为对应的服务器端脚本,例如ASP.NET,然后让服务器帮你编译执行,这样会舒服很多。这和直接写个满是<% %>的CSS有什么不同?我们可以为Macro CSS编写转换到不同服务器端语言的引擎,然后同一种Macro CSS就能够运行于任意动态服务器端了。

2.CSS Script

这个东西我不确定是否可行,其实就是完全用Script实现页面CSS的操作。

CSS Script拥有类似Atlas那样的一套完整的、兼容多种浏览器的Framework,然后能够用Javascript按照类似C#的写法或者类似XML的写法那样直接操作一些Framework中的封装好的CSS对象。简而言之,这就是一个CSS版的Atlas,Atlas用于DHTML和WebService,而CSS Script则用于CSS。或许未来的Atlas将会把CSS操作也封装进去,难说呢。没看过Atlas的一定要先去看看,否则会不明白我说什么的,因为Atlas实在是太过高度封装了。

3.Xml CSS

就是直接用XML来描述一个CSS模型,然后用XSLT来生成CSS,实现起来很简单,只不过用XML来写CSS或许会让人很不习惯,因为要写多很多代码。不过如果有IDE工具支持的话,或许大家都愿意接受。

原本的CSS也是DOM的一部分,除去HTML的DOM,CSS也可以独立成DOM。能够独立成DOM自然也就能够用XML来表示。用XML来表示,就可以向这个DOM增加新的元素,例如常量、运算、条件等,而新增的这些元素都通过XSLT解释最终生成普通的CSS就行了。

2006年3月30日星期四

ASP.NET 2.0解决了Code-Behind需要控件声明同步的问题

这显然是一个非常明智而且很早就应该实现的做法,因为已经在HTML中声明为runat="server"的控件,就应该算是声明过,还要在code-behind中同步的用C#代码再声明一个同名控件显然是违反了《程序员修炼之道》中所谓的DRY(Don't Repeat Yourself)原则。

原本ASP.NET 1.x的编译模型是编译站点时先编译code-behind部分,然后得到code-behind部分的Page派生类,等到运行时再编译aspx部分此事得到code-behind部分的派生类(也就是Page的二级派生类),而一旦aspx和code-behind出现控件声明的不同步那么这个继承关系将出现问题。

ASP.NET 2.0的做法就是把aspx和code-behind都看作Page派生类的partial class,并且合成编译,而aspx中所有的控件声明都将在编译时自动转换为C#声明,这样的好处是只有一层Page派生类而且不用同步什么东西,所有东西都是仅声明一次。不过有一个问题就是,到底aspx中的声明是转换为C#的partial class再编译还是能够直接编译呢?转换为C#编译是很直接的思路,ASP.NET 2.0 的内部变化也是说原本由VS.NET 2002/2003做的声明同步工作现在交给ASP.NET Runtime了,但是这样就有一个问题,如果要开发一种新的ASP.NET语言(例如Delphi for ASP.NET 2.0),那么也就必须建立aspx到该语言的翻译,这是十分麻烦的事情。但是如果aspx和code-behind分开编译的话,这好像超出了partial class的能力范围,根据C# 2.0的规范,partial class的所有部分必须是同时编译的,不可以是增量编译的,也不可以是跨语言编译的,而aspx和code-behind都直接编译的话就需要双语言编译,也就需要增量编译。

ASP.NET 2.0还有一个很好的地方,就是部署编译,你能够把整个网站都编译了(包括aspx和code-behind)然后发布,发布目标的aspx将是一个仅引用后台类的控文件,这样性能最好而且也不用担心代码泄漏(特别是编译后的dll再混淆一下的话)。不过因为aspx部分也编译了,所以这样发布的网站发布之后就不能改动。而ASP.NET 2.0还提供另一个极端,就是完全运行时编译。以前ASP.NET 1.x如果是code-behind的话,code-behind部分就必须在VS.NET里面先编译,不过现在ASP.NET 2.0能够自动监测code-behind部分是否有改动过(甚至是/App_Code目录下的其他非UI逻辑的code),如果有就运行时编译,这对于调试来说是挺方便的,不需要每次调时前先在VS.NET里面按Ctrl+Shift+B编译。

2006年3月27日星期一

关于中学是否应该教Office应用

Jim跟我说,中学花时间去教Office,还不如教程序设计锻炼一下思维能力。不过最近Piggest却提了一些排版问题,显然不上课那些功能就在二级菜单你也不知道它原来是这样用的。

Office这件东西,有人说只有5%的功能常用,95%的功能常人用不到,所以作为一个聪明的开发商就应该把主要精力花在优化着5%常用功能的易用性上,这是非常合理的。问题是,要完成一份Document所需要的成本是全局的,假如5%常用功能的使用成本很低,但是偏偏你要用到几个5%以外的功能而它们的使用成本非常高,那么无论MS如何优化那5%的功能对此都毫无帮助。例如,很可能你不知道插入分页符,然后通过手动插入回车来实现分页,结果你用20min输入完文章,然后花了10min来分页,但之后你每次改动文档时需要手动调整分页的时间和输入改动的时间是1:1,那么显然输入和分页所花费的时间将趋于1:1,即使输入部分(作为常用功能)优化得很好你做得很快,最终生成Document的成本还是被分页而卡得很高。

降低你用非5%常用功能时的成本,唯一途径就是你接受过比较系统的学习。就好像Piggest去上Maya培训那样,就好像我说学Javascript要必须看O'Reilly的《Javascript权威指南》一样,不经过系统学习那些非常用功能你是不会知道的,这时候那些非常用功能你就只能用常用功能去“模拟”,这时候使用非常用功能的成本就会暴增。很多东西称之为“易学难精”正是因为非常用功能自己学难以了解到,甚至系统教材也没有,只有长期钻研的高手才对该领域有所了解,例如ASP.NET的页面生存周期的细节,MS不肯公开细节,于是就出现了个高手自己用Reflector看ASP.NET源代码和自己做实验然后把结果公布到自己的Blog的现象。

2006年3月23日星期四

Client 说她的瘦身计划不能变,所以 Server 你必须再胖些

上次说到“HTML + AJAX + WebService = C/S or B/S?”,我说通过WebService方式调用会不会又让B/S变得类似C/S了,不过结果是Client说她不能再胖,胖了Browser就不让进,呵呵……

首先第一件事就是关于DOM,有人说这才是AJAX的本质而XMLHttpRequest只是一个小工具,不过这个本质(不是McDull的那个本质,咔咔)的执行效率就实在不怎么样,不至于很差,但是你绝对不能把以前用ThickClient的Native Code所做的东西完全交给它,因为太多了你就会发现它忙不过来。

举个CSDN上见到过几次的一个例子,就是做一个类似Google Suggest那样的有筛选功能的ComboBox,遇到问题的人都说那东西只要待筛选项超过5K就没效率了,然后我说不要用DOM来构建下拉的内容而改用拼接HTML同时只有当用户超过500ms没按键时才筛选,结果有所改善,不过可能也无法处理超过10K的待筛选项。

我自己也做过一个动态生成table的东西,用DOM构建table的话一个50*30格的就要300ms~500ms,这个效率实在太低啦。

第二个问题就是复杂的客户端调用规则。例如我有一个用户注册表单要调用服务器端的3个WebMethod:
bool IsUsernameDuplicated(string Username) //用户名是否已被使用
bool IsEmailDuplicated(string Email) //Email是否已被使用
void SignUp(...) //把所有注册信息提交到数据库

现在要求异步调用IsUsernameDuplicated和IsEmailDuplicated,我也不知道哪个先返回,但必须两个都返回false才调用SignUp,任何一个返回true或者Timeout了都不调用SignUp。这样事情就会变得很麻烦,前两个WebMethod返回时必须作标记,然后用一个定式执行的程序不停的检查这两个标记直到都有返回(或者Timeout)为止。

当客户端有一系列复杂的调用规则时,问题就更加复杂了,所以最后你会发现还是不要在客户端搞复杂调用好,这些规则应该都交给服务器端处理,然后封装为一个WebMethod。例如应该只设置一个SignUp,调用时通过返回一个int来表示用户名/Email是否已被使用,又或者用Atlas的Exception机制来返回这个。

简而言之,Client跑Browser的Scripting跑道上时别给太多或者太复杂的东西它干,它根本干不来,事情还是尽量让Server包办好了。不过也有例外的时候,例如那边Flash就在大喊我很Rich(因为它自己叫自己RIA),我可以负责很重的UI任务,呵呵……

2006年3月21日星期二

Benny说不要太早走出社会喔~

上次回去修华附论坛那台服务器时,Benny说第二天就要面试20个本科生,从中要两个,试用期月薪¥1K+,转正后再加¥500。然后我问他招那两个人的工作范围是什么,他说一个负责发布新闻,长期坐在网络中心,另外一个跟吴老师东奔西跑(估计是维修类的)。

Benny的意思就是,能够留在学校里,最好就一直留在学校里不要出来。不过留在学校里虽然什么都好,但是现在好的学校都越来越“敛财”了,所谓教育产业化搞到学校也变成了服务运营商,能够骗到一点钱就骗一点,积累资金“扩大生产”,真正专心搞教学或者研究的人又剩下多少呢?

2006年3月19日星期日

Site moved~

由于sitesled已经有一段时间无法进行FTP上传了,所以改到5000megs,PURL保持不变:
http://purl.oclc.org/NET/cathsfz

由于原来用开GB2312发布,现在服务器的charset为UTF-8,改过来可真不容易。用GB2312发布,则客户端打开时自动根据HTTP的charset而不是HTML的charset设置为UTF-8,用户需要手动改回GB2312才能正常浏览;用UTF-8发布,根本就是乱麻,因为Blogger保存文章和模板时就有charset属性,GB2312的文章按UTF-8发布无论如何都是乱码。

最后我意外找到了解决方案,就是先用GB2312完整发布一次,然后改用UTF-8发布,并把模版和首页上的几篇文章改为UTF-8,最后仅发布索引一次,那就OK了。这个解决方案首先解决了首页显示问题(这是我原本的目标),后来发现打开内页竟然GB2312又能自动识别(难道仅访问/时HTTP协议会返回charset),所以暂时我的Blog“看起来”完全没问题。

2006年3月5日星期日

My Life Rate~

This Is My Life, Rated
Life:
5.6
Mind:
6.2
Body:
5.5
Spirit:
6.3
Friends/Family:
5.9
Love:
1.5
Finance:
5.5
Take the Rate My Life Quiz

2006年2月27日星期一

Unique Part vs Replaceable Part (Part1)

某些统计数据说平均一个大学生把大学里的时间的一半甚至更多花在英语考试上(可能计算上出国原因而要应试的人吧),然后我们上学期那个英语老师又整天在提应试的事情,烦死我了,所以我就在英语作文上狠狠地讽刺了一番拿着一堆人有你也有的"证书"是很难找到工作的,只有你保证你自己的Unique的你才容易让别人招你??特别是那个职位非常适合你的时候,因为你是Unique的所以只能选你,你的开价就能够高。

讲得简单点啊,中大现在单省一它也不一定愿意保送了,要国家奖、双省一或者单省一的前20名,还要参加它的"资格考试",这就是什么东西有的人多了就难以通过它区分人的水平高低,这东西也就贬值了。所以,要么你就拿一个非常Top的证书,要确保足够少人有的那种;要么你就拿几个一般人只能拿一个的证书,证明你可以一个顶几个。

其实很老实说一句,如果你毕业之后出去做Manager,有机会给你招本科毕业生,你会不会觉得很头痛?我觉得会,因为读过的人都知道本科生是读什么的,本科生就只能证明你在高考前还是个不错的人,高考后鬼知道你干什么去了。大学就是一个拉平补齐的地方,不管你原来有多厉害,很容易就被人钝化为一模一样的Replaceable Part,然后出来就是等别人不是很行的时候就上去把别人Replace掉,之后自己不是很行的时候就又给人Replace掉。

接着肯定有人说有问题,嗯……那就先说吧,然后慢慢等Part2吧。

2006年2月23日星期四

SmartClient应该是PDA/SP上PIM软件的发展方向

Yahoo推出了个Yahoo Go Mobile的软件,能够让你直接在手机中访问Yahoo的Mail、Calendar、Weather、Messenger等主要服务,其实这已经相当于把Contact、Appointment无线化,把主要数据存储在服务器中。

Yahoo Go Mobile能否取代手机内置的Contact和Appointment暂时不知道,但这应该是一种趋势。我之前曾经说过网上的Contact、Appointment、Todo、Memo我不用,是因为他们无法和我的PDA同步,不过如果能够同步的话那就会考虑用了。对于这类服务来说,长期挂线当然不可能,难道有来电了软件需要先通过GPRS查询一下线上的Contact表然后才能显示该号码对应的联系人名称,这显然不行,所以就必须在手机内缓存一份离线数据,其实这也就是SmartClient的主要思想??两份数据、智能无缝同步。

其实真正的难度就在于智能与无缝这两个词上,不同软件的特性不同,所以暂时还没有人做出一个SmartClient的Framework出来能够兼容各种软件的数据特性。智能要求就是它懂得什么时候可以同步(例如自动在带宽闲时同步)、优先同步什么数据(例如优先同步可能将要显示的数据和关键数据)、同步对显示的影响(例如哪些数据不同步也能显示给用户看、哪些数据不同步就应该告诉用户数据已过期)。无缝则要求不打扰用户并为用户节省时间,也就是什么都放到后台自动处理掉,好像AJAX那样,用户在前台不需要浪费时间,我个人认为以后所有网络软件/服务都将向无缝发展,包括需要下载才能运行的东西,因为用户一般不会介意去点击一下“允许”按钮,只要在软件/服务真正可用之前的那段时间他可以去干其他事情而不用坐在下载进度调和安装程序面前白等就行,当然也不要过一段时间点一下是否之类的选项。

其实,很难说下一版的SQL Server Mobile Edition会不会内置和SQL Server Standard Edtion智能无缝同步的功能,因为MS竟然把js封装成.NET语法形式(也就是Atlas)这样的事情也做得出,它真的要封装一个SmartClient Framework也不是不行,然后提供一个足够丰富的config文件格式和一个类库给你静态/动态的去配置同步细节。但正如MS一贯的风格,1.0的东西都让人很期待但很不好用,2.0才有点出色,3.0才能够腾飞,所以就算由下一代SQL Server开始有这个功能,普及SmartClient这样的事情也不可能是MS做的了(因为它效率太低了),反而可能使Yahoo或者Google做了。

2006年2月18日星期六

开学了,继续忙

赚钱的项目、社团、学业……都还有很多tasks要做,有部分可以随便应付的,但是我自己想认真对待的tasks将耗费我不少时间。

不过暂时来说最麻烦的就是我有写不完的Blog,很多很多东西存在Draft中,可能因为我一早就养成了写东西写一半然后不想下去的习惯,所以很多东西都收不了尾只能放在Draft中,直到一些我有办法结尾或者我认为过期该删掉了。这是个很严重的问题,不过不是每篇文章都可能有结尾的,很多事情仅仅是有个开头的想法,然后懒得想下去,所以我决定继续按照我以前在别处的做法,就是在文章写到一半的时候不想写就写一个“待续”,然后续不续就看我有没有思路了。

2006年2月15日星期三

纯javascript和汇编越来越像了

首先先说说类似之处:

1.指令都是执行很琐碎的功能,用起来比较吃力。别以为javascript是解释执行的高级语言就好,要获取一个HTML对象还要document.getElementById(),这一情形和用汇编的mov和add差不多??看起来是非常必需的指令,但往往自然语言的一个语义(例如c = a + b)必需翻译成几条这样的基础指令。

2.指令集版本多,而且由商业因素变化而变化,不存在必然的兼容。就好象不同CPU支持的指令集一样,javascript也是这样,你想写一个兼容多几种浏览的javascript那个调试难度就大咯,有些情况下几乎你要为每种浏览器写一次代码,测试也是要分开测试,这和写兼容多种CPU指令集的软件一样。现在有专门为某种硬件优化的编译器,例如你今天可以看到游戏有Run Greats on Pentium4 HyperThreading的欢迎屏,迟点就可能可以看到有网站写着Better Visual Effects on Windows Vista with Internet Explorer 7(IE7 for Vista可能就像IE6 for XP那样是和通用版不同的,鬼知道它会不会对Vista的Theme和DirectX10有没有什么特别支持)。

然后就是我们现在面临的情景:各种各样的Web UI Library出现,这些UI Library和当年的微软的MASM有什么不同?(我个人认为MASM这个缩写中第一个"M"指Macro,如果按现在的叫法应该是MS-MASM,也就是Microsoft Macro Assembler,在MSDN你仍然可以查到MASM的帮助,不过只有关于Macro的,没有关于普通汇编指令的,可见它强调Macro的程度)。我们现在用$()代替document.getElementById(),简直就是一种Macro,我们通过Macro特别是好象MASM那样的高度自动化和智能的Macro省下了很多指令,它能够自动适应环境产生代码甚至根据复杂的逻辑产生代码,但实际上Macro离真正的可编译高级语言还有很远的距离。

什么时候才是javascript好象汇编那样,出现一种能编译的高级语言?我之前说过,有一天可能只需要写服务器端代码,就能够自动把部分生成为javascript在客户端执行,可能那才是javascript全自动生成的时代,我们离这个时代可能还有几年的距离,也可能几年没过完javascript就成为过时的技术而被新的技术取代掉。

2006年2月13日星期一

ASP.NET 2.0 ClientScript Callback

当AJAX出名的时候,ASP.NET 2.0已经基本上完成并且离最后发布时间还剩下半年,此时人人都希望MS为ASP.NET 2.0加上AJAX支持但MS说我们没时间加了,AJAX将成为独立的Atlas项目并出现在ASP.NET 3.0中。不过ASP.NET 2.0中有一个非常通用的但只能称为Method而不能称为Framework的AJAX支持,那就是Callback。

Callback的使用非常简单,首先你要有一个实现了ICallbackEventHandler的Control,例如你在你的Page上面实现ICallbackEventHandler,这个接口会要你实现RaiseCallbackEvent()和GetCallbackResult(),讲简单点其实它们就从客户端接受一个String的传入交给你处理,你处理完就传回一个String给客户端,详细的处理由Page的RenderCallback来负责,这个不需要你操心。

如果你用Callback,好处是你不需要管什么WebService之类的东西,你可以把Callback整合到Page里面(如果你一个Page只需要一个Callback)或者你自己封装的某个Control里面(如果这个Control自己使用一个Callback)。可以看到,Callback是希望你把处理封装到Control,例如你自己可以继承Button写一个CallbackButton实现ICallbackEventHandler及其两个函数,然后你把RaiseCallbackEvent()冒泡为CallbackClick()事件。

Callback有一个有趣的地方,就是传入和传出String分在两个函数里面了。看起来,这是很蠢的行为,但实际上它是为了符合ASP.NET对象模型那种事件处理方式,也就是Event与Render的分离。ASP.NET里面,Event和Render不像ASP那样是直接相关的(因为某个按钮点击了,所以输出某个反馈),Event是影响于ASP.NET对象模型,或者直接点说主要就是控件树和HttpContext,然后Render是根据控件树和HttpContext去生成HTML,但任意多个Event对控件树和HttpContext的影响应该是正交设计的。你可以在Callback的时候好象Postback那样把所有数据都发回来然后填充控件树然后Render时就如Postback一样根据整个完整的控件树去输出。

最后,Callback是一个半成品,MSDN中关于Callback的资料也有很多错漏的地方,所以大家自己弄清楚怎么用好用就够了,MS的目标是让Callback和Postback一致从而方便实现AJAX,但暂时还没有实现,还有很多Script代码要自己去写。另外我在看Callback的文章时看到,在System.Web.Util里面有很多很好用的小工具式代码,可以给你带来不少方便的,在你写例如服务器端String转换为脚本端String之类的代码前请记得找找那里有没有写好的,不要为此而浪费自己的时间。

2006年2月12日星期日

Programmers Eliminate Programmers

开发自动化工具的程序员总是在不停的"消灭"其他程序员,至少在不断让别的程序员的劳动甚至是创意贬值,呵呵……这是一场很有趣的Race,就是你每天在不停的写程序的时候,其实你也就在让很多别人写的代码甚至你自己以前写的代码变成垃圾,因为"可复用(Reusable)"真的是一种很可怕的东西。

物质产品方面,重来没有什么Reusable可言,这就是经典的"价值"与"使用价值"只能取其一理论。只有IP(Intellectual Property,知识财产、知识产权)才可能reuse,这个reuse就是指在不付出价值的情况下,你可以直接得到使用价值。于是,一旦有人做了的东西,它就可以被reuse,其它人也就不需要做了,做了一半的也没用了(这让人想起Civilization里面的奇迹建造,任何奇迹第一个造出来的文明能够获取此奇迹,其余文明就算做到一半也没用)。这时候,作为程序员,最坏的情况不再是不做,而是做了一半然后别人先做出来了,这样的损失比不做还要大,哎……

所以,程序员不仅仅要去工作,还要选择对的来做,否则就很容易给别人干掉。说得好听点就是享受别人的工作成果就是了,但实际上就是自己实现不了任何的价值。

暂时我觉得最好的全能索引方式还是Google Base

所谓"全能索引",就是不仅仅像"全文索引"那样增强对文字(例如时态、人称、单复数变化)的索引能力,而是对任意事物任意属性的索引方式。

因为是任意事物任意属性,所以数据表没办法表示好这种东西,必须使用XML那样的方式。Google Base能够做到,因为它不仅仅允许你好像XML那样发布一个事物及登记其属性,更重要的是它能够对类别与属性的名称进行感知,避免滥用(Abuse)。

首先是发布时输入的类型,虽然不仅可以从已有的热门类别选择还可以任你填,但你别以为真的好像普通的tag系统那样任你填哦,你填一个不是单词的上去看看,或者填一个非名词进去看看,你就会发现Google Base提示错误。至于它怎样做到的?因为它基于现在所拥有的数据库,已经能够懂得什么词能够表示一个类别。同时,我也怀疑这个类别它已经知道同义词的存在并且能够同义词归类,例如Blog、Blogs、Blogger、Bloggers等它应该都知道是同一个东西。在输入类别之后,它就能够进入登记属性页,这时候它又能够自动出现一些此类别对象常见的属性,这个我暂时不确定是它根据其他人登记时创建的属性总结出来的,还是即使你创建一个没人登记过的类别的事物它也能列出若干建议属性来。

在属性输入页,你可以删除已有的建议属性或者添加新的属性,这就是类似XML的地方,这些属性也是有类型的,这样就算是同类的事物不同人创建的登记的属性的详细程度也就不同。这时对于之后搜索很好玩的地方,在搜索的时候它懂得提示你按照某个属性来缩窄搜索范围优化搜索,例如People并非每个都有登记Age,到底是否该提示你通过Age范围段索债搜索范围呢,这也是一个职能的地方。

如果我知道如何写数据库引擎,我也写一个轻量级的Google Base来玩玩,据说Google内部有一种BigTable的半结构数据分布式存储和访问接口,这个是从Dash的Feed看来的,原文在这里:
http://www.wespoke.com/archives/001042.html

其实说起这个,是因为我想来想去都不知道那个协作系统如何发布idea,这真的是一个很头痛的问题。idea,就好像我上面说的那样,有任意多的属性,而不仅仅是通过tag就能解决的,我需要一个办法把它们索引起来。而且,你单作一个这样的系统,别人还未必愿意到你那里登记。反而好像Google Base那样,既不说交友信息招贴栏,也不说出租房子招贴栏,但贴的人就不少,有一天Google突然宣布Google Base该怎么用好了而这时它已经有了大量的数据作为启动基础。

2006年2月8日星期三

卖服务还是卖产品

最近又见到有人讨论,最一种很通用的Portal好不好,就是那种可以直接在Web界面上设计数据库,生成WebForm,设计业务逻辑那种。简单来说,就是一个比Sharepoint更容易直接在Web上灵活定制的东西(Sharepoint的Web定制能力一般,要定制还是要靠继承原有类编写新代码),整一个Web版Access甚至Sql Server那样。

我第一次见到Sharepoint Portal Server 2003时,就有这个想法,当时就觉得它是一个Sql Server to Web,只不过Web定制能力不强。当时对ASP.NET的底层了解不多,不敢去详细想如果做一个更好的有多难。现在觉得不难了,不过倒觉得做这样一个东西拿去卖实在不容易。虽然想想,如果作为一个小站长,不需要懂太多的技术知识,也不用在客户端装Frontpage、Access、Sql Server 企业管理器之类的,打开网站就能够直接在IE里面编辑HTML,设计数据表,然后设计事务逻辑,多爽。然而,还必须关注一个问题是,现在的小站长去哪找一个空间支持你这套系统?人家可能自己设计HTML不怎么好看,但找一个免费的静态空间比起找一个支持这套系统的动态空间可要容易不少哦,可能人家的HTML设计出来才几M甚至几百K,而如果用这套系统他就要去找一个50M的动态空间先把这套系统Upload上去,显然很不划算。这样说来,卖产品还不如自己做Host然后直接提供这样一种服务,客户买空间的同时也就得到了这套系统的使用(实际上用这套系统的人,都不会想获得它的代码)。

其实现在我们看到的情况就是,Web 2.0,Longtail,越来越多普通的End-User加入到其中来,不再是Professional User单向发布的时代,我们需要满足很多自己没有能力Host自己的东西,所以我们必须改掉老一代Web开发者那种制作一个Web站点然后让别人自己host自己用的想法,而是直接提供一个host这种服务的平台让客户可以直接使用。

不过这种趋势实际上就是提高了开发者的门槛,小开发者往往不能自做host,SP之名就更加高攀不起,只能考虑作产品然后卖掉。可是现在“卖掉”这条路不好走咯,那就只有考虑Open Source,看看哪家有能力作host的看中,然后整个拿过去作为合作项目,那样才有可能收到钱。说到Open Source,其实这在国外还算是一条赚钱的方法,不容易找到客户卖掉的就不如Open Source,这样反而更多人关注更容易找到合作机会。当然,国内是另外一回事,无论是创意还是源代码都是可以抄的,对人和知识都没有任何尊重可言,任何东西公开之前还是改深思熟虑。

回归原来的主题,既然潮流正在改变,如果能够抓住这个机会,出一两个主打的服务,至少算是和时代同步,如果继续做“可能能够按copy卖掉的站点”,那就肯定卖不掉咯,今时今日不能copy确保unique的东西才好卖。

是游戏还是感官刺激?

刚刚开始有电子游戏的时候,还是非常之"游戏"的。这里的"游戏",也就是所谓的Game,翻译成"博弈"也没错,总之你就是有一个竞争对手,而你的目标也就是赢它。

游戏的拟真程度本身是一种游戏性的需求,看起来一样游戏方式的游戏,有一个绿色色块表示一个人还使用一个Logo表示人,玩起来后者的感觉显然比前者好。因此,游戏的拟真程度的发展,以及它推动着相关技术的发展,是很自然的事。接下来的事情,就是拟真度不断提高,然后就会有人就发现了“过度拟真”的好处??虽然看起来有点假,但你可以说那叫做艺术,最重要的就是玩家喜欢,因为大部分玩家一定程度上都是个“感觉者”(“感觉者”的定义来自D&D中Planescape背景设定),也就是喜欢去感受一些没有感受过感觉,特别是比较激烈的感觉。

于是有些游戏开发者完全是去讨好玩家的感官刺激需求,同时游戏的感官刺激就有点如drugs,一旦上瘾就放不下(例如现在叫你用17寸屏玩320*240的游戏,你绝对不会玩,你只会说如果能够用PPC玩的话那还不错),而且只有刺激越来越大才能有感觉。这种现象,就是部分玩家所谓的某某游戏让某某类型游戏死亡,例如最近有人说《神秘岛5》让解密游戏死亡,因为它本身不是超级解密游戏但就靠画面强,而如果出来一个游戏性好但画面无法超越它的解密游戏玩家可能又不愿意玩。

然而,实际上技术进步所带来的最终还是应该应用到游戏性上,而感官刺激是次要的。只有有新的游戏特性,那样才能吸引玩家,因为这个“新”是可以无限创新的。而感官刺激是一个一维量,你要增加这个量,总会面临技术所带来的极限,但游戏特性的创新则不会。好的游戏懂得利用技术在游戏性和感官刺激方面同时提升,如果游戏开发者仅仅注重人在某一方面感官上的刺激,那么游戏就真的很容易变成Drugs,因为人是基于本能的去“简单”的追求单方面刺激的提升。

2006年2月6日星期一

从亚健康到不健康

最近常常工作、看电影或者各种原因弄到三四点才睡,幸运的也两点才睡,发现Health程度爆降,然后Strength跟着跌(Max HP也会跌),所以决定从今天起,一定要早睡早起(先试着零点睡觉,这已经算早的啦)。

本猫是非常依赖于睡觉和享受睡觉的,没得睡觉会死猫的,无论采用正常作息时间还是滚动作息时间,都一定要睡够,那样工作的时候才能高效率输出,否则慢慢挨更加累死猫。