2009年4月27日

自製無用小工具系列 - 利用 Excel VBA 產生大量亂數日期

這個工具起因於某日,坎尼要建立測試資料,但日期必須打散
極度懶惰的坎尼就用 Excel 做了個亂數跑日期的小程式

「為什麼要用 Excel 哩?」『簡單、好用、又好玩』

第一、要產生某種格式的資料很快很簡單
第二、啟動不像 visual studio 那麼久
第三、不用再重新拉UI,每個儲存格都是 TextBox

要寫 VBA 之前,先知道 VBA 編輯器要怎麼開啟,見下圖
(快速鍵為 ALT + F11)

再來是原始資料的創建
先全選 Sheet1 的儲存格,右鍵選儲存格內容,將儲存格轉換為文字格式
A1儲存格輸入 1995,B1輸入01,C1輸入01
再利用 Excel 的自動填滿選項功能建立如下圖的資料 (這時候就知道Excel的好用了)

接著一樣把 Sheet2所有的儲存格改為文字格式
以免產生出來的資料,Excel會自以為聰明的幫你改格式 :D

資料準備好之後,就按下 ALT + F11 進入 VBA 編輯器
再來就是寫程式了,當然,是要用 VB 的語法

下圖先用兩個 For 迴圈決定要產生的資料量 (I、J分別為 Column及Row)
新增三個亂數值,分別決定年月日的亂數 Index
再將亂數產生的值組合起來放進 Sheet2 的儲存格裡

寫完程式之後,直接點執行鍵即可 (編輯器上面的綠三角形)
再切到Sheet2就可以看到滿滿的亂數日期了


Excel 檔下載 (若要使用坎尼的檔案,記得打開巨集)

其實這個程式把Sheet1的資料來源改一改 (亂數index的range也可以更改)
就可以變成 電影名稱產生器武功名稱產生器...

最後補充一下,坎尼程式裡年的 index 亂數設錯了 (應該為 14)
所以不會有 2007 及 2008 年的資料

2009年4月19日

微軟內部開始實驗的新 QA 機制:Bug Goal

這個月初去微軟位於南港的創新中心(Microsoft Innovation Center, MIC)上課,
在第三天的課程中聽到一個很有趣的觀念,叫做 Bug Goal,以下就來說說這是什麼。

在上一篇文章:微軟的組織架構 & Developer 的工作態度中曾經提到,基本上每個微軟的 team 都是由 PM、dev、以及 tester 組成,而 Bug Goal 就是由 Tester 這邊提出來的新觀念,目前正在美國總部小規模實驗中,如果成效良好,可能會全面推廣。

顧名思義,Bug Goal 指的是 bug 的指標,更清楚一點的說,是指在每個功能區塊中預期會產生多少 bug。一開始聽到這個觀念大家都覺得不可思議,所以花了不少時間討論。

Bug Goal 一開始大概只能靠 manager 從過去的經驗中做一個接近直覺的估計,但是隨著經驗的累積,理論上這個值應該愈來愈精準。訂定 Bug Goal 的目的如下:
  • 激勵 tester 在程式中找出數量足夠的、有意義的 bug,目標就是 Bug Goal 設定的數量。
  • 激勵 dev 寫出更高品質的 code,讓 tester 沒辦法抓出足夠的 bug 來達到 Bug Goal 設定的數量。
    (有點像是故意在 dev 和 tester 之間建立一個良性的競賽,目的在提高品質)
  • 讓 PM 多了一種衡量程式品質的數據,當某一個功能根據過去的經驗,是很容易產生大量的 bug,但專案執行一段時間以後 tester 卻幾乎沒有找到任何 bug 的時候,就應該主動更深入的了解一下專案執行的狀況,當然有可能是程式的品質真的非常好,但有沒有可能是 teser 在偷懶?或者 dev 偷偷把功能簡化,所以程式變得很簡單,不容易出錯?
會影響 Bug Goal 的因素包括:
  • 功能的複雜度
  • dev 的熟練度
  • tester 的熟練度
  • 需求變化的程度
  • ...(可能還有很多其他的因素,總之是要綜合考量這些因素)
