我在淘宝做弹窗,2022 年初的回顾与展望
空堂2022-05-06

本篇文章作者向各位介绍了自己加入 PopLayer 项目一年多时间以来,为产品所贡献的一份力量,既包含了站在产品视角对产品功能,易用性和未来发展的考量,也包括了站在技术视角,对技术架构,编程范式和功能实现上的思考。

前言

在我刚入职大淘宝技术用户增长团队时,弹窗作为用增站外触达的一种有效手段,需要一种系统的解决方案来提升弹窗的开发效率,扩展弹窗的使用场景,并通过结合唤端能力,扩大使用人群,为大盘贡献 AAC 增量。经内部反复讨论,我们初步确定了由「弹窗编辑器」产出「弹窗描述数据」,搭配 H5,小程序侧「数据渲染引擎」在终端即时渲染弹窗的技术架构,产品名暂定为「全域 POP 搭投平台」。

淘宝老牌弹窗搭投平台 PopLayer 团队成员在听闻该想法后,主动提出合作,希望将淘宝端内外弹窗搭投能力统一收口于 PopLayer 平台,为用户提供一站式端内外弹窗搭投体验。经过反复的沟通交流,我们最终评估通过了这一方案的可行性。我从此成为 PopLayer 团队的一员,并作为产品设计(后期)和开发者推动 PopLayer 平台从 3.0 版本到 4.0 版本的升级改造工作。

在下文中,我将详细地介绍我在此次平台升级的过程中,面临的问题,对应的思考以及最终的解决方案。

面临的问题

工作的价值在于解决问题,在加入 PopLayer 团队后,首先要做的事是了解情况,「明确当下的问题」。了解了项目背景的读者已经知道,我们已经有一个明确待完成的目标「使弹窗搭建能力复用至端内外场景」。但由于我们采用基于现有产品改造升级的策略,就不可避免的需要在此之前,先解决一些历史包袱,轻装上阵。与此同时,跨团队合作也使得团队成员能够从不同角度重新审视平台现状,从而对平台的升级注入更多期待和想法。

通过积极与团队成员沟通交流,我们最终归纳总结出如下 4 个本次升级迭代亟待的问题:

  1. 平台不易扩展的问题:PopLayer 平台作为淘宝老牌的弹窗搭投平台,在弹窗域积累了丰富的领域经验,但平台本身几经团队轮替,其代码也日益变得不易扩展和维护。但另一方面,我们能显著的观察到,近些年行业内弹窗的视觉和交互体验正在不断提升,业务方对弹窗的功能也提出了更多要求,因此,使 PopLayer 平台具备高扩展性以满足行业发展需要,是平台需首要解决的问题;
  2. 平台使用体验不佳的问题:平台使用体验差,会导致平台答疑成本提升,更有可能会使一些用户由于较高的使用成本对平台望而却步,这对于平台和用户都会造成损失:更少的用户意味着更少的需求输入,会导致平台自身发展遭遇瓶颈,而用户也会因为选择手动开发而浪费不必要的人力;
  3. 平台数据缺乏归纳整理的问题:PopLayer 平台作为线上稳定运行多年,支撑亿级业务量的淘宝核心产品,积年累月积攒了大量的弹窗域相关数据,如何将这些数据有效地利用起来,从而指导一次弹窗投放活动拿到更好的业务结果,也是平台顺应精细化运营时代趋势不得不考虑的问题;
  4. 平台现有架构未充分利用的问题:在进一步了解 PopLayer 产品技术架构时,我们发现 PopLayer 的技术架构与之前我们初步确定的「通过弹窗描述数据(一段 JSON 格式的 DSL 数据)解耦弹窗生产和渲染」的思路不谋而合。该架构的好处有以下三点:
    1. 通过将弹窗的生产与渲染分离,可以将弹窗的生产通过无代码或低代码的方式转交给创建弹窗活动的需求方,从而在大幅降低弹窗开发成本的同时,保障弹窗迭代效率满足业务灵活性需要;
    2. 通过「弹窗描述数据」作为弹窗生产的标注输出,弹窗渲染的标准输入,使得弹窗在渲染侧可以不拘泥于特定的技术选型,从而适配各类需求场景,例如为端外开发 H5 渲染引擎,为端内开发 Native 渲染引擎,为小程序开发小程序渲染引擎等,从而在各场景用最适合的技术做一件事,实现业务收益的最大化;
    3. 当业务提出新的业务场景时,可以通过在 DSL 层快速迭代,渲染层快速实现的方式,高效地满足业务的敏捷需要;

然而,目前 PopLayer 平台虽然基于此种技术架构,却因为种种原因仅提供端侧 Weex 弹窗渲染能力,没有将该技术方案的价值最大化,有待进一步拓展。

业务上的思考

在设计产品和进行架构设计时,仅仅是发现问题,提出方案,解决问题是不够的。特别是从 0 到 1 设计一个产品时更是如此。我们需要跳脱出最显而易见的「问题层面」,去思考「问题背后的问题」。只有这样,才能获得一个鸟瞰的视角,清楚地知道哪些问题是更重要的,并发现那些不那么显而易见但却重要的问题。

正如亨利·福特所描述的:

当他问及当时的人们:“您需要一个什么样的更好的交通工具?”时,几乎所有人的答案都是:“我要一匹更快的马”。

当获得一种鸟瞰的视角后,将会有更多机会发现汽车而非一匹更快的马。因此,我与团队在不断尝试为弹窗提供一个合理的业务模型和定位。

