搜尋部落格文章

2012年9月20日 星期四

[轉] Flash 務實主義 - 構建易維護的程序:高效修改

一般程序開發完成後就進入了繁瑣無趣的後期維護階段,請不要以為一個不停更新的項目後期維護是一件輕鬆的事情,它會暴露出開發過程中的所有硬傷,不規範的寫法、混亂的邏輯結構、高耦合導致地牽一發而動全身。 雖然開發內容實際上減少了​​,但人力成本反而更高。
要提高這方面效率有很多技巧,本文介紹的內容只是起點--如何快速找到項目中需要修改的代碼。
一般出現問題首先看到得是表現部分,例如對話框,關係到一些具體邏輯或某個服務端請求,即使不是很清晰的部分也一定有臨近的區域。 根據表現找到其對應代碼,我將其稱為定位。

搜索關鍵字:泛用但低效 搜索關鍵字是廣泛使用的方法。 例如,你在節目上看到某個圖片,找到圖片標誌,在所有代碼中搜索圖片標誌,一定可以找到調用這個圖片的代碼。 再如,屏幕中顯示的文本,也能找到對應的語言包標識,找到相關代碼。 然而,這種做法效率很低,因為你要找到標識的具體拼寫,搜索項目代碼查找關鍵字也需要時間。 所以下面主要介紹如何不借助搜索直接找到目標代碼。

包結構 類一般可以從兩個維度分類,一個維度是結構類別,如模型、視圖、控制器,甚至工具類、組件,另外一個維度是業務類別,如商店、人物、戰斗等各種不同模塊。
目錄裡的文件只有一個根,類似單繼承,所以你只能用一個分類做為大類別。 一般情況都是用結構類別做為大類別,因為結構類別一般是固定不變地,而業務類別可能會經常變化。 例如下圖所示情況:
【Flash <wbr>务实主义】构建易维护的程序:高效修改
這樣做是為了避免大量類混雜在一起,只有分到不同目錄才能徹底解決這個問題(目錄可折疊,必要時子目錄或文件命名可重複)。 開發模塊時,只需展開關心的目錄,避免其他文件干擾。

文件命名 推薦文件名 ​​根據結構類別做前綴,如視圖以UI開頭、後台請求以Rpc開頭等。 如果沒有前綴,命名時很容易遇到重複的情況。 再以業務類型設定第二個前綴,使得沒有目錄時,按字母排序時同一系統中的類被排到一起,當然也可以防止重名。
【Flash <wbr>务实主义】构建易维护的程序:高效修改
恰當的命名會在利用代碼提示引入類時提供便利,而且在打開類(ctrl+shift+T)對話框裡也比較容易找到需要的類。 當然,主要還是在查看包資源時,列表會比較整齊,方便找到特定文件。
以上是為了幫助你在知道類的功能和類別卻不確定具體命名時使用的,你可能不記得具體名字,但應該可以判斷出它所在的包,但僅僅這樣是不夠的。

邏輯分離是前提 邏輯要按一定規則分開到不同類中,否則你的查找目標本身就不存在。
MVC 是實現邏輯分離的方法之一。 根據MVC 思想將類分開,你就會很清楚知道,與用戶交互、顯示有關的類是在視圖中,與數據格式轉換、獲取特定數據(諸如獲得圖標實例)、判斷(諸如isPropTask() 之類)、修改數據邏輯(諸如修改經驗值觸發升級)是在模型中,而製定特定服務器請求、設置模型數據、引起數個視圖更新的代碼一定是在服務器請求類的result 中。 這樣就能確定目標位置,即使不能確定具體某個類,也能界定到某個包範圍內。
當然這是需要事先約定的,但只要開發者理解並遵守這個約定,就可以做到不依賴搜索關鍵字也能立即找到需要修改的代碼。 毫無疑問這種做法是值得的。

從視圖著手 視圖是最容易找到的部分,然後根據交互事件模擬用戶操作過程,通過調用關係一層層查找,最後就能找到需要的部分。
無論你的代碼結構如何,這種方法都是通用可行的。 如果你的目標就是視圖,需要修改的是諸如佈局、顏色、數據填充邏輯,這樣做就可以了。 但如果你的目標不是視圖,這並不是最好的辦法,因為畢竟需要從視圖一層層中轉,會多幾個步驟而不是直接找到,這自然影響效率。

