線上問題已經解決,這就完事了?

1. 前言

做爲一名自信的 QA,對於測試經過的項目,若是有人反饋有問題,腦海中的第一反應必定就是:不可能!必定是操做有問題。入職以來經手大大小小的項目也有 40 多個,一直沒出過問題,也讓我在年度的總結上自信地寫到:全部項目按時按質發版,未出現線上問題。npm

可是,這種自信讓我掉以輕心,使得微信小程序 SDK 的第一個線上問題也隨之而來了。小程序

對於線上問題,可能不少人都覺得把問題解決了就完事了,並不重視對問題的覆盤。事實上,覆盤的做用可能遠大於解決問題自己。微信小程序

在神策的企業文化中重要的一項就是覆盤,每個問題對於咱們來講都是一筆寶貴的財富。經過對於問題的覆盤,總結經驗教訓,可以更好地促進咱們成長。微信

下面咱們來看下對於這個問題是如何進行復盤的。併發

2. 回顧目標

神策微信小程序 SDK 的目標是實現對於主流小程序開發框架的全埋點功能。可是,在測試過程當中發現因爲 Taro3.0 框架從新定義了標籤點擊行爲的邏輯,使得一次點擊行爲會觸發 SDK 的兩次點擊事件 $MPClick,形成了埋點數據重複。app

所以,此次發佈的 v1.14.3 版本旨在解決 Taro3.0 框架下點擊事件重複觸發的問題,實現神策微信小程序 SDK 真正意義上的無框架障礙全埋點採集。框架

3. 評估結果

3.1. 符合目標

  • 解決了 Taro3.0 框架下點擊事件重複觸發的問題;
  • 實現了神策微信小程序 SDK 真正意義上的無框架障礙全埋點採集。

3.2. 低於目標

  • 本次發佈的版本存在嚴重的線上問題。

4. 分析緣由

4.1. 回顧過程

  1. 2020 年 12 月 17 日 19 : 05 微信小程序 SDK 發佈了 v1.14.3 版本,新增了 $MPClick 事件可自定義屬性,修復了 Taro3.0 框架下點擊事件重複觸發的問題;
  2. 2020 年 12 月 18 日 16 : 27 技術顧問收到客戶反饋:微信小程序 SDK 更新到 v1.14.3 版本後,測試過程當中發現 SDK 篡改了他們方法的返回值,屬於破壞型 proxy;
  3. 2020 年 12 月 18 日 16 : 30 技術顧問查看代碼發現這個問題之前在支付寶小程序出現過,並和 QA 一塊兒復現了問題;
  4. 2020 年 12 月 18 日 16 : 35 問題同步給研發和 QA 組長,並分配下一步具體工做:QA 去 GitHub 上刪除對應版本代碼,研發組長協助刪除 npm 上的版本,研發開始修復問題;
  5. 2020 年 12 月 18 日 16 : 37 研發組長和 QA 完成版本刪除;
  6. 2020 年 12 月 18 日 16 : 45 研發修復完成,交由 QA 測試;
  7. 2020 年 12 月 18 日 18 : 05 QA 測試完成,併發布了最新的修復版本 v1.14.4,完成了線上驗證;
  8. 2020 年 12 月 19 日 11 : 31 技術顧問組長找出了全部使用問題版本 v1.14.3 的客戶並同步給技術顧問;
  9. 2020 年 12 月 19 日 15 : 00 技術顧問通知了全部使用 v1.14.3 的客戶,告知他們存在的問題並提醒他們更新版本。

整個問題的生命週期從 2020 年 12 月 17 日 19 : 05 發版,到 2020 年 12 月 19 日 15 : 00 全部客戶通知完成,總共歷時 44 個小時。能夠分爲如圖 4-1 中的 6 個階段:函數

image

圖 4-1 線上問題生命週期測試

此次問題是我經歷的第一個線上問題,此次經歷不只讓我完整了解到線上問題的處理流程,更讓我充分地感覺到各個環節上團隊人員的密切配合。從問題開始到問題解決,小程序團隊全員時刻處於待命狀態,每一個環節都爭分奪秒,確保了這次問題的快速修復,沒有形成較大的影響。this

回顧線上問題的整個過程以後,咱們須要分析產生這個問題的具體緣由。

4.2. 緣由分析

4.2.1. 自動採集點擊事件

在進行具體的緣由分析以前,咱們先來看下神策微信小程序 SDK 自動採集點擊事件的原理。

一、在重寫 Page 函數時,先經過 _.getMethods 獲取除 Page 鉤子之外的自定義事件處理函數集合 methods:

`Page =` `function` `(option) {`

 `//` `先判斷 mpClick 是否配置自動採集,若配置爲真則獲取自定義方法並代理重寫`

 `var methods = sa.para.autoTrack && sa.para.autoTrack.mpClick && _.getMethods(option);`

 `if``(!!methods) {`

 `for``(var i = 0, len = methods.length; i < len; i++) {`

 `//` `對 methods 集合的每個自定義事件處理函數進行重寫`

 `click_proxy(option, methods[i]);`

 `}`

 `}`

