作者:Lucida
原文链接: http://lucida.me/blog/on-mobile-developing-3/
所以我打算做一个『大用户量』的应用(见上文),那么从哪里下手呢?
我的想法很直接——只有解决用户的『根本』问题,才有可能得到大用户量。
说来也巧,这时我正好在 WP 论坛看到大量 WP 用户吐槽 WP 的通讯录反人类。考虑到手机通讯录是打电话和发短信的出口,而打电话和发短信又是每个手机用户不可或缺的日常任务(也就是前面提到的『根本』问题),我决定以通讯录作为入口,打造我的第一个『大用户量』应用。
考虑到很多童鞋都没有接触过 WP,所以这里有必要先介绍下 WP 的通讯录是如何反人类:
我们知道,通讯录一般是以姓/名做索引。但为了找到某个人我们并不需要输入他的全名,更快捷的方式是输入他的姓/名首字母(也就是 Initials),例如查找『张晓明』,理想的情况是输入『ZXM』进行匹配,而不是输入『ZHANGXIAOMING』或是『张晓明』。
然而 WP 只支持两种匹配——第一种是前面提到的颇为二逼的全称匹配;第二种则是简单粗暴的姓首字母匹配——『安』姓在『A』下,『章』姓在『Z』下,依次类推。WP 还用了一个颇为炫酷的控件( LongListSelector
)实现快速跳转:
姓首字母匹配看似快捷,但实际使用起来更加麻烦——因为中文姓氏并不是均匀分配的,常见姓氏集中在『L』(刘,陆,连,李),『W』(王,万,汪,闻),和『Z』(张,赵,章,郑,钟)这几个首字母下。以之前提到的『张晓明』为例,由于 WP 只支持定位到 Z 下,这意味着用户每次都需要在 Z 分类下的几十个甚至上百个联系人里面线性查找,以我自己的通讯录为例,每次我都需要滑动四五秒才能找到这个张姓少年。
这个操作不是一般的傻逼,加上当时不少 WP 用户有不少来自 NOKIA,他们用惯了 Symbian 下面的 T9 模糊匹配,更加无法忍受这种反人类的操作。以至于当时的 WP 论坛里要求微软更新通讯录程序的呼声一片高过一片。
考虑到 Symbian 和 T9 离我们已经很遥远,我在这里再简单介绍下 T9 联系人匹配:
还是以『张晓明』为例,在 T9 模糊匹配中,『ZXM』,『ZHANGXM』,『ZXMING』,『996』(不是 996 加班哈,在九宫格键盘中,『996』分别对应『ZXM』),以及『9426486』(对应『ZHANGXM』)都可以匹配『张晓明』。可以看出这种搜索方式的先进性——既不需要打出全称,也可以迅速的在大量联系人中匹配到需要的联系人。
你可能觉得 WP 的联系人匹配已经够二逼,但它和 WP 的短信群发相比则是小巫见大巫。为什么这么说呢?因为 WP 在 8.0 之前没有联系人多选。
这和 WP 的自带通讯录简直是天作之合——我在这里举个例子,我的手机里有 300 多个联系人,我需要给『刘明』,『李伟』,和『张明』三个人群发短信,我需要这么做:
更要命的是,不知道微软出于什么考虑,短信界面里的『添加联系人』按钮不是一般的小=以至于我每次都要点好几次才能『点中』(下图右上角的圆圈加号)。
也就是说,群发短信选择 3 个联系人,我需要点击屏幕近 30 下,滑动近 20 秒,而这在我原来的 NOKIA 直板手机上 3 秒之内就能搞定,能把触屏手机做的比键盘手机还难用,我怀疑微软的 UX 在哪里。
貌似吐槽 WP 太多了 –_–#,回到正题——『大用户量』应用。
应用的需求很明确——解决前面提到的 WP 中的两个二逼点:
对于需求 1,我可以照搬 Symbian 上的 T9 匹配;对于需求 2,我决定扩展 WP 自带的 ListView
即让其支持多选。
有了需求,接下来就是『紧张』但愉悦的开发工作:
ListView
; 第一版是这个样子:
联系人选择(注意支持多选):
拨打电话(请自动忽略我奇诡的审美 –_–#):
设置(提供了一些额外选项,例如精确搜索,短信前提示等等)
帮助:
以及软件Logo和作者信息:
在主流 WP 论坛上发布了拨号助手的『内测版』之后,我在第一天就收获了 300 余名用户,但到了第二天新用户就只有不到 100 名,我查看了论坛帖子之后发现我的帖子沉的很快,以至于很多论坛用户都没有察觉到我的应用的存在。
我希望自己的帖子被更多的人看到,但如果不停的在论坛里顶贴又显得太 low,于是我决定采用另一个看起来不那么 low 的『办法』——我把它称为左右互搏。
我是在 社交网络 学到的这个方法:电影中 Mark Zuckerberg 为了应对艺术鉴赏作业,他把待鉴赏的艺术图片发到 Facebook上,然后注册了两个账号发表对立且激进的评论,很快他就收到了他人的评论,然后他通过这些评论完成了作业。
参考 Zuckerberg 的套路,我在每个论坛上注册了五个账号,然后人为的为这些账号建立『性格』属性——小白型,喷子型,粉丝型,教学型,以及理智型。接下来的流程大致是这样:
这个过程就像是点火——刚开始需要一点点耐心,但后来激烈的争论燃起来了想停都停不住——所以我注册了一个理智型账号,适当的调整讨论的热度,以至于帖子不至于成为对骂贴或是群嘲贴。
于是,我的帖子成为当时 WP 论坛的超热门贴,在论坛首页停留了一个多月之久,而我的应用在正式上架之前用户量就突破 4000,两倍于我之前的预期。
但不要以为我的应用是靠前面的『左右互搏』得到的用户——『左右互搏』只能把帖子提到首页,但真想要用户买账还是得拿出让用户满意的东西。
一句话:把用户搞 High,你的用户量就会 High。
编写移动应用,我当时奉行的是 行进中开火 (参考 Joel Spolsky 的 Fire and Motion 一文)原则,一边修 Bug,一边加功能,一边做文案,三线齐进。
为了收集用户的需求,我一边搞了一个 QQ 群,一边搞了一个邮件列表,每天把需求收集到一起,然后综合需求的强烈程度和实现的难度,选择需求添加到下一个版本中。
用户需要加键盘音,从市场上找到一个带声音的应用,反编译出声音文件,然后三行代码搞定。
用户想要号码所在地,于是从 CSDN 拿到一个还算新的手机号码所在地数据库,存到 SQLite 然后每次导入联系人时算一遍所在地,搞定。
但之后很快就有用户反映导入联系人太慢,我检查了下发现 SQLite 在 WP 上效率很差,以至于算 300 个号码的所在地就需要 15 秒左右。于是我去掉了 SQLite,把号码所在地数据库整理成内存中的三层哈希表,从而可以在 0.1 秒内搞定 1000 个号码所在地,搞定。
一些用户使用 IP 拨号:所以需要使用前缀号码,几行代码搞定。
一些用户希望使用浅色背景:上 MSDN 上扒了一段示例代码,搞定。
不少用户希望能有短信模板:用 Python 写了一个小爬虫爬了几千条带分类的节日短信,搞定。
一些 NOKIA 老用户习惯一键拨号,即长按某个数字键拨打绑定的电话,于是加了一段 UI 和逻辑,搞定。
我把应用分为两个版本,『内测版』(即论坛的 xap 版)和『市场版』(即微软的官方市场版本),其中:
在这样『合理』但『极速』的更新频率下,到了第三周,我的应用用户量突破了一万;并进入了 WP 工具应用前五名。
一人,三周,从零到一万。
况且还是小众的 WP。
编写应用时我碰到各种各样的 Bug,其中大多数源自把 T9 『移植』到 WP 上:一方面是多音字(比如说『曾』应该是『ZENG』而非『CENG』),另一方面是做字符串模糊匹配时出现的各种奇怪问题。
所以刚开始做『内测』时,每天都有几十个用户反映应用出错或崩溃,这时我会问他们要他们是在操作哪个联系人时出的问题,然后一个联系人一个联系人的修复。
但应用正式上线后这种方式就行不通了——我既没有用户的联系方式,即便有,也不太可能问他要一份完整的通讯录过来——为了便于改善应用质量,我在应用里面加了一段代码,用于上传资料(包括用户的所有联系人信息)和异常信息,这样我就可以快速便捷的重现/定位问题。
我当时还没意识到这样做有什么问题,直到之后和朋友聊天提到这件事,他惊讶的来了一句: 『那你岂不是掌握了几乎所有 WP 用户的联系人信息?』
这时我才反应过来,我可能拿到了一些我不该碰的数据——回到宿舍,我把后台的数据下载到本机,cat grep 了下,我意识到我手上有二百多万人的联系信息。而且这二百万人并不仅仅是一个号码列表(list),而是一个信息量很大的图(graph)——打个比方,通过这些数据,我可以得知:
这里就不一一列举,你可以想象下如果这些资料落在经验丰富的骗子手里会发生什么事情。
出于对犯罪的恐惧(我可不想像某『疯狂的程序员』那般疯狂到监狱里 –_–#),我在接下来的版本删除了上传资料的那段代码,并清除了用户的数据。
但从此之后,我开始担心移动应用带来的安全隐患——如果像我这样普通的个人开发者都可以通过编写应用获取上百万用户的个人信息,那国内那些没有节操的大公司会怎么做呢?
这也是我反感/鄙视 Android 的原因——无论什么应用,小到阅读器,大到社交应用,每个应用都恨不得把所有权限(这自然也包括联网,读取短信,和读取联系人信息)搞到手。
装个官方微博要读联系人和短信
装个官方多看阅读也要读联系人和短信
装个第三方壁纸尼玛还是要读联系人和短信
去尼玛的 Android。只恨当年乔教主剿匪不力,留下 Android 这个祸胎。
I will spend my last dying breath if I need to, and I will spend every penny of Apple’s $40 billion in the bank, to right this wrong. I’m going to destroy Android, because it’s a stolen product. I’m willing to go thermonuclear war on this.
Steve Jobs
尽管拥有一万多个用户让我感到很有成就感,但频繁的更新和没日没夜(每天都要写到三四点)的写代码让我疲惫不堪,寒假过后,在完成了 1.7 版之后,我决定停下这个应用,回微软继续实习。
说来也巧,当时微软正好要招几个开发 WP 的实习生,所以我很轻松就进去了。
然而实习了一段时间之后,我又开始手痒了,这次我打算做一个大幅更新,解决之前所有的问题,也就是 2.0 版。
前面提到中文存在多音字问题,我在应用的第一版并没有去解决这个问题,而是手动的标注多音汉字。
在 2.0 版中,我决定支持多音字,尽管存在一个很全很完整的 微软拼音库 ,但它无法在 WP 下运行,而且速度很慢,于是我花一个晚上把 微软拼音库 移植到 WP 上,又花了一天调整了下效率,这也是Lucida拼音库 的前身。
旧版拨号应用的速度很慢,尤其在联系人上千之后就会感受到明显的卡顿,于是我在新版中更换了数据结构和查询算法,速度是上去了,但代码变的异常复杂,暗坑遍地。
不少用户反映旧版拨号应用的键盘很小,于是我在 2.0 版中按照 WP 的系统拨号键盘的大小重新制作了大号键盘:
但我又发现另一个问题,大号键盘太占地方,以至于一次只能看到 2 条联系人信息,为了能够显示尽可能多的信息,我引入了侧键盘——把大号键盘滑下去,侧键盘就会从屏幕左边弹出来。
我自己认为这个 UI 很炫酷,但我的 UX 朋友非常犀利的指出这个功能过于隐晦,恐怕不会有人用,事实上也是如此。 –_–||
大键盘带来的另一个问题是我没法使用任务栏(即 App Bar ),不然就没有空间显示搜索结果了。
既然不要能用任务栏,那么设置页面的入口应该放在哪呢?
2012年初正好是 iOS 5 发布不久,而iOS 5 引入了下滑 通知中心 ,受到它的影响,我很自然的把设置页面放在了下滑页中:
尽管 T9 模糊匹配已经很方便,但我还是在想能不能把它做的更便捷——因为一些用户反映在面对『张』,『王』这些姓氏时还是需要敲好几下屏幕(『张』,『王』都在『9』下面,所以需要进一步区分)
花了几天,推翻了各种方案,我决定把联想输入法引入拨号应用,我的思路是这样的,把用户的联系人构建成词库,然后以这个词库进行联想输入,从而提高匹配的精度。
由于找不到可以直接用的输入法库,于是我就照着 WP 输入法的样式写了一个输入控件,效果是这样的:
这样的好处在于可以更加快捷的指定联系人,以『杨晓玉』为例:
我几乎把我所有能想到的改进都写进了 2.0 版中,而每一个改进又会引入几个新的问题(例如大键盘的引入导致我加入了侧键盘和下滑设置页面),加上我当时还在微软实习,能自由支配的时间并不多,所以整个这个过程耗费了大量的时间,从开始编写到完工,足足用了三个半月。
2.0 版并没有达到预期效果:由于 2.0 版的改动过大,一方面导致各种各样的新 Bug,另一方面导致一些老用户的流失(不知道如何使用),同时市场上出现了一款更好用的拨号应用 瞬手拨 ,从而我的应用很快就失去了之前的领先位置,逐渐淡出了 WP 市场。
现在回想下,这正是 Fred Brooks 在人月神话 中提到的 第二版效应 的典型示范:
The second-system effect proposes that, when an architect designs a second system, it is the most dangerous system he will ever design, because he will tend to incorporate all of the additions he originated but did not add to the first system due to inherent time constraints. Thus, when embarking on a second system, an engineer should be mindful that he is susceptible to over-engineering it.
总之,这个拨号应用最后还是失败了。但它为我上了一堂异常珍贵的软件工程课——这是读多少本书都学不到的。
下篇:移动开发的那些事——4:非常格调