最终我是这样定义的:弹窗是一种用于引导用户行为的交互控件。而弹窗所对应的现实参照则是「传单」:例如,健身房的销售们会在健身房门口向判断有健身意向的行人派发传单,从而希望吸引他们去健身房参观并最终购买健身卡。这正是互联网上绝大多数弹窗需要做的事情,在合适的场合,向合适的人,展示低成本但有吸引力的内容,从而吸引用户最终产生经济行为

发传单的例子是思索弹窗发展方向的优秀模型(图片来源于网络)

因此在弹窗域我们核心要做的事情也就一目了然:

  1. 降低生产成本:提升弹窗的开发,迭代效率;
  2. 扩展投放渠道:使弹窗能在任何业务需要的场景稳定地投放;
  3. 实现精准投放:理想情况下,弹窗应该只对对其内容感兴趣的人群曝光,从而使对用户的打扰降到最低,收益达到最高;
  4. 丰富弹窗内容:弹窗内容越有吸引力,弹窗的效果就越好,弹窗效果越好,商业目标就越容易满足;
  5. 提升用户体验:弹窗的体验越差,弹窗对用户的吸引力就越低。弹窗的性能,展示方式,微交互等都与弹窗的体验息息相关;
  6. 数据驱动运营:互联网是有记忆的,通过不断沉淀的活动数据,我们有能力不断优化活动投放中的种种细节,从而使一次活动投放的收益最大化;

您应当可以发现,在「面临的问题」这一章中所罗列的种种问题实际上也不过是我们在实现上述目标中的一些绊脚石而已。通过想明白了弹窗域所需要解决的问题,以及它的终极形态。我们终于可以按部就班,有条不紊的展开 PopLayer 产品的升级迭代工作了。

通过稍后阅读的内容您不难发现,我们在这一年多中所做的所有事情都与这 6 个目标息息相关。

做了什么以及如何做

在描述了我们面临的问题,以及对问题的思考后。接下来便是解决「做什么」和「如何做」的问题。对此,我的思路是优先解决平台扩展性的问题,并在解决问题的过程中,解决平台易用性的问题,当这两者的问题都解决完毕之后,不断完善,扩充产品功能

之所以这样判断,是由于观察到行业弹窗日益显露出的复杂化,精细化趋势必然在未来会对弹窗的表达能力提出更高的要求,而现有的平台由于历史原因不具备与之相应的扩展性。因此遵循「打扫好屋子再请客」的思路,优先在技术架构上为平台未来的发展打好「地基」。而之后不断扩展新功能时,则可以放心的把楼越盖越高,让更多的业务方安心入住。

扩展性建设

对于有一定复杂度的平台而言,提升扩展性,大多数情况下意味着需要修改其原有架构。产品设计师不得不在基于原有产品,大刀阔斧的改造和干脆另起炉灶,从零开始搭建产品之间进行艰难取舍。经过团队内部的反复商议,我们最终选择了后一方案,从 0 开始打造新版的 PopLayer 弹窗搭建平台。

通过先前的介绍您应该明白,弹窗搭建平台应该是一个使用户可视化完成弹窗搭建任务的低代码或无代码工具。它的产出物,在技术上表现为一份 JSON 格式的弹窗描述数据。因此,在创建弹窗搭建平台之前,我们首先要做的,就是重新设计一套简洁优雅,包含弹窗域全部语义并能够轻松扩展的数据结构(DSL)。为此,我做了如下工作:

归纳总结历史弹窗样式功能

要想设计一份合理,优雅地 DSL,就首先要对特定领域有深入细致的了解。为此,我搜集了 1~2 年范围内 PopLayer 投放过的弹窗,仔细观察梳理其样式与交互,探索共性与差异。最终根据各弹窗的特性,将其进行如下分类:

弹窗类型分类

不同弹窗类别的特征,视觉展示都被归纳至一篇名为《弹窗类型学》的文档中,可以帮助用户迅速确认需求弹窗所属的类型。

通过归纳总结历史弹窗样式,交互和功能,一方面可以使我更有自信地设计具备良好扩展性的弹窗描述数据,另一方面,稍后可以看到,通过为不同类型的弹窗,提供不同类型的弹窗模版,既可以帮助用户提升弹窗搭建效率,也给产品增加了一个有着深远意义的数据维度,使我们有能力可以对比同类型弹窗数据,并从中探索规律促进业务优化

弹窗模版市场

设计新版弹窗描述数据

在搞清楚业务域的领域边界和领域内容后,就可以开始着手进行 DSL 的设计了,这也是本次项目改造升级的核心环节。DSL 设计的好坏,将直接决定整个项目是否有能力在不断发展变化的业务诉求中始终保持稳定和敏捷。我认为一份好的 DSL 设计,应该同时满足以下要素:

  1. 字段设计应符合「奥卡姆剃刀」原则,如非必要,勿增实体:尽可能让数据字段精简,明确,同时,数据组织要合理;
  2. 数据模块之间应满足「高内聚,低耦合」原则,尽量避免修改某一个字段时,牵一发而动全身,导致大面积的字段修改;
  3. 需紧密围绕特定领域进行设计,既要避免过度设计导致数据结构复杂和字段膨胀,但同时也要充分考虑到未来可能出现的种种可能;理想情况下,未来发展出的新的业务诉求,只需「更新」 DSL 的属性,而非属性;

