l

2008年9月27日 星期六

博士論文口試通過

9月25日是我的博士論文口試,結果當然是通過啦。唸了六整年的博士班,一下子畫下句點,當指導教授握著我的手說: "恭喜你,陳博士" 的時候,我卻少了分喜悅,多了分不捨。

說也奇怪,博五之後,心中最大個願望就是畢業,畢竟待在同一個環境太久了,做事越來越沒衝勁。現在口試通過,也找到工作,應該要高興才對,可是心情卻異常的平靜。

不知道其他人拿到博士學位之後的心情是怎樣?

最高興的可能是我指導教授的兩個小孩,因為以後假日我老闆就不用和我一起改論文,可以陪他們玩了。

2008年9月21日 星期日

找到工作了

由於9月25日即將口試,這一陣子花了一點時間在找工作。由於不急著找工作,因此我在104上面輸入自己的資料,被動的等有緣人上門。整個過程一共面試了五家公司。

公司一:某上市電腦公司某某處的一位經理。基本上整個過程是個誤會,面試我的人也沒仔細看過我的履歷就把我找去面試。我對他們的人力需求而言可能 "太超過"了,最後整個面試過程變成我在教他 SCRUM。我心裡在想,"先生,這可是要收費的,你有付我錢嗎。"

公司二:某開發與銷售監控軟、硬體的公司。由他們公司的技術總監跟我面試。這個人看起來是留美的,問的問題都很尖銳。例如,我問他我到他們公司要做什麼,他反問我,我認為我能為他們公司做什麼。我提到可以改善軟體開發流程、導入 software development best practices、還有我可以當任 architect。他當場把他們公司的 DM 拿給我,要我三分鐘之內描述一下他們軟體的架構... 還好平常書看的多,隨便講了不到一分鐘,他就說OK,不用再講下去了。這家公司給的薪水還算滿高的 (比我指導教授在學校領的薪水高.... 這是一定要的啦),工作也滿有挑戰的,可惜後來因為一件小事沒談妥所以就沒去這家公司了。

公司三:某網路安全與反垃圾郵件的軟體公司。這次面試我的是公司的技術總監和董事長。自己偷偷高興了一下,因為面試的層級越來越高。該公司的技術總監告訴我,我的自傳寫的很棒,他當場念了一小段 (感動)。就在一切都很順利,即將結束的時候,我告訴他們我期望待遇 。為了測試市場行情,我把第二家公司願意付給我的薪水加了2萬,不過好像嚇到對方。原本他們董事長說要找我吃飯再聊一下,但後來就沒聯絡了,害我難過了一小下子。董事長,薪水是可以商量的啊!

一個禮拜之內面試了三家公司,覺得好累,再加上要準備博士論文口試,就把104上面的履歷表關閉。

公司四:這是認識的人介紹的公司。因為是熟人介紹,所以面試過程基本上沒有問什麼。公司的總經理只問我說,想來我們公司上班嗎? 我回答,可以啊。基本上就這樣。說真的,我要來這家公司做什麼,並不是很清楚,只知道有一個小於10人的軟體開發團隊需要我幫忙帶領。

公司五:原本已經決定去公司四上班了,但有一天他們總經理告訴我,他們老闆對於我的 title 有意見,老闆覺得我是剛畢業的新人 (拜託,我以前工作過六年多耶), 因此問我願不願意從 XX工程師做起。這有點奇怪,因為我要去協助的那個團隊,裡面有經理等級的人,有那一家公司的制度,是由工程師去管經理的呢?太奇怪了,所以我拒絕了。因此重新打開104的履歷。很幸運的隔天公司五找我去面試。公司五是一家上櫃的軟體公司,面試我的是他們研發處處長。很巧的是,他7年多前曾經來我工作的公司 demo 過他前一個公司的某種技術 (當場我覺得很不好意思,因為當年我年輕不懂事,對他demo的技術很不以為然,一直給他吐曹)。不過大人有大量,他完全沒有提起。可能是他有點知道我過去的經驗,因此面試的前半場都是他一個人很興奮的在告訴我他們公司在做什麼。後來還是我自己要求要自我介紹一下,否則我看他好像沒打算問我問題。

就在我去公司五面試的隔天,公司四卻又告訴我,原本關於 title 的問題是個誤會,所以還是希望我去他們公司上班 (無言)。

比較這兩家公司:

