The Perfect Is the Enemy of the Good

The perfect is the enemy of the good. The best is the enemy of the good. – Voltaire

Nothing is perfect and waiting for the perfect moment or killing yourself trying to ensure that every thing your hand touches is done perfectly is a sure way to not get anything done at all.

Getting caught up in the idea that your desk, work bench, house, or office must be in perfect shape for you to really get stuff done can just as easily result in getting nothing done. Learn to recognize what’s good enough.

Perfectionism kills me.

Refactory in Python: 使用受控类型而不是Hash和tuple

《Clean Code》中提到了函数传递的参数不应该超过3个,如果超过三个推荐将它们变为符合数据结构。
在Python的应用中,对于这个场景,我看到一般的做法就是使用Hash。其实Hash就是一种Key-Value store,是一种弱类型的结构,好比一个没有shema的object。这样做起初看来是很舒服的,因为它自然的让你可以访问到一个复合数据结构。可是据我观察这一般都是Bad smell。缺点在于:

  • 你不知道这个Hash中有哪些key,经常会造成需要翻看很多代码才能知道key有哪些,从哪里来的。
  • 由于Hash是弱数据类型,你很有可能把Key写错,如有的地方用了”User”有的地方是”user”,就有可能发生由于误解造成的bug。
  • 因为Hash是一个开放数据结构,所以你无法控制它被get和set,这容易造成你的hash在多次传递过程中被意外的覆盖,这是非常危险的一种bug。
  • 如果使用了Hash,随着时间的推移它很有可能成为垃圾桶。就是一个全局的Hash被传递很多层,大家都依赖它并向里面插入自己的数据。由于这样的Hash根本不可能知道自己的数据属于哪些领域模型,所以它可能会承载多个领域模型的部分数据结构。这对复杂度来说是一个灾难,由于数据和行为分离,它会鼓励系统模块间函数的拷贝和粘贴,最后造成一团存在大量重复的乱麻。如果你的代码发展到这个地步,那它基本上是维护和重构的地域。
  • python中hash的访问方式不好看,你需要hash[“user”]这样去访问。:D

对于以数据为中心的系统,你看到一个Hash被传递于超过一次函数调用,那么你最好对它马上进行重购。将它处理为一个可控的数据类型(如Class和Namedtuple)。
非受控类型还有另外一种表现形式,那就是tuple。tuple让python变得强大,尤其是它被用在平行赋值的情况下,如:

def fucntion_a():
    a, b = 10, 20
    return a, b

def function_b():
    price, amount = function_a()

这种情况下它有很不错的表现力。但是在非平行赋值的情况下使用tuple传递数据结构就是一种Bad smell了。如:

def function_a():
     my_tuple = ('tin', 'male', 28)
     return my_tuple

def function_b():
     a_tuple = function_a()
     name = a_tuple[0]
     age = a_tuple[2]
     .....

这种情况的邪恶是使用了顺序来约定数据结构,它比起hash来说明显的问题就是僵化、不容易阅读。僵化是说当你发现需要传递更多数据的时候你需要在顺序中添加新的元素,此时如果你像插入在前面几个元素之间,你会面临大量的index修改操作,非常容易造成bug。不容易阅读是,如果不在同一个文件中,你怎么知道0, 1, 2分别是哪个属性的index,为此你肯定花大量力气写注释,而且这个注释需要随你的修改而修改,非常恼人,遗漏了就是bug。所以它们那是明显的bad smell。
上面两种情况属于同样一种情况,那就是使用非受控数据结构表示结构化数据。那么如何“使用受控类型而不是Hash和tuple”呢?一般来说很简单。一种是写一个数据结构的Class,这种情况是你发现这里的数据结构是潜在的领域模型的时候非常有用:

class BusinessLogData:
    date = datetime.now()
    username = 'Unknow user'
    business_type = ''
    .....

好处是当你发现系统中围绕这个数据结构的算法或者说行为的时候你马上就有一个地方存放这些逻辑了,会让你很舒服。而且逐渐的你的领域模型就会清晰了,这对没有使用领域模型驱动的系统进行重构的时候很有用。另外一种情况,你可能知道没有什么逻辑在数据结构上,它就是给算法访问的纯数据type。那么可以使用namedtuple。它实际上是一种元编程。官方的例子是这样的。