基于以上三个核心设计原则,最终我们产出了淘宝弹窗描述数据规范。其大致可以分为如下 7 个模块:

  1. 基础信息模块:包含弹窗的基本信息,如名称,类型等;
  2. 组件模块:包含弹窗域所需组件的描述,通过分析历年弹窗域活动内容,我们归纳总结出图片文字倒计时热区容器iframe视频状态关闭按钮共 9 种组件,每种组件都围绕弹窗域需求与手淘基础架构设置了特定的字段,例如对于文字组件,可设置行数与内容,对于倒计时组件可设置是否显示毫秒位,倒计时结束后行为,超过某个临界值是否显示文本等;定制化组件使用户可以非常直观便利地使用各组件完成弹窗搭建任务;
  3. 样式模块:负责描述组件的 UI,由于不确定终端渲染环境,因此在样式属性,样式单位的设计上就要充分考虑到不同场景,不同技术选型的限制。通过与客户端同学沟通交流,我们最终将样式属性确定为能满足三端(H5,iOS,Android)与弹窗需要的最小样式集合;
  4. 请求模块:请求模块涵盖了对手淘内常见请求方式的结构化描述,并将该描述同时使用在弹窗曝光前与曝光后,数据内容覆盖了弹窗域请求所需关注的所有关注点,并支持串行,并行请求的配置;
  5. 行为模块:与大多数搭建平台不同的是,PopLayer 弹窗搭建所产出的数据,是对弹窗样式,行为,配置的全面描述。在行为模块中,我们通过梳理历史弹窗行为,对弹窗行为进行结构化定义,从而使弹窗行为可以被简单,清晰地描述,并通过彼此的排列组合,可以灵活适配各类业务需要;
  6. 动画模块:前文有提到过,行业整体的发展,要求更细腻的弹窗展现形式和交互,同时,也要求弹窗对用户有更强的吸引力。为此,我们引入动画模块,通过清晰,灵活的数据结构满足不同场景的动画需要;
  7. 其他功能模块:这里则主要包含其他与弹窗域相关的附加功能模块,例如渐进式曝光,承接页预渲染模块等,是对核心模块的扩充;

目前,淘宝弹窗描述数据一级数据共有 17 个,分类如下:

手淘弹窗描述数据一级字段

每个字段均有清晰,及时更新的文档说明与之对应。下面我将以行为模块的设计为例,让读者对 DSL 的设计有进一步的感受。

行为模块的设计

行为模块描述弹窗对用户行为的响应,在数据结构的设计上,站在被响应物体的角度,描述了物体应响应什么,响应的目标以及响应的内容,具体字段设计如下:

  • type :表示响应事件的类型,如点击(click ),Tab 切换(tabSwitch )等;
  • behavior :表示弹窗的行为类别,经过我们长时间的归纳总结,可将弹窗行为分类为:
    • goto :页面跳转;
    • switch :弹窗内部状态切换;
    • call :端外环境唤端至端内;
    • request :发送请求;
    • close :关闭弹窗;
    • doNothing :什么也不做(默认);
    • show :显示;
    • hide ;隐藏;
  • target :表示弹窗行为对象,会根据 behavior 字段的不同而拥有不同语义,例如当 behavior switch 时,target 表示待切换的状态 ID;
  • content :表示弹窗行为的内容,例如当 behavior 值为 goto target 值为 app content 值为 https://www.taobao.com 时,表明事件发生时,页面需跳转至端内首页;

通过这样的数据结构设计,我们可以最大限度的清晰表达弹窗的行为,并通过基础字段的扩展和组合,在不改变数据结构的情况下灵活,高效地支持各式各样的新需求。

一般而言,弹窗针对用户行为仅会有一次响应。但随着我们对淘宝场景,用户行为感知能力的不断提示,在极少数场景下开始出现需要弹窗响应多个行为的需求。在权衡场景的稀有性和 DSL 的扩展性后,我们针对这种特殊场景开辟了 actions 字段,数据结构如下:

{
    actions:[ 
        {
            "type": "click",
            "content": [
                {
                    "id": "1",
                    "target": "State_2",
                    "behaivior": "switch",
                    "content": "",
                    "nextActions": ["2"],
                    "fallbackActions": []
                },
                {
                    "id": "2",
                    "target": "",
                    "behaivior": "close",
                    "content": "",
                    "nextActions": [],
                    "fallbackActions": [],
                }
            ]
        }
    ]
}

通过调整数据结构,复用 action 字段并同时扩展 nextActionsfallbackActions 字段,我们可以轻松实现一个树状的行为描述,最低成本的实现并行或串行行为的描述。

DSL 的维护

值得一提的是,在设计好一个有着良好架构的 DSL 只不过是完成了万里长征的第一步。随着业务的不断发展,开发者对领域知识的更加深入地理解。DSL 当前的结构总会面临着新的挑战,此时,设计者的核心责任则在于,严格的把控 DSL 的复杂度,坚持仅在必要的时候才会对 DSL 的结构做合理的,小幅的修改。

如果设计者在漫长的维护岁月中逐渐丧失定力,那么这份一开始精心设计的 DSL,最终也会像绝大多数糟糕设计一样,迅速膨胀,变得丑陋,难以理解,不易维护。所以设计者应该始终保持高度的责任感,完成如下事宜:

1撰写细致,友好的文档,并定时更新2文档应及时标明某些字段的特殊性,如已废弃或支持不完全,避免其他开发者踩坑;3在涉及 DSL 的变更时,需要严肃思考变更的合理性,变更方式和潜在隐患,谨小慎微,科学规范的进行迭代;

以上,便是对本次产品升级的核心 -- DSL 重新设计的一些经验分享,在确定好一份可以清晰描述各类弹窗,具备良好扩展性的数据之后,下一步工作则是提供一个面向用户,用于产出满足数据规范数据的弹窗搭建平台。

