專欄文章
RD養成術之Java 學習路徑
對症下藥
撰文者:Jarey
先前提了那麼多的症狀(撞牆期)與藥方(好書),那麼總該要來談談如何對症下藥吧。沒錯現在就讓我們來探討如何對症下藥讓你可以早日脫離苦海(撞牆期)進入到天堂(領悟期)。首先我們將不同學習時期的RD,區分為9個Level,不同的Level一般你會遇到不同的撞牆期,每一次的突破就代表著你又提升了一級。接著我們在依照不同的Level來思考該如何自我提升。最終只要穩札穩打保持熱情的學習態度,相信所有的難關終究都會有突破的一天。
Level 1 剛開始入門學習Java
此刻你正在學習Java程式的語法,你的第一個Java程式HelloWord才剛顯示在畫面上。初期並不會接觸到太多物件導向的東西,你的應用程式只會全部都寫在main函式中,並以System.out.print為你主要的輸出介面,System.in為你主要的輸入管道。有了基本的輸入與輸出管道,你可以開始著手寫一些小型的計算程式(99成法表),或是一些小遊戲(例如獨數字),並藉由此熟悉了解Java的語法和基本的控制邏輯(如if else while switch..)
一段時間後當你寫的程式變多,main函式變大後,你開始學會如何去切分函式,將部份功能切分出去另外寫一個函式呼叫,此時你要會習到何謂call by value與call by reference接著在過了一段時間你開始想要使用一些外部的lib函式庫,你會找到一些包裝成jar的函式庫,並試著使用它。通常在此時會遇到一個小撞牆期,你開始對於lib要放在那裡產生疑惑,接著為了要使用lib你會接觸package與import的議題,同時在使用lib時會遇到物件的初始化與使用,你開始會對何謂類別與物件產生困擾。Lib是如何載入的?為何要有package? import套件為何有時會找不到?什麼是classPath?此刻的你或許程式的執行與使用上都沒有問題,因為你會找到許多網路教學教你如何設定與使用,但在心中卻不知道為什麼要這麼做,為何這麼做就可以正常執行。
對症下藥:
王森的Java深度歷險可以為你提供解答,雖然現今在高度依賴Eclipse IDE工具的情況下,一般人是很少會在用command line去執行程式,只需利用Eclipse點一個Run鈕一切就都幫你搞定了。但相對的這也會讓你失去許多底層的運作知識,這將會在未來那天當你按下Run鈕時程式跑不出來了,你就無法自行解決了.因為你不知其內部的執行原理自然也沒有線索讓你去追查錯誤來原了。往往一個卡住可能就會讓你束手無策,這也是過度依賴IDE工具下的問題,所以IDE工具還是要用,只工具在背後為我們做了什麼樣的事情我們還是要懂。
Level 2 開始進入學習Java API函式庫
進入此時期的你,你的最佳伙伴便是JAVA DOC文件,你會開始花大量的時間在查文件,了解API的用法。由於此時你還沒有物件導向的觀念,所以你會覺得要花費很多的時間去死記這些函式,建構的方法、呼叫的函式名稱、需要傳入的參數、執行回傳的結果。此刻你會發覺Java的函式庫相當的複雜與龐大,在與其對抗一段時間後你會遇到下一個撞牆期。
學習Java API可以說是一個門檻,很多入門者到了這一關撐不住就放棄了。因為Java最大的特色就是本身函式庫功能相當的強大。強大的背後就是需要學習的東西很多,你會時常遇到怎麼函式呼叫的流程明明都照書上的打了,功能怎麼還是跑不出來,怎麼還是一堆紅色的Bug.此刻的你會常遇到卡關,卡關的次數可能多到超乎你的想像。通常此刻可以很明顯的分析出那一些人是具有寫程式熱情的人,那些人是不具有寫程式熱情的人。有熱情的人你會發覺他愈戰愈勇,開始每天要不宅在宿舍裡狂寫程式,就是去圖書館裡抱一堆書回家查資料。你會發覺與他吃飯時他會時常恍神,或是兩眼無神,因為他的腦子己神遊在程式碼之中在正苦思(媽的怎麼會跑不出來,一定有什麼地方寫錯了,不對呀明明我都確認過了,會是昨天明上我加了個新功能影響到的嗎?不會呀昨天寫的程式應該與不至於會造成這個結果?靠對了有可能是那個造成的),接著你就會發現他突然放下碗筷飛速的衝進電腦房裡,接著過了五分鐘你會聽到他突然大叫(YA!爽啦,解決了,靠!我怎麼會被這一個小問題卡那麼多天)然後就會很高興跑出來繼續吃飯,然後不斷的在與你分享他剛剛解決了什麼問題(重點是也不管你聽不聽的懂)。
對症下藥:
看到這裡如果你發覺曾經有我上述所提的經驗,那麼首先要恭喜你,你是具有成為一位程式設計師的潛力。為什麼這麼說呢?因為你的經驗正在慢慢的累積中,通常卡愈久的難關被你破解後你的印象會愈深刻,而且通常卡一個關同時至少會為你帶來五個以上的解法,因為你在苦思去try各種解決時,無形之間你也吸收學習了許多的知識,而且這些會是印象深刻的。 API函式庫的學習其實就是在不斷的卡關與破解中累積而來的,當你看到一個人可以很順的打出一段完整的IO檔案讀取寫程式,或是一段Socket連線讀寫取程式,別懷疑他不一定曾經為這二段程式遇到許多奇怪的Error與Bug並花了數天的時間才通通解完,這二段程式曾經是他廢寢忘食,拼了命才順利解決的程式,相同的程式碼他可能重覆打了不下數十次並且還試過了各種不同的寫法。你想在他經歷過那些痛苦的卡關過程後,現在打起來不會很順嗎?重點是這個流暢的撰寫技能並不是靠死記而來的,而是靠錯誤的解決累積而來的。所以最佳的藥方就是不要死記,而是動手去寫去嘗試錯誤,並要有熱情去解決錯誤.如此你才會記的住,並同時可以舉一反三。若錯誤無法激的起你的熱情去動手解決它,那麼或許程式設計這條路可能不適合你因為往後要遇到的關卡還多
的很。
在此要推薦的工具是從Java IO與Network兩個API函式庫熟悉的方向去練習.
Level 3 開始進入學習物件導向概念與架構設計
有人可能會問說,沒有物件導向的概念怎麼去使用Java API函式庫。沒錯你在學習使用API函式庫時會接觸到一些物件導向的概念,但僅此於讓你會使用別人利用物導向架構寫好的API如何去建置與使用,也就是你用的工具(API函式庫)本身是具物件導向的,但你自己寫去呼叫這些API的主程式結構是不同物件導向的。所以不會物件導向還是可以學會如何去使用API,因為有許多API都己高度的包裝成容易使用的結構,許多的資料結構設計技巧與演算法都己被封裝在該API內部,一般人是看不到的。
一般人在學習物件導向概念時都會經歷二個階段,我將其稱之為:程式切割與應用組合,接著讓我們來探討這兩個時期的學習過程:
程式切割時期:
當你的程式規模開始變大後,你就會開始需要做切割的動作,在這之前你的應用程式許是一隻很龐大的類別,裡面有許許多多你所撰寫的函式,函式愈來愈多後你開始思考是否要將一些屬性相同或功能類似的函式另外寫成一個類別來使用,到了這個階段你會開始思考如何做程式切割的動作。
應用組合時期:
當你把應用切割成許多類別後,你開始要來組合利用它們。但往往此時你會發覺怎麼感覺好像切太細了,切割後組合出來的程式碼怎麼比沒有切割時的還要肥,多了許多的物件建構流程,而且還有許多參數傳遞上的問題,原本都寫在同一類別裡很直覺的參數使用,現在切到了不同類別去後好像不太容易組的起來,而且互相之間的關係變復雜了,程式三不五時就會發生NULL Point的例外,為了解決這些錯誤你又多撰寫了很多判斷碼,到最後發覺組出了個四不像,看起來一但都不像是物件導向,雖然最終程式是可以動。
上述提到的是一般剛進入這領域的開發者最容易遇到的困境,這就學習物件導向精神的撞牆期。在這個時期你會不斷的學習切割與組合,不斷的學習各種不同的切割方法,與不同的組合應用方式,在這學習的過程中你所使用的工具絕大多數都是,物件、繼承、封裝其它比較抽像的精神(如多形、抽像、介面)在此刻並還不會了解如何使用。卡關了一陣子最後你將會體悟到問題原來是發生在,你只是單單把應用程式切割成許多獨立的物件,但這些物件之間並沒有在組合運作成一個功能,因此你的應用程式單單拿這麼多小物件來組合應用自然應用程式之間到處都是重覆的程式碼。因此你會開始學習體悟到原來要切割完後還必須要把許多小物件在加以組合成Lib函式庫.而切割的許多小物件的好處就在於可以重覆利用去組出許多不同的函式庫。而最終主程式主要是利用這些己組合好的函式庫而不是直接去存取這些小物件。到了這個階段你才會開始思考學習使用多形、抽像、介面,這些比較抽像的概念去組合出你自己的函式庫。然而當你開始要學習自己組函式庫時會在遇到一個撞牆期,就是要如何才能組出好用又有彈性的函式庫。OK好不容易你突破組出了個函式庫,接下來你想說終於可以來寫主程式好好利用一下剛開發的函式庫。但事情往往沒有想像中的簡單,因為當你要開始用它時,會發覺不如該從何下手,如何應用才能發揮這函式庫最大的優點。或者是當你要實作某個應用功能時才驚覺當初沒有預先思考到會有此用途,所以架構上根本不支持,或是需要在回頭去大改你的函式庫架構才能加入此新功能,更慘的是可能還要回頭去從切割物件開始重新切割設計在組才行。由上述可得知在光在學習物導向時就會遇到三次的撞牆期,一次在了解如何切割,第二次在了解如何組合,最後第三次在了解如何應用,而且這三關都相當不好突破。還記得我在第二章學習曲線中提到的低潮期嗎?一般低潮期就是遇到撞牆期卡太久無法突破時而發生,而在這階段你一口氣撞了三次牆,所以幾乎學習Java的人一般在此是極容易進入低潮期。一般人在這階段會停留相當長的一段時間,因為你會不斷的來回在這三個週期之間,你會從應用面去思考出組合的設計面,然後退一步去重新思考組合的設計,接著會在從組合設計的元件需求在退一步去思考你的物件要如何切割,就這麼一直來來回回的重覆學習。對於有熱情的人在這一段時間將會是你最充實的時光,因為你會有很多關卡可以突破,每次的突破都可以為你帶來成就感,成就感會支持你不斷的在往前去追尋更巧妙的設計技巧。
對症下藥:
就理論面來說在此刻你開始必須要對Java的中與物件導向相關的語法和限制相當熟悉了解,要了解這些語法與限制最快的方式就是去研讀SCJP(但我不建議去考它),利用SCJP來補足自己在理論面的不足。
接著你必須要充實實作面的經驗,最快的方式就是去吸收大師們的經驗,也就是開始研讀有關於Design Patterns的相關書籍,在此我特別推薦結城 浩的一本Design Patterns於Java語言上的實習應用,理由是這本相當的深入淺出,對於初學者來說是最佳的入門書藉,若你一開始就研讀原著Design Patterns反而會更容易造成你的困惑。
當然最後要靠不斷的累積練習,此時要練習撰寫大型的應用程式,嘗試自行開發撰寫一個超過一萬行的應用程式,因為只有大型的應用程式才會感覺的出來物件導向架構所帶來的差異。Design Patterns的書籍不應只是看過一次,你必須要動手每一個去動作實作了解其存在的意義,接著需要學習多種Pattern混合應用。所以通常此書需要一段時間後就重新在去翻一次,你會發覺你每次重看它時所得到的領悟都會有所不同,當你有這種感受時,恭喜你,這代表你己有所成長了。
Level 4 開始進入學習多執行緒技巧
多重執行緒程式設計,將會是學習過程中另一個重大的關卡。一般人在學習路線上首次遇到多執行緒的需求通常是在撰寫與網路服務連線相關的應用軟體上。由於要同時能讀與寫,加上網路的狀況時常會有IO Block的機會,因此你需要為你的程式碼加上執行緒。由於Java是本質就支援多重新行緒,所以在Java 上執行緒的入門是簡單的。但只要多重執行緒又關係到資料共用,那麼一切事情就會變的複雜,你會開始為了控制執行緒而讓整個應用程式愈來愈複雜,同時在多重執行緒裡的除錯難度很高,你會常苦於解決偶爾才發生的異常現象,但又不知如何複製這問題,就算複製出來了也很難找到問題的徵結在那裡。synchronized、wait、notify、notifyall...等等控制函式你會知道他們存在,但卻很難理解使用他們的方式,有時連自己都不太有把握這樣寫是否正確,現在執行起來看來是正常的,但卻不敢保證在各種多執行緒運作狀況下一但都能永遠保持正常。這種不確定感會一直持續長久的一段時間,直到有一天你需要撰寫一個大型複雜的多執行緒程式時,你才會真正深入去研究了解它一但運作的機制與需要注意的地方.
舉個例子來說,當你正在為你的畢業論文利用Java Multi Thread技術去撰寫實驗模擬程式,你會開始發覺怎麼每次跑出來的數據都不太一樣,感覺事情總有點怪怪的,為了你的畢業論文與實驗數據,你必須要深入去了解多執行緒設計上的限制與考量,在大量實驗模擬的環境中,你必須有辦法控制每個執行緒執分配執行的時間、控制存取資料的一致性、避免lock的狀況發生,每一個微小的差別都會造成最總結果很大的變異。最終你會體認到用多執緒相當不容易控制,在需要精準控制的實驗中到不如以單執行緒自行撰寫排程以自定的虛擬時鐘以軟體模擬多工同步的執行。這是因為多執行緒的問題與通常是要在相當大量的應用規模時才會被突顯出來。所以除了通常只有到了職場撰寫真正要具有廣大用戶規模應用軟體時(例如訂票程式,電影訂位、火車訂票或是為論文驗證所撰寫的軟體實驗模擬器),才會有機會去體認到多執行緒的一些複雜運作機制與設計。
對症下藥:
在學習Android過程中最常遇到的問題就是什麼是UI Thread?什麼是WorkThread,為什麼我在work thread無法直接去存取UI Thread的資源?我要如何設計非同步的UI更新元件?什麼是Handler ? 什麼是Looper? 這些都是因為Android是手機平台,在資源有限的情況下,你必須要很懂得利用Thread 才能為用戶創造出很平順的操作體驗,這也是在進入Android設計最容易卡關的地方。以下這本書同樣是結城浩所著的,Java Multithread Design Pattern。裡面介紹了許多經典的Thread設計模式,學習這些其實最主要的目的是在於讓你可以比較容易看的懂框架設計的Thread處理機制為何,要如何配合著框架使用。
Level 5 開始進入學習架構應用與最佳化方式
在你看完了Design Pattern 相關的書籍,開始對物件導向有些概念後。你開始會習慣在每次開始寫程式前,先行規劃此專案的結構。要你完全先利用UML或是紙上談兵把所有的架構都規劃好在開始動手反而會另你無所適從,思考不出完整的結構。而是需先動手寫了一些東西後,你才會有感覺想到要怎麼去架構它,但往往當你發現不對勁了想要去改變程式結構時。此時往往是牽一髮而動全身,因為所有的互件之間相依性太重,加上程式碼愈大愈肥,每次要你動刀去執行架構的最佳化或重新設計,都像是要叫你全部砍掉重練一樣的難以抉擇。也或許這些肥胖醜陋的程式是公司長期下來累積的成果,你根本不敢去動它,只能依造前人的寫法繼續在它身上加料直到它肥胖到動不了為止。我們都知道程式設計師每天所要面對的東西是什麼呢? 程式碼嗎?完全沒錯除了程式碼還是程式碼,當你每天都要面對的東西是你心裡很想去改造它但又不敢改就算了,還被迫要在上面持續的加料讓它更難以維護,就像是給你把鏟子叫你自掘墳墓。
上述的狀況或許你會問說,那怎麼不一開始就先把程式架構設計好在來寫就好了。當然這是最理想的狀況,但職場上現實的狀態是。你一進去時可能接手的是前一位離職員工所留下的屎尾,你可以把它砍掉重練,但你有把握重練的出來嗎?況且重練可能要天天加班到半夜,但薪水卻不會增加。更慘的是重練成功了你還有可能得背上教育所有人用你新的做法去寫程式。因為可能絕大多數的人己經習慣在一團屎上加料了,現在你把屎換成了全新美麗的容器,大家反而不敢把屎在亂放上去,只好把屎全移轉給你,請你動手幫忙處理,理由只有一個,這是你設計的還是由你來做比較熟吧。
對症下藥:
此時你需要學習的不在是撰寫一套全新的應用軟體時的設計技能,而是一套可以把各種不同結構問題的程式進行部份的矯正導向正途的技能。其實這能力往往比給你重新打造新的應用程式還要困難。想想在一棟己經半倒的房子上進行結構性的補強,並且在補強的過程中還不能讓它倒下,這比讓你重蓋一棟是難多了。你可能一次只能改一點點,並且利用有限度的工具去做改變。在這裡就是Java重構派上用場的時後了,你需要開始學習如何去做重構。
在此我推薦三本工具書協助你,第一本為結城皓著的Java重構,這此並沒有一口氣將原著的近70個實踐全寫進去,而是精選了一些重點來講,另外每個實踐都會附上一張表,清濋的說明了遇到的問題、可解決的方法、此方法帶來的優點、此方法同時會帶來的缺點、實踐的流程...,是本相當適合初學者入門的書籍。 另外二本侯捷的書籍則是在你看完第一本後接著可以研讀的,該書為完整含蓋了原著所有的實踐手則。第三本則是在將重構與Design Pattern 做結合,告訴你可以導入何種Design Pattern去進行程式碼的重構,可以讓你將重構與Design Pattern 之間的關聯性連結起來,有助讓你思緒更加清晰。
Level 6 開始進入學習框架結構
當然進入框架學習的階段,代表的你將要投入去學習某的應用領域,不同的領域與平台都會有各自其設計的框架系統需要學習。一般在進入學習框架應用時,最容易遇到的狀況為,控制權主要是掌握在框架身上,你必須要先了解框架的應用才能在其上撰寫開發應用程式,這與一般撰寫應用程式主控權在開發者身上有相當大的差別。這是由於現今的框架大多是以Ioc(反轉控制)的方式去設計,以Android框架來說,你大概會遇到許多的override、許多需要繼承實作的元件、許多元件需要實作後在向框架註冊使用、同時你會遇到許多的抽象類別與介面。主要的目的都是在降低類別之間的相依性,而降低相依性的做法就是全部都針對介面而不是直接對面實作。高階的應用模組與低階實作模組,兩者之間都將相依於抽象介面,而不是直接連接。同時抽像介面不應該相依於細節,而需將細節留給用戶去實作撰寫。說到在是否感覺更抽象了呢,沒錯框架本身就是由一組抽象的結構所組合而成,而開發者的任務就是去一一的實作細節的部份。函式庫主要著重的是演算法、與片段功能的重覆利用,而框架是著重於架構的通用性、可重覆利用的流程與結構。因此許多剛要進入Android框架領域的開發者,往往會在一開始就被一堆抽象的結構搞的一頭霧水,更別說要去一一實作這些抽象結構,將你的應用程式依附在其中。你會發現要學的不只是單純的函式呼叫的方式,而是一整個系統的流程與結構你都必須相當的清濋,才會知道該override那些函式,同時該在這些override函式中實作什麼內容、物件資料該如何在框架之間互相傳遞與分享。同時隨著你使用到愈來愈多的框架元件後,所帶來的複雜度也就愈高,你開始會感覺到自己好像許多程式用撰寫上都因受限與框架結構而無法造以往的開發經驗撰寫,必須要重新學習或設計符合此框架的開發方式。
對症下藥:
一般而言當你學習的程度愈高時,你就會發現愈會找到相關的書籍工具在輔助。因為你現在需要的不是一個工具,而是一整套的工具,這些工具全都在你以往學習的過程中累積而來的.框架的應用主要著重在抽象,所以你必須要重拾design pattern與重構,並加深自己在繼承、多形、抽像類別與介面之間的理解力。
此時需依照你要直接深入的去熟讀該框架的定義、規則、結構,要大量的閱讀官方撰寫的範例程式(直接看Android的Sample Code或是內建的應用程式其原始碼),因為框架是Google制定的,內建的應用程式也是他們寫的,直接參考或閱讀內建的軟體原始碼,將會有助於你加速理解框架的應用方式與技巧。
Level 7 開始進入大量學習工具與第三方函式庫
當你開始要真的接觸到各項專案開發時,你會發覺到若全部的軟體工作都要你從無到有的打造幾乎是不可能即時在期限內完工。就像你今天想要出門釣魚,但卻在家從釣竿開始做起,等你釣竿做完時大概夜己晚也不用出門了。這讓我們思考有必要全部都自己從頭做起嗎?通常一個專案都會有你需要專注的核心部份,核心功能與應用是需要自己做起,但細部的零件卻是可以拿現成的來組裝,也就是不需要自己打造各項細部的零件,但這些零件組裝成成品的工作卻是不能假手他人的。接下來你會遇到的問題是,那我要去那裡找這些零組件?同樣零組件卻有好多不同的工廠都有出,我到底要拿那一套的來用比較適合我? 就算是同一家工廠出的零件卻又有著不同的批號,到底是拿最新一批好還是拿舊的貨比較穩呢? 當然開始時常出現這些疑惑時,代表的是你己進入大量學習工具與第三方函式庫領域,每個領域都具有其專業的門檻在,你必須要花時間在大量吸收資訊與閱讀,並要與OpenSource打交道。簡單的說你必須要與外界大量的接軌,而不在是閉門造車。接軌不是一蹴可成的,你必需養成習慣長時間的接觸最新的技術與知識,參於一些大型技術論譠,唯有廣泛的涉略吸收不同的技術知識。才能在你需要某些零件應用時有門路或方向可以供你去思考與尋找。有時光要找到對的技術方向與對的零件工具來打造你的應用程,也是一門很難的學問。
對症下藥:
若你是Android的開發者,那麼你可以在openintents組織的網站找,找到一個第三方函式庫資訊收集列表。裡面收集了絕大多數的Android第三方函式庫,這就像是個大型倉庫可以幫你節省掉到處去找零件的時間。但你必須要平時就隨時的去關注了解每個零件的做用與更新狀態,如此才能在你有需要時去聯想到它(培養技術敏感度)。不然或許你可能都己經自己動手寫完了回過頭來才發現,原來有一套現成的零件可以用,但可惜我己經自己寫好了。
http://www.openintents.org/en/libraries
Level 8 學習非程式相關技能-專案管理、UI設計、色彩學、市場學
到了此層級大概你己經是一個 Team的Leader或是技術主管。此時你主要的工作可能以撰寫規格書與技術文件為主,以Android專案來說,你可能必須要決定UI操作的流程、功能規格、安裝與使用流程、收費與退費等金流處理機制、軟體升級的方式與流程、軟體推出的時機與搭配的行銷手法、軟體說用說明手冊的撰寫、若有帳號系統則需要考量用戶如何申請帳號、如果用戶忘記自己的帳號密碼要如何處理、帳戶的登入機制、若軟體有搭配雲端Server則需要考量Server建置的平台為何?要選擇那個雲端供應商、要租用的硬體設備等級、租用Server的成本估算是否有辦法長久提供用戶免費服務、若要提供另外付費的加質服務申請流程該如何設計、Server的負載能力如何。基本上你會有處理不完的流程需要思考與撰寫文件。這將會是另一個挑戰,因為你必須要從撰寫程式碼的工作轉變成撰寫文件,你的思緒將必須重新轉換成市場與消費者導向,而不在是以工程和技術導向。
對症下藥:
到了這個階段是沒有任何絕對的工具或正確的方法,我只能推薦幾本我覺得還不錯的書籍。每個軟體專案的開發與經營往往會因人、事、地、物的不同,而有著很大的變化。每天都會有著不同的挑戰發生,但要記得的是你必須要改以面向消費者的角度去思考良好解決之道,而不是面向技術與工程。