公司四:硬體公司,起薪比較高,團隊人數 10 以下。
公司五:純軟體公司,起薪比較低,團隊人數可能在 20 ~ N 之間 (因為他希望我除了去幫忙研發之外,還要帶一個 coding center 的 programmers,人數不詳)。

最後選擇了公司四,是因為薪水比較高嗎? 不是。那是因為工作看起來比較輕鬆嗎? 不是。是因為離家比較近嗎,也不是。那倒底是為了什麼? ㄟ ...... 一切盡在不言中。

下禮拜還要趕快跟公司五連絡,告訴他們我的決定。

2008年9月12日 星期五

喝看看就知道

看過維大露P的廣告嗎? 一位外國朋友問蔡振南: "這飲料好喝嗎?" 蔡振南回答:"你自己喝看看就知道"。的確,飲料好不好,喝了就知道,再多的言語也無法取代親自嘗試。很多軟體開發的作法 (practices) 也是如此,好不好,動手試了就知道。

這幾個月在幫忙某個軟體開發團隊導入Scrum,經過了好幾個 sprints 之後,我嘗試導入 pair programming (自找麻煩,我知道...)。在苦口婆心說明了 pair programming 的好處之後,原本希望 programmers 可以被我的三寸不爛之舌給說動,可惜用講的效果不彰,沒有人主動採用。後來,我親自下海 (我承認是我偷懶,一開始就應該自己帶頭做),"趴"在幾個 programmers 身邊一起 pair。這樣試了兩個 sprints,到了第三個 sprint 之後,所有的 programmers 都已經接受了 pair programming。現在幾乎大部分的工作都採用這種方式進行。Pair programming 帶來的效益實在太多,例如:增進學習機會、藉由合作來改善軟體設計、減少加班 (因為太累了,沒體力加班)、趕走瞌睡蟲等等。

同樣的效果也出現在"寫測試"這件事情上面。實施 pair programming 之前,programmers 也被要求 (嚴格講起來是"被期待") 要用 JUnit 寫測試。的確有些人也作的不錯,但是這些由個別 programmer 所寫的測試效果如何,並沒有其他人再加以驗證。實施 pair programming 之後,對於撰寫測試的討論與花在撰寫測試的時間越來越多。此外,由於配對的關係,對於程式碼品質與設計的討論也增多,自然而然地,programmers 也經常利用 refactoring 來改善設計。由於 refactoring 之後需要執行測試案例來確保沒有把原本可以動的軟體弄壞,因此測試的重要性與效益變的越來越高, programmers 也變的越來越喜歡寫測試 (也許還沒到喜歡的地步,但至少意願與動機提高很多)。

我越來越相信,改善軟體開發,幫團隊成員洗腦固然重要,但一定要動手去做。如果要等所有人都認同再動手,有可能永遠都等不到這一天。

在你決定嘗試這些 practices 之前,最好能找到ㄧ個好的 Scrum Master,確保你所嘗試的方向與作法是正確的。我曾經聽說,有團隊宣稱採用 XP 開發一個軟體專案,在過程中曾經花了幾個月的時間在做 refactoring,最後專案以失敗收場。他們得到的結論是,agile methods 不可行。我真的很想問他們:"你們確定這是 XP,還是戴著 XP 帽子,但實質上是不知道什麼亂七八糟方法的軟體開發?"

PS: 最近因為三聚氰胺的新聞,赫然發現,飲料還是不能亂喝。

2008年3月13日 星期四

讀書筆記 (別讓員工瞎忙)

Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency

Chapter 3:
任務轉換成本 = 轉換的機械成本 + 重複的工作 + 進入狀況的時間 + 挫折代價 (平靜情緒) + 團隊能量的損失

Chapter 5:
為了保持控制權,你必須要放棄控制權。你要儘量少用你的權威,使他人不感覺到你在使用它。你要讓大家感覺控制權是由組織中的眾人分享,而非由你一人來掌握。

你給夏娃和他同事的鬆弛,不是時間上的鬆弛,而是控制上的鬆弛。

Chapter 6:
人力資本 = 完全進入狀況的時間 * (薪資 + 經常費用) * 50%

Chapter 7:
人在時間的壓力之下並不會想的更快

知識工作者應付壓力的方法不外乎:
1. 消除浪費掉的時間
2. 延後處理不在要徑上的任務
3. 晚下班

Chapter 8:
如果進度表訂下的完成日期沒有做到,它就是不好的進度表。這是判斷進度表好壞的唯一標準

Chapter 9:
過度忙碌的主管正在做他們不該做的事