开发无代码弹窗搭建平台 - xEditor

弹窗搭建平台的核心功用在于「降低生产成本」。但从产品架构设计的角度出发,还需要保障产品在未来演进的过程中,始终保持能够高效,稳定地迭代功能。因此对于弹窗搭建平台从 0 到 1 的建设,始终需要兼顾以下两个问题:

  1. 产品设计上:如何让用户更顺畅地使用产品?
  2. 技术架构上:如何让产品更方便地持续扩展?

对于第一个问题,将留待下一章说明,在本章的剩余篇幅,我将向您介绍我是如何在技术架构设计上保障产品的稳定性与扩展性的。

下方是弹窗编辑器 xEditor 的技术架构图:

xEditor 技术架构图

从架构图中可以清晰地看到,xEditor 的整体架构可以分为数据层逻辑层工程层三个部分,要想让整个应用始终保持稳定性与高扩展性,我在每层做了如下设计:

数据层设计

数据层主要包含编辑器内部状态的管理以及对外的数据交互。由于编辑器的功能在于产出满足 DSL 规范的数据,因此对外的数据交互较为简单,核心应关注内部状态的管理。

为了保障状态变更的有序性和可维护性,我通过 immutable.js 将用户的每一次操作结果保存为一个「数据快照」,并压入栈中。由于每一个快照都是一份不可变的满足 DSL 规范的数据,因此快照的每一次更新都可以促使预览模块即时渲染出最新的弹窗样式。从而通过严格的数据驱动渲染使整个应用的状态井然有序。并且由于预览模块采用了和线上一致的渲染引擎,因此还可以真正实现「所见即所得」的效果。

基于不可变数据结构的状态管理

同时,由于用户的每次操作结构都被保存下来,因此整个应用还可以轻松实现用户行为记录,回退功能,进一步提升用户体验。

逻辑层设计

在逻辑层要解决的核心问题是让应用具备灵活的扩展能力,为此,我将整个用户界面按照功能模块拆分成一个个有标准化接口的组件,并通过在底层实现一个有标准化「插槽」的 Layout 基座,使得每个功能模块都能以类似插件的方式,通过插拔形式拼装出一个具备完整功能的应用界面。

插件模块用于灵活插拔功能面板

通过这样的设计,使得每个功能区块均彼此独立,且可根据需求迅速扩展或移除,开发者不必担心会影响其他模块功能,并且应用还可以根据不同用户区分所要对外暴露的功能(稍后我们还会看到关于这项特性的一个实例)。

工程层设计

在工程层上,整个应用采用 TypeScript 约束变量类型并为开发者提供接口提示,并对核心工具类函数进行单元测试。通过集成集团 AppLint 规范,使代码在风格和使用上对齐淘宝最佳实践,从而最大限度减缓应用代码在多次迭代后的腐烂速率。

除了代码上的种种约束外,撰写清晰的产品,技术文档,并持续保持文档的新鲜程度,也是保障应用始终维持在可维护可扩展水平的重要因素。

下方展示了 PopLayer 整体方案的相关产品,技术文档目录,包含了用户,开发者所需了解的几乎所有内容。

PopLayer 4.0 官方文档

以上便是弹窗搭建平台 xEditor 在技术架构上的一些思考和设计,正是基于这些设计,xEditor 在能在业务快速迭代的过程中,始终保持敏捷,将弹窗搭建能力赋能给越来越多的业务。

易用性建设

在介绍完技术架构上为产品可扩展性作出的种种努力后,本章将着重介绍弹窗搭建平台 xEditor 是如何在产品设计上为用户服务,大幅提升弹窗搭建效率。

在产品设计之初,我就受到各方伙伴的质询?这个产品是给谁用?这显然是个非常好的问题,想清楚为谁设计,永远是产品设计的第一步。对此,我的思考是,基于线上弹窗的复杂程度不一,弹窗的搭建工作也必然不可能完全由运营完成,因此,对于简单的弹窗应该提供足够符合直觉的交互界面,让无技术背景的用户可以轻松完成搭建,而对于交互复杂的弹窗,可以允许有一定技术背景的用户完成,但整个应用的交互复杂度要要尽量控制在非技术用户在经过文档培训后便能成功搭建

鉴于产品的用户既可能是运营或产品,也可能是开发,因此在产品的界面设计上,就不能偏向任何一方,而是要选择一个尽量符合两方操作习惯和认知系统的设计。为此,我调研了集团与行业内各类搭建平台(iceluna,云凤蝶,xEditor 等)和设计工具(Axure,Sketch,Photoshop 等),最终决定在产品界面上参照 Axure 的界面设计,使用拖拽 + 配置的核心交互形式。

之所以这样选择,主要因为以下三点:

  1. 拖拽 + 配置生成视觉要素是一种符合用户直觉的 UI 创建方式,很多年来 Axure,Sketch,Photoshop 等应用已帮助用户树立了心智模型;
  2. Axure 的界面设计十分经典,大多数用户对此十分熟悉;
  3. Axure 作为业界专业的原型设计工具,本身覆盖的功能就基本能满足弹窗搭建需要,因此 follow 其功能设计规范,是站在巨人的肩膀上,能最大限度避免未来踩坑;

下面是最终的产品界面展示:

xEditor 交互界面

交互设计优化

除了在界面上尽量遵循用户使用习惯,合理分区排布功能外,xEditor 另一个值得一提的交互设计优化便是能够根据弹窗模版类型的不同,为用户展示不同的交互界面,对于一个展示类型的弹窗(即弹窗本身不发送请求,仅展示内容,点击弹窗后跳转),用户看到的界面将是这样:

注意到了吗?相较于「完全体」的编辑器而言,展示类弹窗模版缺失了右上角的「数据中心」面板,并在左侧「组件库」中也仅展示了必要的三个组件。这一切都归功于 xEditor 插拔式模块的技术架构,通过这种方式,我们可以尽量降低用户的理解成本,让用户仅需关心自己需要关心的事情。通过将产品噪音降至最低,我们可以实现对于纯展示类弹窗,用户的搭建成本不超过 1 分钟。

相较于实际开发中项目启动,注册埋点,功能实现和测试的时间,xEditor 至少节省了 2 人日的弹窗开发工作量

新增易用功能

除了为不同需求的用户提供恰到好处的功能之外,我们还新增了一些功能用来进一步提升用户的搭建效率,并将更多过去无法通过搭建形式创建的弹窗需求纳入新的搭建体系。在众多功能中,比较有代表性的是以下两个:

数据 MOCK 功能

当弹窗涉及与服务端的请求交互时,特别是弹窗的内容取决于服务端返回的字段时,以往的弹窗编辑器均不能很好的处理这样的情景,只能兜底返回 undefined 这样的字段,破坏所见即所得的使用体验。

而 xEditor 通过新增数据 mock 功能来解决这个问题,通过在配置接口时,允许用户填充与线上响应数据一致的 mock 数据,即时显示对应的弹窗样式,从而避免反复扫码真机预览所带来的时间损耗。

基于数据 mock 功能,xEditor 还可以在搭建侧轻松实现「前后端分离」的生产效果,即当服务端接口尚在开发中时,只要双方约定一致的数据结构,运营或开发就可以按照该数据提前搭建好弹窗样式,待接口完毕后无缝衔接上线。

注意到了吗?用户甚至可以添加多份 mock 数据,并任意切换,视图会根据选择的 mock 数据即时更新!这在弹窗对不同响应数据响应不同样式时就会非常便利,并且用户也可以通过故意设置特殊的数据值,来测试检验弹窗的样式是否正常。

注意:所设置的 mock 数据仅在编辑器中生效。

复合条件判断功能

除了在弹窗上直接展示服务端返回的数据之外,在一些场景下,弹窗需要根据服务端返回的数据展示不一样的界面,并且对数据的判断逻辑也较为复杂。此时,就是 xEditor 复合条件判断功能登场的好时机了。

通过 xEditor 提供的多状态切换 + 状态曝光条件判断 + 数据 mock 功能,用户可以非常直观且方便的搭建包含复杂逻辑判断的弹窗,下面的视频展示了这样一个案例:弹窗包含 2 两个状态。

除此之外,状态的条件判断功能理论上支持无限嵌套,能够满足各类复合条件判断需求。

可无限延伸的数据判断面板

最终的复合条件将会表现为如下数据结构:

{
  "condition": {
    "left": {
       "left": "{{store.$username.nickname}}",
      "operator": "=",
      "right": "kongtang"
    },
    "operator": "&&",
    "right": {
      "left": "{{store.$age}}",
      "operator": ">=",
      "right": "20"
    }
  }
}

功能建设

在对产品的扩展性,易用性进行系统升级后,下一步要做的就是不断丰富弹窗的功能。如果将前面做的事情比作「打地基」,那么这一步以及之后所要做的事情就是基于这个坚实的地基,将房子越盖越高,以满足更多,更复杂的弹窗搭建需求。

无论是添加什么新功能,在渲染侧我们的核心目标始终围绕以下两个主题:

  1. 丰富弹窗内容
  2. 提升用户体验

通过这两点,我们希望尽量减少用户对弹窗抵触情绪,带给用户更舒适,新奇地体验,从而更好的促使弹窗的引导目标达成。对弹窗功能建设的量化指标,最终将落地在以下两个方面:

  1. 用户满意度,来源于定期用研数据
  2. 弹窗的曝光率,点击率以及弹窗点击后承接页的到达率

下面将介绍一些本次产品升级中一些较有代表性的新增功能。

弹窗曝光优化

弹窗曝光是弹窗成功引导用户行为的第一层漏斗,弹窗曝光率的提升,会使更多用户有机会看到弹窗内容,意味着某种业务策略或意图能够影响更多的用户。因此提升弹窗曝光率,将弹窗曝光率逼近 100% 的理想值,是弹窗域永恒探索的方向

为了提升弹窗曝光率,有以下两个方向可供探索:

  1. 投放侧:优化投放通道,提升活动配置的命中率和响应时间;
  2. 渲染侧:提升弹窗的渲染性能,或至少在体验上为让用户认为弹窗响应速度很快;

由于投放侧的建设目前正在进行中,下面将主要为各位分享一些渲染侧功能的实现与效果。

H5 原生弹窗渲染引擎 - xRender

在与 PopLayer 团队展开合作之初,我们首要解决的问题便是打通弹窗搭建的站外投放链路。因此,基于新版 DSL 规范开发的第一个渲染引擎在技术选型上自然选择了 H5 方案。由于站外环境的不确定性,以及对性能的苛刻要求,渲染引擎在实现上选择尽量避免第三方框架和库的使用,核心逻辑全部使用原生 JavaScript 实现。

