記一次返工之後記
記一次返工之後記
作者:Grey
時間:2018-11-25
原文地址: https://www.cnblogs.com/greyzeng/p/10018247.html
說明
之前做的功能, 又有新的需求了,原先的需求是支援某個型別的待辦審批,現在是要支援系統所有型別待辦的審批,雖然之前的程式碼寫的很匆忙,比較“醜陋”,但是好在未出什麼bug,新需求來了以後,我本想乘此機會重構一下自己之前寫的比較醜陋的程式碼,但是因為陸陸續續有插入進來的優先順序更高的任務,所以這個新需求一直被hold住,最後有一週的時間來做這個需求,由於要測試的流程比較多,而且建立流程的過程比較費時,為了給測試預留多一些時間,我放棄了重構的念頭,先快速實現需求,在保證原有功能和新增需求沒有問題的情況下,再一點點重構自己的程式碼。
原需求
有一個Web系統X,使用者可以通過這個系統檢視自己的待辦資訊,並且可以用於待辦的審批,還有一個我們做的手機應用Y,Y系統需要支援檢視X系統的待辦資訊並完成審批操作。
新需求
原需求裡面說的待辦資訊只是某兩個型別的待辦,實際上這個X系統有很多待辦型別,而且每個型別的處理邏輯,顯示元素都是不一樣的,我們現在要實現再Y上支援X系統的所有待辦型別的審批。
資源
- X系統的原始碼。
- X系統雖然不是我們公司做的,但是我司運維人員對於X系統的業務相對熟悉。
開發前的準備
為了避免上一次返工的問題之一:需求沒有梳理清楚。在寫程式碼之前,開發和測試都需要非常瞭解業務邏輯,所以,在開發之前,我特意申請了一次培訓,讓運維人員給我們(我作為開發,還有一位測試人應)講解一下整個系統的流程,也不需要特別正式的會議室,就幾個人在電腦旁邊,運維人員從頭到尾給我們整個走一遍流程,有任何疑問都當下提出,當下解決, 解決不了的記錄下來,運維人員後去請教實際使用者這些問題。補充一點:最瞭解X系統業務的人當然是使用這個系統的使用者,可是這個系統比較特殊的一點是,大部分使用者都是領導,我們幾乎不太可能讓領導來花時間來給我們講整個業務邏輯,只能是當我們遇到一些實際的業務問題,再去和他們請教。而運維人員,算是除了使用者以外,相對比較瞭解X系統的人了,什麼?你說X系統的開發人員?這個系統的開發商已經“跑路”了:)
在培訓完業務流程後,我還沒有急著做開發,而是先讓測試人員在X系統上走一遍流程,並把走流程中的一些關鍵資訊(如待辦詳情,操作按鈕,下一步操作選擇)截圖,一來測試需要了解整個業務流程才知道如何設計測試用例,二來截圖也可以給我開發做一些參考,比如需要顯示待辦詳情裡面的哪些資訊,操作按鈕要如何顯示,下一步操作要如何處理等。
測試人員在X系統上走完流程以後,我自己也參考測試人員寫的操作步驟和截圖,走了一遍流程,算是心裡有個底了。
遇到的問題
X系統有個測試環境,我們都是在X系統的測試環境中開發和測試的,但是這個環境很不穩定,因為運維人員經常為了排查X系統的問題,會經常把X系統正式環境的資料匯入到測試環境,這樣我們在X系統做的資料就會被重置,這就尷尬了,我們的開發週期是一週,想在這一週保證測試資料穩定是不可能的了,所以,我又做了一件事,找了一個新的伺服器,在這個伺服器上重新搭建一個X系統的測試環境(包括應用伺服器,資料庫),總算是解決了這個問題。
遇到的另外一個問題是,每次X系統中的待辦建走到特定節點比較費時,而每個特定節點需要定製開發,比如我們的手機應用Y要支援X系統某個待辦的第五個環節,那我需要在X系統上建一個待辦,然後一步一步走到第五個環節,然後找這個環節需要顯示的資訊,需要做的操作,非常麻煩,而且一旦我在手機上操作了這個環節(比如審批了),這個環節就跳到了第六個環節了,如果我第五個環節的東西還沒有完全開發完,我又要建一個流程並走到第五個環節,比較麻煩。所以我想了一個辦法,就是在走到某個環節的時候,先備份一下資料庫,走完這個環節如果想再回去看下的話,直接恢復備份資料庫就可以了。
開發和測試
放棄重構想法以後,我開發相對比較謹慎,基本沒有改動之前的程式碼,新的需求都是重新寫的程式碼,併為考慮複用太多之前的程式碼,雖然幾次很想重構,但是還是忍住了,求穩。
業務邏輯理清了,接下來就是要看懂X系統的原始碼了,X原始碼註釋也比較少,充斥著類似以下這樣的程式碼:
if(StringUtils.equalsIgnoreCase(subTypeId, "501")){
// do something
...
}else if(StringUtils.equalsIgnoreCase(subTypeId, "502")){
// do something
...
}else if(StringUtils.equalsIgnoreCase(subTypeId, "601")){
// do something
...
}else if(StringUtils.equalsIgnoreCase(subTypeId, "602")){
// do something
...
} else if(StringUtils.equalsIgnoreCase(subTypeId, "604")){
// do something
...
}
我必須一個一個節點走才知道這裡的諸如:"501","604"是什麼意思,然後把這裡面對應的SQL拿出來分析,看下需要哪些引數,這些引數是如何獲取的,而且有些SQL的查詢還很複雜,引數很多,我本想直接用正則匹配頁面中的這些引數值,後來想想,還是不能依賴X系統的頁面資訊,我都是直接查資料庫獲取需要的引數,分析SQL和獲取查詢引數,耗費了巨大的時間,不過事實證明,這樣做是對的,我這相當於重做了一遍X系統了。
接下來是設計X系統整合到我們手機APP系統Y中以後的展示和操作,由於資料都拿到了,我就需要把這些資料轉換成我們手機APP中展示的元素,比如:Table,KeyValue,List,這些東西實際上沒有一個統一的標準,我們就把詳情中比較關鍵的一些資訊顯示出來,至於是顯示成Table還是KeyValue,這個沒有嚴格的標準,使用者似乎不太關注內容的排版,只要是顯示了必要資訊,簡單明瞭,就足夠了,所以這部分”設計“,就按照我自己的想法來做了。
接下來是審批操作,審批操作比較麻煩的一點是,你必須完全瞭解,點選這個待辦的操作按鈕背後的所有邏輯,因為我們是要整合待辦的操作,所以我們實現的邏輯要和X系統一模一樣,最簡單粗暴的方案當然是模擬X系統的操作,比如用一些爬蟲工具模擬點選操作的按鈕,這樣我們就完全不需要了解X系統的操作流程了,但是這並不保險,還是因為上一次返工給我帶來的教訓:萬一操作的元素變動了一下,我們的操作就完全失效了。所以這次我還是選擇直接理解操作背後的邏輯,說白了就是把操作對應的Ajax請求一個一個看懂並找到對應的引數值,然後發一個一模一樣的Ajax操作,當然X系統點選操作還不是簡單的拿一些現有的引數發請求,有一些是頁面中的js拼裝的一些資料,這部分也要完全理解並完全移植過來,一旦有一些操作沒有移植過來,如果待辦審批出了問題,是非常嚴重的,因為這些待辦涉及比較重要的招投標流程,流程涉及的金額也是很大的。
我回憶了一下,真正寫程式碼的時間實際上不多,花時間最多的是看X系統的原始碼,和熟悉X系統的業務流程。
最後是測試,因為要在手機APP上測試流程,但是我們自己的工號下面都沒有對應的待辦資訊,需要登入相應的領導的賬戶才可以拿到待辦資訊,雖然是測試環境,但是我們手機APP是不會用使用者的資訊去登入測試的,因為登入後,使用者的所有資訊我們都可以看到了,解決辦法就是,在獲取使用者待辦的時候,我們只拿使用者的X系統的待辦,其他資訊不獲取,所以獲取X系統的待辦邏輯的程式碼,加了這麼一小段邏輯,大概意思就是如下:
this.工號 = 獲取登入人的工號(); // 登入人是自己人
Map<String,String> changedInfo = newHashMap();
changedInfo.put("自己人的工號1","有待辦的人的工號1");
changedInfo.put("自己人的工號2","有待辦的人的工號2");
changedInfo.put("自己人的工號3","有待辦的人的工號3");
this.工號 = changedInfo.get(this.工號);
List todoList = 通過工號獲取某人X系統的待辦資訊(this.工號);
感悟
這個需求開發並上線已經兩週了,我監控了一段時間執行日誌,暫時未發現問題,本次整個開發過程,吸取了上一次返工的教訓,為我以後的開發工作也積累了一些新的經驗,謹以這兩篇部落格(本篇部落格, 上一篇部落格)作為一個記錄,也希望可以分享給有需要的人。