很多php程式設計師存在未來發展方面的困擾,介於各方面的因素,phper 比其他程式設計師更容易遇到上升天花板。
一方面,一般只有初創企業為了快速實現產品上市以及極容易招到 phper 才使用 php 來實現公司的全部業務,大廠的核心業務都不是 php 做的(阿里用 java,騰訊用 c++),php在大廠只能做邊緣功能如管理後臺。
另一方面,相比於 javascript 在前端領域的一枝獨秀,各種玩出花,php 在後端雖然市場份額可觀,但有 java、go、python 甚至是 node 的強力挑戰。
最大的問題其實在於,由於把 php 作為核心程式語言的基本都是中小公司,而這些公司的業務體量根本和大廠不是一個量級,並不需要面對高併發、高可用什麼的高階架構設計,結果就是大部分 phper 終其一生都是在做著毫無挑戰的程式碼堆砌工作,技術上並無多大成長。
php 程式設計師很少涉及底層,甚至很少涉及巨集觀。phper 缺少平臺。
(在面試過程中,我發現 phper 面臨的一個尷尬局面:他們所在的公司,最終要麼倒閉,要麼轉了 java,php 只是作為“快速原型”時期的工具而已)
現實中很多程式設計師意識到這點,想要轉型,於是通過業餘時間學習諸如 go、python 等第二語言。有轉型成功的,但大部分都失敗了。
也有人想轉架構,於是去學 k8s、docker、分散式架構、“三高”架構等,但相對於前者,這種成功率更低——因為根本就沒有實踐的機會,終究是紙上談兵,一知半解(很多人僅僅是會使用而已)。
於是,很多人 35 歲前在各種創業公司碼程式碼(很多人是碼一家倒一家),35 歲後成了水果販子。
然而,在我看來,phper 並非完全沒有出路,而且和其他主流語言一樣,出路是一樣的,雖然可能相對來說走得要更辛苦些。
每個 phper 要想擺脫平庸,首先要構建自己的技能樹。
那麼,phper 技能樹中最重要的是哪些?分散式?容器編排?微服務?serverless?
都不是。在我的排位中,這些看著高大上的東西一個都排不上前十,在你還沒有真的達到架構師的水平之前,我的建議是一個都不用研究。
c 語言
網上廣為流傳的標語是類似“我用 3 行 python 就能實現的東西,為啥要用 300 行 c 去實現?”
這好比問阿里:市面上有那麼多訊息佇列中介軟體可以直接用,你為啥要花費人力再去搞個 rocketMQ?
我們說不要重複造輪子,但實際情況是我們(特別是大廠)天天在造輪子(谷歌三天兩頭就搞個什麼語言出來),目的是增加自己的技術儲備。
c 語言是程式設計師界的通行證,是一個程式設計師(特別是 php 程式設計師)段位高低的重要標誌,也是 phper 突破瓶頸的最直接有效的手段。
c 語言是 phper 最重要的第二語言。
為啥?正是因為 c 語言是底層語言,直接面對計算機(記憶體)。因為 php 太過方便,遮蔽了大量底層細節,這對公司、對工程是好事,對程式設計師的成長卻不是。另一方面,php 底層是 c 實現的,學會 c 語言有機會去研究 php 語言本身的實現機制,進而編寫 php 擴充套件,甚至成為 php 核心貢獻者。
c 語言簡單而優雅(是的,你沒聽錯),是你真正能直接跟計算機對話的語言(當然你可能要抬槓說是彙編),是深入瞭解作業系統(主要指 Unix 家族)的鑰匙。
c 語言讓你具有微觀視野,知其然而知其所以然。後面說到的資料結構與演算法、socket 程式設計、計算機原理等知識對於熟悉 c 語言的人學起來事半功倍。
資料結構與演算法
我想大部分程式設計師都有(或曾經有)一個學好演算法的夢,但大部分中途(甚至是一開始)就放棄了,一方面感覺太難了,另一方面感覺跟實際工作不相關,用不到(這一點和放棄 c 的理由一樣)。
還是那句話,不要認為實際業務開發中“用不到”的東西就沒有學習的價值,實際情況正好相反,那些實際開發中所謂“用不到”的東西才是真正要掌握的東西,是平庸和高手之間的分水嶺。
很多 phper 敲了多年程式碼,連個遞迴呼叫都不會寫,一個組織架構功能就把他難倒了,各種奇淫技巧,各種讓人看不懂。
不掌握資料結構與演算法,你去閱讀原始碼,頂多也就停留在 MVC 框架層面了,稍微底層的東西如資料庫、訊息佇列、Web 伺服器就根本無從下手。
演算法決定一個人的深度。
我建議你去慕課網或者極客時間上買一門課系統地學一下常見的演算法。並且手邊還要有一本書(c 語言實現)。
要練習。很多人放棄的原因其實是隻看不練習,前面看後面忘,於是就放棄了。沒有人光通過看能掌握演算法的(特別稍微複雜點的演算法)。
要總結,寫筆記。每種演算法都是一種思想(比如快排的分治思想就是一種通用思想),只有參透了思想才算真正掌握,才能舉一反三。比如我們掌握了分治思想,不僅僅能用於排序,還能用於大資料批處理中。
熟練掌握遞迴。很多演算法都能用遞迴實現。遞迴的本質是整體和部分間存在一致性(重複性),作為程式設計師的你要善於發現這種一致性。當一個演算法的操作具有重複性時,往往意味著可以用遞迴實現(比如二分查詢、快速排序,它們的操作都具有很規律的一致性,因而都能用遞迴實現)。
將所有學到的資料結構和演算法先用 c 實現一遍,再用 php 實現一遍(不要認為 php 跟演算法無關,實際是演算法跟語言無關)。
計算機與作業系統原理
去看看二進位制的世界長什麼樣,CPU 的運作原理,程式的執行過程,作業系統原理等。把這些搞明白後,很多問題會恍然大悟,以前覺得特別複雜的東西比如執行緒併發、核心態使用者態、緩衝區等現在會覺得特別簡單。
從這些學習中你還會學到很多偉大的設計思想,比如 Unix 中將一切視為檔案、虛擬化(硬體虛擬、虛擬記憶體等)、抽象(硬體抽象)、大道至簡(CPU 如何通過簡單的與或非異或電路實現複雜的儲存與計算),對你巨集觀層面的架構、設計都會有很大幫助。
socket 程式設計
phper 一輩子都在從事 Web 程式設計,卻有一大部分 phper 不懂 socket,也搞不懂 php 裡面的 pack、unpack 到底幹嘛用的。
一般高階語言都在底層 socket 上再做了一層封裝,並實現了常用協議如 http 功能,使得我們平時基本碰不到 socket。同樣,這對工程是好事,對程式設計師的成長卻不是。
比如我們都說 tcp 是流式協議,存在粘包問題,但面試中我問了很多嘗試過 socket 程式設計的都沒處理過粘包問題,把 tcp 分組當資料包用。
雖然 socket 對底層協議如 tcp、udp 進行了封裝,但如果直接面向 socket 程式設計,仍然有很多細節需要處理,如粘包、緩衝區、異常等,而這些細節讓我們能更真實地接觸底層知識。
另外,這些底層細節倒逼你去學習 tcp/ip 協議細節,更有甚你會把 tcp/ip 協議簇中的每層都學習一遍,自此你也瞭解了一個請求包在每層到底是怎麼封裝的,一次網路請求在區域網、廣域網到底是怎麼傳輸的。
真正實踐過,你才能真正搞明白 I/O 多路複用、reactor 事件模型這些看似高大上的東西——不但明白,還能在實際中使用。
熟悉了 socket 程式設計,你就可以設計自己的應用協議,這時候你就會用上 php 的 pack/unpack(假如你是用 php 寫)。
同樣,我建議買一本講解網路程式設計的書,用 c 語言實現的。或者是一本講解網路協議、tcp/ip 協議的書。同樣是要買經典,不要買什麼 30 天精通、7 天搞定的。
另外,我還是推薦你在慕課網、極客時間等 app 上買一節注重實踐的課程,跟著老師、同行一起學。要買注重實踐、有大量程式碼實現的,不要買那種阿貓阿狗比喻滿天飛的。
和演算法一樣,我建議你先用 c 語言實現一個 http 伺服器(當然如果只是為了學知識,沒必要做成 nginx),然後再用 php 實現一次。
物件導向、設計原則和設計模式
在面試過程中我發現,大部分工作 5 年的 phper 對設計原則和設計模式都知之甚少,對物件導向也是隻言片語,卻自認為自己一直在用 OOP。
很多人都認為這些原則很虛,離自己很遠,實際情況是,相比於 c 語言和演算法,物件導向和設計模式離業務程式設計師更近,也更容易、更需要掌握。
人們常說,程式設計師都認為別人寫的程式碼都是垃圾。但如果你去看看 laravel 等優秀開源專案的程式碼,你還覺得是垃圾嗎?
我們如何在實際工作中寫出開源專案水平的程式碼?
換句話說,我們如何寫出可維護、可讀、可擴充套件、可複用的程式碼?
你可能覺得上面一串概念很好聽但很虛,那麼你就想一件事:你在實際專案中看到某些人寫的程式碼想罵人,就說明對方的程式碼沒有滿足上面的條件;如果再進一步細想,你也不知道如何寫更優,那說明你也沒搞明白麵向物件設計原則,你寫出來的程式碼註定也是那樣,註定也會被後人罵。
另一個更可悲的事實是,市面上絕大多數 MVC 框架都是程式導向程式設計的,卻很少有人意識到這點。絕大部分 MVC 框架的示例程式都是寫個諸如部落格文章的增刪改查,控制器裡面寫業務邏輯,Model 層接收並存取資料。這裡至少有兩個問題:
- 所有的業務邏輯都寫在控制器裡面,根本沒有物件建模;
- Model 實際上是個貧血類(只有屬性沒有行為,當然有人可能認為對資料庫的增刪改查是 Model 的行為,但那實際上只是 Model 委託資料庫驅動去做的事情);
有些 MVC 框架主張在 Model 裡面寫業務邏輯,但這會導致 Model 違反單一職責原則:Model 同時負責了業務邏輯和資料庫操作。
框架們可能認為物件建模不是他們管的事,通過一個足夠簡單的示例能夠讓使用者更快速的掌握框架,從而獲得更多的粉絲使用者。
但事實是,很少有實際專案是像示例程式那麼簡單的。框架真正的罪責在於:通過一個過於簡化的示例程式引導了一批又一批追隨者們用同樣簡單的方式去實現複雜的業務。
框架設計者們無疑在 OOP、設計模式上有著很深的造詣,但這種造詣僅僅體現在框架本身,卻沒有延展到框架的使用上( Laravel 做得稍微好些)
不過話說回來,OOP 和設計模式是框架不能承載的設計之重,設計本身需要程式設計師自己去事先掌握,再好的框架也不能讓一個不懂 OOP 設計原則和設計模式的人去使用 OOP 程式設計(Laravel 在這個方向上給予了指示,僅僅是指示,就讓人們覺得 Laravel 相對於其他框架較難上手了)。
詳細討論 OOP 和設計模式超出了本文範圍,我們著重討論下怎樣學習這些東西。
學習 OOP 和設計模式最重要的是學習 - 實踐 - 複習 - 再實踐,而且,相對於演算法,OOP 和設計模式在實際中有更多的機會去實踐,只要你願意,幾乎天天都可以實踐。開發新專案時當然可以實踐,維護就專案也可以實踐,試著用 OOP 設計原則和設計模式去審查既有程式碼的問題並執行重構。很多人忽略了重構的價值(以及不知道怎麼重構),於是抱怨說公司沒有合適的新專案去實踐這些原則、模式。下單邏輯中被各種支付方式搞得亂七八糟?不妨把支付抽象成介面吧,試試橋接模式?各種優惠繞得人云裡霧裡?試試策略模式吧;訂單支付回撥裡面又是送積分又是發通知,各種後續業務塞不停?試試觀察者模式吧。
你需要買本設計模式的書,相比國內各種禪啊道啊,我建議你直接買 GoF 的《設計模式》,直接面對經典。
讀不懂經典?我再建議你去買一門課程,要買注重實戰的課程。極客時間上的一些課程就相當不錯。不要不捨得花錢。
不要認為只有單例、工廠、策略、代理常用就只學這幾種,要把 23 種全部掌握。很多設計模式雖然不常用,但一旦遇到對應的場景用上它跟不用它完全是兩個樣子,比如組合模式(composite)。
學習設計模式時,不要將思維侷限於 Web 開發,否則很多模式你會完全不能理解。比如命令模式、備忘錄模式在 Web 開發中很少用到,但在桌面應用中卻很常見,狀態模式則在遊戲開發中很常見。
相對於設計模式,設計原則更難把握,更依賴實踐領悟。比如 SOLID 五原則,光一個單一職責原則,如果沒有足夠的專案開發經驗與反思,都很難真正理解。
設計原則有很多,如 SOLID、GRASP、DRY、KISS,很多原則都是從不同的側面說一個東西,如果你不想把所有的都搞通,建議你著重研究並實踐 SOLID 五原則,我認為它是最經典、最重要的 OOP 原則。
最後,強烈建議你讀讀《領域驅動設計》這本經典(前提是你要有一定的專案經驗以及 OOP 和設計模式基礎)。
原始碼
上面的知識都掌握得差不多的時候,個人建議開始大量擼原始碼。
很多人在早期都擼過某些開源專案的原始碼,比如 Laravel,但大多半途而廢,原因是看不懂,或者是每段程式碼都看懂了,但放一起就看不懂,只知樹木不知森林。原因很簡單:你擼得太早了,上面的知識一個都還沒掌握就開始擼,人家優秀的開源專案各種設計模式各種抽象封裝,擼得動才怪。你連依賴注入都不知道,如何搞得懂服務容器和服務提供者?
要擼經典專案,star 多的,如 Laravel、composer、phpunit 等。要記筆記,擼出感想。
還要擼 c 專案,如 php 原始碼、swoole 等——這也是你學習 c 語言的好機會。
如果這些都擼得不過癮,可以放寬視角,擼其他語言的,可以去擼訊息佇列、資料庫、伺服器等經典專案,如mysql、kafka、nginx等,只要你有耐心有時間。如果真能擼到這種程度,你遠遠不只是個phper了。
部落格
每個程式設計師都應該寫部落格。堅持不斷地寫部落格,這點非常重要,我是很晚才意識到這點,以前一直相信一種觀點認為牛人都很忙,哪有時間寫部落格,後面發現牛人都有自己的獨立部落格,粉絲量也羨人。
寫部落格有兩個最重要的效果:促進自我總結與反思,建立個人品牌。
不過,寫部落格的時候不能功利性太強,為了建立品牌而寫,天天盯著閱讀量。因為這樣一方面導致你不敢寫,生怕質量不行,一心想憋大招,一文成名,結果是一個月才憋出一篇,結果卻沒人訪問,於是不想寫了。
寫部落格的直接目的一定是第一點,促進自我成長,第二點是順帶的、量變到質變的必然過程。
架構
至此,如果你也有一定的專案經驗,你可以重點考慮架構了——因為此時你已經有微觀(作業系統原理、資料結構與演算法)、準巨集觀(OOP、設計原則、設計模式)的加持,面對那些高大上的架構設計時,不會知其然不知其所以然。
架構有兩個特點:
- 架構是演化出來的,而不是一次性設計出來的。相應地,架構不是學出來的,而是實踐出來的。
- 架構裡面的東西大部分是”標價 15 美元,實際只值 5 美分“,所以沒必要被那些高大上的東西唬住。
有個誤區認為只有大規模公司才需要架構,小公司不需要。
在我認為,架構要解決兩個層面的複雜性:系統(技術)複雜性和業務複雜性,一般小公司不存在系統複雜性,但極有可能存在業務複雜性(很多小公司為了快速佔領市場,會開拓各種業務領域)。相應地,架構師可分為業務架構師和系統架構師。不過很多時候這兩者有很大的交集(比如複雜的業務架構往往需要相應的系統架構如訊息中介軟體的支援,頻繁的對外合作業務則需要開放平臺、應用閘道器的支援),因而無論你的架構側重點是什麼,你都要在技術和業務兩個維度有較高的修為。
另一個誤區是,phper 不可能成為架構師。
的確,從統計意義上說,java 程式設計師佔絕對優勢,但這不代表說只有 java 程式設計師才能成為架構師。架構師跟使用什麼語言沒有必然關係,只是實際中 java 程式設計師在生態上具有近水樓臺的優勢。架構師更重要的是架構思維,能夠統籌資源解決系統和業務兩個維度的複雜性。不過,就實際來說,因為很多公司在系統複雜性上來後,會轉而使用 go、java 等靜態語言代替 php、python 這種動態語言,因而,如果一個 phper 想成為架構師,最好會一門比 c 更高階的靜態語言,個人推薦 go,因為相對於 java 來說,go 更年輕,競爭對手要少一些(十年的 java 程式設計師一大把,而兩年的 go 程式設計師一大把),另外 go 很多地方和 c 類似,如果有很好的 c 基礎,會比較容易深入。
架構師要務實,就如我們在 OOP 時強調不要過度設計一樣,不要過度架構。當你公司的使用者量才十幾萬的時候就搞上各種訊息佇列、叢集、分散式、容器編排,往往會帶來不必要的複雜性,而且由於團隊成員專業能力以及服務治理能力跟不上,可能會導致使用上的混亂。
管理
我在架構後面寫管理,意思很明確:技術管理者需要有一定的架構能力。
我們一般認為,架構和管理是程式設計師職業發展的兩個方向,這話沒錯,但不代表兩者沒有重疊,相反,兩者之間有很大重疊。
架構師可以不具備管理能力,但如果他具備的話會如虎添翼。架構師往往需要統籌各方資源,以及規劃整合各業務團隊的公共訴求,需要具備溝通、協調、服務能力。
反過來,優秀的技術管理者則一定要有架構能力。
一方面是服人。雖然說管理要講究技巧,但如果作為團隊 leader 的你技不如人太多,想必團隊成員很難服你,很多時候你也無法就成員間的分歧給出合理的意見。
更重要的是團隊的成長。一個不具備架構思維的 leader 很難給團隊制定長期成長計劃,也很難做出合理的長期技術選型與技術儲備。
在中小公司,很多管理者是被從技術崗位逼上梁山的,剛開始的時候工作的區別僅是多了一項“分配任務”而已。
從技術到管理,個人認為需要進行如下思維轉換:
- 問題到此為止。
我們作為開發人員的時候,喜歡帥鍋。“這是產品問題,得找產品”、“這是 z 團隊負責的專案,要找他們”、“這是前人留下的 bug”。作為管理者,要明白這就是你的問題,如果源頭在其他團隊,那你就有責任去協調其他團隊解決問題。 - 不要抱怨。
"前面人腦子生鏽了?寫出這種程式碼"、“上面老是壓工時、堆需求”。
作為管理者,唯一要做的是解決問題。前人的程式碼有問題,組織人去重構;上面壓需求,需要向上管理你的上級。 - 不要憤怒。
你是不是因為某人寫了一堆爛程式碼而朝他大吼?實際問題更可能是他們缺少培訓,而這正是管理者的責任。 - 從執行者成為培育者、老師。
不要什麼都自己做,那是最差勁的管理者才做的事情。初為管理者往往會有一種擔憂,認為如果我不敲程式碼,團隊成員會不會認為我啥都不幹全讓他們幹?另一種擔憂是:其他人不如我,幹不好。讓他人做事,給他人成長的機會。管理者要做的是培訓、幫助。 - 從用技術的視角看產品轉成用產品的視角看技術。
- 有意識的訓練戰略決策能力(短期主義目光轉換成長期主義目光)。這也是為啥我強調技術管理者要有架構能力,要能從長期眼光規劃團隊技術發展道路。
未來之路
個人認為,phper 35 歲後大致有以下幾種職業方向:
- 創業。有人去做社群電商,有人做外貿,也有人想到個點子和幾個朋友開公司了。
- 做付費內容。很多部落格寫得好或者講座做得好的,適合去做付費內容,現在有很多知識付費平臺如慕課網、極客時間等,一些老牌部落格網站如 CSDN 也在做這塊,當然也可以自己建公眾號做付費內容、出書等。這需要你長期積累個人品牌以及較深厚的功底、一定的專案經驗。
- 技術管理。你可以朝著 CTO 的終極目標前進。這要求你具有較好的架構能力和一定的管理經驗。
- 架構師。並非每個人都喜歡做管理,有人就喜歡一直鑽研技術。無論是做管理還是做架構,對於 phper 來說,至少要會三門語言:c、php 以及一門更高階的主流靜態語言。
- 得過且過。很多人到了 35 歲還沒有較明確的職業規劃,跳來跳去還是個普通程式設計師,就屬於這種。把它作為一個選項是因為實際上該型別並不在少數。
總結
回應本文標題,一句話總結:phper 的未來出路就是不要把自己定位成一個 phper。