“一念”之间

我的“杂货铺”又上新了:“一念”。这是我做过的最复杂的网站,代码总数超过 1 万行。规模虽然还不能与另一个项目管理网站相比,但后者是模块化的设计,而且前前后后已经维护、更新了十几年;“一念”则是一个一体化的社区。然而即便如此复杂,在 codex 的帮助下,从有想法到上线,区区 3 天而已。

“念念不忘,必有回响”。表面上看,这似乎又是一次灵机一动的创新,但仔细回忆,其实脑海里有这个念头久矣。自从意识到言论管控的存在,压抑感就成为了精神上挥之不去的底色。“陈仓 · 暗渡”、“风中的微光”的诞生,无非是这种压抑感下的本能。

“一念”也是如此。

一、什么是“一念”?

“一念”酝酿的起点是一个树洞网站。树洞扮演的是一个有别于自我的聆听者,如果表达仅仅把自己作为对象,那就不需要树洞了。有了树洞的存在,表达在形式上并不只停留在内心世界,而是找到了一个外部的出口,这才有了“倾诉”的意味。

在这样一个处处强调“实名制”的国度,我们忘记了“陌生人社交”的存在。它原本是另一片沃土,对于像我这样的 I 人而言,有一个无需现实身份加持的倾诉平台,又无需与陌生人真正面对面,是刚需,也是自由。

无身份很重要,它代表着你在平台上的身份仅仅是“一个人”,别无其它。这种纯粹性会给 I 人带来莫大的安全感。

但我又不希望它仅仅是一个树洞。人的大脑其实很少休息,各种念头总是纷至沓来,可惜现实常常让这些思想的片段尘封在忙碌的背景板里,直至遗忘。在各大社交平台上,人们精心组织着语言,经营着自己的形象,但这种表达只与“人设”有关,与灵魂无关。纷纷扰扰的世界里,噪音常如雷鸣,而灵魂却无处安放,于是压抑、焦虑与迷茫如影随形。

我们需要安全的倾诉空间,需要脱离现实身份的真实表达,需要抓住灵魂深处的一念之间。“一念”因此得名。

二、树洞类网站的风险性与局限性

由于其本质上的匿名性,树洞类网站的风险是显而易见的。

之前在体验 Amethyst 的时候就发现,如果一个社交工具是匿名的,如果不加以强有力的管理手段,它首当其冲的风险就是会沦为一个垃圾场,机器人、广告、诈骗满天飞,信息流中几乎找不到正常的内容。第二种风险是西方价值观语境下的有害内容,例如也许有人会直播自残或自杀的过程,从而鼓励更多人效仿。儿童色情类内容也是无论哪个国家都严厉打击的对象。第三种风险就比较中国特色了,是定义更宽泛的“负能量”信息,不用展开大家也会明白那是什么。最后一种同样是中国特色,就是社交平台可能会针对某件刚刚发生的热点新闻突然爆发舆情,这种舆情带有很强的情绪驱动力,很容易演变为群体性事件。

所以,一个树洞网站既要兼顾它本质上的匿名性,又要尽量避免上述主要缺陷,这就注定了它天然带有一些局限性。找到一个合适的产品设计切入点至关重要。

三、“一念”的核心逻辑

1、双重账号体系

当一个新浏览器访问网站时,前端立即自己生成一个随机 ID,它不是浏览器指纹,不带有任何身份信息。之后这个随机 ID 会同时存入数据库和用户浏览器本地的的 LocalStorage、IndexedDB。只要浏览器缓存不清除,那么用户就可以用同一个浏览器确保身份的延续性。

这种方式的缺陷在于,用户一旦使用另一台设备上的浏览器访问网站,它就变成了另一个身份。当然,这在部分用户看来可能反而是优点。但如果用户需要将多个设备上的活动都归集到同一个身份之下,那就还是需要一个注册系统。

“一念”提供了注册系统,用户名 + 密码,不要求手机号也不要求邮箱。一旦用户注册,在不同的设备上登录同一个账号,那么不同设备上的浏览器对应的随机 ID 将全部关联登录的账号。在平台上互动时,关注与非关注,判断发帖人是不是自己,都会将这些不同的随机 ID 视作同一个用户。

用户可以在某个设备上注销账号,新建一个账号。新账号只要在其他设备上登录,将“接管”该设备对应的随机 ID。

需要注意的是,整个平台上不显示账号名称,只显示通过随机 ID 生成的一个 8 位字符串(显示名称)。因此,虽然注册用户可以以多个不同的显示名称发布信息,但其他用户并不能直观地识别出它们属于同一个人。