有一點要強調的是,tester 找到的 bug count 有沒有 meet Bug Goal 絕對不是一個適合用來衡量 tester 能力的指標,例如 bug 的品質就是一項重要的因素(有沒有濫竽充數?),而有經驗的 tester 在 system design 的階段就會密切參與討論,貢獻自己的專業知識,提高系統的 testability,以及避免可能很難測試的設計,這些都可能造成 bug count 的降低,自然就達不到預先設定的 Bug Goal。

反過來說,達不到 Bug Goal 可以看成是一個好現象(前提是沒有人掩耳盜鈴),而且整個 team 長遠的目標應該是要讓 Bug Goal 越來越低,這表示 team member 的成熟度很高,可以產出高品質的 code。(這當然是個非常遙遠的理想)

2009年4月18日

[InfoQ QCon] 10 ways to improve our code

早上看了這個 talk (InfoQ Video link, Summary),主題是講 10 個改善程式碼品質的原則,有些不錯的地方值得記錄一下。

主講人 Neal Ford 先生是 ThoughtWorks 的架構師(跟 Martin Fowler 同一家公司),
演講的內容是從他寫的書:The Productive Programmer 裡面整理出來的,他講的很流暢,也蠻幽默的,演講時間大約一小時,投影片可以在這裡下載。

由於重點在 Summary 裡面都有列出來了,因此以下採用補充的形式記錄我印象深刻的部份,請搭配 Summary 服用。

Composed Method & SLAP (Single Level of Abstraction Principle)
Composed Method 這個原則講的是透過 method 的切割,盡可能的縮短每個 method 的行數,最後完整的 class 會由很多小小的 method 組成。

以切割 method 的方式來縮短行數的目的在於將程式碼的權責劃分清楚,以便達到最大程度的 reuse。但是在設計上也不應該為了切割而切割,此時可利用 SLAP 作為切割 method 時的 guideline。

SLAP 看來是 Neal 發明的縮寫,在 Wikipedia 上目前查不到,原始出處就是他寫的 The Productive Programmer,另外可以參考 Microsoft Architect Journal 2004 年 7 月號:Secrets of Great Architects(Levels of Abstraction: A Powerful Weapon for All Engineers)。

簡單的說,程式碼本來就是很抽象的,但還是可以區分出不同的抽象層次。最粗略的分法是,對 DB 的操作歸類為系統中較底層的程式碼,而 Domain Logic 則是系統的核心,UI 則是系統與使用者互動的介面,因此這三個層次的程式碼不應該混淆在同一個 method 中,就算不抽離到其他的 class 中,起碼也要拆解成不同的 method。

以下是同一個 method 中包含多個抽象層次的 pseudo code(節錄自投影片):
addOrder(WithMixedLevelOfAbstraction)

在這個未經 refactor 的版本中,可以看到非常詳細的操作 DB、Transaction 的程式碼,跟此 method 要處理的「新增訂單」Domain Logic 混雜在一起,因此閱讀的時候你的”心智”(mind)要多次在不同的抽象層次間的切換(mental shift),這種額外的負擔會造成閱讀程式碼時的不順暢。

以下是 refactor 之後的結果:
addOrder(WithSeparatedLevelOfAbstraction)

經過 refactor 後程式碼明顯縮短很多,而且現在此 method 中的抽象層次(大致)是一致的,如「completeTransaction」、「rollbackTransactionFor」等等的 method 不但名稱更有 business 上的意義,也隱藏了與 business 無關的、底層 API call(操作 DB、Transaction), 因此這段程式碼閱讀起來比上一個版本順暢很多,一行一行的順著讀下來比較接近日常生活的會話
(撰寫此 method 的目的:新增訂單)
  1. 建立所需的 DB Connection 和 SQL Statement。
  2. 開啟 Connection 和準備 SQL Statement。
  3. 設定 transaction 的狀態。
  4. 新增一筆訂單。
  5. 設定訂單號碼。
  6. 將購物車中的物品資料寫入訂單。
  7. 完成交易。