而由于技术选型上选择使用原生 JavaScript 实现,那么就必须要在技术架构和代码结构上精心设计,从而保障代码的稳定性,健壮性以适应未来业务发展持续的功能迭代需要。为此,在渲染引擎的编码范式上,我借鉴了函数式编程的思想,将渲染引擎的各个功能封装成一个个纯函数,并通过管道式调用的方式,让代码的各个功能在接口上保持一致,在功能上保持内聚。无论是未来出于 debug 需要,还是要新增功能,都可以通过修改,新增,删除「管道」的方式对应用进行稳定,高效的迭代。

xRender 代码结构图

通过展示的 xRender 代码结构图可以看到,整个 xRender 都可以近似看成一个「纯函数」,统一的 DSL 数据输入,会生成一致的弹窗行为和样式。从下方的代码截图可以看出,实际的代码通过函数式编程范式,也和整体设计保持一一映射的关系。

xRender 主逻辑代码

通过线上验证,由原生 JavaScript 开发的 H5 弹窗渲染引擎,渲染时间在十几毫秒几十几十毫秒之间(不包含异步数据请求),整体的弹窗业务数据与老的 Weex 1.0 渲染引擎保持一致

Native 轻量化渲染引擎

在 xRender 上线稳定服役一段时间后,我们开始探索更极致的渲染侧弹窗性能优化之路,经过综合评估,我们决定基于新版 DSL 数据规范,在端侧开发仅满足弹窗域渲染所需的,轻量化弹窗渲染引擎,从而节省其他方案所必需的容器启动时间,提供更极致的渲染体验。

要打通 Native 渲染,需要对 DSL 的部分字段进行更强的约束,并且,由于三端在部分场景下渲染方案存在巨大差异,还需在尽量不更改原先 DSL 结构的基础上,对 DSL 进行扩展,以满足三端渲染的一致性需要。通过团队内部的反复讨论和打磨,测试同学的严谨测试,Native 轻量化渲染引擎成功应运而出,稳定服务线上业务场景,并逐渐覆盖更多业务。

通过在非大促时期不同时间投放同一活动的 Weex 1.0 渲染版本与 Native 轻量化渲染版本数据,我们发现 Native 轻量化渲染引擎可促使弹窗曝光率提升 26 pt,特别是双十一期间「88 VIP 开卡弹窗」的单日 PV 曝光增加 43 pt

弹窗点击优化

除了想方设法提升弹窗的曝光率,弹窗的业务目标最终是否实现,还是要落在用户是否有效点击弹窗上。因此,弹窗域要解决的另一个核心问题在于如何提升弹窗点击率。

为此,我们的探索方向是多维度的,主要包含以下几个层面:

  1. 通过与设计师共同制定淘宝弹窗样式,交互规范,使搭建侧产出的弹窗始终保持标准化的弹窗样式和交互行为。例如规定弹窗尺寸,关闭按钮大小和位置等,从而为用户带来更好的体验,增强用户的点击意愿。通过弹窗模版,搭建侧可以强制约束弹窗的基本样式和交互;
  2. 通过添加动画模块,使用户能够借助快捷添加弹窗动效能力,在弹窗点击效果不佳时,多一种有效调控手段;
  3. 通过接入 UCP 智能管控,通过端智能算法,使弹窗曝光给点击意愿更强的用户

下面将主要介绍动画模块的设计和线上效果。

动画模块

我们对动画模块的设计要求有以下三点原则:

  1. 足够简单,仅支持一般常见动画;
  2. 足够合理,能保障三端均可实现一致的动画效果;
  3. 足够灵活,能满足弹窗域多变的简易动画需求;

最终,基于以上原则,我们确定了动画描述 DSL 规范。使弹窗元素具备快速添加动画的能力,除此之外,我们还与端侧同学合作,获得端侧用户行为感知能力,可以使弹窗感知到,用户在端内的滑动,切换 Tab 等行为,通过为不同的用户行为绑定对应的动画效果,我们有能力为弹窗带来更细腻的视觉和交互体验。

下面展示一些具有代表性的事例:

  • 2021 年双十一购物车开奖提醒弹窗:该弹窗本来采用静态图片方式呈现后,上线后发现点击数据不佳,后决定添加摇一摇动效,由于该动效在之前的业务中已沉淀为可复用的动画模块,因此此次迭代只需数分钟便可完成上线。动效弹窗上线后,促使弹窗点击率提升 3.6 个百分点
  • 淘宝二楼飘条:通过将滑动感知与动画模块相结合,我们可以根据用户的滑动轨迹触发弹窗对应的动效,从而给用户带来更细腻的体验:

承接页到达率优化

除了从弹窗曝光率,点击率入手以期为业务带来更大价值外。在团队同学的建议下,我们还开辟了弹窗域可探索的新场景:弹窗承接页的到达率优化。还用发传单的例子,我们之前所做的事情是在尽可能低成本地印刷对目标用户有吸引力的传单,并尽可能在更多场合,向目标用户稳定派送,而「承接页到达率优化」则是在用户拿到弹窗,产生兴趣,但是由于目标地点太远正在犹豫不决时,将用户瞬间传送至目标地点,直接打消用户的顾虑,减少犹豫和等待中可能的用户流失。

为了实现承接页到达率优化,我们借用会场预加载能力,在弹窗曝光时对页面进行「预加载」,待用户点击后,便能直接看到加载好的页面。

基于该技术原理,我制定了两期的项目迭代计划:

一期迭代:快速跑通技术链路,线上验证业务价值

本期迭代包含以下内容:

  1. 端侧打通 POP 预加载接口;
  2. 在 xEditor,xRender 上集成预加载相关功能;
  3. 推动承接页埋点改造;
  4. 梳理对齐全流程埋点,通过 A/B 实验测试技术方案的业务效果;