这种设计在保证匿名性的同时,也最大程度照顾到了身份的延续性。

用户如果想要彻底与旧身份告别,那么可以“注销账号”,清除所有设备上的浏览器缓存后重新注册。此时新账号将与旧身份毫无关联。

2、显示名称不可定义,模糊身份识别

通常社交平台上都会让用户自定义“昵称”,这会增加身份认同感,增加用户粘性。但对于“树洞”类网站来说恰恰相反。

“一念”上所有用户的显示名称都是枯燥无味的 8 位字符,由大写字母与数字组成,不可自定义。这样设计的目的是让用户避免因为过强的自我身份特征而陷入一种自我展示、打造人设的窠臼之中,这恰恰是传统社交平台最庸俗的部分。

这样设计还有一个好处:广告商是最强烈需要身份识别的,如此一来,用这样模糊的显示名称来打广告,效果将大打折扣,削弱了垃圾广告投放的动力。

3、沉淀期:延后公开

这是“一念”最特别的设计之一。所有信息发布后,不会立即公开,而是经过一个刚性的“沉淀期”后才会公开。一旦我想到“延后公开”这个点子,就立即发现它能带来一大堆的好处:

首先是用户发布任何内容时,不会再有心理障碍。不用担心用词不当,不用担心得罪了什么人,不用担心想法不成熟,不会立刻引发任何不良的后果——因为根本没人能看到,有大把的时间可以修改甚至删除。这种无门槛的安全感,对于鼓励记录“一闪念”来说是至关重要的。而经过几个小时的思考,用户可能会对自己原本粗糙的想法进一步完善,这也是为什么我称之为“沉淀期”的原因。

其次是极大程度上缓解了舆情的集中爆发。我们知道,咱们的政府管控舆情的一个常用手段就是“时间差”,把今天发生的事情改到明天,通过拉长时间来平复大众激烈的情绪。“沉淀期”默认为12小时,失去了实时性,也就抹除了“一念”因为讨论热点事件而集中产生激烈舆情的可能性。“一念”的定位本就不是时事评论。

最后,这种机制对于发送垃圾广告的用户非常不友好,因此可以更大程度上阻止了垃圾内容的产生。

4、公开信息的奖惩机制

一条信息经过“沉淀”之后,将会转为公开信息。沉淀一下并不代表万事大吉了,仍然可能会有部分用户蓄意发送恶意信息或垃圾内容,这些内容将面临公众的“审判”。任何用户都可以对任何公开信息进行“喜欢”、“不喜欢”的操作,对于1条信息而言,喜欢超过阈值,则发布者的“沉淀期”会缩短;反之,信息被“不喜欢”的数量超过阈值,该条信息将从公共信息流中移除,同时发布者的“沉淀期”会加长。

沉淀期的缩短有下限,最少不低于 2 小时。但加长没有上限,如果一个用户反复发送恶意、垃圾信息,收到很多的“不喜欢”,他的沉淀期会很快增长到难以接受。当然,为了防止用户恶意点击“不喜欢”,在新用户和 IP 来源上作了相应的限制。

而“喜欢”是令人欢迎的事情。“一念”鼓励用户发布有意思的想法,或者内心深处的真实感受。在公共信息流中,大家可以通过回应、点击“喜欢”来互相激发创意、取得共鸣、得到安慰。以及,在公共信息流中找到同频的好友,关注或互相关注。

5、公开信息定期销毁

所有公开的信息具有寿命,目前设置的是 90 天。公共信息在 90 天将自动销毁(删除),这是为什么呢?

我们来看微信就知道,大部分人都喜欢把朋友圈设置为“一定期限内”可见。其实,历史也是一种包袱,你某时某刻的想法,未来很大可能会变。太久远的过去,已经不能代表你的当下,如果它仍然显示在那里,反而变成了“不可承受之重”。我们当然需要证明自己的存在,但不一定要通过陈列所有的历史来证明。

从树洞的本质来讲,无论它承载的是情绪,还是想法,它也都不需要永存。我的设想中,用户可以在 3 个月之内,对自己的想法片段进行梳理,保存在自己的电脑或放在“一念”的私密信息中。对于注册用户,私密信息将永久保存。用户也可以随时将某条私密信息再次转为公开(当然要再经过一次沉淀期)。

希望这样的设计会给用户一种“轻盈”的感觉。

此外,有限生命周期的机制也在一定程度上遏制了某些有害信息的危害烈度。

四、“一念”的互动逻辑

1、表达优先