Chapter 15:
知識型工作的作業標準幾乎總是捨本逐末。我見過不告訴你如何產生優質設計 (只管如何撰寫設計報告書) 的設計作業標準、不告訴你如何設計有效測試案例的測試作業標準。這些作業標準等於在說:我將規定你如何執行工作的每一步驟,只除了困難的部份。

Chapter 16:
真正的品質和有無缺陷少有關係,但我們所謂的品質計畫卻只和缺點有關。企業的品質計畫,只不過是消除缺點計畫,如果計畫成功,能讓產品零缺點或將近零缺點。但是這些產品真的有用嗎? 也許是,也許不是,但不管如何,都與品質計畫無關。

Chapter 20:
領導就是號召他人加入陣營的能力。
領導的特質:
1. 明確指出方向
2. 坦白承認短期的痛苦
3. 後續追蹤
4. 後續追蹤
5. 後續追蹤

2008年1月29日 星期二

工程還是藝術

對於軟體開發這檔子事,長期以來一直有兩種截然不同的看法。有人認為軟體開發是一種工程,因此可以採用工程的方法來控管與執行軟體開發的各項活動,希望能藉此開發出高品質的軟體產品。因此,程式設計師被要求紀錄工作時數、每日撰寫程式碼的數量(包含增加、修改與刪除的程式碼行數)、軟體缺陷 (defects)產生的數量與原因、修復缺陷所花費的時間等等。對於身為程式設計師的你而言,最直接的結果就是有一大堆填不完的報表等著你。近幾年政府與學界在台灣推行的軟體流程改善方法,例如 PSP (不是 Sony 的掌上型電玩,而是 Personal Software Process 的簡寫) 與 CMMI 就是兩個典型的例子。

也有人認為軟體開發比較接近於藝術創作,因為軟體開發屬於是思考性與創作性的活動,這一點和大多數的藝術創作很類似。難道我們會要求畢卡索每天記錄工作時間、畫了幾幅畫、浪費了多少顏料與畫布?

將軟體開發視為藝術創作最大的問題可能是生產力難以預估。大多數的人可以接受創作一件藝術品是需要時間的蘊釀,但我們很難告訴顧客說:「目前本公司的 chief architect正在尋找下一個創作的靈感,因此你們產品交貨的時間將被無限期延後

不管我們偉大的阿扁總統告訴我們:沒有所謂的中間路線,或是新中間路線,我相信通常對於一個問題有兩種截然不同的看法時,真正比較可行的作法總是介於這兩者之間 。近年來廣為流行的 agile methods 就是一種試圖平衡軟體開發的工程面向與藝術面向的一種方法 。

關於軟體開發倒底是什麼東東,我覺得最好的兩個比喻是 Kent Beck 在 Extreme Programming Explained 這本書中所提出的開車」(driving),以及 Andrew Hunt 與 David Thomas 在 The Pragmatic Programmer 這本書中所提出的園藝」(gardening) Beck 認為軟體開發好比開車,並非永遠朝直線前進,而是要打起精神,隨時準備向這邊修正一點、向那邊修正一點。由於改變是軟體開發中唯一不變的事情,因此程式設計師永遠要作好修正的準備。有時候我們甚至要朝向一個完全相反的方向前進 (開錯路 ?!),但這就是程式設計師的宿命。

Hunt 與 Thomas 認為軟體開發是一種園藝,原始碼就好比花園,身為程式設計的我們是就是園丁。因此我們需要「時時勤拂拭,不使惹塵埃」,我們的軟體才會長的頭好壯壯。想像一下你所看過的所有美麗的花園,如果一個月不去整理那會是個怎樣的情況! 千萬別忽視「雜草」的生命力,一周不除草就可能毀掉你心愛的草坪。因此,Hunt 與 Thomas 進一步提出:All Programming is maintenance programming 」,因為我們鮮少寫真正新的程式碼,大部分的情況是,我們維護已經存在的程式碼 (無論是寫新的程式碼或是修改、刪除原有的程式碼),使它變的更好。

在大多數的程式碼還是需要依靠人來撰寫的情況下,我們還是需要抱持著「時時勤拂拭,不使惹塵埃」的心態來照顧我們所開發的軟體。也許有一天 MDA (Modern-Driven Architecture) 與程式碼自動產生的技術成熟到可以取代程式設計師的角色,我們方可昇華到「本來無一物,何處惹塵埃」的境界;只是,我們可能需要擔心工作不保了。