Question Authority
這個原則中文應該可以稱為「挑戰權威」吧!例如挑戰 coding convention,或者(公司內)常見的系統設計方式。Neal 舉的例子是一個有名的猴子實驗,我找到一篇文章:The Origin of Tradition: A Monkey Experiment (圖文說明),另外很久之前在書上看過一篇類似的文章,我自己打字以後做成 PDF 檔,可以在這裡下載(這都是文字,沒有圖,但是內容比較充實)。
比較有趣的是上面那篇我另外找的文章裡面有引述愛因斯坦的話:

Only two things are infinite, the universe and human stupidity, and I’m not sure about the former.
                                                                                               -Albert Einstein

建立 convention 對 productivity 是一件好事,但是深入的了解 convention 形成的原因,才有辦法在適當的時候打破 convention,以新的方法做事情,創造更大的價值!

詳細內容就不贅述了,不管這是真的實驗還是一個故事,總之很發人深省!

Use the Anti-Objects Pattern
在這裡 Neal 利用早年大型機台上的老遊戲 – Pac-Man(中譯:小精靈)來解釋何謂 Anti-Objects Pattern。在 Wikipedia 上有個 entry 就叫做 Antiobjects,剛好裡面就有講到 Pac-Man(警告!以下資訊可能會破壞你對小精靈這款遊戲美好的回憶 XD)
The notion of antiobjects is a computational metaphor useful to conceptualize and solve hard problems by swapping computational foreground and background.
If we implement, as part of a Pac-Man game, a ghost we are tempted to think of the necessary behavior associated with the ghost object.
Antiobjects turn things on their head. In the case of Pacman we put the main computation into the maze.
                                                                                                            - Wikipedia


在當年運算能力十分缺乏的平台上,是無法將「追逐小精靈」的 AI 設計到「鬼」這個 object 上的(由鬼來計算迷宮中的 shortest path ),因此反過來設計者把 AI 設計到迷宮的地板上去,並且提出一個 Pac-Man Scent(小精靈的氣味)的觀念,也就是目前小精靈所在的那塊地板氣味最強,而這個氣味是交由迷宮的地板來記錄的,當小精靈遠離這塊地板時,它的氣味就逐漸減弱。

因此鬼實際上沒辦法知道小精靈的位置,鬼都是漫無目的的瞎逛,若剛好踩到一段有小精靈氣味殘留的地板,才會一路往氣味更強的方向去「追殺」小精靈。

透過 antiobjects 可以簡化 AI 的設計,另外也是訓練你如何 think outside of the box 的好方法喔!

最後來回憶一下經典的小精靈遊戲畫面吧!
6

2009年4月14日

John Resig: The DOM is a Mess (and the inspiration I got from this talk)

這個 talk 約 1 小時 12 分,推薦給對 jQuery/JavaScript 有興趣的人,對於開發 Framework/API 的人來講也有很多可以借鏡的地方。(線上觀賞影片在這裡)

John Resig 是目前很紅的 Open Source JavaScript Library – jQuery 的發明人,
他任職於 Mozilla Corporation,這場 talk 是他分享在開發 jQuery 的過程中遇到的困難以及心得感想,對我來說蠻有啟發性的,雖然 scope 差了十萬八千里,但我維護的元件性質也類似 jQuery,也會被很多 client 以各種意想不到的方式使用,也要面對 backward compatibility、graceful degradation 等等問題。

以下是我聽到的一些重點:

Graceful Degradation


這裡有個定義,在 web browser 這個領域裡面,很常見的 reference 是 YUI Graded Browser Support

這個概念講的是由於實務上的限制(時間、金錢),(JavaScript) framework 沒辦法 support 快速變化的各家 browser 的各個版本(的各個 mode),因此要有一套 support 的策略,細節包括各家、各版 browser 的市佔率,以及要 support 所必須付出的成本(這通常跟 browser 遵守 standard 的程度成正比)等等。

除了要制定一套策略,程式的寫法也要注意,以下是從影片中節錄的圖(有點糊@@)
ResigSpeech_GracefulDegradation(EventBinding)

這裡的程式寫法的順序大有學問,首先在 if statement 裡面試圖用標準的 W3C 語法來附加 EventListener,但是並非所有 browser 都有實作 W3C Spec,因此針對 IE 這個尚未實作 W3C Spec 的 browser 的 API Call 就寫在 else if 裡面。