一期迭代的核心在于通过完整的设计,将会场预加载方案与 POP-承接页技术体系相融合,并确定整条链路的数据如何串联,与核心关注指标,保障数据科学性。通过团队内部的反复讨论,我们最终通过约定 URL 参数标识的方式完整串联整个数据链路,整个数据链路和核心指标如下图所示:

POP 承接页预加载数据链路图

通过清晰定义数据的串联方式和核心关注指标,我们可以很高效的与数据团队对接,快速,准确地衡量,评估这次技术改造所带来的业务价值。

通过选取一周的线上业务 A/B 实验数据证明,POP 承接页预加载功能促使页面到达率提升约 12.58pt,促使页面可视耗时平均降低 1.76 秒,并间接提升承接页点击 UV 2.47pt

基本符合预期,达成承接页秒开效果,获得了正向的业务收益。

二期迭代:承接页秒开常态化

在快速验证承接页预加载技术能为业务带来正向价值后,接下来我需要做的核心事项就是大力推广该功能,让更多业务能够高效,稳定的享受技术带来的业务增量,因此,二期迭代主要包含如下内容:

  1. 推动 native 轻量化渲染引擎实现预加载相关功能;
  2. 为经过埋点改造的页面默认开启承接页秒开功能,为未经过埋点改造的页面提供改造方案以及手动开启功能的入口;
  3. 推动淘宝新人版,银发版等版本日常开启承接页预加载接口;
  4. 借用一休 ER A/B 实验能力,在每次承接页秒开能力开启时,自动创建低流量空桶进行效果比对,让技术带来的业务收益看得见,可衡量,也方便后续的不断优化。

整个程序的运行时序图如下:

承接页秒开二期时序图

从用户视角来看,当 xEditor 在弹窗发布前检测到用户弹窗包含不在白名单,但有效的跳转链接时,会对用户进行功能提示,由用户判断是否开启该功能:

页面不在白名单时,提示用户感知功能

而当 xEditor 检测到弹窗的跳转页面已经完成预加载埋点改造后,则会默认创建 ER A/B 实验,对大流量桶开启预加载功能,并在发布前通知用户。

当页面在白名单时,默认开启承接页预加载

同时,当 xEditor 检测到页面有多个有效的跳转链接时,则会给用户提示,让用户主动选择需要针对哪个页面开启功能:

通过承接页秒开项目的二期迭代,我们成功做到对于已完成埋点改造页面,平台默认赋能预加载功能,从而让更多业务享受页面到达率提升带来的增量价值。与此同时,通过默认的 ER 实验分流,平台也可以清晰感知到所赋能的业务数量以及创造的价值增量。

稳定性建设

自从我入职以来,集团就在大力推动安全生产。对于弹窗这种需要快速迭代,活动期间亿级流量的产品而言,如何更好地提升产品稳定性,更是我在产品设计和开发过程中一直思考的问题。

得益于 PopLayer 平台作为老牌的淘宝弹窗搭投平台,在稳定性保障上的建设已经足够优秀,所谓珠玉在前,木椟在后,我能做的也只有在搭建侧和渲染侧作出如下优化:

  1. 提升 xRender 测试覆盖率,接入 JSTracker 与舆情管控,并在每次迭代时进行严格的回归测试,确保应用线上稳定运行,如有异常,及时报警;
  2. 在 xEditor 中自动检测用户填入的跳转链接地址是否为预发地址或无效地址,若发现则在用户发布时及时给用户反馈,同时,在渲染侧对首屏图片资源的加载状态进行监控,当图片加载失败时,阻止弹窗曝光;

当监测到用户填写预发地址时,主动预警

  1. 在用户发布弹窗时,为用户展示疲劳度等弹窗全局配置,避免用户由于疏忽大意,错误配置导致线上弹窗行为与预期不符;

发布前外化全局配置,避免非系统性风险

成果,不足与发展规划

成果展示

通过一年多时间团队成员在 PopLayer 扩展性易用性功能丰富度稳定性上的共同建设,如今回首看来,我们在弹窗域取得了以下成就:

  • 【大盘数据】自 2021 年 8 月 PopLayer 4.0 版本正式上线以来,至今共承接手淘端内外各类弹窗活动 46 个,并涵盖具备动效,场景感知等原搭建无法支持类型,至少节省 92 人日人力成本,期无线上故障

线上部分弹窗活动示例

  • 【系统扩展】完成了 PopLayer 从 3.0 至 4.0 版本的大版本升级,通过重构底层 DSL,从 0 到 1 开发弹窗编辑器,使整个系统变得更加健壮并能够持续响应业务发展需要,快速,稳定扩展功能,支持更多业务场景
  • 【生产效率】通过从 0 到 1 开发弹窗编辑器,大幅提升弹窗搭建效率,以及可搭建弹窗的覆盖范围,对于简单弹窗,实现了无技术背景用户搭建时长 < 1 分钟,大幅节约了人力成本(至少 2 人日/个),获得了用户的高度认可;
  • 【触达范围】通过开发 H5 渲染引擎并打通端外投放渠道,实现了弹窗搭建链路的端内外全场景覆盖
  • 【精准投放】通过在引擎侧接入端智能算法管控 SDK,营销型弹窗能够通过算法调控,实现精准投放,降低用户打扰的同时提升弹窗点击;
  • 【极致性能】通过 H5 原生渲染引擎,保障端外弹窗性能,通过 Native 轻量化渲染引擎,提升端内弹窗曝光率 26pt,通过 POP 承接页预渲染功能提升承接页到达率 12.58pt,点击率 1.82pt
  • 【丰富内容】通过新增动画模块,淘宝场景感知模块,为弹窗搭建提供了通过添加动效提升弹窗点击的运营策略选择;
  • 【体验提升】通过在搭建侧为弹窗提供统一的视觉交互规范,进一步提升弹窗用户体验;

