关于界面的价值观与方法论
12345678910

说说啤酒和尿布

2July2010

“先生,我注意到你买了啤酒,请问要不要再来一些尿布?” 如果超市收银员这样问你,你会不会想K人?即使,你知道那个关于啤酒和尿布的故事。

其实原故事是说,发现很多男人周五买尿布,所以超市就把啤酒也摆在尿布旁边。所以刚刚我故意混淆了两个细节:尿布和啤酒的相关性是“单向”的;推荐方式是“隐式”的(摆在一起)而不是“显式”的(口头推荐)。更重要的是,它是针对一个特定目标用户群(已婚有小孩的妻管严男人)的行为。

令人吃惊的是,我看到大多在讲“啤酒和尿布的故事”的地方,都故意忽视了这些细节,转而大谈诸如协同过滤或数据挖掘什么的。恐怕这就是为什么现在很多网站的推荐系统都做得相当糟糕的缘故吧。推荐系统,本质上一种产品,而不是什么技术架构,回归到产品设计的根本原则,才有可能把它做得“有用”,进而“好用”。

我其实也对推荐系统的技术一知半解,不妨抛开那些技术算法,谈几点我认为很重要的设计原则:

一,着眼于“后续期望”。举个例子,假设我在浏览ipad的产品介绍,旁边的相关推荐应该是什么?设想几种答案:A:iphone,ipod;B:ipad皮套等配件;C:不同渠道商的ipad报价;D:仿ipad的其他山寨产品。如果甲同学想买一个时尚电子产品送给女友,乙同学是ipad的狂热粉丝,丙同学还在为ipad的价格犹豫,丁同学只是想要一个电子阅读器,那上面这四个答案都恰好能让他们可以继续多看一些产品。所以,推荐系统是否成功的最关键因素,并非算法实现等技术问题,而是如何洞悉用户的当前行为以及后续期望。

值得一提的是,除了揣测用户本身已有的期望外,为用户创造出一个新的期望也是推荐系统常常做的。比如卖书的网站就经常告诉我,这两本书可以配套买。但这种为用户推荐他原本并不期待的东西,成功率就会低很多,相反可能会打乱用户原本的行为路径。所以要慎重,不能自作聪明弄巧成拙。

二,牢记80-20法则。想用一套算法解决千万用户不同的需求是不可能的,这就要求我们作一些取舍。我有一个绕口的原则是:用最简单的办法顾好大多数人在大多数情况下的最常见需求。我的这个原则的灵感来自于一个叫everything的桌面搜索软件。不管是微软还是google的桌面搜索软件,一开始总是要花很长时间(几个小时)来建索引。但这个everything只用1分钟就能建好整个硬盘的文件索引,很神奇!后来才发现,它只能搜文件名,而不能搜文件内容,而后者正是其他桌面搜索长时间建索引的原因。问题就在于,其实我们绝大多数时候找文件都是在找文件名而非内容,everything正是抓住了这个问题的核心,用20%的精力解决了80%的问题,然后,将剩下20%的问题直接抛弃!

将这个80-20法则用到推荐系统里,是再合适不过的了。你只需要集中精力在最常发生的情况下,用合适的算法找出合适的推荐结果,剩下的结果只要保证“相对过得去”就好。当然,这样做的前提是,你对用户的后续期望很有把握。

三,解决信息焦虑。假设“釜山料理”餐厅介绍页上,相关餐厅列出“港丽茶餐厅”,你会觉得他们相关么?那,“韩膳宫烧烤”呢?会不会觉得后一个明显靠谱很多?其原因是后一个你可以看得出它与“釜山料理”都是韩式烧烤店。但如果你是一个要在人民广场约朋友吃饭的人,“釜山”和“港丽”都恰好在人民广场,而“韩膳宫”其实是在离人民广场很远的徐家汇,那不用说自然“港丽”应该作为你下一个要浏览的餐厅。