這樣有什麼好處呢?當未來 IE 實作了 W3C Spec 之後,這個 attachEvent function 的程式一行都不用改,IE 自然可以執行到 if statement 中的標準 W3C 語法!而遇到還沒實作 W3C Spec 的 browser 也還是可以正常的執行這個 function(只是經過額外的判斷,效能稍微差了一點點)。

結論就是:愈符合標準/愈新的 API Call 應該寫在越前面,vendor-specific 的 (non-standard_ API Call 應該要往後挪,如此才可減少未來升級的 effort。

Feature Simulation


接下來一個重點是如何判斷目前執行這段 js 的 browser 是否有提供特定功能?
 
最早的時候都是透過 browser sniffing/user agent sniffing 的技術,但是這樣的寫法太沒有彈性,每次 browser 推出新版的時候,程式可能都需要修改。甚至當網站被攻擊的時候,可能 header 中的資訊會被竄改(或者 power user 自己修改),導致 js 判斷錯誤,進而產生了奇怪的畫面等等。

比較好的程式寫法如下圖所示(還是有點糊@@)
ResigSpeech_FeatureSimulation(Verify API)


前半段的程式 create 了一個 div,然後在這個 div 上加上 comment,最後 return getElementByTagName(“*”) 的長度是否為零的 boolean 值。根據這個值就可以知道目前的 browser 對於 getElementByTagName 的 implementation 是否有 bug(一切以 W3C Spec 為準),而接下來的程式就可以根據這個 boolean 值做適當的處理。


這裡的觀念類似前面講的 Graceful Degradation,重點在於不要根據 browser/user agent 的版本來假設目前 browser 對某個 API (e.g., getElementByTagName) 的 implementation 為何,實際上用程式測出來的結果才是最準的!
(這也許可以算是 unit test 的進階/變形應用?)


Reduce the number of assumptions


這其實是比較一般性的通則,在程式裡面通常都會有很多假設(assumptions),
很多時候寫程式的人不會特別去注意這些假設,但是就如同去年 MS TechEd 的心得
當假設出了問題,或許是假設不符合實際情況,或者是被駭客攻破(e.g., 設法製造一個出乎你意料之外的 input),那麼系統就會出很大的問題。因此盡量設法減少系統中的假設是一個很好的 practice,系統的假設少了,出錯的機會就少(因為可能要多寫程式去處理一些特殊狀況)

但是適量的假設是有必要的,例如你很難(大概也沒有必要)對系統中每一個變數都額外再寫程式去驗證這個變數的 type 是否正確,這基本上是 type system 的工作,因此「type system 要負責抓到如 InvalidCastException 這樣的例外狀況,並停止程式的執行,以免程式真的 run 下去之後導致更嚴重的錯誤(buffer overflow?)」就是一個典型的假設,此時通常都需要信任這個 programming language 所提供的 infrastructure 是夠嚴謹的,而不是自己寫一大堆程式到處去做 type checking。

今天不知道為什麼突然想寫寫看這樣的心得,大概是因為最近類似影片看很多,
以後有空應該會多寫一點類似的文章 :p

2009年4月13日

The “I Suck” button in ASP.NET MVC Visual Studio Project Creation Dialog

上禮拜在看 Channel 9 一部請 ASP.NET MVC 的 PM – Phil Haack 現身說法的訪問中,
他提到了一個由 Scott Hanselman 發明的 private joke:The “I Suck” button.
 
到底這個 button 長什麼樣子呢?

當你安裝好 ASP.NET MVC V1 以後,安裝程式會順便安裝 VS 的 Project Template,
有趣的地方在於,當你 create 一個新的 ASP.NET MVC Application 之後,
VS 馬上會跳出一個詢問你是否要順便建立 unit test 專案的對話框:

ASP.NET MVC_WithUnitTestProject

上圖是系統的預設值,也就是微軟建議你應該順手建立一個 unit test 專案,
如果你 follow 了微軟的建議,那麼這時候螢幕上的就只是一般的「OK Button」。
(PS. Test Framework 不限定 VS Unit Test,也可以用 NUnit 等,作法參考這裡

但是若你選擇忽略微軟的建議,不要建立 unit test 專案,這時候畫面會像下圖這樣:

ASP.NET MVC_NoUnitTestProject

這時候原本的「OK Button」就變成「I Suck Button」了!

我覺得這個 private joke 某種程度上反應了微軟的 devs 對 unit testing 的看法,
也可以感受到他們樂在工作的感覺。可能某種程度也是要表達「MVC Pattern 本來就比較是合作 unit test」這個觀點吧。

接下來有空就來學一下 ASP.NET MVC 好了,順便練習 TDD!

2009年4月11日

[轉錄][合約]-保固期限的陷阱

這是在公司論壇看到的,偷偷轉出來 ... 雖然現在不需要處理這種問題,但還是可以多了解一下專案的各個層面。也許砍尼可以分享一些相關的心得 :p

========================= 以下是轉錄的內容 =============================

大家都知道,合約中的條款規定要特別注意。本專案開始訂定相關專案 RFP 及專案工作計畫時,有說明保固期限是一年;但在訂定合約時,因合約完成日期訂於年底(e.g. 2007/12/20),承辦人要求將保固期的說明寫成「自驗收合格日次日起,至次年十二月三十一日止,由廠商提供系統保固服務」,便於日後辦理計畫案之維護合約時,均可切齊到年底(一切是那麼的合情合理),當時未多加考量延遲驗收之風險而答應之。

專案進行後,因使用者驗證資料未依期望準時完成,故驗收拖至次年(e.g. 2008/1/5)才完成;保固期限原定至 2008/12/31 結束,但上述合約文件中的保固期文字為「自驗收合格日次日起,至次年十二月三十一日止」,故保固期限需依合約解釋至 2009/12/31 才結束,白白被多拗了一年。

以這個例子來看,如果能夠準時在該年年底(2007/12/31)前驗收完畢,保固期就只會算到 2008/12/31。但一旦超過 2007/12/31 才完成驗收,哪怕趕在 2008/1/1 當天驗收完畢,還是會被多拗一年的保固。日期切齊月底或年底是很自然的想法,所以這個要求可以理解。如果已努力過而客戶堅持要切齊,那就要特別注意結案的日期,推算一下最晚要在什麼時候驗收。從那個日期往前推 n 個工作天跑流程,以確保能在月底/年底前驗收完畢,避免發生類似的狀況發生。

========================= 以上是轉錄的內容 =============================

法律條文真的是很重要,莫名其妙的多扛了一年的保固,要付出的成本真是難以想像,
除了維護這個專案的成本以外,還有因為維護此專案而無法全力投入其他專案而產生的機會成本,還有對 team member 士氣的打擊,對 sales 的打擊 … 等等,實在是不可不慎阿!

2009年4月8日

自製無用小工具系列 - 格式化檔名

坎尼之前寫過 自製無用小工具 - part 1
沒想到這系列已經過了快半年了 (嚇)
但卻沒發半篇 囧

今天坎尼想要把檔案夾裡的檔名改成同一格式
ex. Img001.png、word002.doc...
一個一個改的話,幾千個檔案坎尼會改到臉抽筋吧
坎尼又懶的上網找工具

剛好想到以前寫過的副檔名更改小程式
於是坎尼花個二十分鐘做個小改寫

執行時,和之前的操作方式很像,先選擇路徑
接著格式設定完之後,就可進行更名動作
(這邊也還保有之前的副檔名更換功能)


執行成功之後
可以看到img資料夾裡的 png 檔都變成 IMG+流水號 的名稱
並且會新增一個 note 檔案,裡面記載更名前的對照表


程式的寫作流程基本上和改副檔名的那段差不多
利用 Directory.GetFiles 取得檔名
再替檔名換上新的格式及流水號,並記錄至對照表中
最後把對照表用 StreamWriter 輸出成文字檔

懶人更名小工具的 下載

這個工具目前不支援回復成原檔名的動作,所以使用前請三思
剛剛發現有點bug,明天修過後再補上新檔吧 :p

Google Spreadsheet 裡用規則運算式

最近因為工作關係,遇到要用 Google Form 及 Google Sheet 所以研究了 Google Sheet 裡的一些 function 怎麼用 首先,分享一下如何在 Google Sheet 裡用規則運算 :D