PostHog:新功能先给谁用,之后要看什么
PostHog把产品分析、会话回放、实验与功能开关放在一起。团队可以先向一部分用户开放新功能,再结合使用事件、回放和异常判断是否继续扩大。
先尝试拆解问题、设计和实现,再展开思路,检查状态、边界与取舍,并设计验证用例。思路提供分析路径,不给出完整实现。
01
代码思考进阶
多次放量变化,如何避免反复扫描所有用户?
练习场景
设计一个纯内存“放量影响预览器”。它不运行PostHog SDK,也不调用发布接口。假设目标人群已经固定,每个用户的分桶值由上游给定;你只处理很多次阈值变化,避免每次都扫描全部用户。
输入与输出合同
- users最多100,000项,每项为非null对象,含唯一非空字符串id和整数bucket,0≤bucket<10,000。桶值可以相同。其他字段忽略,输入只读。桶值已计算,不要求实现哈希,也不能假设分布均匀。所有ID总字符长度为L。
- initial为0到10,000的整数;targets为最多100,000个同范围整数。阈值t表示仅bucket<t的用户开启。每个target从上一次阈值变化,第一项从initial开始。10%用1000表示,100%用10000表示。
- 对每次变化输出beforeCount、afterCount、addedCount、removedCount,仅输出计数,不为每次构造ID列表。另给一个可选detailIndex,必须是targets中的合法下标;省略时无需详情。
- 只对detailIndex那一次返回实际新增或移除的ID,按原users输入顺序排列,分别放在addedIds和removedIds。不存在变化时两列表为空。其他步骤不能产生完整成员列表。
- 任何输入字段或下标非法、ID重复,整批报错并定位;不返回部分结果,不修改输入。只校验题面字段。空users、空targets都合法;targets为空时不能给detailIndex。
推演例子
users按顺序为A:100、B:1000、C:1000、D:2999、E:9000。initial=1000,targets=[3000,1000,1000,0,10000],detailIndex=1。请写出五步计数和详情ID;特别解释bucket恰好等于阈值时是否开启,以及相同桶的B/C如何变化。
再检查:(a)加入重复ID但桶不同;(b)交换users顺序但不改桶;(c)detailIndex缺省;(d)所有用户都在同一桶。不要把“提高到30%”误写成恰好30%的人命中。
交付物
提出一次预处理、批量计数和单步详情的方案,说明需要哪些索引或累积信息。要求避免O(nq)次完整扫描,分析n个用户、q次变化、10,000个桶、L和详情人数k的时间与空间。列出至少四个不变量,不写完整实现或逐行伪代码。
查看思路
- 先校验完整输入。 以ID集合检测重复并保存双方位置,桶与阈值必须在指定整数范围内。detailIndex要与targets长度一起校验,空数组不能被默认选中。
- 把问题转成“低于阈值有多少人”。 桶只有10,000种,可以统计每桶人数并建立前缀计数;阈值0对应0人,10000对应全部。也可排序桶值后做lower_bound,但无需为了排序而修改users。
- 相邻阈值只计算差量。 afterCount取新阈值前缀,beforeCount取旧阈值前缀。提高阈值只有新增,降低只有移除,不变则两者为0。相同桶的人一起跨过边界,不能拆成指定比例。
- 只扫描一次取得选定步骤详情。 对detailIndex对应的旧、新阈值,按原users顺序检查区间。原例计数依次为(1,4,3,0)、(4,1,0,3)、(1,1,0,0)、(1,0,0,1)、(0,5,5,0);详情addedIds为空,removedIds=[B,C,D]。
- 验证边界与成本。 ID重复整批失败;输入重排不改计数但按要求改变详情顺序;无detailIndex不扫描详情;同桶用户同时变化。始终有after=before+added−removed,且不能同一步既增又减,计数在0到n内,输入保持不变。令B=10,000,前缀方案平均哈希操作下O(n+B+q)时间,ID校验字符成本另计L;详情额外O(n+k),空间含ID索引、桶前缀与输出为O(n+B+q+k+L)。不能声称仅输出k个ID就只需O(k)时间。