走出軟件開發法則
如果你也是一名程序員,那么相信從你第一天學習編程起,就會被灌輸很多關于軟件開發中的法則,它們有些來自于課堂,有些來自于書本,還有些則來自于工作中前輩的教導。我們總是努力地去學習這些法則,然后再將它們傳授給更多后來人。然而,我們是否只是不假思索地接受它們,而沒有真正嘗試著去理解過這些軟件開發中的法則呢?在這篇文章里,我將嘗試通過來自開發、測試以及流程3個不同方面的問題,談談我對這些軟件開發法則的認知。
面向對象?
今天我們在軟件開發時最常使用的編程語言,如Java、C++、Python、Swift等等,都無一例外地支持面向對象的編程特性。而那些有關程序員的招聘信息中,也幾乎都能看到“具備面向對象的程序設計和開發能力”的要求。盡管大部分程序員都能熟練地背出面向對象編程的三大特性:繼承、封裝、多態,但似乎他們對面向對象的認識也僅僅停留在了這些概念以及某一種編程語言的實現語法上了。我之前曾提到自己在考察程序員時經常使用的方法,我會讓應試者嘗試用面相對象設計的方法來描述面試所在的房間,結果卻發現大部分面試者無法給出令人滿意的答案,甚至有些人完全沒有思路。可見程序員們雖然都會在簡歷中寫上自己精通面向對象編程,但實際卻沒并沒能真正理解它,更別說使用面向對象的思想去解決問題了。
面向對象并不是一句假大空的口號,它其實為我們提供了一種思維方式,幫助我們更好地進行軟件的構建、組織以及復用。但要想掌握這種思維方式卻并不簡單,這有點像我們都知道正確的價值觀應該是怎樣的,但一旦需要應用到自己身上卻很難做到一樣,面向對象的思維方式需要通過不斷的實踐運用才能獲得。然而大部分程序員并沒能這么做,或者說沒有機會去進行更多的練習。今天的開發與以往相比已經大大簡化了,那些底層需要復雜抽象的設計都有了可以直接拿來使用的框架,程序員要做的更多是基于這些框架去寫業務實現邏輯。雖然開發變得更簡單了,但這卻在一定程度上減弱了我們的編程能力,也出現了很多程序員不會編程的事例。當我們需要運用面向對象的思維去進行分析和設計以解決那些復雜問題時,往往就會覺得力不從心,無法精準地完成它們。
我所看到另一個更讓人擔憂的問題是,很多程序員錯誤地認識了面向對象。例如,他們會想當然地認為,面向對象就是把任何實體描述為一個DTO(Data Transfer Object),用Getter,Setter方法去存取它們的屬性,然后在其他業務組件中去處理它們。這的確是一個常見、也在大部分編程書籍中被作為代碼示例的應用模式,但我想說DTO,你真的被濫用了。當你必須把所有實體看作DTO時,本身你的編程思維就受到了限制,你所開發的程序也將變得機械、缺乏擴展性,越來越難以維護。DTO只是面向對象中描述對象的一種形式,你應該以更高的緯度去判斷一個實體應該如何表現。比如,數據庫中的某一條記錄,它既可以通過那些OR Mapping框架被映射為DTO,同樣的,你也可以創造一個類似Record這樣的鍵值對的類來表示它,而后一種往往在批量數據分析、報表加工等場景下更加合適。
我們需要具備面向對象的編程思維,但在我們沒有真正擁有它之前,也千萬不要被那些已有的原則、模式和框架束縛住你的思維,多看那些優秀的程序,并認真思考自己的每一次的程序設計,及時進行總結和反思,你將會從中逐漸獲得超越面向對象本身的正確編程思維。
測試非常重要?
測試的重要性不言而喻,從倡導進行單元測試,到TDD(測試驅動開發),我們似乎對程序員進行嚴格的測試并保證代碼質量有了越來越高的要求。今天,有很多開發團隊都會要求程序員們采用TDD等方式來測試他們的代碼,甚至還會通過測試覆蓋率等指標來對程序員進行考核。這不禁讓我想到,我的一位馬來同事曾經為了滿足公司代碼注釋行數要求,而把一行注釋硬是拆成每個單詞一行的趣事。我們是不是又一次為了滿足某種教條而本末倒置地去做一些不那么必要的測試了呢?
-
測試不是為了證明那些必然正確的東西:我始終認為程序員們自己是最明白哪些功能需要測試的。如果這一點是成立的,那又何必要求他們去為每一個功能或方法寫測試案例,又或者讓他們在開發之前就去編寫完整的測試用例呢?測試一定是被用來證明特定需求是否得到滿足的,你應該為那些可能存在不確定性的需求或者對外提供的服務來編寫全面的測試案例,而不僅僅是為了滿足測試覆蓋率,去給那些明明知道必然正確的實現細節做測試。
-
測試無法提高代碼的質量也不會讓代碼更易于維護:有人說測試是為了提高代碼的可維護性,是為后來人而寫的,但在我看來,代碼才是能夠決定可維護性的唯一條件,如果開發者的思路清晰,代碼又寫得優雅而具有條理,那它必然是可維護性好的。反過來,盡管有那些自動化測試案例,但代碼卻寫得非常混亂,這樣的程序同樣難于維護。完善的測試確實能夠有效保證程序的準確性,使得我們每次修改可能造成的錯誤風險降低,但我們仍然需要優秀的代碼來提供良好的可維護性。
-
測試的方法很多:關于如何測試,我們也不應機械地僅僅去應用那些所謂的自動化測試,在一些較小的,或者需求存在不斷變更可能的項目中,我們完全可以用人工測試的方法去快速判斷一個功能是否準確,而不是每次需求發生變化,就去重復地寫一個測試案例以及一套實現。當需求穩定下來之后,我們還可以完善測試案例,讓它們可以在未來被重復執行。總之,根據項目情況和環境,靈活地決定最合適的測試方法。
-
集成測試越早越好:最后我想說,集成測試必須盡早去做,我看到很多項目中出現的問題,往往是系統間的接口沒有盡早約定和測試驗證所導致的。雙方都錯誤地認為對方會在接口中提供這樣的功能或數據,但最后卻發現他們的理解存在偏差,這往往需要極大的代價去修復這些問題。盡早進行集成測試,甚至前期使用一些Mock數據來做驗證,能夠有效保證系統開發的平穩進行,以及團隊間更加順暢的協作。
層出不窮的方法論?
幾乎每隔2、3年我們就能看到軟件開發領域誕生一套新的方法論,比如在軟件架構領域,我們經歷了面向模塊、面向組件、面向服務(SOA)直到今天我們提出微服務架構。而在開發流程與團隊協作領域,我們又經歷了從瀑布式和工程化的開發方法到敏捷、XP、Scrum開發,以及今天我們經常掛在嘴邊的DEVOPS。每一種新方法論的出現,都會伴隨著新一輪大規模的系統改造,同時也會對團隊協作方式產生巨大影響。當我們對這些新的潮流趨之若鶩之時,是否也曾想過這些最新流行出現的原因,以及它們是否真的適合你的企業或團隊呢?
我曾作為甲方參與由一家知名咨詢公司所組建的開發團隊,團隊的任務是開發一套集團內部的電銷核心系統。這個開發團隊號稱采用了Scrum的管理方式和流程。但我卻很快發現,那些所謂的Scrum方法往往只是停留于表面的形式而已,例如,每日的Standup晨會,團隊成員們只是例行公事般報一下流水賬,而在開發過程中所采用更小的迭代以及每日集成等方法,也由于團隊成員技能的參差不齊,而經常導致項目版本的延誤,或者因不必要的等待造成的開發效率低下等問題。與之類似,諸如結對編程等在國外流行起來的開發方式,我也幾乎從未在國內開發團隊中看到成功的實施案例。
那么,我們又應該如何看待這些層出不窮的方法論呢?在我看來,這些所謂方法論都出現在不同的時代大背景之下,又與當時的技術環境緊密相關。比如SOA最流行的時候,恰恰是那些大型企業為了應對內部日益復雜的業務需求而提出的,而作為它的基礎設施提供者,像IBM、Weblogic、Oracle等一批中間件服務廠商也在那個時期獲得了快速發展。而今天微服務架構以及DEVOPS的出現,則是為了應對如今互聯網環境下需求快速變化,以及越來越復雜的運維場景而產生的,它們更是與當前云計算、大數據等領域的飛速發展緊密相關。不難發現,無論是軟件架構還是開發協作,這些方法論都在引導著我們向更小、更高效以及更能適應變化的方向發展。對任何企業或團隊來說,永遠沒有什么萬能的方法論,你需要根據自己企業所面臨的問題和目標,來對這些流行的業界最佳實踐進行深入的切割或補充,從而得到對自身最行之有效的實踐方法,而不要像趕時髦般去急著應用用那些所謂最新技術或方法。
程序開發領域中還有著很多可以拿來探討的問題,通過對這些問題的思考,我們發現在軟件領域并不存在那些非黑即白的所謂真理或法則。程序開發的美妙之處在于,它是一種深入的腦力活動,充滿著令人興奮的變化和各種抽象思維,我們在一次次選擇和解決問題的過程中獲得進步。因此,不要被任何思想、教條、方法論束縛住你的思維,只有這樣你才能體會到程序開發中的真正樂趣。
來自:http://www.jianshu.com/p/c1bcb7c5c29a