Point = namedtuple('Point', 'x y', verbose=True)
p1 = Point(11, y=22)
p2 = Point._make((11, 22))

我个人认为namedtuple非常方便,很象ruby中的struct。它对于已经使用tuple传递数据的系统的重构非常有效,因为_make这样使用tuple创建namedtuple实例的方法非常适合重构,可以马上消除0, 1, 2这样的index magic number。而且在使用sql的时候它也是非常有用的工具,官方例子:

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print emp.name, emp.title

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print emp.name, emp.title

OK,到这里这个重构实践就阐述完毕了。下面我会继续讨论Refactory in Python这个话题。

Talk with Douglas Corkford

我问他最近在研究什么,他说他最近在研究安全。我问他安全是指哪方面的安全,他说主要是跨站攻击的相关标准。他说网站的安全主要是HTML标准的落后造成的,所以这里非常混乱,总有各种棘手的跨站攻击问题。要想解决跨站攻击的问题,一定要有标准来规范跨domain的通讯,来保证其安全。

关于Lucas Film,他说那段时间非常棒!他负责技术的研究,他举例说CD啦、DVD啦还有各种他们特效相关的一些技术。
我问了他为什么的新版本为什么没有人推广,反观HTML就有很多人在推广。
关于Html,Corkford说这里根本就没有一个标准,已经很久都没有一个标准发布了。他说HTML 5只是一个proposal,它不是一个标准。我问他真正在推广HTML 5的大公司有哪些呢,他说只有Google在真正的推广它。

我问他对服务器端使用Javascript怎么样?他说这是Great的,而且能看出他对此非常高兴。我问他是否在使用Node.js,他说Yahoo已经在尝试使用Node.js,其中包括用它来帮助测试YUI3。我问他现在Node.js的api变化似乎还比较大,他说是这样的,因为它正在被活跃的开发中,他说非常期待他尽快成熟并被更加广泛的使用。

我问他对CSS3现状的看法。他说现在CSS也是很久没有一个标准了,而且先前的CSS标准设计的非常不好,没有解决Web开发者遇到的问题,给他们带来了很多的痛苦。我问他对CSS3的看法,他说现在的路线走的不对,它没有很好的去解决关键问题。他认为CSS现在需要解决关键的问题是对于不同的显示设备的排版的支持。他说现在大的显示器,还有更细密的显示器,还有小的显示设备,他们对复杂排版的支持的特性的考虑都太差了。所以我们就无法用css实现让你的排版/布局在各种设备上看起来都是”Great”。
我问他对于这些不同设计的显示设备的布局是不是有两个瓶颈,一个是设计师本身的瓶颈,另外一个是css特性的瓶颈。他说不是的,他说设计师是没有瓶颈的,问题都处在css标准对这些多列的布局的描述太欠缺了。我问他从Ux的角度看人类的阅读不能很宽,但是似乎CSS3已经开始想要解决这个问题了。他说现在的解决方案还很不够,因为它们都没有从阅读和设计者的角度去考虑排版,所以它就无法让你的Web页面在手机上看起来是单列布局,而到了巨大的显示器上的时候可以像报纸一样使用阅读舒适的多列布局。他认为是这个问题限制了设计师的创造力,他认为在合理的css特性下,设计师可以完成很完美的自适应布局设计。

我问他对于Jim Webber所说的Web as platform的看法,他说Web是一个非常棒的东西,但是Web标准是非常烂的。因为现在大家越来越认识到Web的强大好用的时候,标准已经成了万恶之渊(这个词是我杜撰的),所以现在大家要花更大的力量在Web标准上。他说现在Web标准的一个很大问题是模块化不够好,或者说切分的不够细。造成超级多的特性被堆积在一个标准里面,这样这个标准就一直无法发布,并且也会越来越难用。他认为应该按照我们的使用场合和特性将Web标准切分开,帮助每一个部分可以关注一个点,这样的Web标准发布的就会频繁很多。解决我们现在面临的大量问题。