如果访问过“一念”的人一定会发现,它怎么一上来就弹出一个输入框让我输入?Sorry,这不是 bug ,是 feature :) 由于网站的一个重要定位是“记下一闪而过的想法”,因此它必须做到“打开即输”。通过“延迟公开”给予用户发布内容的安全感也是同样的逻辑,“一念”当然可以像普通社交平台那样让你浏览信息流,但它更鼓励表达,而不是在别人的信息流中大脑空空地度过整个下午。

2、没有“消息中心”

传统社交平台的一个核心设计思想是“多巴胺驱动”,具体表现就是各种互动提醒:XX 点赞了你的评论!XX 关注了你!在软件的首页用醒目的红色未读数字来提醒你还不够,还要给你的通知栏发消息。这种机制有毒,当你发表了一句看似深刻的话被若干人点赞——这是一种很让人上瘾的体验,很容易你会陷进去,渐渐地,你会为了追逐这种互动的感觉而故作惊人之语,这时候你已经不再是你,至少不再是那个冷静、客观的你了,你变成了舞台上的演员,期待着聚光灯的照射。

但完全没有互动提示当然也不行,如果你的倾诉在网上有了别人的回应,这是莫大的慰藉。如果你发布了一个了不得的创意点子,也希望会有人和你互动,一起头脑风暴。所以,提示要有,但关键是要克制。

“一念”的互动提示全部位于“我的”页面。对于阅读优先级更高的“被回应”,它在比较靠前的位置;而其他人对你表示“喜欢”、“不喜欢”这一类信息则放在最右侧——在手机上受限于宽度,它大部分时候默认不显示——这是我自认为非常 Nice 的设计。

有新的消息未读时,页面上只会显示一个淡淡的红点,没有数字,也就减少了焦虑。

3、隐私边界

在最初的版本里,用户点击别人的“显示名称”进入用户详情页时,除了可以看到他发布的、回应的信息流,还可以看到他的关注列表、喜欢列表、不喜欢列表。但在最新的版本里我删掉了它们。如果要判断是否要关注一个人,看他发布的信息就足够了,“关注”列表、“喜欢”、“不喜欢”太过隐私,没必要提供这个近乎“人肉”的功能。推特上的点赞信息也是隐藏的,这个改动我支持马斯克。

前面已经说过,“树洞”是要扮演第三方聆听的角色的。所以,我并没有保留完整意义上的“私密”信息功能。对于互相关注的用户来说,他们的私密信息彼此可见,而且是立即可见。这提供了一个相对舒适的交流环境:实时、匿名、小范围。对于私密信息,可以“喜欢”,但不能“不喜欢”,这是从避免“侵入感”的角度来考虑的。

4、没有“私信”

基于“一念”的设计思路,用户的安全感和舒适感是核心考虑要素。私信功能和必须与之配套的“消息中心”是一种太大的打扰,我希望用户在“一念”上始终是“自己主动”的、家的感觉,而不是随时会被别人拉住问东问西的拥挤街头。

五、实现上的折腾

老实说,在真正动手建造“一念”之前,我对一个社区网站的复杂性缺乏充分的认识。经过 3 天的高强度折腾,codex 各种冒烟的同时,我的经验值也在不断上涨。

对截至目前为止,碰到的一些情况作个记录。

1、无限滚动的假象

如果网站真的用户特别多,信息特别多,显然直接在信息流中加载全部数据是不可能的。用户之所以可以在信息流上刷个不停,本质上它是基于一个动态分段机制,一次性读取若干条信息,当用户的滚动接近边界时,再加载第二段的信息。这是任何信息流设计的基础逻辑。

2、多重身份的确认

由于网站是双重身份系统,所以无论是关注列表、互相关注的判断,还是“喜欢”、“不喜欢”,乃至信息流中“发帖人是不是自己”的判断,逻辑上都更为复杂。

同时,考虑到同一个用户的不同设备严格来说也是两个“二级身份”,所以用户详情页上,只显示当前设备(随机 ID)身份的发布、回应历史。这同样是“克制”的设计思维。

3、返回信息流的逻辑

用户在信息流中点击某条信息,打开这条信息,之后返回。这么一个简单的动作,其实隐藏着一个逻辑:系统需要“记住”用户是从信息流的哪个位置点进去的,之后的返回还要回到原来的位置。作为使用者,我们在使用其他软件的时候甚至不会注意到这一点,因为这“难道不是自然而然的吗”?答案:不是。这些需要代码来实现。

4、“自然”的横向滑动