`}`

`//` `_.getMethods 方法,獲取用戶自定義的全部事件`

`_.getMethods =` `function``(option) {`

 `var methods = [];`

 `for` `(var m` `in` `option) {`

 `if` `(typeof(option[m])===``'function'` `&& !mpHook[m]) {`

 `methods.push(m);`

 `}`

 `}`

 `return` `methods;`

`}`

二、對 methods 集合的每個自定義事件處理函數進行重寫,獲取事件觸發時的 type 類型,type 爲 tap、longpress 或者 longtap 則觸發 $MPClick 事件,將 wxml 文件標籤中 dataset 定義的屬性做爲事件屬性:

`//` `點擊事件代理處理函數`

 `function` `click_proxy(option, method) {`

 `var oldFunc = option[method];`

 `option[method] =` `function``() {`

 `//` `在重寫 oldFunc 以前就已經判斷是一個方法類型,此處是作一次重複的校驗`

 `var res = oldFunc.apply(this, arguments);`

 `var prop = {},`

 `type` `=` `''``;`

 `if``(_.isObject(arguments[0])) {`

 `//` `將 wxml 標籤中 dataset 定義的屬性做爲事件屬性`

 `var dataset = current_target.dataset || {};`

 `type` `= arguments[0][``'type'``];`

 `prop[``'$element_id'``] = current_target.``id``;`

 `prop[``'$element_type'``] = dataset[``'type'``];`

 `prop[``'$element_content'``] = dataset[``'content'``];`

 `prop[``'$element_name'``] = dataset[``'name'``];`

 `}`

 `if``(``type` `&& _.isClick(``type``)) {`

 `prop[``'$url_path'``] = _.getCurrentPath();`

 `sa.track(``'$MPClick'``, prop);`

 `}`

 `return` `res;`

 `}`

 `};`

`//` `點擊類型判斷方法`

`_.isClick =` `function``(``type``) {`

 `var mpTaps = {`

 `"tap"``: 1,`

 `"longpress"``: 1,`

 `"longtap"``: 1,`

 `};`

 `return` `!!mpTaps[``type``];`

`}`

點擊事件的自動採集不只能採集到用戶的點擊行爲,還能自動採集點擊標籤的相關屬性。
只要在 wxml 文件的標籤中經過 data- 定義的屬性均可以採集到,能夠自動採集的屬性如表 4-1 所示:
image
表 4-1 自動採集的屬性

建議在元素中定義 id 、data-content、data-name 這三個元素之一做爲元素標識,若無這三個屬性,則在神策分析平臺沒法進行標識。

接下來,咱們來看一個自動採集點擊事件的例子。

一、配置以下的 button 標籤:

`<button bindtap=``"test"` `data-name=``"button"` `id``=``"button"` `data-content=``'button'` `data-``type``=``"button"``>測試<``/button``>`

二、點擊 button 後觸發的事件內容以下所示:

`{`

`"distinct_id"``:``"1610349175397-726909-0e567a51188708-20891891"`

`"lib"``:{`

`"$lib"``:``"MiniProgram"`

`"$lib_method"``:``"code"`

`"$lib_version"``:``"1.14.4"`

`}`

`"properties"``:{`

`"$lib"``:``"MiniProgram"`

`"$lib_version"``:``"1.14.4"`

`"$network_type"``:``"wifi"`

`"$manufacturer"``:``"devtools"`

`"$model"``:``"iPhone 6/7/8 Plus"`

`"$screen_width"``:414`

`"$screen_height"``:736`

`"$os"``:``"devtools"`

`"$os_version"``:``"10.0.1"`

`"$timezone_offset"``:-480`

`"$app_id"``:``"wx82a49f7cb5547449"`

`"$url_path"``:``"pages/index/index"`

`"$element_id"``:``"button"`

`"$element_type"``:``"button"`

`"$element_content"``:``"button"`

`"$element_name"``:``"button"`

`"$is_first_day"``:``false`

`"$ip"``:``"117.71.111.48"`

`"$browser"``:``"WeChat"`

`"$browser_version"``:``"7.0.4"`

`"$is_login_id"``:``false`

`"$city"``:``"合肥"`

`"$province"``:``"安徽"`

`"$country"``:``"中國"`

`}`

`"anonymous_id"``:``"1610349175397-726909-0e567a51188708-20891891"`

`"type"``:``"track"`

`"event"``:``"$MPClick"`

`"time"``:1615194119222`

`"is_login_id"``:``false`

`"map_id"``:``"1610349175397-726909-0e567a51188708-20891891"`

`"user_id"``:-8183290914376425000`

`"recv_time"``:1615194119222`

`"project"``:``"gongcheng"`

`}`
  1. 至此,咱們能夠看到自動採集了 button 的點擊事件。

4.2.2. 具體緣由

瞭解了微信小程序 SDK 是如何實現自動採集點擊事件的原理,這次問題的緣由就比較容易分析了,下面咱們看下致使這次問題的具體緣由是什麼。

