給創業碼農的話--如何提升開發效率
開篇先友情提示一下,此篇文章所談論的部分技術點與微信關聯不大,如有描述不準確的地方,也歡迎大家指出與討論。筆者去年從微信團隊“畢業”,變成一個創業碼農,期間也踩過一些坑,這裡與大家分享一些我個人的經驗。
微信的整體氛圍很像創業公司,快速、高效。但微信團隊對技術的挖掘還是很深的,這一點在創業公司比較難做到。創業公司更追求快速、穩定的做出功能,完成迭代。
下面給大家介紹一點我個人覺得很大的提高了我的開發效率的工具。
App架構
RxJava
首先給大家安利ReactiveX,其中Android的核心實現為RxJava。
為了App不卡頓,我們會把所有耗時的操作(比如:網路訪問、檔案訪問)放到Worker Thread中。但是Android本身的AsyncTask的設計個人覺得設計的十分糟糕,不但寫出來的程式碼冗長,而且稍微複雜一些的多流操作就會寫的完全無法維護(這裡可以用Java本身的執行緒模式來實現)。而且肆意的開執行緒也會造成App的卡頓。這裡本身最初的想法就是需要一個執行緒池,以Promise的方式對外提供介面。原先試用過facebook的開源方案Bolts-Android
這裡微信也有類似方案,通過將所有的執行緒和Handler使用介面收斂,以監控和控制無節操的開執行緒、卡頓為主要目標。而Rx的方案以幫助我們用少量的code,清晰的實現複雜的時序邏輯為主。
首先Rx會大大減少你的程式碼量,這一點對“懶惰”的我們十分重要。 下面舉2個平時開發都會遇到的問題來舉例:
1. 搜尋介面
我們需要在使用者輸入完畢後第一時間顯示搜尋結果,由於這個需要請求後臺,我們又不想使用者每次輸入的時候都去後臺請求。並且總需要顯示當前最新輸入內容的結果,不能因為網路的原因產生亂序的結果。
RxTextView.textChanges(searchEditText)
.compose(this.bindToLifecycle())
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap(SearchService::searchFeed)
.subscribe(
feeds -> updateUI(),
throwable -> RxUtil.handleError(throwable, activity)
);
幾句簡單明瞭的程式碼,滿足上述的需求,而且看起來十分明瞭簡單。其中.compose.(this.bindToLifecycle())
.debounce(300,
TimeUnit.MILLISECONDS)
是表示間隔為300毫秒,使用switchMap是會停止之前發出的請求,防止髒資料重入。 由於Android並不支援Java 8,所以我們需要Retrolambda,來支援lambda表示式。
2. 防止多次點選重入
RxView.clickEvents(button)
.throttleFirst(300, TimeUnit.MILLISECONDS)
.subscribe(this::onButtonClick);
MVP & MVVM
關於MVP&MVVM我一直是拒絕的,因為一開始的幾個Screen我是用硬套MVP&MVVM的模式來做的,雖然activity的程式碼十分簡單,但是View和ViewModel都會寫一些晦澀、重複的邏輯來保證資料繫結,這不符合D.R.Y.。後來發現google官方有一個data-binding(http://developer.android.com/tools/data-binding/guide.html)的實現,感覺實現和prism十分類似,已經在最新的迭代中開始使用data-binding來實現MVVM,具體可以參考一個第三方例子(https://github.com/ivacf/archi)。
如何優雅的偷懶
REST Client
關於REST API是一件幾乎純體力活,這裡應當使用程式碼生成工具來幫助我們完成繁瑣的工作。如果你的App像微信一樣追求極致的效能和極少流量耗費,這裡可以使用protocal buffer。這個有一個坑,就是PB原生的生成器生成的方法數非常多,會造成Android方法數64K的問題。微信裡的pb生成器做了比較多的優化,來減少方法數問題。對於創業者來說,可以關注Square開源的wire。
筆者的APP使用了更容易除錯的JSON。其中我們可以定義JSON Schema來描述協議,後臺與客戶端都可以拿這個schema來生成自己的Model和驗證協議資料。Android中可以jsonschema2pojo(https://github.com/joelittlejohn/jsonschema2pojo)來生成自己的Model程式碼,並且可以生成Parcelable程式碼(PS:這一部分可能還存在隱藏BUG,如果你在使用過程中有什麼問題可以提issue或者直接聯絡筆者)。
關於REST API還有一個殺手級的庫Retrofit。Retrofit可以完美配合jackson+Rxjava來實現一個基於ReactiveX的REST Client。
@GET("/v2/feeds/search")
Observable<List<FeedDetail>> searchFeeds(
@Query("query") String query,
@Query("tag") String tag,
@Query("page") int page
);
宣告十分簡單明瞭,具體可以去retrofit的官網瞭解更多。
Image Loader
整體APP的架構完成後,圖片庫也是對於APP十分重要的。筆者剛入職的時候,就是在照著google tutorial上的圖片載入的例子寫過一個ImageLoader,深深感到做一個高效的圖片庫還是有很大難度的。還好現在各路大神給了我們很多選擇,下面3款筆者認為是可以選擇的option:
1. Picasso (https://github.com/square/picasso)
2. Glide (https://github.com/bumptech/glide)
3. Fresco (https://github.com/facebook/fresco)
其中Picasso
和Glide
的介面十分接近,但是benckmark下來Glide
的效能更好一些,並且支援更多格式的圖片,我們現在使用的的是Glide
,而Fresco
的功能是這3個庫中最強大的,且支援PJPG
。但是他需要替換你的View,並且介面設計的不如上述2個庫。筆者在3個多月以前用Fresco
的時候,他在載入多張圖片的時候偶爾會有顯示不出的情況,不確定現在是否修復。
微信內的ImageLoader針對自身的一些特有業務做了比較多定製化的工作,特別對記憶體做了比較深入的優化與監控,其他大體功能上相差不大。
ButterKnife
Jake Wharton是個非常高產的大神,諸多開源庫都是他主導的(RxAndroid也是他主要在主導)。ButterKnife可以幫助你少寫很多重複的code。配合IDEA的外掛可以不用寫很多繁瑣的findviewByid
的搬磚程式碼。
質量保證
監控資料對於App來講也十分重要,這方面雖然不體現任何功能,Growth Hacker和開發都需要經常關注。微信的監控與上報可以說做的非常強大,但是對於創業者來說,無法花那麼多時間與精力在這些方面,還好有一些第三方提供一些類似的相關服務。筆者現在在用的有一下幾款產品:
1. fabric (https://get.fabric.io/)
2. umeng (http://umeng.com)
3. splunk (http://www.splunk.com)
fabric和umeng的功能有很大的重疊,fabric是twitter旗下的資料上報和分析系統,筆者這裡使用了他的crash報上,做的十分強大,給App的質量提供了保證。splunk是一款服務端的log分析系統,有了他的支援客戶端可以減少需要無謂的事件上報。
另外,DebugDrawer也值得推薦,可以幫你快速的在debug版本分析、診斷問題。
微信內的質量資料監控與上報則因為資料保密方面的考慮使用了自研平臺。有實時的分鐘級別的上報與報警平臺,崩潰上報與分析,以及卡頓、記憶體、SQL等各種精細化監控模組。
最佳實踐
關於最佳實踐當然見仁見智,不過筆者還是推薦一些比較成熟的方案android-best-practices,這個建議精讀一下,裡面的每一條都是別人踩過的坑總結來的,十分有價值。
微信內部的開發流程基本會遵循git-flow(https://github.com/nvie/gitflow),即單feature單branch,功能完成合入穩定分支。微信在git實踐上因為大量使用並行開發,存在多個並行的release分支。筆者在創業時依然延續了這個規則,雖然每個repo只有1-2個人同時提交程式碼,但是這麼做可以快速應對需求的變更,並保證commit的規整性。雖然在commit時會多花5秒鐘來操作一下,但是這樣留下的是一個規整的歷史,方便後續review和bisect。另外TJ開發的git-extras(https://github.com/tj/git-extras)會有很多對github友好的命令,會讓你每天少打很多無腦的命令,以下是git-flow官網的流程,建議大家儘量按照其流程進行迭代開發。
另外關於程式碼格式,也沒有官方統一的方案,筆者這裡推薦使用Square的java-code-styles(https://github.com/square/java-code-styles),也可以自己fork做相應的修改。
另外高壓的開發很容易讓程式設計師感覺到焦躁,這裡我們還是要引入一些趣味的獎懲,筆者這裡沿襲微信的“餅乾法則”。對於很傻瓜的Bug我們要對Bug的引入者進行一點小小的懲罰,比如可以讓他給大家買咖啡或者甜筒。而對於寫出優雅且魯棒的程式碼,我們可以給他加一個雞腿。
另外強烈push設計的同學使用Sketch,這樣不僅可以解放設計的同學在無盡的切圖中,也可以讓自己節約更多的時間。
總結
感謝大家可以看完筆者的碎碎念,也感謝微信讓筆者從一個青澀的學生成長了還算合格的程式設計師。筆者離職一年,感覺創業和做freelancer有很多相似的地方,有大量靈活的時間,你需要學習如何去掌握你的時間,畢竟工作只是生活的一部分,你需要合理的分配時間。所以你的程式碼要儘可能的少些,即能自動生成的就用指令碼來做,能抽象的就不重複去寫,可以給自己節約更多的時間去玩耍。
編者後記: sim離開微信團隊的這一年中,我們完成了平臺期發展的思路轉換,關注的重點從原來的功能開發迭代開始轉向更基礎化的平臺研發能力。開源和分散式開發的思想也在團隊內部興起,微信內使用的開發工具、元件、流程也陸續誕生了一批內部開源專案。從內到外,相信在不遠的未來,大家就可以在github上看到它們。