AB_test是一个常用方法和面试考点,本文通过基础讲解+重点提示+案例分析的方式进行讲解:

如果你没什么统计学的知识或者忘干净了,可能需要先去充充电,不过需要的统计学知识并不太多,也可以硬背,达到使用目的即可...

一、基本介绍

1.1 Why:为什么要用它

比如更新了一个新功能,是否会对产品有正向作用,主观猜测可能会犯错误,此时进行假设检验:

原假设H0:老方案和新方案无区别,备择假设H1:老方案和新方案有区别(双尾检验,\neq,更严格

原假设H0:老方案>=新方案,备择假设H1:老方案<新方案(单尾检验,我们想通过反证法,推翻原假设,证明新方案确实有效,标准宽松一些

通过构造检验统计量,应用Z值法或者P值法,以数值的形式确定结果。

企业最终目的,铁定是赚更多钱,或者未来能赚更多,现在有个例子:

你是一个卖清洁剂的,老方案是网站显示的缩略图,是一张高清产品正面实拍图,新方案是带着使用场景,喷一下让人感觉厨房焕然一新的图;产品经理或者team leader认为,用新方案会让更多用户点进来看,从而间接提高销量;

但是这种说法不能让人信服,此时通过AB_test,如果新方案通过AB测试验证后,带来的点击率更高,证明了用户更喜欢有场景演示的图,则采用新方案;否则还是用旧方案,证明用户喜欢看产品高清图,不喜欢那些看似花里胡哨的东西;

*注意:AB测试,验证的是直接指标,即看到图后,是否会被吸引而点进来,可以说是点击率或者点击数量,如果将指标变为店铺该产品的销售额,则是错误的,一是销售额是看到图片点进来--查看产品情况--考虑价格--其他环节--下单购买不退单等之后的结果,二是销售额,受到价格、产品品牌、影响力、图文宣传力度等多方面影响,不能一口吃个大胖子,必须是验证直接效果指标;

现在团队里有技术手段,让一部分人看到的还是老方案的图,毕竟以前都是用这个,让另一部分人看到新方案的图,通过对比看到图后,点进来查看详情的点击率,来验证新方案是否可行;

此时要注意:

1.AB测试往往不是两个方案,各取50%的流量展现,因为实际过程中,我们可能同时在优化很多个功能,即在进行多个AB测试,不可能让一个测试占据这么多流量。

2.新方案经常会先进行灰度实验,即用只选择一小部分群体,先试试水看看效果,万一新方案非常糟糕,不至于损失很大,毕竟老方案是之前就经过验证并且用过很久的;

3.一般较少用绝对值指标,测试我们一般会小心谨慎点,比如大部分用户看到的还是老方案,少部分看到的是新方案,老方案的点击人数,一般肯定要大一些,转为概率才有比较性;

1.2 Who 对哪些用户进行测试

此时考虑对哪些用户进行测试,即哪些用老方案,哪些用新方案:

AB测试,经常是同时在进行多个,是否有互斥?比如上述例子中(称为一号测试),首页商品图,用产品高清图还是使用场景图。

比如还有个AB测试(称为二号测试),首页上,是否显示优惠和价格信息,老方案写功效,新方案写最新价格信息,图就那么大,字不可能太小,只能选择放一个信息,我们想看放哪个信息进店率比较高;那么二号和一号是互斥的,两者都是影响点进店铺详情的概率;

有的测试是不互斥的,比如进店之后,详情页第一页(称为三号测试)。  

我们研究看了第一张详情页后,是否继续往下看的续看率,老方案是宣传我店铺是老店、卖的是好产品,你可以信任我这家店;新方案是宣传产品使用功效,通过图片展示污垢带来的麻烦,引起消费者共鸣,从而产生今个儿我必须把它买了的情感。一般可以认为,第一张详情页图片很重要,如果消费者看到第一张图,感到很不靠谱就不想继续往下看,销售额肯定不好,通过对比两种方式,如果哪个方案能让消费者继续往下看,往往更容易将产品卖出去;此时消费者已经点进来了,与上一层就没太大业务关联了;

1.3分层分流

此时引入新的关键点:分流分层

为什么有这个东西:分流分层,说直白点,就是小公司,流量没那么多,就要想办法让很多个AB测试同时进行,又不会互相造成影响,想尽一切办法把这么些流量重复用来用去;对大公司来说,就是追求效率和准确性,不让分流的用户差异很大,一边很多富二代有钱人,一边大都是穷人,财富只是一个形象的举例说法

1.简单分流,一号、二号测试都是关注是否点进店铺,如我们通过后台软件,知道用户的customer_id,我们在一号测试中,尾号为0,1的用新方案,2-4的用老方案,二号测试中,5,6号用新方案,7-9用老方案;

优点:实现简单 缺点:如有多个互斥实验,则流量不够用,并且简单的用户ID分流,此处仅为举例,不一定准确

2.简单情况下的分层,比如各组AB测试,并不互斥,举个例子:

比如一号测试,点进店铺详情页率,三号测试,续看率,两者并不影响,在进行三号测试时,用户已经点进来了;

此时还有四号测试,详情页总体长度对下一步点开评价页的影响,看完详情页面,消费者要么去看评价,要么去看价格页面,要么走人。太长对导致有些人看得没耐心,好处是介绍全面。我们有一个老方案篇幅比较长,介绍很全,新方案篇幅短而精,注重讲要点;如果我们认为消费者购买之前,会看看评价情况,故四号测试直接效果指标可定为继续查看评价率,或者说是查看价格详情页面的概率;

那么一三四号测试,关联度不大,简称不互斥,同一用户可以在这三个测试里面都存在,好处是流量可以重复用。

3.现实情况下分层分流的交叉嵌套,上述例子,仅有四个测试,实际上同一层次,比如是否点进店铺页面,可能存在多个方案多个AB测试同时进行,下一层亦是如此,互斥情况下,简单的分流,我们没那么多流量可用;

此时,可以采用:

(1)先分流再分层,最先一步的AB测试,根据有多少个测试,划分一次,当用户已经完成第一步,第二步跟第一步没太大关系,第二步使用已有的全部流量,再根据有多少个测试再划分,这样第二步也用了全部流量;

(2)目前多用hash分流,分流这块内容其实不少,本文不细说了,要研究多看看其他的;

1.4 重点关注

需要注意的是:

在AB测试前,可能会先进一波AA测试,判断两组用户,在使用同一种方案系,点击率是否有明显区别,若无,则证明用户分流并无显著区别;

实验中,除了我们要研究的变量,其他可能影响结果额变量应保持一致,说简单点,即不能一边男的多一部分女的多,因为男女在购买、使用某些产品的时候,经验都能告诉我们,有明显差异。不能一组多是北上广,一组多是十八线小城市,一组多是某东VIP大会员,一组多是某多多刷券高手;即保持AB两组的用户,没有明显区别性,各标签、画像要比例基本相同,否则会导致辛普森悖论

此处搬运一个例子:

一所大学的两个学院,商学院和法学院。新学期招生,人们怀疑这两个学院有性别歧视。两个学院的招生统计数据汇总如下:

单独看两个学院,都是女生录取率高,但是合并汇总后,发现女生的录取率居然还不如男生,简直是气抖冷;

原因很简单,男生虽然在法学院遭遇重创,但是在商学院总数多,并且录取率并没有低太多,而女生在商学院申请总数少;

这个例子意思是,我们在进行AB测试中,如果有某个变量分布不均衡,比如男、女生数量比例问题,会导致我们的实验结果看起来很对(单看哪个都是女生高),汇总后实际结果相反(新方案应用后效果变差),可能某个因素看起来对结果没什么影响,但实际他有影响,有些影响因素并不像性别、地域、收入那么显而易见,你可能并没有收集到这个因素的信息或者没有察觉到它的存在,故AA测试可从结果上证明,两个分组并无太大区别。

二、关键数值计算

一般AB测试分为两种,绝对值型和概率型,本文主要写概率型,绝对值型的公式亦附在后面;

有个网站可以很方便地计算:Evan's Awesome A/B Tools - sample size calculator, A/B test results, and more

2.1前期定下的数值

我TM裂开,公式居然不能直接复制,我是在markdown上写的,直接上传还一堆错误,郁闷了。

 一些基本的统计学知识不太详细讲,相信大家都知道;

前期,要明确的几个基本变量名字及含义:

(1)\alpha 犯弃真错误的概率

即H0原假设为真时,拒绝H0选择了H1的话,犯错误的概率,常取alpha=0.05,或0.1和0.01

(2)1-\alpha,置信水平,即不犯弃真错误的概率,因为我们要保证我们的决策,至少9成以上是对的。

(3)\beta 犯取伪错误的概率,

即H0原假设为假时,接受H0拒绝H1的话,犯错误的概率,一般取beta=0.2

在固定样本量的情况下,不能使两种错误都降低,两者犯错误概率呈此消彼长状态;

那为什么不增加样本量呢?因为有成本,增加样本量无非是测试更久、分配更多用户给这个AB测试,要占用资源的。一般地,我们严格控制alpha,对beta稍微宽松一些。

为什么?比如原假设H0:老方案>=新方案,备择假设H1:老方案<新方案。

如果原假设为真,即老方案更好,我们测试结果显示新方案更好,上线新方案,实际上选择了效果差的,那我们可能失去五百万;

如果原假设为假,即实际上老方案没有新方案好,我们取了伪,还是认同老方案好,那我们可能错过一个亿。

换做生活中的你,可能失去五百万,可能错过一个亿,你选哪个?一个亿我们本来就没有,但五百万是我们荷包里的钱,所以对待alpha我们要求更严,在抓一个就必须放下另一个的情况下,我们选择严抓alpha.(比喻略夸张,话糙理不糙)

同时,统计学上习惯,先把alpha死死搞住,再考虑beta的事;

(4)1-\beta,统计功效,亦称POWER,当alpha,beta固定下来,则标准正态分布Z_{1-\frac{\alpha}{2}}Z_{1-\beta}的值就固定了。

from scipy.stats import norm
# alpha=0.05
# beta =0.2
norm.ppf(0.975) = 1.96 #1.95996
norm.ppf(0.8) = 0.84   #0.8416

(5)p=可理解为原假设为真时样本出现该情况的概率

AB测试本质是反证法,如果H0原假设为真,出现了极小概率事件,我们则可拒绝H0,此时犯错概率较小

(6)d,预期目标变化量,是\delta--delta的缩写,the number you wish to detect,假设我们经过努力,想从5%的点击率,到8%,那么就是3%,我们的目标并不一定是要增长3%,但就AB测试而言,需要定下一个d;

假如之前的点击率是5%,我们想测试点击率有没有到50%,这就很明显,因为点击率从来就没有到50%;那测试是否到10%,发现偶尔有那么一天会到10%,显而易见,基本不可能到10%的;测试是否到5.1%,这么细微的差别,就需要更多的样本来佐证,测试是否到5.001%,这明显就要更多的样本才能得出确定的结论,所以这个d的精度,决定了需要多少样本量。简单来讲,想验证得更精确,样本数就要求更多。

同时,优化需要消耗人力财力,如果消耗过大但提升过小则不一定要优化,即我们要看看我们的努力是否达到了预期,该值一般团队协商定义,一般不会取太大,很难一个优化就起飞;

重点:我们搞测试要避免犯弃真错误取伪错误,弃真错误可以通过设定alpha的值搞定;而取伪错误,则对样本量和delta--d有要求,所以上面有一个d;根据统计学书上讲的,OC函数,如果d太小,样本量需要极其之多,还不一定能有效证明两者却有差异;所以d不要搞太小,样本容量公式如下(AB测试用的Z检验,t检验对样本容量又是另一套了,本文不讨论):

了解不追求完全搞懂,讲得准确点:样本容量的多少,公式依赖于alpha,beta和sigma和d,而Alpha基本都是0.05或者0.01,β习惯定0.2,Sigma又是样本或者总体的标准差,必须要定一个d,才能确定样本容量;

用公式的话:\sqrt{n} \geq \frac{(Z_{1-\alpha} + Z_{\beta})\sigma}{d}

如果是双边检验的话,上面的Z变成1-0.5 α,当然这个公式跟下面的公式,并不完全相同,这属于学究派,讲究百分百正确,实践过程中,大家都没有搞这么准确,知道即可,按照下面的公式来

2.2过程中数值

需要多少样本量,太少结果不可靠,统计学上都无法通过,太多会增加成本、时间,但也不能太多,万一你的新点子是个馊主意呢;

同时要注意实验一般至少要一周,通常为2-3周,根据该功能改变的重要性确定,满一个整周是为了避免指标的周期性效应,比如工作日与周末之间的差异可能会比较大;

同时注意界面改版,那种一眼能让用户看出来了,可能会有个适应阶段,可能还要加长时间;

同时AB测试也具有一定的时效性,比如推出一个新玩法,一开始用户觉得很新鲜,后来逐渐识破套路,如某“砍一刀”,发现根本就砍不完,会从活跃人数很多到逐步锐减;

(1)大致计算,推荐

可以在测试前,预估一下需要多少样本量:

令k=n_a/n_b

即两组样本比值,一般两组样本差距不会太大,经常定为1:1

此时假设两组方差相等,都用历史数据的方差,此时又假设AB两组样本量比值=分配的流量比值,比如各10%的流量,则K=1,则需要的实验组最小样本量:

(2)刨根究底细算,不推荐

硬要算准点,要在过程中根据情况,动态查看需要多少样本量,才能把结果定下来:

很明显,我们不能假设对照组(老方案A组)与实验组(新方案B组)具有相同的均值及方差;

 

2.3 结果指标

 

(1)Z值法

一般进行AB测试的样本数都较多,基本用Z值法判断,T值法在数量大的情况下,结果同Z值法;

 

为什么Z值这么计算,此时再多的言语已经无法说明,让我们翻开书本《概率论与数理统计》(浙大第五版)

 

 

 相信看到上述3张图,你已经完全彻底明白了,如果不明白,记住就行了。

# 标准正态分布中,一个数值出现在正负1.96之外的概率,合计小于5%
# 故原假设正确的情况下,Z值会在靠近中间处
from scipy import stats
x = np.linspace(-5,5,num=2000)
y1 = stats.norm.pdf(x,loc=0,scale=1)
plt.figure(figsize=(8,6))
plt.plot(x,y1,label='N(0,1)')
plt.title('Z--标准正太分布')
plt.xticks(range(-5,6,1))
plt.axvline(x=-1.96,color='r',ls='dashed')
plt.axvline(x=1.96,color='r',ls='dashed')
plt.legend()

如果此时Z太大太小,我们可以认为,如果原假设正确,居然发生如此小概率事件,我们拒绝原假设,大概率上是对的,如果Z值在接受域内,我们无法从统计学上拒绝原假设,即使P_b的确是大于P_a的,此时应该继续观察,即增加样本量,如果还是无法拒绝,则认为两方案没有明显区别;

 (2)P值

算出Z值,可以手算P值,假设Z=1.5

print(norm.cdf(1.5))  # 0.933
p_half = 1-norm.cdf(1.5)  # 0.0668
# 双尾检验中,要乘2
p = 2*p_half # 0.1336

p值较小,比如小于alpha,则可拒绝原假设,接受备则假设H1,在较为明显的区别中,p值往往极其小,P值法跟Z值法是一个道理,只是转化了一下比较的数值;

(3)效应量 effect size

如果说Z值或者P值能让你确定两个方案是否有区别,那么effect size可以告诉你,差异有多大,之前计算的合并标准差,此时发挥作用了;

既然最优选择是粗略地计算而非刨根究底地算,那就都粗略算,大家基本都是这样算滴,结果有点差异,但并不大;

复制一下别人的PPT,公式真多。

(4)MDE,Minimum Detectable Effect,最小检测效应,也称检验灵敏度;

这个指标很容易让人混淆,即便是英文含义也是,并且很多文章、包括某引擎官方都没有搞明白,当然不排除有些人写东西只是ctrl+C。

Minimal Detectable Effect (MDE) Minimal Detectable Effect is the minimum difference in performance between the control and treatment groups that can be detected by the A/B test, given a certain statistical significance threshold and power. The MDE is an important consideration when designing an A/B test because if the expected effect size is smaller than the MDE, then the test may not be able to detect a significant difference between the groups, even if one exists. Therefore, it is useful to calculate the MDE based on the desired level of statistical significance, power, and sample size, and ensure that the expected effect size is larger than the MDE in order to ensure that the A/B test is able to accurately detect the difference between the control and treatment groups.  

上面这段话的意思很直白,只有效应量effect size>MDE,则你的AB测试能够准确地检查两个方案的差异,当然,实践中可能并没有那么严格,咱们讲的是100%确定,则必须进行这一步。

(5)置信区间,confidence interval

需要注意的是,如果alpha=0.05,则Z是负的-1.96那个数字,有些文章、书本写的是Z_{1-\alpha/2},即正的1.96,前面换成p_b - p_a,下面的案例中将演示这种骚操作。

$CI = (p_a - p_b)\pm Z_{\alpha/2}\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}$

2.4 分析定论

出结果,接受还是拒绝H0,P值,置信区间,效应量(effect size)和MDE这两个要写最好一起写出来,要么都不写;

AB测试结果是单纯地针对某一个直接指标而言,比如某厂推出游戏充值VIP8即变强,VIP88可吊打对面,VIP888即可横着走,短期看营收会增加,但很多不想冲那么多的玩家会愤而退出,导致活跃用户数降低;即便AB测试结果的直接指标暴涨,但会导致其他间接指标暴跌,此时要进行取舍权衡。

2.5 绝对值型的

绝对值型和概率型,不同之处在于sigma标准差或者说方差的计算:

数值型的方差则是:

$\sigma_a^2=n_a*\frac{\sum(x_i-\overline x)}{(n_a-1)}$

$\sigma_c^2 = \frac{(n_a-1)\sigma_a^2+(n_b-1)\sigma_b^2}{n_a+n_b-2}$

样本量预估同绝对值型

Z值:

$Z=\frac{\mu_b-\mu_a}{\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}}$