我问了他如何做Javascript的测试,他说的确很烦人,说Javascript的一个麻烦的问题就是无法在服务器端测试。我问他Yahoo是否也就是使用Selenium这样的客户端测试工具,他说实际上他们也是使用这样的工具。他说这里的问题还是在于标准,因为你做客户端测试实际上不是在测试你的代码,而是在测试浏览器。他说因为浏览器对标准实现各异,而且他们还有自己的bug,造成你实际上是在这些浏览器写测试。他说如果标准能够更好,这里就会减少痛苦。

我问他你认为在View这一层是否应该分开给人看的View和给计算机读的View,这里是否有一种中间的View能够结合它们呢?他说这不就是Json么?我问他Json对于人类来说易读么?他反问我他不是已经比XML容易读了很多么?他说Json已经是一种非常接近于人类自然的描述数据的方式了。(而Html还是倾向于为人类的阅读而设计的数据结构,当然他是面向浏览器的。)

他说今晚他要讲的话题就是关于我们谈的这些问题的,关于标准,关于Web。

Qcon Beijing 2010笔记:失败来临的征兆

Aiming for the wrong target

Assumption $1
Users care about the things the do-features-not the software or hardware you run
Assumption #2: Faults and errors will occur.
Your can choose to engineer safe failure modes into your system or to accept whatever random failure modes naturally occur

Engineering Failure Modes
Tolerance : Absorb shocks . but do not transmit them
Severability: Limit functionality instead of crashing completely
Recoverablility: Allow component-level restarts instead of rebooting the world
Resilience: Recover from transient effects automatically
These produce consistent availability of reatures

工程化失败模式
容忍:将震荡吸收,而不是传递它
服务能力:功能缩水而不是整个损坏
恢复能力:允许组件重启,而不是让整个世界“重新启动”
弹性:能够从瞬时性(Transient)的影响中恢复
这样可以保持功能的可用性

Stability Antipatterns

1. Intergration Poinnts
Intergrations are the #1 risk to stability
Your first job is to protect against integration points
Every socket process. Pip or remote procedure call can and will eventlually kill your system
Even database calls can hang. in obvious and not-so-obvious ways

“In Spec” vs. “Out of Spec”
“In Spec” failures
TCP connection refused
HTTP response code 500
Error message in XML response

Out of spec failures
TCP connection

Remember this

Large systems fail faster than small ones

2. Chain Reaction:
Cascading Failure: Failure in one system causes calling systems to be jeopardized

Remember this
Prevent Cascading Failure to stop cracks from jumping to the gap

3. Users: Can’t live with them…
First type of “bad” user
Front-page viewer: creates useless sessions, ties up memory for no reason
Application servers are all fragile to sessions: Users can ….

Handle traffic surges gracefully: Turn off expensive features when the system is busy. Divert of throttle users. Preserve a good experience for some when you can’t server all. Reduce the burden of serving each user. Be especially …

Second type of “bad” user
Buyers: (most expensive type of user to service, secure pages requires more cpu, more pages, external integration), High conversion rate is bad for the systems!. Your sponsors may not agree

Blocked Threads: Request handling threads are precious. Protect them.
Most common for of “crash”: all request threads blocked. Very difficult to test for:. Best bet: keep threads isolated. Use well-tested. High-lvel contracts for cross-thread communication

Attacks of Self-Denail: Good marketing can kill your system at any time

Defending the ramparts: avoid deep links, setup static landing pages, only allow the user’s second click to reach application servers. Allow throtting of …

Remember this
Keep lines of communication open , protect shared resources, expect ..

Scaling Effects
*QA and Dev balance?

Unbalanced Capacities
Traffic floods sometimes start inside the data center walls.

SLA Inversion: Surviving by luck alone.

Unbounded Result Sets: Limited resources, unlimited data volumns
记住:要使用显示的数据容量测试

解决了我的Tunnelblick连接再断开openvpn服务后路由出错

每次用Tunnelblick连接我的zztin.com主机后(我的是Mac OSX 10.6)再断开后,我的zztin.com的主机就无法到达了。ping的时候会报告:

ping: sendto: No route to host

这是路由错误的表现,用netstat -nr查看当前的路由设置,发现连接OpenVPN时候推送的route信息没有被清除。我手动试验了一下重建route表:

sudo route flush

然后所有网都连不上了,又netstat -nr一下,发现默认路由没有了,手动添加一下(我家的无线路由器IP是192.168.1.1:

sudo route add 0.0.0.0 192.168.1.1

所有网站都可以用了,包括ssh我的zztin.com。可是不能每次都手动清理呀。查看了一下log,发现的确有问题,有好几行route -delete的时候报错:

ERROR: OS X route delete command failed: external program exited with error status: 77

搜索了一下,发现需要注释掉我的openvpn客户端配置里面的:

# user nobody
# group nobody

然后一切都OK了。

Android and iPhone/iPod touch

配合O’reilly老爷爷的一些想法,我也想想我共鸣的想法:

  • iPhone/iPod touch的界面让你感觉非常自然(人性化),几乎不会给你什么惊讶,学习成本比较小。但是gPhone上面的不少东西都需要你自己的捉摸才能搞定,当然,搞定以后就轻松多了。但是iP系列的确更平滑。
  • gPhone的滚球这个东西,也好也不好。因为很多任务你可以通过拖拽屏幕和触摸实现,你也可以通过滚球和点击滚球实现。所以,由于有两条路,你总会问我应该走哪一条呢?走这两条完成这个任务有什么区别呢?这件事让我很苦恼。估计大部分的gPhone开发者在设计自己的app的时候也会问这个问题吧?
  • gPhone上面联系人与Google联系人,日历与Google Calendar的集成绝对是杀手应用。对于一个喜欢google服务,并且已经将这两个服务在客户端(Address/iCal或者Thunderbird)管理的井井有条的朋友,拿到gPhone以后几乎就是无缝迁移了。非常轻松。配合无线,它简直比通过iTunes同步这些数据要高明多了。这就是云服务的力量。当然那些mac下使用mobileme的朋友使用iP系列也是有同样的感觉。但是mobileme的质量和服务水平都差Google services很远。云服务在无限网络下,才是真正的云服务。
  • 但是在音乐和podcast管理上,gPhone让用户感觉还是差了很多。iTunes对于音乐这种个人收藏来说可能是最佳的管理方式,因为一个好得客户端能够让这些大数据量的同步变得轻松和快乐。而使用了gPhone以后我就在犹豫,我是否应该在手机上听音乐呢?但是如果你有的是iPhone,那么它本来就是一个增强了的iPod,配合iTunes管理好你的音乐,生活就真的自由而快乐了。我希望google能够想办法做一个sunbird的插件,sunbird可以读iTunes的数据,这样我就可以依然使用iTunes,但是通过sunbird享受这种便捷了。
  • gPhone上面访问picasa的功能还没有很好的整合,而Youtube也完全没有利用好,没有提供便捷的上传服务。
  • gPhone上的大部分软件都不不够好,在用户界面设计方面还差iPhone竞争激烈的App store里面的顶级应用很远。这也许因为app sotre启航很早,不过gPhone要走的路可就长了去了。比如Twitter客户端,tweetie/twiterrific/tweetdeck在iPhone上几乎是雄霸,而且都很好用。而Twidroid明显还不够好用……
  • Android的Market不好用,因为管理需要在手机上面完成,很不方便。对比iTunes已经集成了管理、升级、删除applications的功能,相比好用了不知多少倍。
  • Android上的游戏简直就是悲剧。因为没有一个让人眼前一亮的东西。相比之下iPhone平台上让人欲罢不能的游戏简直太多了。可是这里有个转机,就是iPod这个中间产品的出现。似乎拥有gPhone后再买个iPod touch能够更好的解决娱乐的问题,而且电力问题也得到了一定程度上的解决。因为商务部分用电话,娱乐部分用iPod touch,不会因为娱乐耽误了商务问题。

这只是第一部分,时间不够了,待续……

数据导入的过程也应该是一个“事务Transaction”

上上周导入数据,我们约定了数据格式,写好了导入脚本,进行了充分的测试。但是当天给我们的数据结构却发生了巨大的变化,但是给我们的更新window就是当天,所以我们只能再写程序将格式转化为我们先前约定的格式。我和 @nasiless 同学结对做这件事。经过3、4个小时的努力,转换没问题了,将中间数据转化的操作演练了一下,没啥问题。当准备好停机升级,又从数据提供方得知其中一部分数据是错误的,然后又给我我们一份补丁文件(名-值对,需要覆盖现有值)。我们由于担心重新生成数据非常费时间,所以分析一下补丁对我们操作的影响。@nasiless 同学和我确认应该只影响其中一个中间数据文件,然后写脚本修正了一下。最后我们“成功”导入数据恢复服务了,当时很庆幸居然成功了(那个时候已经是晚上11点了)。当然其中有一部分导入失败的数据(9xx条)我们输出了一份文件准备后面手工输入。

一周后来(期间系统又进来很多新数据),我们发现导入的数据中失败的那部分可能是由于补丁文件也需要应用在另一部分的中间文件上造成的。可是当我们想反推这个过程并重现它的时候,我们发现我们的临时转换脚本(就是把那天修改的数据文件向中间文件转换的程序)居然放在了我的/tmp目录下,而其间我的mac重启过,所以这些脚本已经不见了。剩下的只有那个导入失败的log和映射补丁文件,我们经过推演问题已经变得非常复杂了。几个错误因素结合在一起,数据再回复的确是个非常费脑子的工作。还好经过反复排查,这些结果都是可逆的,不过其中人工操作众多,非常费事。我们也只能硬着头皮做了。因为这个系统还涉及到钱的问题,钱又涉及分帐问题,所以反推非常麻烦。

我们的结果还算好的,因为有方法反退效果。可是最大的问题在于这个过程本身应该是“事务”,必须全部完成或者全部恢复,当时我们的做法没有遵循这个基本的原则。而且我们的导入程序中复用了系统逻辑代码,但是忘记修改事务边界,没有将多个事务join起来,所以造成了脏数据的出现。这个也是后来折腾我们的一个主要原因。

所以教训就是:数据导入操作本身就应该使用事务,确定好所有的事务边界。而且数据导入的流程也应该是一个事务,不应该允许可能出现脏数据的请款存在,因为这种问题往往是追悔莫及的,也就是safe steps的极致。

“刷机惊魂险变砖”始末

周六才到手的G1险些在今天变砖,历程是这样的。内容不专业,不是帮您刷机的,只是告诉您怎样刷坏的。

中午吃饭下楼正巧碰到Andriod牛人“小新(quakelee@twitter)”,吃饭间请他一起研究我新买的G1。小新本人用的也是G1,旁边几位同事也不少G1,刷机大都是由小新帮忙。而小新也欣然接受帮我刷机。

吃饭归来就去我们的“不拆不舒服司机”和“不焊不舒服司机”的小魔屋(SA办公室)刷机。小新看了下我的基本情况,是TIM的西班牙版本机(或者是意大利版),当时的主Rom是hiapk的2.2版本,里面有SPL能够启动Fastboot,副rom不明。

  1. 小新首先察看了一下机器的版本,发现root权限已经有了(俗称“采权”完毕)。因为已经刷了非官方的hipak 2.2 rom所以小新启动检查了刷机的SPL认为这个机器应该比较容易刷新rom。小新首先尝试了刷新SPL到工程版本,后来小新发现这个机器的SPL也能进入3个绿机器人滑滑板的界面,所以小新说这个已经是工程SPL了,可以直接刷新的副Rom(Recovery)到自定义版本的Recovery,这样就可以用它刷主Rom了。
  2. 小新启动了ubuntu,然后让G1进入SPL,连上Fastboot,发现连接一切正常。然后小新就格式化了Recovery分区(fastboot erase recovery),然后小新使用fastboot更新那个自定义recovery,但是出错了,报告signed verify failed,签名错误。小新大呼可能要瞎!他和我解释他没有备份我的recovery,现在无法刷recovery就只有主rom了,而这种情况下面的所有刷机都回困难重重。而且刷不进去自定义rom很有可能是SPL有问题,但是没有了recovery分区就很难刷SPL……
  3. 小新向蛋总求救,听说蛋总身在米国,半夜帮忙,实在感谢。小新咨询了一下当时的情况,发现情况可能比想像中要遭。但是蛋总的意思是这个手机没啥特殊,应该肯定能刷好。小新还去“机锋”和“安卓”论坛寻找有用线索,无果。他尝试了几个不同版本的自定义recovery,都是报告签名错误,包括蛋总推荐的RaMon也不可以。此时气氛凝重,小新告诉我下面每件尝试都是高风险,随时可能变砖。我心想管理员做事谨慎,所以应该不会有问题,充分相信小新。
  4. 死马当活马医,小新发现居然Fastboot现在工作还正常,也能用adb练到手机里面。他与蛋总切磋了一下,蛋总推荐降级,说可以通过fastboot boot recovery.img的方式重启并刷入rom。小新尝试了一下,惊喜的发现居然可以通过这种方法引导进入自定义recovery,当时使用的是RaMon 1.5.2的recovery rom。这个露出了一丝曙光。
  5. 然后小新仔细梳理了一下刷机流程,并对比了他自己的G1,发现问题出在我的baseband和SPL。首先我的baseband是老版本,所以一开始刷入工程版SPL的操作失败了。而后进入的SPL虽然有三个绿色机器人滑滑板界面,但是它是一个新版本的非工程版(或者说官方版本,检测签名的版本)的SPL。它虽然看起来和工程版SPL一样,但是完全不能用来刷自定义rom。
  6. 小新说唯一的出路就是重刷SPL。但是要先升级baseband。其实到了这个地步,我的主rom(hiapk 2.2)还是可以启动的,只是如果不做后面操作一个是以后主rom坏了就再也无法recovery了,再有就是SPL也就无法升级了。所以小新推荐我继续刷机,不过他警告我操作风险很大,我说继续。
  7. 用fastboot boot recovery.img进入自定义recovery,然后刷新了baseband,一开始重启不了了,我们以为要砖。小新想起这个需要重启进入recovery另外一次,所以又fastboot boot了一次recovery,重启就又可以进入主rom系统。也就是说此时机器还是可用,而且离成功进了一步。
  8. 下面要刷SPL,风险很大,小新特意去网上找了一个和它G1一样的版本并检查了md5sum。然后继续fastboot bott recovery.img重启,刷工程SPL很快,小新问了下蛋总这样做没啥风险(用fastboot boot img的方式进入临时recovery刷SPL的这个行为)?蛋总说没有问题。小新重启机器。此时舜佳鹏一两位团队成员跑过来围观,听说现在状况很危急纷纷表示我的机器不会这么容易变“砖”的,但是也幸灾乐祸的表示如果”真得变砖“也不要过度悲伤,然后两人协同超哥去给我买了一瓶美年达。这美年达喝在嘴里那叫一个酸呀,真要砖了那可太心酸了。
  9. 此时心都跳到嗓子眼了。重启后小新用adb试着连,能连上,可以看到引导了。因为这个过程需要再进入recovery两次,所以小新fastboot boot recovery了一次。但是……这次重启后,我俩彻底崩溃了,机器无法引导,adb连上后报错,无法建立连接。所以就不能再次fastboot boot recovery了,那么就瞎了,也就是说砖了。这次小新用低沉的声音和我说:“完了,这次是真砖了……”
  10. 此时屋里鸦雀无声,大家都被“砖了”这个词震惊了,大家纷纷围观过来……我心情无比沉重,小新明显也是,一直和我说对不起。可是我知道这个完全是我造成的,托小新那是找人帮忙,哪有人家帮我的不是。我心想不能给小新压力,故作震惊,说没关系,机器先放在你这里,看看还有啥补救措施啥的,然后我就出去了。
  11. 回到作为先是浑身发冷,然后浑身发热,然后浑身无力。赶紧和老婆用gtalk报告噩耗,还要老婆外出看不到。但是晚上老婆要过来找我看电影,电话不能用了她一定很着急。而且这不是最麻烦的,这是老婆好心怕我手机太破才给我批款子买的,到手里两天,用了还没超过3个小时就变成高科技“板砖”,这是何等可怕的“悲剧”呀,心情一下子十分黯淡。我故作镇静的开始看手头的程序,可是哪有心情呀,幸好pair不在,否则魂不守舍的我肯定会让pair很郁闷。
  12. 恍惚了有半小时还是一个小时?我求助了twitter,有热心朋友帮RT,但是显然也没啥帮助信息出现。心灰意冷呀。此时小新从远处摆出“囧”字脸走向我,和我说:“真的是砖了,你明天拿到村里找奸商看看能否加钱换一个吧。我拿到机器就要拆后盖,其实当时有点恍惚,就像宠物走了想要再检查一遍它的身体一样……超哥和小新阻止了我,并说你先看看机器呀。我一看,发现屏幕居然亮着,系统已经启动了!赛,当时真是喜出望外!

尾声。小新告诉我原来是大胖同学解救了我俩。这个机器按着照相快门键启动就可以引导入SPL,然后就可以刷机,刷机后就好了!所以是大胖救了我们。原因是小新刷的机器都是按return和开机进入SPL,但是大胖的机器按快门和开机进入。所以按照大胖的习惯我的机器就开开了。后来测试发现,我的机器只支持快门+开机进入SPL,而小新的机器只支持return+开机进入SPL,而大胖的机器两个快捷键都可以。所以世界还真是无奇不有。

老婆到达的时候我的G1已经又工作正常了,不过心灵真的受到了打击。一个到手3小时的新G1,居然马上就砖了,本来为了省钱买它,如果再入手一个那还真要用上一个iPhone 3G的价格了,吓人呀。不过还好,修好了,这1850没有打水漂。一个教训就是,下次做这样心跳的事情要多做功课,每一步想好撤退方案再行动,所有危险动作前要double check前置条件是否达到,否则,那还真是一步一步走向“变砖”,连头你都没法回了。

感谢帮助刷机3个半小时的小新,感谢帮助G1起死回生的大胖,感谢资深技术支持蛋总。感谢团队的围观群众舜佳、彭一、远超,还感谢老婆没有责怪我。

实际实验了一下手机,感觉可以暂时放弃iPhone 3Gs了

圣诞夜和老婆去逛三里屯,着重逛了一下顺电。体验一下手机。

一直犹豫是否应该选择iPhone 3G或者iPhone 3Gs,其实大部分的YY都是在我的iPod touch上完成的,所以我非常希望这个用户体验流畅的开放平台。几天前实验一位同事的3Gs的时候还觉得它是我的终极选择。可是今天在顺电又实际体验了一下发现它与iPod touch的差异部分,也就是电话部分并不好用。比如短信界面乍看来不错,可是中文比较短,所以在精美的气泡布局上面显得很奇怪,不好看。与Android手机或者任何同价位的手机比起来,iPhone的屏幕也不显得精细了。而通讯录,不好不坏,与Android上面的通讯录无法来开档次。从价格上面来说,我觉得有点贵了,它已经比同样硬件平台的手机贵接近一半了。所以我准备暂时打消iPhone的期盼,期待联通带wifi版的补贴iPhone出现了。

接下来实验了一下G3,比较认真的体验了短信及输入法的体验。感觉软键盘对于这样一个手机还是不舒服,失去了很多输入的快感。相比之下今天白天实验超哥的G1,里面的硬键盘配合触摸屏选择文字很舒服。而Google maps和Gtalk也是非常的亲切,它们在无限通讯上会给我很大的安慰。我想实时网络应用,如Twitter和Gtalk估计是我现在对于G1/G2/G3最大的期待了。G1/G3的屏幕我非常喜欢,细腻明亮。键盘、屏幕、原生app与google的高度集成目前让G1成为我最希望入手的手机。

最后剩下黑莓(8820/8310),其实按理说它是和G1一样价位的手机,可是号称十四天机和打孔机的出现让它跌入1k价位,这个让我有点不放心。再说黑莓不是个开放平台,下午学虎也跟我说因此少了很多DIY的乐趣,它似乎更适合希望省心的偏商务的人士。而且黑莓的屏幕是横向的,体积比较小,看起来不是很舒服。而且黑莓的字体似乎是我非常不喜欢的“宋体”,我更喜欢平滑的“黑体”,这也是一个让我不爽的地方。

所以,我想,周末如果允许的话,我和老婆想去中关村现场实验一下黑莓和G1,然后结束这场犹豫的选择游戏。