这里很重要的,其实是要告诉用户“为什么相关”。否则用户就会困惑,从而忽略掉你精心为他推荐的内容。一个很好的例子是网易新闻,在它的相关新闻列表上,都会将它匹配的标签显示出来。比如“与 富士康 相关的新闻”。

四,始终记得商业目标。做推荐系统的最终目的,是为了商业目标:增加后续转化率?增加总用户数?还是增加成交量?其他产品设计,或许有时候需要牺牲一下眼前的商业利益,来满足用户目标。但推荐系统的商业目标与用户目标的分歧并不大,相反往往更加统一,所以这时候就要特别提醒自己注意商业目标,所有的功夫都要朝那个方向努力。当然一些很基本的用户体验还是要保证的,像在推荐系统里塞广告这种杀鸡取卵的事情还是做不得,呵呵。

管他们去死

4May2010

回来啦。

之前挺累,就懒得写。不过关键的原因是我一直在思考一个问题:互联网好玩在哪里?由来是我开始觉得这东西越来越无聊了。最近又恰好看到两篇文:《警惕信息窄化》,及《我们正进入另一个黑暗和无知的时代》。我的老天,他们的观点正好将我沉闷心底的想法打着旋的给搅出水面。

不过,得到共鸣并不意味着我就赞同他们的观点。他们讲来讲去,无非就是在说“孩儿们,你们太堕落了,要警惕啊”。首先“警惕”两个字就很好笑,下一代若真是要垮掉,警惕也没用。再说了,除非你老人家愿意对着摄像头用裸体说唱的方式把文章念一遍传到土豆再转到人人,那垮掉的一代压根就不知道你的逆耳忠言,你是要谁警惕?

第二,诚然,老先生们讲的都有道理。我也觉得在咱眼里,90后是挺无聊堕落的(数据说话-> 点这里)。但80后在70后眼里,不一样的无聊堕落嘛?这里有一个逻辑是:1. 你玩的东西我都不感兴趣,2. 我也看不出对我有什么价值,3.我自己玩的东西我能证明(对我)是有价值的,结论:你挺无聊堕落的。这样推断出的观点和结论,尤其那些再戴上“世代”帽子的,是很不靠谱的。你觉得魔兽装备很没价值,哈?人家可用这个来赚钱呢~

话说几年前,我跟一70后的姐姐说到最近一个新兴的网站叫twitter。我兴高采烈的跟她描述这个网站的特点,就是可以随时随地的发一条自己想说的话,她就一脸疑惑的说这听起来挺无聊的啊,我说那只能说明你老了跟不上时代了。好啦,现在该我得到报应了:我已经感觉不到foursquare有什么好玩的了,虽然我能理解那种升级和收集的动机(跟我在植物大战僵尸里攒花一个道理),但我打心底里说:这TMD的也太无聊了吧!anyway,喊归喊,我还是听说mayor头衔是可以换酒喝的,哎。

所以呢,胡诌一通,我想说的是:老先生你们讲的现象都是对的,但这没什么好紧张的:世界变得和你当初以为的不一样了而已。不用高呼“警惕”,放松点,管他们去死呢。

选择符的命名原则

2January2010

其实这个主题还蛮无聊的。因为我想来想去,选择符的命名,其实并不是那么重要。况且,对于不同的人,有不同的习惯,我在这里也没法定出什么完美的标准来号召大家都使用。

不过,规划好选择符的命名,还是有几点好处的:
1. 节约时间。不得不承认,我本人经常把10%-20%左右的时间花在斟酌选择符命名上。当然,或许这只是我个人的强迫症问题。

2. 防止冲突。虽然概率很小,但还是会遇得到这种情况:某个选择符的名字,已然被用过了,导致样式冲突。这种情况通常发生在不同尺度的样式:比如登录框和登录页,某个模块里的下拉菜单和导航栏,等等。

3. 防止冗余。其实这点就比较关键啦。如果命名冲突,换个名字就是了。但如果是前后由不同的人来写样式,很可能为了避免冲突而另起炉灶。一方面浪费人力,另一方面久而久之会产生大量被废弃或覆盖的样式:打开firebug,某个样式被不同的人在不同的样式表里覆盖了N次。这就比较糟糕了。