P值由Z计算而来,故同;

CI置信区间由正态分布累积分布函数计算,故同

2.6 补充

1.如果新方案和老方案,均值看起来的确有差异,统计学上无法做出定论,可查看CI,比如置信区间始终是正数,如果不是非常重要的改动,并且时间上要求快,则可采纳新方案;

2.再退一步,如果新方案始终略高老方案一点,亦可采纳,毕竟始终朝着更好的方向走,终归是好的;

3.由于AB测试很频繁,故要在战术上重视他,在战略上藐视它,并非必须百分百确定才能上线,并非必须达到预估的3%的提升才行,提升1%也是提升。一个按钮从方形变成圆形,一个图标从红色变成渐变橙色,一些小事都要很久才能定夺,反而得不偿失,要在大方向、重要战略上占据优势;

三、案例

3.1纯手算

从别人那里扒了一份数据:

数据源:一文入门A/B测试(含流程、原理及示例) - 知乎 (zhihu.com)

比如新老页面

\sigma_a^2=p_a(1-p_a)*n_a/(n_a-1)

\sigma_b^2=p_b(1-p_b)*n_b/(n_b-1)

n_old = 145274
n_old_click = 17489

n_new = 145310
n_new_click = 17872

p_old = n_old_click/n_old # 0.1203863045004612
p_new = n_new_click/n_new #  0.12299222352212512
# 点击率从0.12038增长到0.12299
sigma_old = p_old*(1-p_old)*n_old/(n_old-1) # 0.10589417111639075
sigma_new = p_new*(1-p_new)*n_new/(n_new-1) # 0.10786587879080153