不足与发展规划

虽然经过一年多在弹窗域的深耕,我们取得了一些看得见的成果,但是距离将 PopLayer 打造为淘宝弹窗解决方案的目标,依然还有很多地方需要继续探索。归纳起来,主要有如下几个方面:

解决 Native 轻量化渲染引擎版本覆盖率问题

虽然通过 Native 轻量化渲染引擎可以显著提升弹窗曝光率,但引擎本身涉及版本覆盖率的问题,在版本尚未覆盖到业务可接受的范围之前(一般而言 > 95%),如何使弹窗尽可能覆盖到足量人群是我们需要面对的核心问题。

对于这个问题,我们当前给出的解决思路是,持续探索 H5 渲染方案在淘宝首页直出场景下的性能优化方案,并在平台侧建设引擎自动分流机制,使满足 Native 渲染条件的弹窗使用 Native 轻量化渲染引擎渲染,而不满足条件的弹窗自动降级为 H5 渲染方案。从而使搭建侧用户无感知的获得最大限度的业务收益。

加强动效能力建设

目前根据我们的经验,是否添加动效与弹窗点击率提升之间并没有必然的相关性。但在一些场景中,我们可以明显看到弹窗从静态转为包含动效的动态弹窗后,弹窗的点击率有明显提升。因此,至少我们可以说,动效可以作为一种提升弹窗点击率,更好达成业务目标的一种有效手段。

但更进一步的问题是,除了有助于提升用户体验之外,究竟动效与弹窗点击率之间的相关性是什么?目前我们在这方面的探索仍稍显不足,为了回答这个问题,我们接下来会在以下方面持续探索和建设:

  1. 进一步打通 A/B 实验能力,使平台和用户能够快速创建弹窗 A/B 实验,探索和验证弹窗动效与点击率的相关性;
  2. 建设常用动效模版,在搭建侧提供快速为弹窗组件添加动效能力,提升业务迭代敏捷性;
  3. 结合行业观察与业界最佳实践,持续探索更适合弹窗域的动效表达方式;

通过在弹窗动效上的持续探索,希望能够在提升弹窗体验的同时,为弹窗内容的表达提供更丰富的技术支持,从而增强弹窗吸引力,提升用户点击意愿。

进一步扩大弹窗搭投链路的场景覆盖率

目前淘宝端内弹窗,还有约 30% 左右的活动由于其形态,交互复杂度超出弹窗搭建能力的覆盖范围,只能通过开发者采用编码方式手动进行开发。针对这些业务场景,我们需要持续探索如何通过继续扩展搭建能力或其他方式最大限度的降低弹窗的开发成本,并给终端用户提供稳定,高性能,丰富的内容。

与此同时,进一步降低复杂交互弹窗的搭建成本,也是我们需要持续探索的重要课题。

手淘全域弹窗数据体系建设

回顾我在本章开头部分提到的弹窗域的 6 大核心业务目标:

  1. 降低生产成本
  2. 扩展投放渠道
  3. 实现精准投放
  4. 丰富弹窗内容
  5. 提升用户体验
  6. 数据驱动运营

我们这一年对最后一个目标的建设还稍显不足,尚未有一个可以清晰展示淘宝弹窗分布,弹窗形态与数据的视图,能够让我们对比同类型弹窗的效果数据,发现规律为运营提供改进建议。也尚为建成一个高效的 A/B 实验创建通道,让用户可通过不断实验,持续优化弹窗数据。

但好消息是,这些正是我们接下来的建设方向,我们正在通过淘宝弹窗管控平台,摸清整个淘宝端内外弹窗的分布,形态,类型和效果数据,并在投放侧设计,建设高效的弹窗域 A/B 实验方案。还请各位用户关注我们的后续开发进展。

总结

在本篇文章中,我向各位介绍了我加入 PopLayer 项目以来,在一年多时间里,为产品所贡献的一份力量。既包含了站在产品视角对产品功能,易用性和未来发展的考量,也包括了站在技术视角,对技术架构,编程范式和功能实现上的思考。通过这一年多时间,和团队共同打磨一款产品的经历,着实令我受益良多,在很多方面都有了可喜的进步,并且也发现了自己在做事方法上的一些不足。这些都沉淀为我宝贵的经验。

通过这篇文章,虽然不算是事无巨细,但也算是系统的,把我目前能想到的一些经验以及做事的方法沉淀下来,希望能够给各位读者带来一些灵感和收获。

最后感谢各位读者能坚持将这篇近 2 万字的文章阅读到最后,希望您能觉得不虚此行,也欢迎您和我交流您阅读后的感受或提出建议。祝您工作愉快。

团队介绍

我们是大淘宝技术前端用户增长团队,负责吸引淘宝的新用户,留存及转化等消费者运营业务,保障淘宝的DAU提升及大盘活跃,探索淘宝的增长方法论,沉淀增长平台,打造智能数据驱动的用户增长引擎,支撑集团多APP矩阵共同增长;

我们有什么?我们有服务集团APP矩阵的拉端引流技术体系,全链路用户触达及干预的承接页搭建中心,帮助产品不断迭代试错及优化的AB实验体系,提升用户活跃的玩法平台等。