做開(kāi)發(fā)十年,我總結出了這些開(kāi)發(fā)經(jīng)驗 在一線(xiàn)做了十年的開(kāi)發(fā),經(jīng)歷了網(wǎng)易、百度、騰訊研究院、MIG 等幾個(gè)地方,陸續做過(guò) 3D 游戲、2D 頁(yè)游、瀏覽器、移動(dòng)端翻譯 app 等。 積累了一些感悟。必然有依然幼稚的地方,就當拋磚引玉,聊為笑談。 一、對于團隊而言,流程太重要了 行軍打仗,你需要一個(gè)向導;如果沒(méi)有向導,你需要一個(gè)地圖;如果沒(méi)有地圖,至少要學(xué)習李廣,找一匹識途的老馬;如果你連老馬也沒(méi)有,那最好可以三個(gè)臭皮匠好好討論,力圖勝過(guò)一個(gè)諸葛亮;如果三個(gè)臭皮匠連好好討論也做不到,那就是典型的烏合之眾了,最好寫(xiě)代碼前,點(diǎn)上三炷香,斟上一杯濁酒,先拜拜菩薩,再拜拜谷歌。 我個(gè)人屬于性格溫和的(程序員大多性格不錯),但確實(shí)見(jiàn)過(guò)少數強勢的人,說(shuō)很多強勢的話(huà)。在技術(shù)上一言而決,一聽(tīng)到任何反對就上升到私人恩怨。這樣的風(fēng)格,到底是剛愎自用,還是胸有成竹,就需要仔細判斷了。 為什么說(shuō)流程重要呢?實(shí)際上,如果團隊上有孫悟空存在,去西天取經(jīng),大概也不需要什么流程,只要方向就可以了。 但作為普通的戰士,應該先慮敗。找人算命時(shí),應該先聽(tīng)聽(tīng)不好的地方,好的地方就不用聽(tīng)了,總歸是好的,不好的地方一定要聽(tīng),這樣才能規避。 這就是我的態(tài)度:先悲觀(guān)一點(diǎn),劃清底線(xiàn),考慮在這個(gè)底線(xiàn)上你該怎么做? 這是我做開(kāi)發(fā)的一個(gè)習慣,但這個(gè)習慣肯定不適用于買(mǎi)房。怎么劃清底線(xiàn)呢?就是假想團隊中沒(méi)有孫悟空了,光靠你唐玄奘、豬八戒和沙和尚,應該怎么去取經(jīng)。 這個(gè)月走什么地方,遇到山怎么走,遇到河怎么過(guò),遇到路上有妖怪劫道,誰(shuí)去抵擋。遇到路上有少女要搭救,怎么辦?這就是流程,是原則。 我經(jīng)歷過(guò)一個(gè)流程很混亂的階段。都是很多年前的事情了,可以拿出來(lái)說(shuō)說(shuō),不涉及單個(gè)人。 2011年在百度瀏覽器團隊時(shí)遇到幾件讓人影響深刻的事情。 有一次開(kāi)會(huì ),產(chǎn)品拿出 Google 某個(gè)產(chǎn)品的 DEMO,里面有一段很酷炫 3D 效果,要求開(kāi)發(fā)加上,只給2天時(shí)間,大家目瞪口呆。后續的開(kāi)發(fā)為了趕節奏,導致非常多的 bug ,又為了修改 bug ,leader 將所有的 bug 按照人員平均分配,導致不同模塊間的同學(xué)相互修改......實(shí)在難以想象。好比讓做花卷的廚子,去修改西湖醋魚(yú)的味道。 最初的現象是:bug下降的慢,延伸 bug 反而增加,每個(gè)人都累的半死,代碼風(fēng)格極其雜亂,為了趕工導致的臨時(shí)方案層出不窮; 到了中期:人員離職越來(lái)也多,代碼難以維護,新加的需求與之前的臨時(shí)方案沖突。 到了后期:想做一些修復,想調整架構,又要保證正常運行,其難度好比在一架飛行的飛機上拆換零件。 然后我也急忙離職了......實(shí)在看不到成功的可能性。 后來(lái)到了騰訊的團隊,感覺(jué)流程就規范多了。需求和 bug 有 Tapd 跟蹤,產(chǎn)品發(fā)布按照節奏,需求提出前會(huì )和開(kāi)發(fā)反復討論可行性,有專(zhuān)門(mén)的質(zhì)量跟蹤,有專(zhuān)門(mén)的用戶(hù)反饋,每天知道要做什么,也知道明天要做什么。有產(chǎn)品需求,也有開(kāi)發(fā)需求!這個(gè)非常重要。很多團隊,都是只有產(chǎn)品需求,開(kāi)發(fā)好像牛一樣,耕完地就不管了? 流程其實(shí)沒(méi)那么復雜,就是各司其責+節奏。我們都是“哆瑞咪發(fā)梭拉西多”中的一員,各自有各自的責任,然后組合在一起,按照一個(gè)節奏跑起來(lái)。把該做的事情與該跑的節奏定好。 二、不要炫技,老老實(shí)實(shí)寫(xiě)代碼 網(wǎng)上有一個(gè)段子,說(shuō)有人要用JS實(shí)現一個(gè)簡(jiǎn)單的功能,然后朋友給他推薦了幾十個(gè)庫。 真的有必要嗎?具體情況具體分析。 居家過(guò)日子,你只需要一套普通的工具就可以了;如果你是修車(chē)的,你需要一套修車(chē)的工具;如果你是光頭強,你需要一臺伐木機。 吃飯用筷子,用刀叉,都可以,但不要用殺豬刀,不要用丈八長(cháng)矛!,當然也不能用牙簽。 用什么工具,用什么庫,問(wèn)問(wèn)過(guò)來(lái)人,多在KM上搜索一下。舉個(gè)例子:android 上加密,用 SQLChpher就可以了,微信也在用,你當然可以學(xué)習;數據庫 ORM 思想,用 KM 上推薦的 GreenDAO 就可以了;PC 上 3D 引擎,用OGRE就可以了;小型游戲 DEMO,用 Irrlicht 足夠;寫(xiě) WebGL,用 ThreeJS 足夠。 首先想想:一些大庫 hold 的住嗎,后續發(fā)展如何?這些庫對安裝包的體積影響有多大?有沒(méi)有調研過(guò)同樣的產(chǎn)品在用什么? 想清楚了再決定用什么,最好是跟隨成功項目的腳步。 三、架構上實(shí)用+適用 很喜歡曾國藩的一句話(huà):結硬寨、打呆仗。 一字長(cháng)蛇陣、八門(mén)金鎖陣,哪個(gè)好?iOS 都是單個(gè)進(jìn)程,微信 Android 版本3.5以前是單進(jìn)程,3.5以后有獨立的網(wǎng)絡(luò )進(jìn)程; PC 瀏覽器的進(jìn)程架構更加復雜,UI 進(jìn)程、內核進(jìn)程、Render 進(jìn)程,而且還有根據頁(yè)面多少的進(jìn)程調節模型。 這些設計都很好,各有各的道理,都適用于當前的產(chǎn)品。所以我的觀(guān)點(diǎn)是:首先分析當前產(chǎn)品的規模、性質(zhì),然后再設計架構。 在當前階段達到:開(kāi)發(fā)效率+架構的平衡;并向后展望3個(gè)月,或者半年左右,看看架構能不能適應。 我做騰訊翻譯君時(shí),曾反復猶豫要不要模仿微信加入獨立的網(wǎng)絡(luò )進(jìn)程。后來(lái)逆向了有排在第一二位的競品,最終采用了現在的主功能單進(jìn)程模型。 產(chǎn)品規模、人員規模、功能階段,具體問(wèn)題具體分析。 四、既要有攻城之力,也要有熬戰之氣——BUG 產(chǎn)品開(kāi)發(fā)完成后,必然有 bug 。其實(shí)開(kāi)發(fā)人員在工作過(guò)程中,是有一定的直覺(jué)或者心理預判的,即:某個(gè)功能模塊的質(zhì)量如何。 這里面的質(zhì)量包括:可維護性、擴展性、算法\渲染效率,還有就是bug與崩潰率。 功能開(kāi)發(fā)完成后,就要開(kāi)始守城了。 bug,一部分產(chǎn)生是由于架構帶來(lái)的,例如比較復雜的架構,會(huì )導致復雜的實(shí)現細節; 但還有很大部分bug,其實(shí)是基于如下三個(gè)原因產(chǎn)生的: 對于某個(gè)api的不了解,或者對于某個(gè)平臺,或者 SDK 版本的不了解。 舉例而言:android里面非主線(xiàn)程,是不能直接處理UI相關(guān)的事情的;JAVA 的內存釋放也不是絕對的,相互指向是無(wú)法釋放的;函數個(gè)數是有DEX問(wèn)題制約的---------------------這些bug的產(chǎn)生,也是開(kāi)發(fā)人員摸索學(xué)習的過(guò)程,經(jīng)歷過(guò)一次就不會(huì )再犯了。這是學(xué)習廣度與熟練度的問(wèn)題; 還有一些bug,是由于粗心大意導致的。例如空指針的問(wèn)題,野指針的問(wèn)題。在 C 的開(kāi)發(fā)中,野指針的問(wèn)題,GDI 句柄的釋放問(wèn)題,這些都是嚴謹的代碼需要避免的; 而又一些工具,或者方法是可以規避這些問(wèn)題的,例如 android中 的利用@ Nullable 和@ NonNull 加強空指針檢測等方法; 還有一些bug,是由于“使用情況各異導致的”。例如:偶現在某個(gè)模塊crash。這里的本質(zhì)還是因為邏輯的異常邊界沒(méi)有處理好。例如 android 上的 OOM 問(wèn)題,還有 PC 上 UI 焦點(diǎn)導致的對象釋放問(wèn)題。這些異常情況,一部分靠測試發(fā)現,一部分靠用戶(hù)反饋,還有一部分就靠自己的異常處理。例如Android中的try catch機制,其實(shí)就是遇到異常了,你能糾正錯誤的機會(huì )。 五、自審 每過(guò)一段時(shí)間,都要站在高空俯視自己,問(wèn)問(wèn):到底是在承擔過(guò)去,還是在改變未來(lái)。 如果之前程序代碼質(zhì)量不好,后面修改問(wèn)題的時(shí)間就會(huì )比較多。到了開(kāi)發(fā)的中期,得多問(wèn)問(wèn)自己,你在不停的改正以前的錯誤,還是在做新的東西。 如果修改錯誤的時(shí)間多一點(diǎn),那就要注意自己的代碼質(zhì)量了! 六、注釋 我很喜歡寫(xiě)注釋。有大牛說(shuō):代碼就是最好的注釋。 可惜我還沒(méi)有達到那個(gè)程度。所以,我會(huì )把注釋寫(xiě)的非常清楚。其一:為了自己以后維護的方便; 其二:為了其他人接手的方便。 這是我在翻譯君項目中寫(xiě)注釋的方式。1:對于很復雜的邏輯,務(wù)必用12345的順序依次寫(xiě)清楚;2 :對于函數中的某個(gè)參數,需要解釋為什么要設置這個(gè)參數,尤其是公用工具類(lèi)里面的函數---說(shuō)清楚參數的背景含義,可以讓其他調用者理解的更加清晰。 我一般不用英文寫(xiě)。雖然這樣看起來(lái)格調很低,但勝在大家都能輕松的看懂。寫(xiě)代碼不能太傲嬌,寫(xiě)注釋也不要太傲嬌,目的是讓你的搭檔或者接手者,更輕松的理解,讓她/他少加班。 七、代碼結構 代碼結構要清晰。有按照功能劃分的,有按照 UI 結構劃分的。還有公用工具類(lèi),有數據管理,有主邏輯控制。不管用哪種思想,有序的代碼結構,可以讓每個(gè)人感覺(jué)很干凈。好比日本的收納整理技巧讓很多小資推崇,無(wú)非就是干凈、整潔、便于管理。 而且,還有一個(gè)重要的好處:代碼結構表現出來(lái)的其實(shí)是——程序的一個(gè)模塊\邏輯思想——讓大家工作在不同的區域。 八、代碼風(fēng)格 代碼風(fēng)格統一!好比一家人,有叫 Tom 的,有叫安東尼的,還有叫流川楓、石破天、圣杰夫拉斯基,無(wú)所適從。理論上,看一個(gè)函數,就能從名稱(chēng)上區分哪些是成員變量,哪些是局部變量,哪些是全局靜態(tài)值。 除了命名統一外,還有一行代碼最大的寬度,函數的連續調用長(cháng)度等,頭文件的包含風(fēng)格,也最好有一個(gè)約定。類(lèi)的出現時(shí)間,創(chuàng )建人名,最好也加上,看起來(lái)沒(méi)用,但到了追蹤問(wèn)題時(shí),就能看出時(shí)間線(xiàn)的好處。 九、安全與逆向 這是針對Android說(shuō)的,還有PC插件也需要考慮。Android 上首先要防止被別人逆向,我成功逆向并重新打包過(guò)有第一位和第二位的競品。這似乎有點(diǎn)不可思議,但確實(shí)做到了。加固+混淆+代碼判斷,最好都有。 安全上,可以看金剛掃描的漏洞,逐一修改就行。公司很多工具很好用的! 十、開(kāi)發(fā)效率 開(kāi)發(fā)效率可以用這些方式提升: 構建公用工具類(lèi),方便大家使用。 使用開(kāi)源的一些包,例如 ORM 思想的數據庫等。 可以很快的找到問(wèn)題。開(kāi)發(fā)中,找 bug 的時(shí)間,往往是很多的。我用的方法有3個(gè): 使用 try catch; 攔截所有 crash 到我指定的地方;超多的 Log,Log 有統一的控制開(kāi)關(guān)。 借力:數據上報用燈塔,崩潰上報用 bugly,公司 KM 上很多經(jīng)驗,拿過(guò)來(lái)用。 十一、安裝包體積 TINY 壓縮圖片 刪除無(wú)效的資源文件 十二、UI渲染效率 UI 是用戶(hù)的第一感覺(jué);UI 快并穩定,第一感覺(jué)就不會(huì )差太多;管理好內存,基本管理好了一半 crash;管理好 UI,等于管理了人機交互感受。 UI 上的開(kāi)發(fā)是:渲染效率與渲染效果的平衡。 很匆忙的寫(xiě)的,必然有很幼稚的地方,歡迎斧正。 來(lái)自:https://www.qcloud.com/community/article/382005001489731581 作者:康亮,騰訊高級工程師。歷經(jīng)網(wǎng)易在線(xiàn)游戲事業(yè)部、百度客戶(hù)端部門(mén)、騰訊研究院、騰訊MIG,橫跨多個(gè)平臺10年開(kāi)發(fā)。 想學(xué)習的你和我聯(lián)系預約就可以免費聽(tīng)課了。 以下課程可免費試聽(tīng)C語(yǔ)言、電子、PCB、STM32、Linux、FPGA、JAVA、安卓等。 宋工企鵝號:3524-6590-88 Tel/WX:173--1795--1908 |