早期的版本不支持标签页之间的横向滑动,直到有一次我在测试的时候自己下意识滑动了一下,我这才意识到,我们使用手机的习惯早已经被训练出了一系列的本能。仔细研究了微信之后,我发现微信标签之间的切换做的非常有娱乐性,它跟随手指,模拟了一个类似翻页的效果,如果手指在切换的途中停住,那么这个切换过程也会停下来,显得特别“跟手”。嗯,这也属于“用着自然而然”的效果。为了实现这个效果,我从中午一直调试到第二天凌晨,占据整个网站开发时间的1/4。

我很想知道,微信、抖音是如何设置用户的手指初始感应和方向锁定的,这可能属于用户体验中的核心机密。

过程中最大的一个坑是,页面的每张信息卡片上的操作图标,会影响页面的横移——必须将它们单独设计成“不会阻断横移的判断和操作,但同时不影响直接点击”。

5、刷新的设计

在安卓上兴高采烈地实现完之后,掏出苹果手机一测试,问题一大堆。最让人不能理解的,是 Safari 的 PWA 竟然不支持“页面顶端再下拉时刷新”!它的不可理喻重点表现在, Safari 本身反而是支持的!那么问题来了,iPhone 的 PWA 里该怎么刷新呢?网站本质上不需要刷新,有新消息会出现浮窗提示(类似推特),点一下就可以加载新的消息。但我也深刻地认识到,用户不能没有刷新。“刷新”早已经超越了其功能本身,而是一种赛博时代的自我安慰,全人类级别的心理鸦片。我不止一次地看到身边有人疯狂地刷新 Windows 桌面和微博(它还专门设计了一个非常上瘾的叮咚声)。微信不需要“刷新”,因为它本质上不是信息流的设计模式。

然而,这个“刷新”放在在哪里?推特给了我答案:远在天边,近在眼前——就是底边标签栏本身。点一下滑动到顶部;再点一下刷新。Perfect。

6、自动隐藏的地址栏和底边栏,以及 iPhone 的“弹性”

个人认为,马斯克接手推特后做的最好的改进,就是自动隐藏的顶部标签页和底部功能区。它是如此地易于上手,易于习惯,以至于我特别纳闷为什么之前它没有这样设计。如今反过来看微博、知乎,就觉得非常愚蠢,一个固定的顶部、一个固定的底部,占据了那么多的屏幕空间,而绝大多数时间用户只是浏览信息流,根本不会用到它们。

“一念”当然要向优秀的标杆看齐。用户在信息流中上拉,信息流向上滚动时,页面底部的底边栏会自动隐藏,腾出空间给信息流。用户如果向下拉则重新出现。

这效果非常好,直到我再次掏出 iPhone。iPhone 当页面已经处于顶部,用户继续往下拉时,它会出现一个“弹性”的效果,整个页面被往下拉了一段距离,然后又“回弹”回去。嗯,很酷炫,但也很烦躁,因为它“回弹”的这一下会导致底边栏隐藏——而用户从来没有向上拉过,这就令用户的操作与预期结果出现了不一致。

没错,这里需要专门为 iPhone 添加相关的代码。

7、iPhone 的底部 “安全区域”

iPhone 的烦躁还不止于此。我用的是 iPhone 16 Plus,它的屏幕带有巨大的圆角,同时系统底部有一个醒目的横条。“一念”一开始在上面显示的效果非常糟糕:底边栏被那个横条悍然挡掉了 1/3。OK,我们需要引入一个仅 iPhone 可以识别的参数:safe-area。

同样地,iPhone 的所谓“灵动岛”也是一个让人头疼的东西,viewport 把它那块也全部算进来了,于是 PWA 里最顶部的信息卡片被灵动岛挡了个严严实实。

在 style.css 中一顿加减乘除后,总算是解决了这个问题。

六、最后

不用担心我会窥探大家的隐私,因为我压根不知道你们是谁。也有朋友提出:为什么不设计一套加密机制,让“私密”信息连你也看不到?

原因很简单:因为这不是一个通信系统(比如“陈仓 · 暗渡”)。通信系统可以“实时”协商一个只有你知我知的密钥出来,对当前连接中传递的信息进行自动加密、解密,用户无需参与这个过程。但“一念”是社交平台,加密、解密并不发生同一个“安全连接”之中,这意味着用户必须自己输入密码进行加密、解密。如果想要服务器管理员无法解密,用户就不得不在每次加密、解密的时候重新输入密码,这种用户体验就太极客了,你们会不适应的。

现在“一念”肯定还不完善,因为数据量有限,一定还有很多的 bug 没有暴露出来。Anyway,“一念”还是上线了,希望大家多来光顾,有意见可以直接在“一念”上发布哦!