模型 模型不只是數據。
很多人不明白為什麼要在數據之外套一層模型。 代碼放哪裡比較好要以可複用性做為標準,放在模型裡的邏輯應該是和數據密切交流的,最基本的是數據序列化和反序列化。 這些內容不少人認為應該寫在請求完成函數里,而實際應該寫在模型中,因為同一個模型可能會由不同請求生成,它們傳入的數據格式是一樣的,只有在模型中解析才能重複利用這段功能代碼。
此外模型還需要負責和數據相關的邏輯,以某個RPG 遊戲為例:
• 人物屬性變化:包括金錢變化(錢不夠會失敗並提示充值),經驗變化(可能需要升級),還有數據更新後對應視圖更新;
• 道具管理:增加/刪除道具,獲得道具數量,判斷道具滿;
• 計算:諸如保存地圖模型可以提供計算A* 的方法;

上述邏輯是針對遊戲玩家的,只會存在一個模型,數據模型是固定的,所以無論放在哪裡只要集中都容易查找,但顯然放在模型裡最好理解,而且這樣即使出現多角色需求,需要修改的地方也很少。
模型通常也會提供一些簡單的數據轉換方法,例如:
• 獲得圖標,類似的方法有獲取格式化文本、獲得ToolTip 信息等;
• 校驗,一般一組條件的與或關係或者大於等於小於判斷,也可能有循環遍歷數據進行統計等複雜表​​達式;

如果按照約定編碼,將這些邏輯存放在模型中,這樣就不能通過視圖快速找到代碼,但模型數量少、邏輯少,會比放在視圖裡找快很多。 你也可以用查找引用方法找到調用模型方法的代碼片段,以確定這個邏輯的入口,方便逆向追踪。 這樣只需修改一處,所有相關部分都會發生變化。

命令(Command/Action)
所謂命令,其實很大一部分都是用來請求服務端數據的,設計中有result 方法可以在返回結果後處理一些事情,例如整理數據格式、設置模型、調用視圖更新方法。 雖然很多人將這些功能發明放在視圖中,但顯然放在Command 裡重用率更高且更易於定位。
服務端返回的數據會經常變換,雖然具體解析是在模型中完成,但返回的數據常常是多個數據拼湊在一起,可能是數組或者一些簡單數據類型,這部分可以有Command 處理,做特殊解析並給相關模型賦值。 由於這部分需要與服務端溝通,是容易出錯的地方,放在Command 裡容易找到,修改時也可以省去不少麻煩。
命令除了給模型賦值,也還會有一些觸發操作。 如果確定某個邏輯是請求返回一定執行的也可以放在這裡。 例如更新視圖、觸發附加邏輯、首次購買某物品的彈窗。 這部分常發生變化,放在Command 執行也易於調整。當然Command 也可以與服務端請求無關,但道理是一樣的。
總而言之,原則是盡可能不要將代碼放在視圖,而是放在聯繫更緊且數量少、代碼少的一方,這樣就能更快找到修改代碼位置。 Command 一般用來調用模型和視圖方法,是其他邏輯的入口,自己只有少量代碼。

常量類 配置類數據只可能存在於三個地方:服務端,本地配置文件,常量類。
對於服務端數據配置,客戶端只單純接受,本地配置文件一般都保持經常更新的大量數據,所以零散數據配置通常都存在常量類裡,例如等級上限、各級經驗分配、特定功能花費。
很多開發者都喜歡偷懶,例如一個功能需要花費5元開啟,開發者直接在代碼裡寫5。 這樣看起來算不算神秘數字先不談,要知道,這種數據即使說絕對不會變而它未來變化的機率也會超過30%。 所以常量是必須有的,哪怕數值是1,也應該寫成常量,因為未來可能變成2,在代碼裡保留數字始終會有隱患。 如果你設置為常量,對於這類內容就可以直接找到常量修改,而不用關心其他部分,也很容易找到使用這個常量的代碼片段。 如果沒有常量​​的話,就只能藉助和這個數值相關的內容引導並藉助關鍵字搜索以確保修改無遺漏了。
此外,有多版本時配置可能會變化,如果硬編碼寫死在程序中,需求會很難實現。

其他 這裡介紹是以通用MVC為例,因為熟悉的人較多,容易理解。 遊戲中除用戶界面外,結構會更複雜,雖然也有類似模型視圖這樣的概念,但層次需要分得更細緻。 其實這些分離方法都是約定的,既然要分離,就要更合理、更易於理解、更具有可複用性。 高效修改首先要容易找到問題癥結點,要達到這個目的,就要求代碼結構整理。 良好的結構也可以讓約定更加簡潔,易於記憶和理解。
上述這些內容,框架並不能幫到你,因為框架大多是限制你分成幾部分,而沒有也無法限定這幾部分具體是什麼內容。 因此你需要刻意地約定,而這個刻意地行為,對於減少修改維護時的人力成本,比框架重要百倍。


沒有留言:

張貼留言