2008年1月10日 星期四

例外處理 (3):Exceptions and exception handling mechanisms

Exception is an abstraction of errors and failures. As such, an exception carries information about the errors or failures it represents. Exception handling is the programmed activities conducted among multiple collaborating components in a program in response to an exception. These activities are conducted by code units called exception handlers or handlers. A handler can be attached to a statement, a block, a method, an object, a class, a module, or an exception. The plan about how to choose or devise an exception to represent errors and failures and how to respond to an exception is called exception handling design. An exception handling mechanism (EHM) is a programming language’s fundamental supports for dealing with exceptions, including representation, definition, signaling, propagation, resolution, and continuation of exceptions.

An important objective in the design of EHM is to keep separated the code for delivering normal functionalities and the code for dealing with exceptional conditions. In a language that lacks adequate EHM support, programs explicitly check each function call on the return code, data fields, flags, or global variables for finding out about the execution status. Since the checks and handling of anomalies are mixed with the logic for normal functionalities, code becomes cluttered and the program becomes incomprehensible. EHMs in modern programming languages provide better supports for separation of concerns in this regard. With exceptions, it is no longer needed to check every statement for error state. Once the execution of a statement gives rise to an exception, the runtime environment automatically alters the program execution from a normal path to an exceptional path. This allows the programmer to structure the logic for exception handling in appropriate exception handling constructs without cluttering the program.
Exception representation is the way that a programming language expresses an exception internally. It defines an exception context which contains information explicitly passed by the exception creator or implicitly passed by the language runtime. An exception can be represented as a symbol, a data object, or a full object [1]. Exceptions defined as symbols are strings or numbers. Data-object exceptions are primarily used to hold error and failure information only. Full-object exceptions directly encapsulate signaling, propagation, and continuation behaviors of exceptions in the class definition.

Programmers use exception definition to define exceptions in a program. If exceptions are represented as symbols, new exceptions are defined as strings or numbers. If exceptions are data objects and full objects, a class is used to define an exception. Some languages allow any class to be exceptions while others require that only particular types of classes can be exceptions. For example, in C++ any class can be exceptions but in Java only classes which directly or indirectly inherit from Throwable class can be exceptions.
An exception occurrence is an instance of an exception. The instruction to explicitly transmit an exception occurrence to the exception receiver is called throwing, signaling, raising, or triggering an exception. The sender of the exception is called signaler; the receiver of an exception is called the exception target, or target. An explicit throw instruction creates a synchronous exception, which is a direct result of performing the instruction. Conversely, an asynchronous exception can occur at any time in spite of the program statements under execution. Asynchronous exceptions can be produced by the runtime environment upon encountering an internal error or by stopping or suspending a thread.

If an exception is signaled and not coped with locally, the exception can be propagated to the caller of the signaling method. Exception propagation can be explicit or implicit (or automatic). In the former, a receiver must explicitly re-throw an unhandled received exception for further propagation; in the latter, an unhandled exception is automatically propagated. An exception is internal if it is not propagated; otherwise it is external. Some languages require propagated exceptions to be declared in signatures while others allow exceptions to be propagated without declaration.

Exception resolution or handler binding is a process of finding a suitable handler in the target, which is resolved by static scoping at compiler-time, dynamic invocation chain at runtime, or both. There are two methods to dynamically find a handler: stack unwinding and stack cutting. Stack unwinding pops the stack frames to search for the matching exception handler while stack cutting maintains a list of registered exception handlers and looks up the list for a suitable exception handler. While stack unwinding incurs no overhead in the normal execution, a significant overhead is involved in the exceptional execution. In contrast, stack cutting requires some housekeeping overhead to register and deregister exception handlers in the normal execution but incurs only a relatively minor overhead in the exceptional execution.
An exception continuation or exception model specifies the execution flow after an exception handler returns its control. In the termination model or the nonresumptive model, the execution of the component is terminated. A variation of the termination model is the retry model where the original execution is terminated and then the component is engaged for execution again. In the resumption model, the execution continues from the location or the next location where the exception was raised. Although program languages can support more than one model, mainstream programming languages such as C++, Java, and C# favor the termination model for its simplicity.

Reference
  1. A. F. Garcia, C. M. F. Rubira, A. Romanovsky, and J. Xu, A comparative study of exception handling mechanisms for building dependable object-oriented software, Journal of Systems and Software, vol. 59, no. 2: 197-222, 2001.