我看HTML5到来的那一日,会比我们想象的都要快。虽然微软的IE还占据这大部分的浏览器市场,但是不要对它拖后腿的力量估计的太高。也许2011,也许2012年,大量基于HTML5的应用将要出现在我们的身边。
也许那一天,我们还会发现大量的桌面浏览器是基于Trident内核的IE6,IE7,IE8,遨游,TT。但是这又有什么关系呢?因为HTML5将首先出现在移动终端中!出现在Android和iPhone的手机里,然后是大量的手机厂商。对于他们来说,无非是更换一个手机浏览器的版本而已。何乐而不为呢?如果手机厂商们发现,只要更新一个浏览器版本,会支持更多的基于云端的离线应用,而不仅仅是看看网页的话,基于浏览器的app,就会和基于java的app一样,成为手机的一个增值点。
当然这不是运营商喜欢的模式,移动、联通们刚开始动app store的念头,连钱的腥味都还没有闻到的时候,科技浪潮已经把他们拍死在了礁石上。如果那些交互不太丰富的终端,html5的技术已经完全可以支持。那么app store又要开给谁呢?运营商就应该把服务做好,并且安心的收取它们应得的流量费而不是其他的什么。
由于HTML5的蓬勃发展,它必然首先从移动终端平台起步,进而带动大量的云存储产品提供html5的支持。接下来,就要冲击以flash为核心的sns app市场了。有谁不希望通过facebook实现一个基于html5的游戏平台,不但让游戏可以在浏览器内可以玩,还可以在移动终端上玩呢?(看起来苹果的态度是那么地坚决)然后,很多网站发现,它们做一个基于浏览器版本,并且稍微增加一点html5的特性是有利可图的。于是更加适应小屏幕(640*480以下)的页面的应用会发生。直到有一天,我们发现通过移动终端打开的flash网站都变成了html5网站。
但是客观的讲,在ie家族还没有从这个世界上销声匿迹之前,对html5的支持始终是一个痛。好在html5已经有了一个出口,这里有google和apple两家公司开道,移动终端会发展得比互联网应用更加快。年轻的开发者们已经看到了这里的机会,而在Windows平台或者传统互联网上赚钱的公司,正在变得越来越难。两个善于利用他人智慧的公司,走在了html5的前面,虽然它们各自有自己的小算盘。但是至少通往html5的大门已经因为它们而打开了。
上帝保佑HTML5。因为它将大大缩短程序员开发的时间和发布代码的周期,让移动终端的应用变得更加方便和易用。
今天大清早起来,就看到Twitter上很多人在说Buzz的事情,因为在做其他的事情,没有仔细地去用。等晚上回到家的时候,才开始在iPod touch上摆弄,然后再电脑上继续摆弄这个。Buzz的小宇宙确实很强大,尤其是将它和地图连接起来之后,Buzz给人的感觉就是可以看到周围很多人正在讨论什么问题。不是从人的熟悉程度来看,而是从人的物理位置这个角度来看的。但问题是,之前已经有不少公司做过了这样的项目,而且项目的结果都很惨淡。
难道Google的Buzz会有所不同么?
Google Buzz是基于Gmail的一个应用,然后在刚刚开始试用的时候,就已经有人说:我要关掉他。理由就是隐私问题。如果是一个新的应用,很好。但是请不要和我的Gmail绑定起来,至少允许我建立另外一套好友关系。就好像我在碗Twitter的时候,并不愿意我的合作伙伴和我的老板都看到我每天絮絮叨叨些什么。这会让人感觉很郁闷。
Google Buzz的另外一个问题是关于时间轴。对于一个人的操作,有主题和回复两个模块。Twitter的时间轴是很清楚的,一切都是主题,所有的回复也是主题。Facebook’s Wall时间轴也是很清楚的,只跟着主题走,而主题跟着人走,而所有回复或者再回复,都是通过通知来搞定,但是Facebook’s Wall的量不会很大,因为主题隶属于人的关系,阅读是分裂的,也恰恰是因为这个原因,所以通知量不会很大,可以解决。
Google Buzz刚好介于两者之间,一方面把所有朋友的主题都搜罗到一个时间轴中,一方面回复又需要通过通知来解决。这样的结果就会造成通知量大增,但是阅读又是割裂的(你得到主题下面找到相应的回复,再继续往下读)。
Buzz这个产品,让我想起了之前雷声很大的Wave项目。Wave这个项目应该是失败了的,死用户很多,因为这个功能非常强大的Wave,除了折腾人之外,不知道能够让人获得什么。相对来说,我觉得Buzz的命运会好很多,但是也仅仅能座位Gmail的一个附属功能而存在。也是因为它依附于Gmail,所以才会继续存活下去。说起来还是有点让人伤心。
互联网的作用,就是让信息流变得更快,促进了信息的沟通,就会让项目成功。而Googler现在的问题在于,虽然他们试图利用自己可以控制的资源,让信息流通更快起来,但是他们却忽略了一个很重要的问题——最后一公里。最后一公里,往往决定了许多电信公司是否能够活下去,就算是它的主干网络再如何先进,如果没有最后一公里的服务和落地的政策保护,所有的强项都没有用。
当Google在致力于聚集所有的信息,并且以最快的速度传达到个人手中的时候,它需要解决的问题无非是两个:1. 如何有序的汇总信息,2.如何知道哪个用户需要什么信息。在这个基础上,各种模式都是可以探讨的,但是任何模式都不能缺少一个重要的环节——直观的界面。
现在我相信,一个好的互联网产品,需要的可能不仅仅是技术,或者交互思想。它可能需要一点点philosophy,对于人类应该成为这样的一点点思考。虽然我现在已经很久没有用FriendFeed了,但是它和Twitter一样,闪现出这方面的很多想法。那么Buzz究竟是一个东西呢?为什么它应该寄宿于Gmail之中呢?这些问题,我想,Buzz的产品经理不知道是否考虑过,希望不是因为这是一个Gmail team做的东西,而利用这个平台更好推广之类的原因吧。
首先需要声明一下的是,这篇文章不是从普通用户的视角,来看到Android的。也不是从商业行为的角度来看待一个有钱的大公司是如何进入移动终端领域的。而仅仅是从一个普通开发工程师的需求来看待Android。当然参照的对象是——iPhone OS。
今天下载了Android 1.5的SDK,把大致的开发流程和SDK的功能都走了一边。也许是之前接触了比较多iPhone OS 3.0 SDK的缘故,脑子里总是有这方面的比较。这种挥之不去的印象,在最后打开Android模拟器的时候,到达了顶点。渐渐地,我也意识到了,Android能吸引的是怎样的一群开发工程师,而哪些开发工程师会对Android产生排斥的感觉。
我们先来看看iPhone OS的Cocoa架构吧:
对于程序员来说,用最少的代码达到想要的效果是令人愉快的SDK。iPhone OS有着天然的优势,它只是把原来在Mac上的Cocoa做了一下平台的移植和瘦身,比如删掉了一些在Core Graphics里面对位图的filter效果,就把整个移动终端的性能控制到一个可以接受的程度。在OpenGL ES版本中,也去掉了Perspective的透视效果,只支持正交透视的效果,从而达到了对3D渲染性能问题的控制。而常见的Quartz Framework关于界面的操作,基本没有动。这给许多已经在mac上拥有开发经验,甚至已经有mac版本客户端软件的用户一个很简单的方法,去移植到iPhone上应用。因为对于程序员来说,牺牲一些效果,删掉一些功能的移植工作,几乎是所以项目移植中最省事的事情,同样,学习成本也是最低的。因为程序员只需要知道——什么东西不再支持了,不要用就是了。
而对于Android的程序员,则完全不是,从Android的SDK开发思路来看,他们做了唯一一件事情,就是在JAVA的平台上,把设备和程序连接了起来,例如界面的操控直接借鉴了Applet之前对于布局的一些处理方式,而使用XML来描述页面元素的模式,很像Flex的定义模式(这方面我不太熟,可能存在一个更早的规范标准,让它们对布局中各元素的定义那么相近)。
从Android的开发模型(或者说对于界面理解的视角)来看,虽然Android提供了一个可以写更少代码来完成界面制作的方法,但是通过这种方式制作出来的界面,却很难达到消费人群所希望获得的更好的体验。而这些问题,恰恰是一个缺少时尚设计元素的公司很难做到的。对于一个数据驱动的公司来说,操作的间接性已经成了公司的核心竞争力。但是,移动终端的大部分应用,简洁而高效的界面操作流程,并不能给设备厂商带来丰厚的利润。
从这一点来看,多数的开发商,尤其是从PC市场转过来的工程师,会觉得基于JAVA的界面模式,限制了他们更好实现产品经理以及美术设计意图的办法。而更多喜欢使用这个平台的是,那些以网络服务提供商行业切入进来了工程师,他们看到它的界面定义就是Java Applet的延续和增强,他们也看到了Flex这个基于Adobe Flash的,富客户端的编程模式。这已经很强大了,甚至比浏览器中可以做到的界面工作多更多,交互性也更好。
但是,再强大的浏览器增强SDK,也依旧无法和天生就出植根于客户端的界面SDK竞争。
Google App Engine前端和大部分的Java Web Server的设计相当。通过配制web.xml设置URL规则,比如<servlet>, <servlet-mapping>和<welcome-file-list>。对了,还有<filter>和<filter-mapping>。
为了简单处理常用的JSP动态页面脚本,与普通的web.xml不一样,直接用<jsp-file>替代<servlet>中的<class-name>。但是这个处理方式有点别扭。主要是因为在普通的Java Web Server中,只需要配制好url-pattern,所有符合规则的JSP都会使用JSP解释器操作。而GAE的配制则不行,它需要对每个JSP都做一下配制……这会让开发变得明显的不容易,至少这个事情会变得很麻烦。
另外一个重要的设计是,是对于配制文件的。坦率的说,我很喜欢在配制文件appengine-web.xml可以把所有相应的配制信息都管理起来。但是在GAE的设计中,反而限制得更多了。相比之下,spring对配制文件的理解则要可爱得多。GAE限制了直接读取本地文件的java.io的类,但是又没有通过配制文件给出一个可以获得配制文件内容的方法。毕竟不光是logging,其他大量的框架和应用jar包,都有自己特有的properties和xml文件,需要读取。
如果能够像spring读取配制文件一样,提供一个:”classpath:myproperties.xml”,这样的配制方式,就可以指定所有的配制文件只会从WEB-INF/classes目录下读取,或者也可以从其他的指定目录的子目录中读取了。如果可以解决这个问题,那么就可以比较容易地解决许多第三方框架对配制文件地需求,重新把读取部分重新加载一下,类似于struts for GAE的架构就比较容易实现了。
但是现在Java for GAE的前端设计,给项目开发的余量很小。尤其是针对业务逻辑的开发模式,Module部分的支持不够强。同样,虽然JSP还是一个最广泛使用的动态页面模式,但是也是因为配制文件的问题,导致利用其他可以模板进行开发的难度就比较大了……
所以综上所述,GAE的架构更接近于开发一个Service而不是一个Application。至少它的Java体系太独立,与其他第三方的开发包不能很好的相匹配。作为一个开发语言,Java最大的长处是在于可以利用大量的第三方Package,才使得它的开发速度能够变得更快,但是GAE的设计,则没有考虑到这方面的因素,导致大家像写C语言一样,在只有一些基础类的前提下,来逐步开发应用。这个事情让人就很头疼了。所以也难怪,GAE在推出这段事件内,并没有引起大家使用的热潮,还是处于半试验的阶段。
但是,从另外一个角度。我们可以看到,一个从架构、自动分发角度触发的Java Web Server是怎么看待开发环境的。也从中学到了很多思路,比如说:通过配制文件来实现crontab,可能是一个很好的分布式算法的基础,而GAE禁止了Thread的相关操作,也说明,为了保证服务器的性能可以评估和监控。所以把任何可能长时间执行的Thread变成一个定期执行的脚本,这一点上,更接近分布式系统的思路——过度一类一个线程,只有开始没有结束地让它运行,并不是一个让Google喜欢的运行模式。
看完Google App Engine的说明之后,我比较赞同它后端的设计理念,虽然有些类似于count的瑕疵。而对于前端的灵活性方面,GAE做得明显不够。想做成一个真正好用的分布式平台,GAE还有很长的路要走啊。
PS: 今天又重新翻了一遍GAE的说明,发现在部署(Deploy)部分,对数据存储的索引有一个单独的步骤,就像处理定期事件一样。所以索引的建立,是通过命令行触发的,GAE引擎通过上传的配制文件,确定索引表的建立方式。
Google App Engine 的 Java 版本出来已经有一个月了。之前一直没有机会深入的看下去,只是申请了一个帐号。今天抽空,把GAE的架构设计,整个看了一遍,觉得要完全适应GAE的开发模式,或者把复杂应用迁移到GAE上的成本还是不小的。但是作为一个很有想法的架构设计,有许多值得参考的地方。
在Java for GAE中介绍最详细的,也最重要的涉及部分,就是对于数据库的操作。Java for GAE使用的是JDO的标准,对数据库进行操作。可以从这个项目隐约看到的是,后台一个强大的底层数据库支持。因为是基于POJO封装的,所以基本上不支持利用数据做关联查询(注:在JPA的说明中,明确提到了不支持Join。也不支持Group by, Having, sum ,avg, max, min 这些常见的语言),或者更加复杂的存储过程、触发器等操作。正明确说明了Google对于DataStore的态度——数据库就是存储为最终目标,而所有的计算都应该让Java来实现。Java for GAE仅仅对于自增量的ID索引,提供了一个简单的解决方案:
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
而在JDO的定义中,项目之间的关联,也被清楚地设置成为 立即加载的1对1,立即加载的1对多,非立即加载的1对1,非立即加载的1对多,非包含关系的1对1,非包含关系的1对多。让跨表的查询和关联查询,尽可能地在Java的语言层面有一个解决方案,而不是利用数据库的模式来解决。
以这种模式来推断,我们其实可以把GAE后端的数据库引擎看做是独立的若干个数据库表+索引。索引本身只是通过配制文件,让查询更加有效。但并不作为搜索关键字的依据。把索引作为一个独立的配制文件列出来,是一个聪明的做法。而避免了类似于Hibernate一样的配制文件,来约定数据库表的结构。但是有一个比较神奇的地方,是让人想不明白的。
那就是,GAE的后端数据库是怎么维护数据存储的呢?如果我在第一个版本上传了一些POJO的封装,而下一次我更改了这些POJO的规则,那原来的旧数据会被如何处置?这是一个需要尝试的问题。看到GAE的设计指标里面,只对一个数据库表的条目有1M的限制,而不限制表的总长度和表的数量。凭借这个依据,也许可以猜测到GAE对数据的存储是基于完全hash的。顶多,会根据POJO多定义一个读取数据表的规范。
这个规范让我想起了ROR的动态语言对数据库封装的设计思路。也许就是这样的,对于不存在的数值或者多出来的数值,GAE自有它的一套机制来给出缺省值。这保证对于任何的一个POJO,只要原始的存储中存在这个 hash( 表名 + 主键 ) 的实例,就能读出来。而索引的建立,到底是降序还是升序,那些字段增加索引,则是通过配制文件,建立另外一个 hash(表名 + 字段名 ) 来实现的。这种模式,就是典型的搜索引擎的逆向表的设计方法,对于GOOGLE来说,简直就是小菜一碟了。
对于数据库的描述。JDO可以说是一种最清爽的模式,而配合了外部的一个PersistenceManager的封装。并且给PersistenceManager增加了Transaction的功能,这也是一个Java的实现策略,而不是数据库的实现方案。
综合上面这些对于DB的限制,我们基本上可以看成,GAE后端的DataStore,真的只是一个数据仓库,唯一比Mencached强大的在于,它总算还是提供了一个排序和筛选的功能,支持Range,支持 >=, <= ,也支持 order by。这对数据库来说已经够了。在合理地筛选出来必要地数据之后,深度计算地工作。应该交给Java来做。
当然这么做也是有代价的。如果要统计已经有了多少条记录,原来的sql语言,只要count一下就可以了。而对于GAE的操作,也许需要把整个存储空间都翻一遍才可以。而为了避免这种翻一遍的事情发生,就需要在改动数据的时候,建立一个常数表。这么在Java对数据操作上,操作就麻烦了许多。