應(yīng)用中不同的場景细疚、設(shè)計方案蔗彤,不經(jīng)過測試,你永遠(yuǎn)不知道消費(fèi)者會更偏好哪一種疯兼。面對隨時可能變更的產(chǎn)品需求然遏,開發(fā)人員如何才能在保證測試進(jìn)程的同時,讓工作也變得高效吧彪、省力待侵?
本章內(nèi)容,網(wǎng)易嚴(yán)選Android資深開發(fā)張云龍為您解讀《Android ABTest 的框架設(shè)計》
概述
什么是Android ABTest 姨裸?
AB測試是為web或app制作兩個(A/B)或多個(A/B/n)版本秧倾,在同一時間維度,分別讓組成成分相同或相似的訪客群組隨機(jī)訪問這些版本傀缩,收集各群組的用戶體驗(yàn)數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)那先,最后分析評估出最好版本正式采用。
在網(wǎng)易嚴(yán)選中赡艰,張云龍團(tuán)隊涉及的業(yè)務(wù)內(nèi)容基本分為兩類:
1售淡、純業(yè)務(wù)邏輯的測試。如:分享給微信好友瞄摊、分享微信小程序勋又、分享網(wǎng)頁。
但由于我們無法預(yù)判不同的業(yè)務(wù)場景對用戶拉新的助力效果如何换帜,所以這種情況下,會進(jìn)行AB測試鹤啡。
2惯驼、UI變化。下圖表現(xiàn)的就是一個UI的改變,“立即購買”和“加入購物車”的位置發(fā)生變化祟牲,當(dāng)然屬性也有變化隙畜,背景顏色也有替換。
本章內(nèi)容將圍繞四部分展開:
A/B/n設(shè)計與實(shí)現(xiàn)
ViewID實(shí)現(xiàn)與優(yōu)化
UI屬性動態(tài)修改
UI重排版與替換
A/B/n設(shè)計與實(shí)現(xiàn)
以上是一段常見的業(yè)務(wù)邏輯測試方案代碼说贝,從這個方案中可以發(fā)現(xiàn)存在以下問題:
業(yè)務(wù)上層開發(fā)的同學(xué)需要關(guān)心協(xié)議數(shù)據(jù)內(nèi)容议惰;
if/else方案出現(xiàn)重復(fù)代碼,當(dāng)產(chǎn)品上線后乡恕,測試版本發(fā)生變化時言询,會出現(xiàn)一個協(xié)議多處代碼隨時變化的情況,解決起來費(fèi)時費(fèi)力傲宜;
另外也容易出現(xiàn)歷史老版本兩端表現(xiàn)不一致問題运杭。
因此,做A/B/n的設(shè)計與實(shí)現(xiàn)時函卒,要注意以下方面:設(shè)計協(xié)議對接層規(guī)避 if/else
A/B/n 實(shí)例管理
后臺數(shù)據(jù)同步
多種生效策略
下圖是我寫的ABTest的實(shí)例辆憔,這是協(xié)議對接層的代碼,通過注解的方式报嵌,指定itemID虱咧。
在ABTest的更新邏輯中,涉及了立即更新锚国、熱啟動更新腕巡、冷啟動更新。
當(dāng)數(shù)據(jù)處于立即更新策略時跷叉,會自動調(diào)用基類接口 onUpdateConfig逸雹,協(xié)議對接層的同學(xué)只需要通過這個接口就可以實(shí)現(xiàn)需求,并可以通過注解來指定不同caseld下的初始化方法云挟。通過指定 defaultInit 注解梆砸,后臺的AB協(xié)議即使撤銷,業(yè)務(wù)層的執(zhí)行邏輯也能明確园欣。
這種通過協(xié)議對接層隔離業(yè)務(wù)上層和協(xié)議數(shù)據(jù)的做法帖世,能保證在協(xié)議數(shù)據(jù)發(fā)生變化的時候,業(yè)務(wù)上層代碼并不需要改動沸枯,避免了業(yè)務(wù)上層邏輯的頻繁多處修改日矫,以提高效率。
ViewID實(shí)現(xiàn)與優(yōu)化
ViewID的實(shí)現(xiàn)有兩點(diǎn)原則:
唯一性绑榴,是指同一界面中哪轿,各個控件的ID是唯一的、不同的
一致性翔怎,是指多次進(jìn)入同一個界面窃诉,控件 ID 是相同的杨耙、不變的。
初步有以下方案:
1飘痛、View.getId()珊膜。該方案可以排除,因?yàn)榇蟛糠挚丶?ID 是不會指定的宣脉,布局文件中指定了多次編譯也會發(fā)生變化车柠;
2、XPath塑猖,根據(jù)場景樹計算竹祷。大部分可視化埋點(diǎn)方案或無埋點(diǎn)方案都是用這種方法去做的,mixpanel萌庆、百分點(diǎn)溶褪、網(wǎng)易樂得和網(wǎng)易 HubbleData 使用的就是這種方案。
XPath優(yōu)點(diǎn)和缺點(diǎn)都非常明顯:
優(yōu)點(diǎn)是XPath對于業(yè)務(wù)層開發(fā)是完全無侵入的践险,無論是用xml生成布局還是通過動態(tài)生成猿妈,都可以計算XPath值;
XPath缺點(diǎn)是在多版本開發(fā)過程中巍虫,如果布局發(fā)生變化彭则,同一個控件的XPath值就會發(fā)生變化,無法保證跨版本的 ViewID 一致性占遥,會對后臺的數(shù)據(jù)分析產(chǎn)生麻煩俯抖。
3、得到 Android 提出的 TouchTarget 方案瓦胎,針對 XPath 的缺點(diǎn)做了改進(jìn):在用戶點(diǎn)擊時芬萍,可以根據(jù)當(dāng)前的 Activity 名字加上控件所在布局的資源名、ID資源名搔啊,拼湊起來得到它的 ViewID柬祠。
但這種方案會對業(yè)務(wù)開發(fā)產(chǎn)生入侵。
考慮到 ABTest 的場景中负芋,很可能不需要跨多版本收集數(shù)據(jù)分析漫蛔,我們采用 XPath 的方案。
UI屬性動態(tài)修改
如何動態(tài)地修改線上UI屬性旧蛾?
總結(jié)下來有以下幾點(diǎn):
利用 ViewID 定位控件莽龟;
修訂數(shù)據(jù)協(xié)議,修改控件锨天,修改屬性毯盈;
把握作用時機(jī)。要保證在客戶看到頁面之前就修改完成病袄;
可視化方式奶镶,生成數(shù)據(jù)和效果檢查
-
自定義控件和屬性迟赃。SDK 可以預(yù)置大部分常見屬性陪拘;而自定義屬性厂镇,可以讓業(yè)務(wù)層開發(fā)制定,包含兩方面:屬性的設(shè)置左刽、可視化編輯器增加編輯項(xiàng)捺信。
5.png
UI 重排版與替換
可以從上圖看到,A和B之間的修改并不只是屬性修改欠痴,布局也在發(fā)生變化迄靠。這其中涉及了兩點(diǎn):
定位控件,原布局阻斷喇辽,新布局算法應(yīng)用掌挚;
重布局后需要屬性設(shè)置繼續(xù)生效,所以ViewID不能變化菩咨。
類似上述這種場景吠式,假設(shè)有三個子控件,重新布局該如何做抽米?
實(shí)現(xiàn)其實(shí)非常簡單特占,我們只需要在中間加入StubCSSLayout(SDK 內(nèi)置布局控件),插進(jìn)去就可以起到承上啟下的作用(承上:阻隔原布局算法云茸,啟下:應(yīng)用新布局算法)是目。
想要 ViewID 在重布局前后不變,只需在計算 XPath 的過程中标捺,將 StubCSSLayout 忽略掉懊纳,就能保證這一點(diǎn)。
在實(shí)際操作中亡容,也可能遇到特殊需求嗤疯,這就要求創(chuàng)建新的布局。
ndroid 開發(fā)中萍倡,常用的 setContentView(@LayoutRes int layoutResID) 方式創(chuàng)建布局有如下幾點(diǎn)關(guān)鍵步驟:
根據(jù)ID得到文件路徑身弊,進(jìn)行布局;
根據(jù)路徑列敲,獲取long類型的xmlBlock阱佛;
構(gòu)建Java類XmlBlock;
清楚了原生流程戴而,通過利用 XmlBlock(byte[] data) 構(gòu)造函數(shù)凑术,構(gòu)建 XmlBlock 對象來實(shí)現(xiàn)布局下發(fā)和創(chuàng)建的功能。