所以,好的命名规划,一定程度上还是比较的。一些关键的命名原则有:

1. 通用的样式,一定要规范好命名。所谓通用的样式,主要有:

    a) 页面布局:比如头部顶部啦,左侧栏右侧栏啦,负责整个页面“骨架”的一些样式。

    b) 常用布局:比如列表,田字格布局(1排5个,一共5排),标签切换(tab),翻页这种经常被网页设计所用的模块布局样式。

  上面两种,在各处的样式定义可能完全不同,但由于经常用到这些布局结构,所以可以统一命名。

    c) 通用模块:这里指的是一些“固定样式”的模块,会在全站各处出现。比如登录框、搜索框、浮动工具箱等等。

    d) 小尺度的通用样式:比如菜单激活状态,文字高亮之类的。还例如某些同学喜欢用的清除浮动的样式。
把这几种类型的样式的命名规范好,就能避免很多问题。原因是因为它们通常会在很多页面里被反复使用到,所以是最容易出现冲突和冗余的地方。

2. 页面布局、常用布局以及通用模块的样式,命名要特别。

比如对于全站导航菜单,我比较喜欢用nav(navigation,即导航)来命名,而不是menu,或是main_menu之类的。原因是,可预见的是,在某些特定的页面内,会出现“菜单”这种元素,比如分类索引页,侧栏可能会出现分类的菜单列表。那如果menu被全站导航占用,到时候就容易出问题。

同样的问题也出在“登陆框”或是“搜索框”,如果简单的用login或是search,那你到“登录页”或“搜索页”的时候,就又头疼了。我比较习惯的是用login_box和search_box。

总之呢,一些“自然而然就能想到”的名词,尽量不要用在大尺度或全站通用的样式上,一开始把它们挤占了,就会导致后来的样式命名不得不另想花样,命名的混乱就由此开始。

3. 相反,小尺度的通用样式,命名要通俗简短

其实小尺度的通用样式命名,就纯粹是一个“惯例”了。比如激活的菜单,有的人用on,有的人用now,有的人用active。你管不着别人的,只能作为一个惯例推广给团队里其他同事。但不要认为“惯例”就没约束性,如果坚持用同一个名字,到处都用,其实其他同学会潜移默化的也跟着用的。比如土豆网的视频截图模块,几年来一直被称作pack。这就是aether同学最初的发明。

下面稍微列了一下,可能用到的通用样式,后面附的英文是我个人的习惯,可以参考,也可以忽略。

页面布局:

  -页面头部:header
    -图标:logo
    -右上快捷区域:quicklinks
  -页面中部:page
    -侧栏:side column
    -主栏:main column
    -第三栏:extra column
    -区块:section
      -区块顶部:heading
      -区块中部:container
      -区块底部:footing
  -页面底部:footer
    -版权说明:copyright

常用布局:

  -田字格布局:show case
  -列表布局:list
  -标签切换:tab
  -排行榜:billboard
  -表单:post form
  -纯文字区域:text area
  -翻页:page navigation

通用模块:

  -导航栏:navigation
  -登陆框:login box
  -搜索框:search box

通用样式:

  -高亮:highlight
  -激活:active,或者on
  -清除浮动:fix,或者clear
  -图:pic
  -文:txt

自己可以根据具体情况来编写这个命名规范表。比如有些网站可能全站底部有个通用的工具栏(比如facebook),那就可以把tool box放到“通用模块”里。又比如,对于“田字格”布局,有些同学可能习惯每一行用一个框套起来,每一项再用一个框套起来,那就会衍生出“row”和“item”这样的样式,另外的做法是每一行末尾用一个空div隔开,可能需要用的是“line”或者直接就用“clear”。whatever,自己决定。