$Z=\frac{p_a-p_b}{\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}}$

Z =  (p_old-p_new)/np.sqrt(sigma_old/n_old + sigma_new /n_new ) # -2.14841779404773
# Z小于 -1.96 在拒绝域,拒绝原假设,两方案有区别
p = norm.cdf(Z) # 0.015840290231178385 <0.05

$\sigma_c=\sqrt{\frac{(n_a-1)p_a(1-p_a)+(n_b-1)p_b(1-p_b)}{n_a+n_b-2}}$

cohen`s d = \frac{p_1 - p_2}{\sigma_c}

sigma_c_sqrt  = np.sqrt((p_old*(1-p_old)*(n_old-1) + p_new*(1-p_new)*(n_new-1))/(n_old+n_new-2))
# sigma_c_sqrt = 0.32692416776388156
ken_d = (p_old-p_new)/sigma_c_sqrt # -0.007971019822388976

$MDE=(Z_{1-\alpha/2}+Z_{1-\beta})*\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}$

mde = (norm.ppf(1-0.05/2) + norm.ppf(1-0.2))*np.sqrt(sigma_old/n_old+sigma_new/n_new)
# mde = 0.0033981771287316235
# ken_d绝对值0.0079 大于0.003398
# 比较绝对值就行了,此处符合条件

$CI = (p_a - p_b)\pm Z_{\alpha/2}\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}$

置信区间正规计算方法:

diff = p_old-p_new
print('老方案-新方案:',diff)
temp=norm.ppf(0.05/2)*np.sqrt(sigma_old/n_old+sigma_new/n_new)
print('右半边是:',temp)
print('置信区间:',diff + pp,diff-pp)
# 老方案-新方案: -0.002605919021663919
# 右半边是: -0.0023773343542581294
# 置信区间: -0.004983253375922049 -0.00022858466740578948

因为norm.ppf(0.05/2)是负数,开根号里绝对正数,所以公式右边绝对是个负数,在AB测试中(单尾,左尾,即H1假设是新方案>老方案),可以定死,下限是+,上限是- ;当然统计学功底略浅,记住算出两个数,小的放左边,大的放右边即可。

置信区间骚操作方法:主要是有些文章,可能作者写的时候提前知道答案,直接用了比较方便的方式计算。

$CI_2 = (p_b - p_a)\pm Z_{1-\alpha/2}\sqrt{\frac{\sigma_a^2}{n_a}+\frac{\sigma_b^2}{n_b}}$

比如此时我们明知新方案要好点,不喜欢搞一堆负数的,也可以这样,反正正态分布两边是对称的,说白了将数字全部乘了-1,注意要将正态分布的Z临界值从左边换到右边,同时上下限+和-要对调,当然你完全可以无视这个CI_2,这属于是有经验的瞎搞、骚操作。

写第二种方法,主要是很多文章,写的时候作者肯定已经提前知道结果,所以在计算Z值的时候,用的就是p_新 - p_旧,也没毛病,但注意要把$Z_{\alpha} $换成$Z_{1-\alpha} $,正态分布左边曲线下面积对应临界值(X轴上的数)肯定是负数,换成正数,如果统计学基础没学到基本的融会贯通,建议死死按照常规方法来搞,避免出错,不是每个新方案都比旧方案好。

ci_down = (p_new-p_old)-norm.ppf(1-0.05/2)*np.sqrt(sigma_old/n_old+sigma_new/n_new)
ci_ceil = (p_new-p_old)+norm.ppf(1-0.05/2)*np.sqrt(sigma_old/n_old+sigma_new/n_new)
(0.00022858466740578991, 0.004983253375922048)
# 可知置信区间没有包含0,即可以做出新方案要好一些

3.2 现成方法算

我们发现纯手算比较麻烦,也有现成的库可用

import statsmodels.stats.proportion as sp
# alternative='smaller'在两个样本对比
# 意味着备择假设是 p_new > p_old
z_score,p_value = sp.proportions_ztest(count=[n_old_converted,n_new_converted]
                                       ,nobs=[n_old,n_new],alternative='smaller')
print('检验统计量z:', z_score, ',p值:', p_value)
检验统计量z: -2.1484056695589 ,p值: 0.015840771394875417

不过effect size和MDE,好像没找到什么库能自动算,反正就这简单几步,写个函数即可。

在数据源那里,可以看作者的案例详解...

不足和错误之处,敬请指正

参考:

1.《概率论与数理统计》浙大第五版

2.open-guide-to-ab-testing.v1.0.pdf (growthbook.io)

3.数据科学 | 绕不过去的 AB 实验基本功 + 手撕真实应用案例集锦(附代码和示例) - 知乎 (zhihu.com)

4.A/B测试(AB实验)的基础、原理、公式推导、Python实现和应用 - 知乎 (zhihu.com)

5.A/B测试系列文章之怎么计算实验所需样本量 – Jeff的数据科学笔记 (jeffshow.com)

6.从案例实战看AB Test系统设计及其原理 | 人人都是产品经理 (woshipm.com)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