一、首先咱們須要瞭解下小程序的頁面邏輯,每一個頁面都有一個單獨的 JS 文件爲頁面組件添加執行邏輯,全部方法都寫在 Page( { } ) 中,主要包含三個部分:頁面的初始數據,小程序自己帶有的生命週期函數和自定義的函數方法。例以下面示例中定義的兩個方法 testA 和 testB:

`Page({`

 `/**`

 `* 頁面的初始數據`

 `*/`

 `data: {`

 `},`

 `/**`

 `* 生命週期函數--監聽頁面加載`

 `*/`

 `onLoad:` `function` `(options) {`

 `},`

 `/**`

 `* 自定義方法 testA`

 `*/`

 `testA:` `function` `() {`

 `console.log(``'執行方法 B'``,this.B())`

 `},`

 `/**`

 `* 自定義方法 testB`

 `*/`

 `testB:` `function` `() {`

 `return` `'執行方法 B'`

 `}`

`})`

二、根據上一節提到的點擊事件自動採集原理,咱們對客戶小程序的全部自定義方法進行了重寫代理,判斷 type 類型爲點擊時觸發 $MPClick 事件,但前提必定是不能影響客戶自定義方法的執行;
三、小程序 SDK v1.14.3 版本在更新現有邏輯時,修改了代理方法的返回值,由返回客戶方法的執行結果改爲了直接返回 false,如圖 4-2 所示:
image
圖 4-2 小程序 SDK v1.14.3 版本代碼 diff 圖
四、這就使得上面代碼中 Page 自定義的方法 testB(),本來客戶業務邏輯是 「return '執行方法 B'」,可是通過咱們 SDK 的方法重寫,變成了 「return false」。
五、testA() 原本應該打印出 testB() 中定義的返回值,不過因爲 SDK 代理使得 testB() 返回 false,致使 testA() 的執行結果不符合預期,如圖 4-3 所示:
image
圖 4-3 testA() 的錯誤執行結果
正確的業務邏輯執行結果應該如圖 4-4 所示:image
圖 4-4 testA() 的正確執行結果

4.2.3. 解決方案

知道了問題的緣由以後,解決問題就比較容易了。只須要在代理客戶方法時修改返回值爲客戶原來方法的返回值,如圖 4-5 所示:
image

5. 總結規律

5.1. 經驗教訓

雖然這次線上問題的緣由比較簡單,可是通過深入的檢討以後,我總結了以下幾點經驗教訓:

  1. QA 對代碼的改動須要具備敏銳的感知,要詳盡追究每行代碼改動的目的。對於代碼的 diff,必定要知其然,知其因此然。QA 可能不須要編寫很複雜的代碼,可是必定要能看懂代碼,不然測試覆蓋率必定不高;
  2. 這次問題的發生主要在於 QA 的測試 case 未覆蓋到方法的返回值,對於小程序基本原理理解的不夠深刻。所以,QA 須要對測試的業務很是熟悉,經過業務屬性探索測試 case;
  3. QA 沒有遵照流程,在研發組長沒有給出 code review 經過的回覆以前,就直接開始測試。這樣使得測試代碼是未通過 double check 的,很容易出現問題;
  4. 這次問題屬於再犯,以前在其餘小程序上也出現過一樣的問題。這種再犯的問題是最可怕的,代表了沒有對出現的問題作好總結。對於 QA 而言,須要將漏測的 case 加入迴歸測試的 case 中,按期對迴歸測試的 case 進行總結。

5.2. 問題

經過這次線上問題暴露了本身做爲一名 QA 所存在的一些問題:

  1. 對於 SDK 代碼和小程序基本原理還不夠熟悉;
  2. 對於代碼的改動沒有追根究底,相關邏輯的瞭解不夠充分;
  3. 沒有嚴格遵照測試流程;
  4. 沒有及時總結已有的問題,致使一樣的問題再次出現。

5.3. 改進

通過這次線上問題的覆盤,有以下行動做爲改進的方向:

  1. QA 在 2021 年的 Q1 季度完成對微信小程序 SDK 代碼的熟讀,研發負責組織 2 次以上針對 QA 的小程序基本原理培訓,從而讓 QA 和研發在代碼理解上達到水平一致;
  2. 研發在之後項目中須要詳細評估改動,準肯定位影響範圍,並在相應的提測郵件上重點備註,讓 QA 能更詳盡的設計測試 case;
  3. 這次問題以後,QA 和研發都須要嚴格遵照開發測試流程,相互監督,毫不在任何一個流程環節中出現越界或者違規;
  4. QA 在 2020 年 12 月底以前完成對這次問題的詳細總結,並把漏測的 case 加入到迴歸測試 case 中,防止再次出現一樣的問題。

6. 結語

本文經過對於一次線上問題的覆盤,介紹了覆盤的總體流程,但願經過本文能給你們提供一些覆盤相關的參考。

相關文章
相關標籤/搜索