4. 选择符命名的常用方法有:

  a) 基于结构的命名:比如头部/底部,主栏/侧栏,菜单列表/菜单项,区块,按钮

  b) 基于功能的命名:登录框、搜索框、排行榜、翻页、提示(tip),等等

  c) 基于内容的命名:今日焦点(focus)、用户排行榜(top users)、评论(comments)、搜索结果(search results),等等

  d) 基于样式的命名:列表、田字格、tab、高亮、标红或加粗,等等

  e) 基于状态或行为的命名:激活、拖拽、展开,等等

我没那么教条,不去从什么“样式和结构分离”的形而上原则来规定该用什么。只是谈谈,如果在未来发生需求变动,怎样的命名会让你尽量少做改动

基本上呢,前两种——结构和功能——是最安全的。因为如果结构或功能发生巨大变化,你要做的工作就多着去了,也不在乎这个命名会改动多大了。

基于内容和样式命名,就比较危险。很可能只是将“今日焦点”改名为“最新话题”,而样式完全不变。或是新增的“分类索引”模块,设计上直接照搬“搜索结果”的排列样式。遇到这种情况,你的命名就尴尬啦。基于样式命名的危险,就更不用说了。

基于状态或行为来命名,通常发生在两种情况:1. 用作JS的钩子;2. 用作某种状态变化的样式。以我的经验,它们的问题往往不是“改动”,而是“不能改动”。一旦用了,就会一直用下去,除非相应的行为方式发生变化。对此我还没深思熟虑过,但值得提醒的就是,对它们的命名要慎重,而且,最关键的是,要将它们和其他的样式剥离开来。当然,这就不是“命名”的范畴,而是“架构”的范畴,这里就不多讲,以后再说。

最后还要特别强调的是:不管采用哪种方式命名,最忌讳的是同时基于两种方式。最常见的就是“左侧栏(left column)”,它同时基于样式和结构。还比如“顶部介绍(top intro)”,同时基于样式和内容;“频道下拉框(channel dropbox),同时基于内容和功能。这些命名,在遇到样式变动,或是新增同样式的模块时候,就会陷入尴尬。

5 最后讲一个比较棘手的问题:层叠(Cascading)。写CSS,经常会遇到层叠的情况:

    搜索
      搜索关键字
      搜索提示
      搜索结果
       搜索过滤选项

这个例子,其实还好解决:就按照各元素的内容或功能直接命名即可。之所以好解决,是因为这些元素大多是本模块(搜索)所特有的,不大可能重复。但另一种情况就比较麻烦了:表单。我举个例子:

    登录
      用户名
      密码

    注册
      用户名
      密码

类似的例子还有:blog的文章(标题、内容)和留言(标题、内容)。问题的关键在于,它们是不同的模块,包含同样内容或功能的元素。更要命的是,有时候,这些元素的样式是一致的,有时候,又有点小不同,有时候,又是迥然不同。

对于层叠的情况,有三种命名方式:

  a) 模块名和元素名绑成一个名字。比如.comment_title。

  b) 只用元素名,只对元素名定义样式。比如.keywords。

  c) 也是只用元素名,但是将选择符层叠定义,比如.login .username。

至于什么情况采用什么方式,完全在于经验。但关键要考虑的因素是:一,在其他模块中是否会出现同样的元素?二,它们在样式上有一致性吗?像“搜索关键字”这种元素,如果断定在其他模块不会有同样的元素,就大胆只用元素名吧。而“登录 用户名”和“注册 用户名”,可推断的是它们的样式有一致性,或许只是一些小不同(比如输入框宽度),那就用选择符层叠定义。而“文章标题”和“留言标题”,很明显它们在样式(甚至结构)上会有很大不同,那最好各取各的名字。

我个人呢,比较倾向于用a),即模块名和元素名绑在一起。这样可能会造成一些冗余的样式定义,但即便冗余,也有一个好处:解耦。样式各管各的,不用互相牵扯。只有对于那些特别通用的模块,我才会用c)方式,比如.list .item这样。

呼,这个无聊的主题,居然也洋洋洒洒写了这么多。其中肯定有很多漏洞,毕竟我也不能预见到所有的情况。就当是一个自我总结,供参考吧。