程序員如何高效地進行開發工作?Facebook的10x效率,了解一下
程序員如何高效地進行開發工作?
最近比較流行的一個說法是 10x 程序員,也就是 10 倍程序員,意思是一個好的程序員,
工作效率可以達到普通程序員的 10 倍。要做到這一點并不容易,我們需要在編程技術、工作方式、工具使用等方面全面提高。
第一條原則:抽象和分而治之
拿到一個任務之后,我們要做的首先就是進行模塊的定義,也就是抽象,然后對其分而治之。
為方便理解,我再和你分享一個在 Facebook 時,幾個前后端開發者同時開發一個功能的案例吧。
這個功能由一個前端開發者和兩個后端開發者完成,整個研發過程至少涉及 3 個抽象和分而治之的操作:第一步,前后端模塊進行自然的拆分。這時,前后端開發者一定會一塊兒認真討論,明確前后端代碼運行時的流程,后端需要提供的 API,以及交付這些 API 的時間。
第二步,兩個后端開發者對后端工作進行拆分,確定各自的工作任務和邊界。
第三步,每個開發者對自己負責的部分再進行抽象和拆分。
在這個過程中,一定要明確模塊之間的依賴關系,盡快確定接口規格和可調用性。比如,在前后端的拆分中,常常會采用這幾個步驟處理 API:
1. 前后端開發者一起討論,明確需要的 API。
2. 后端人員會先實現 API 的 Mock,返回符合格式規范的數據。在這個過程中,后端開發者會盡快發出代碼審查的要求給另一個后端和前端開發者,以確保格式正確。
3. Mock 實現之后盡快推到主倉的 master 上 (也就是 origin/master),并盡快將其部署到內部測試環境,讓前端開發者可以使用內部測試環境進行開發和調試。
4. 這些 API 還不能面對用戶,通常會先使用功能開關讓它只對公司開發人員可見。這樣的話,即使 API 的代碼在 origin/master 上部署到了生產環境,也不會對用戶產生影響。
通過這樣的操作,前后端的任務拆分就順利完成了。
提高抽象和分而治之效率的一個技巧是,在設計代碼架構時注意尋找合適的設計模式。
設計模式指的是,設計過程中可以反復使用的、可以解決特定問題的設計方法,最經典的莫過于《設計模式:可復用面向對象軟件的基礎》中列舉的 23 個設計模式,以及針對企業軟件架構的《企業應用架構模式》。同時,我們還要注意公司內部具體的常用模式。這些模式都是經實踐檢驗有效的,且傳播較廣容易理解,都可以作為你進行模塊拆分的參照。
具體實現功能的過程中,也會處處體現分而治之的思想。最主要的一個表現是,每個開發者都會把自己的代碼盡量做到原子性。代碼的原子性指的是,一個提交包含一個不可分割的特性、修復或者優化。
在實際工作中,功能往往比較大。如果只用一個提交完成一個功能,那這個提交往往會比較大,所以我們需要把這個功能再拆分為子功能。
比如,某個后端 API 的實現,我們很可能會把它拆分成數據模型和 API 業務兩部分,但如果這樣的提交還是太大的話,可以進一步將其拆小,把 API 業務再分為重構和添加新業務兩部分。
總之,我們的目的是讓每個提交都做成能夠獨立完成一些任務,但是又不太大。一般來說,一個提交通常不超過 800 行代碼。
第二條原則:快速迭代
第一,不要追求完美,不要過度計劃,而是要盡快實現功能,通過不斷迭代來完善。優秀的
架構往往不是設計出來的,而是在實現過程中逐步發展、完善起來的。
Facebook 有一條常見的海報標語,叫作“Done is better than perfect”,意思就是完成比完美要重要。要實現快速迭代,我們在設計和實現功能時都要注意簡單化。
有些開發者過于追求技術,投入了大量時間去設計精美、復雜的系統。這樣做沒有問題,但
一定要有一個度,切忌殺雞用牛刀。因為復雜的系統雖然精美,但往往不容易理解,維護成
本也比較高,修改起來更是不容易。
所以,我們在 Facebook 進行開發的時候,盡量使用簡單實用的設計,然后快速進行版本
迭代。
第二,在設計的實現中,盡量讓自己的代碼能夠盡快運行起來,從而盡快地驗證結果。我們
常常會先實現一個可以運行起來的腳手架,然后再持續地往里面添加內容。
在工作中,因為往往是在一個比較大的系統里工作,不能很容易地運行新代碼。這時,我們可以編寫腳本或者單元測試用例來觸發新寫的代碼。通常情況下,我們更傾向于使用后者,
因為這些測試用例,在功能開發完成上線之后,還可以繼續用于保證代碼質量。
在我看來,在開發過程中,能觸發新寫的代碼幫助我開發,是單元測試的一個重要功能。
第三,為了能夠快速進行驗證,一個重要實踐是設置好本地的代碼檢驗,包括靜態掃描、相關單元測試的方便運行,以及 IDE 能夠進行的實時檢查等。
第四,代碼寫好之后,盡快提交到主代碼倉并保證不會阻塞其他開發人員。實際上,這是代碼提交原子性的另外一個重要特點,即代碼提交的原子性,可以保證主代碼倉在理論上能夠隨時基于 master 分支上的任何提交,構建出可以運行的、直接面對用戶的產品。在這種方式下,每個開發者在任何時候都可以基于 origin/master 進行開發,從而確保 Facebook 幾千人共主干開發時分而治之能夠順利進行。
關于實現代碼提交的原子性,我還有一個小技巧,就是如果當前編寫的代碼提交實在不方便馬上推送到 origin/master 分支上,我們也可以頻繁地 fetch origin/master 的代碼到本地,并在本地對 orgin/master 進行 rebase 來解決沖突。這樣就可以確保,我們開發的代碼是基于最新的主倉代碼,從而降低代碼完成之后 push 時沖突的可能性。
第三條原則:不要做重復的事情
不做重復的事情,是很多開發模式的基礎,也是我們非常熟悉的一條開發原則了。比如,我們把一段經常使用的代碼封裝到一個函數里,在使用它的地方直接調用這個函數。
代碼邏輯的重復,不僅僅是工作量的浪費,還會大大降低代碼的質量和可維護性。所以,我們在開發時,需要留意重復的代碼邏輯,并進行適當的處理。
具體來說,首先是尋找重復的邏輯和代碼。在動手實現功能之前,我們會花一些時間在內部代碼倉和知識庫中進行查找,尋找是否有類似的功能實現,以及一些底層可以復用的庫,過程中也可以直接聯系類似功能的實現者進行討論和尋求幫助。另外,有一些 IDE,比如Intellij IDEA,可以在編碼的過程中自動探測項目中可能的代碼重復。
找到重復的邏輯和代碼之后,主要的處理方式是,把共同的部分抽象出來,封裝到一個模塊、類或者函數等結構中去。
如果在開發新功能時發現有需要重構的地方,一個常見的有效辦法是,先用幾個提交完成重構,然后再基于重構用幾個提交實現新功能。