我的 2016 年總結
時光飛逝,一轉眼已經是一年過去了, 去年的今天我寫下了第一篇年度總結:一個普通iOS開發者的2015大總結。在寫作那篇文章之前,我覺得一年前的自己完全是一個傻逼;今天重讀一遍以後,我感覺一年前的自己也非常傻逼。在寫下這一年總結的同時,我也希望明年的自己在回顧這篇文章的時候,可以發出不屑的鄙視。
實際上我認為:
剛開始學習的前五年是發展最快的五年,每一年都應該感覺到自己在過去的一年中發生了天翻地覆的變化。
本文既然是總結, 自然是充滿了大量的主觀看法。如果讀者不認可其中的某些觀點,大可呵呵一笑,拋之腦後,切勿較真,做無意義的爭論。
Swift
我從元旦後就開始著手準備春招。首先翻譯完了
如果 Xcode 對 Swift 的支援能更友好,業內再提出成熟的動態化方案,我相信 Swift 會有更光明的未來和使用場景。
Swift 與後端開發
隨著 Swift 的愈發成熟,業內出現了很多比較成熟的後端開發框架, 比如 perfect、vapor
理論上來說,任何可以呼叫 socket 介面處理網路請求的語言都可以用來做後端開發,然而對於 Swift 來說,除了處理網路請求以外,一個優秀的 API 也至關重要。不管是 HTTP 協議的解析,還是字串、棧、時間等常用資料結構的操作,都不方便由做業務的程式設計師去手動解析。
框架的使用者應該關注業務開發,而不是通用業務的處理。比較遺憾的是,Swift 目前在這一方面做的還不夠好,很多重要的操作缺乏語言層面的支援,導致開發者造輪子的成本過高。不過 Swift 已經成立了官方小組,致力於解決這一問題。
考慮到 Swift 還不是個非常成熟的語言,目前還在快速迭代。相比於語言本身,我認為人的問題才是阻礙 Swift 在服務端發力的最大原因。不管是現有哪種用來進行後端開發的語言,都有它本身的賣點。比如 Java 的高效(執行時效率)、穩定、全面,或者 PHP、Ruby 的語法簡潔,易上手,還是 GO 的高併發,亦或是 Node.js 的全棧,都能在某個特定場景下派上用場。
目前的 Swift 似乎還沒有找到屬於自己的舞臺,由於絕大多數開發者都是 iOS 開發者,他們並不適合轉向服務端開發,這就意味著 Swift 能寫 iOS 毫無吸引力(參考一下 JS 能做哪些事)。而對於具有服務的開發經驗的開發者來說,Swift 又沒有吸引他們切換過去的理由。
準備春招
一不小心就扯遠了, 話題回到總結上來。完成了 Swift 學習的收尾工作後,我的精力主要放在春招上。由於大二下學期積累了三個月的實習經驗,這一階段的目的主要是夯實基礎。因此重點讀了兩本書,《圖解 TCP/IP》(總結)、《劍指 Offer》。
圖解 TCP/IP
這本書主要是講解了 TCP/IP 四層協議棧(或者分得更細點就是七層),通過一些插圖和實際例子來解釋枯燥的概念。我認為這是一本不可多得的好書,尤其適合新手入門。不過,如果想精通網路層,還是建議買 《TCP/IP 詳解》和 《HTTP 權威指南》或者直接查閱 RFC 協議。
不過在準備面試,或者新手入門時,我覺得非常有必要通過一本簡短的書籍來形成大致的知識框架和,這樣後續才能有針對性的學習總結,對自己的知識框架進行各種修修補補。
劍指 Offer
這本書相當應試,不過也必須承認它概括了絕大多數常見的演算法面試題。如果我們把面試看做是企業對應聘者的能力篩選和鑑定而不是刁難,那麼從一定角度來說,也可以證明這本書涵蓋了絕大多數常見的場景和演算法。
如果不想只是紙上談兵,還可以去 Leetcode 上找找書中問題對應的題目,參考全世界大牛的精妙解法也會受益匪淺。
iOS
作為一名 iOS 開發者,iOS 開發是我的本業,除了準備計算機基礎知識外,我也學習了很多 iOS 開發的知識。以上的詳細內容都總結在 《讓 BAT 的 Offer 不再難拿》,就不贅述了。
入職
春招順利的拿到了百度貼吧的 offer,入職以後受益匪淺。在善品、權叔等老司機的帶領下,我有一種鄉下人進城的興奮感,感覺自己的成長速度非常快。
MVC 與 UITableview
UITableview
是 iOS 開發中最常見的 UI 控制元件之一,但是想寫好一個 UITableview
,做到封裝、解耦,並與網路請求良好的結合起來並不容易。我花了一定時間學習了貼吧以前的框架,對其做了一些簡化和整理,總結在這裡: 如何寫好一個UITableView。框架沒有最優與全能,適合團隊業務的就是最好的,所以這套框架主要是為了貼吧業務打造,但也有自己的不足,讀者切不可照搬全抄。
高效使用 Mac
我比較看重開發效率,因為我認為開發者應該把寶貴的時間花費在工作本身,而不是與之無關的雜事上。並不耗時的高頻操作和比較耗時的中頻操作都應該使用快捷鍵或自動化工具對其進行簡化,不過也切忌矯枉過正。對非常低頻的操作進行自動化或者僅僅是為了裝逼,往往會浪費大量不必要的時間,反而適得其反。
我總結了一篇文章 並做了一次直播,主要涉及全域性快捷鍵、Xcode、Vim、Chrome、Vimium、Git、Zsh、Alfred、Zsh、Emacs 等. 強烈建議對此還不瞭解的讀者收看直播回放。
iOS 深入
在工作之餘,我對 iOS 領域的一些常用知識做了深入學習。
GCD 與多執行緒
雖然去年就複習過類似的話題,但僅僅是停留在總結整理的層面,說白了就是把所有 API 熟悉了一遍。這次學習時,我閱讀了 GCD 的原始碼,從而從更深層次理解了 GCD 的實現原理,總結了一篇文章: 深入理解 GCD。
Runloop
最初接觸 runloop 是聽了孫源大神的分享,隨著學習的深入,發現還是有必要對 Runloop 進行深入的理解。不過 Runloop 雖然重要,但實際使用中接觸得並不太多,除了常見的 NSTimer 觸發問題外,也就是效能檢測時會與之打交道。所以它原始碼閱讀的必要性並不是太高,我覺得只要對 Runloop 的基本概念和工作原理有所涉獵即可。遇到實際問題時可以查閱 ibireme 的 深入理解RunLoop。
執行緒呼叫棧
上一節談到了利用 runloop 檢測主執行緒的卡頓。為了找到效能瓶頸,也就是優化點,我們需要在卡頓發生時得到實時的執行緒呼叫棧。這就意味著一切依賴於執行緒層面的操作都會破壞原來執行緒的呼叫棧。在嘗試使用訊號無果後,最終我選擇了參考第三方開源框架,直接利用 C 語言解析函式呼叫棧。具體總結參考: 獲取任意執行緒呼叫棧的那些事。
鎖
iOS 中有很多鎖,從最底層的互斥鎖、訊號量到頂層的 @synchronized
,應有盡有。雖然我實際使用經驗並不多,但還是研究了一下他們的實現原理和效能優劣: 深入理解 iOS 開發中的鎖。隨著對多執行緒在理論和實踐上的進一步接觸,我相信還會有更具深度的總結面世。
Xcode 專案配置
出於對 Cocoapods 工作原理的興趣,我前段時間手動模擬了它的工作過程(自動化是通過 ruby 指令碼完成的,相對而言重要性低很多)。在這一過程中,更重要的是對編譯、連結、Xcode 工程配置的理解。由於時間原因,目前還沒有形成總結性文件。
全棧
相比於 iOS 方面的鑽研,2016 年最讓我感到激動和收益滿滿的是橫向的拓展。關於為什麼會選擇橫向發展路線,在我的 新的開始 一文中已經有了詳細的闡述。
雜湊表
雜湊表是常見的資料結構,但是很多人對他的掌握都非常淺顯。曾經問過很多人一個很簡單的問題:“為什麼很多雜湊表的實現中,陣列的長度都是 2 的整數次冪?”。根據我的觀察,能答出這個問題的人寥寥無幾,有很多看上去很正確的廢話,其實恰恰說明了大多數人多雜湊表的理解還不夠深入。
除此以外,不同的語言和框架(OC、Java、Redis、一致性雜湊) 對雜湊表的實現都各不相同,他們的取捨恰恰說明不同場景下我們關注的指標並不一致,必須捨棄一些無關緊要的功能點,來換取主要功能的效能的大幅度提高。具體對比請參考: 深入理解雜湊表。
Node.js
市面上有很多介紹 Node.js 的優秀文章和書籍,作為一個不懂 Node.js 的小白,其實我只關係以下幾個問題:
- 為什麼要從現有的後端開發框架切換到 Node.js?
- Node.js 是銀彈麼,還是有特別適合自己的使用場景?
- Node.js 的事件迴圈是如何工作的?有什麼好處?
- Node.js 是非同步單執行緒的, 那麼如何最大程度的利用多核 CPU 的所有效能?
前後端分離與前端開發流程
在學習 Node.js 的過程中,我接觸到了一個新名詞:前後端分離。對於客戶端開發者來說,前後端分離是一件天經地義的事情。前端介面是由編譯後的程式碼生成的,相對來說比較固定。前後端的主要交流方式是 JSON/protobuf 等資料交換格式。
然而對於前端開發者來說,事情遠遠不止這麼簡單。由於前端的 UI 樣式完全由 Server 下發,所以很容易就產生了前後端業務和程式碼的耦合。所以前後端分離說的就是前端開發和後端開發如何進行解耦和資料互動,詳見 移動端開發者眼中的前端開發流程變遷與前後端分離。
利用 JS 等指令碼語言實現客戶端熱更新
不管是 JSPatch 還是 React Native,它們都能做到客戶端的熱更新,甚至無需通過 AppStore 即可發一個新版本。它們之所以能夠做到客戶端熱更新,主要是依賴了客戶端對 JavaScript 的支援以及 iOS 自身基於 runtime 的超程式設計技術。首先,利用 JSON 傳遞資訊的區別在於它僅有描述資訊,卻無法攜帶邏輯資訊。
通過官方認可的 JavaScriptCore 框架,我們可以執行一段 JavaScript 程式碼並獲取執行結果。通過對執行結果的解析,我們可以利用 runtime 動態的呼叫本地預定義好的方法,從而實現了動態化。
React Native 的本質是一個 Hybrid 橋。它與 React 具有相同的 API,為了實現相同的效果,客戶端會呼叫本地的方法(比如 addSubview
等)。詳細請參考: React Native 從入門到原理。
指令碼語言
一般來說我們認為指令碼語言就是沒有編譯器的、由直譯器動態解釋的語言。它通常具有弱型別、格式簡單、開發效率高等優點,但是作為代價,用指令碼語言來開發大型專案會遇到諸多問題。比如效能、除錯等等,畢竟它們原本只是用來快速完成某個小的需求。
我最先接觸的是 python,我使用 python 編寫了 alfred 的一個 workflow,後來在 leader 的帶領下實現了一個可以 hook 請求和返回結果的 http 代理伺服器。有了實戰的機會,也就成功脫離了 hello world 的水平了。
同時我也簡單接觸了 Ruby。光從指令碼語言的角度來看,它和 Python 的作用相仿。不過很多領域特定語言(DSL) 都選擇了 Ruby 來實現, 比如我們常用的 cocoapods 中的 Podfile,如果不說,可能只有少數人能意識到這其實是一段標準的 Ruby 程式碼。
之所以選擇用 Ruby 來實現,是因為它的語法可讀性更好,看上去就像一段普通的描述性文字。詳細的分析可以參考: 白話 Ruby 與 DSL 以及在 iOS 開發中的運用。
嚴格意義上來說,Shell 指令碼才是指令碼語言的鼻祖,它提供了非常多常用的工具,比如 awk
和 sed
兩大文字處理利器。如果需要對文字、檔案目錄做簡單的邏輯操作,應該優先使用 Shell 而不是其他指令碼語言。
不同的指令碼語言往往是為了解決不同領域的問題而誕生的(雖然它們也可以解決其他問題),遇到問題的時候應該選擇最合適、優雅的解決方案,而不是總想著複用當前技術棧。俗話說:“如果你只有錘頭,那看什麼都是釘子”。
面向介面程式設計
Swift 誕生後就一直宣傳自己面向介面程式設計的特性,然而在我看來它不過是一種多繼承的實現方案。且不談繼承的缺點以及在它和組合之間如何選擇,光是多繼承,就有很多種實現。比如 C++、Python、Java、Ruby 都有各自的實現。其中有優雅的,也有相對來說比較暴力直接的。
我個人更喜歡 Java 對多繼承的實現,與之相比,Swift 的面向介面程式設計還有一些可以提高的地方。詳細可以參考: 從 Swift 的面向協議程式設計說開去
安卓
從 12 月份開始,由於安卓同事返校上課,我有機會開始接觸安卓開發。目前還停留在小白階段,只能根據前人的程式碼抄抄改改。安卓的學習主要還是 API 的積累和 Java 語言的學習,希望能在明年總結出更多關於安卓的優秀文章。
我的 2016
對於把好好的年終總結寫成了部落格摘要我是很不滿意的,如果用一個詞來總結我的 2016 年,我想那毫無疑問就是:“拓寬”。雖然 iOS 還沒有達到爐火純青的地步,但我還是義無反顧的開始了橫向拓寬。我相信一個人才的最大價值,不是做好某一個具體的小需求(這是前提),而是站在更高的角度做更大的事。
16 年技術棧拓展中,最大的三個收穫應該是前端、Python 和安卓。然而考慮到與工作相結合,我想前端技術暫時可以放一放,重點學習 Python 和安卓也許會對 KPI 更加有利。
當然,好的書還是要讀的。部落格可以解釋清楚某一個問題,而好書可以解釋清楚某一個領域。在 Server 方面,李智慧的 《大型網站技術架構》 可以算作一本非常優秀的入門版書籍,介紹了諸多常見的屬於和概念。而《計算機程式的構造和解釋》(SICP) 作為 MIT 幾十年來的教科書,是一本非常經典的介紹函數語言程式設計的書籍。以上兩本書推薦給感興趣的讀者。
過去的這一年成長了很多,從簡書、微博幾十個粉絲的小菜鳥,到幾千粉絲的小 V,一路走來收穫滿滿。不過我逐漸意識到越是大型的平臺,普通使用者的質量就越接近於行業平均水平。因此粉絲數、喜歡數並不值得參考,而且很多交流其實是浪費時間。因此在新的一年中我會減少社交平臺上的互動,把有限的精力投入到線下的生活、工作、學習中去。
2017 年的計劃
在去年的年終總結裡,我列出了五點計劃:
- 繼續翻譯優秀的英文文章。這一點做的不太好,雖然有幸加入了 SwiftGG 並翻譯了一些 Swift 文章,但是總的來說數量還不夠。不過考慮到還有非常多要做的事,翻譯文章的價效比似乎就不太高了,所以暫時擱淺。
- 閱讀優秀的博文。objc.cn 的文章在帶著讀,由於掌握了 Google 搜尋, 所以再也不會像去年一樣看 CSDN 了,從這一點來說,第二個目標算是圓滿完成。
- 技術與基礎。今年學習了 GCD、Runloop、Runtime、鎖、Cocoapods、React Native 等技術,算是加深了技術深度,
- 讀書。讀完了 《圖解 TCP/IP 》、《劍指 Offer》、《大型網站技術架構》、《計算機程式的構造與解釋》,雙十一還買(挖)了不少書(坑)。
- 實習。在貼吧和鳳巢的日子裡,小組裡的各位同事一直在幫助我成長,我的每一絲進步都要感謝他們的幫助。
總的來說 16 年的計劃圓滿完成了,在新的一年裡我為自己制定了幾個小目標:
- 業務: 也許業務沒有技術重要,但是沒有業務的積累,再厲害的技術也只會浪費時間,甚至帶來負面作用。踏入工作崗位後,我希望在 2017 年更加深入的理解團隊業務,更好的融入團隊的交流協作中。
- 讀書: 雙十一買了十幾本書,目前看來優先順序最高的是《七週七併發模型》和 《改善 Python 程式的 91 個建議》,如果有空的話 《Java 程式設計思想》和 《Effective Java》、《Android 開發藝術探索》也在計劃中。
- 技術: 所謂的全棧工程師,或者 T 型人才並不是全乾工程師,每一門技術必須掌握到一定深度。因此在跨界時切忌自我麻痺,不能總以“我是新手”為理由來安慰自己。我希望在新的一年裡在 Python 和 Android 方面達到一定深度,以工作為標準來要求自己。