2010年12月30日 星期四

持續整合樣式:剩下的 Patterns

Dec. 30 20:18~20:39

[續上兩篇的內容] 在 paper 中一共提到 11 個 patterns(參考下表),前兩天 Teddy 介紹(其實也不算介紹,只是把內容貼出來)了其中兩個,今天把剩下的用 Problem-Solution 的簡短形式全部介紹完畢。相信大部分的鄉民們應該都沒把內容看完... 如果是換作 Teddy,應該也是看不下去... XD... 但是切記這幾篇的目的是『作帳』,對於內容是否過於文言文就不要太計較啦。

Project Installation Project, Single Shared Library Project, Interface Project, Cross-Platform Project, Native Project, Patch Project
Build Local Private Build, Remote Private Build, Cross-Platform Integration, Integration Workflow
Good Habit Single Responsible Person

Interface Project


Problem: How to isolate platform and implementation specific code from platform-independent projects? 
Solution: Define programming interfaces to encapsulate platform-dependent services or to allow a service to have multiple implementations. Put the interface definition code in an interface project. Do not mix interface definition code with interface implementation one. “Programming to an interface, not an implementation” and “dependence injection” are well-know software development practices that require clearly defined interfaces. For cross-platform software, strictly separating interfaces from the implementation hides platform-dependent details and enhances the flexibility and maintainability of software systems.


Cross-Platform Project


Problem: How to organize platform-independent code?

Solution: Classify implementation code into two types: platform-dependent and platform-dependent. Put platform-independent code in cross-platform projects. From the continuous integration perspective, cross-platform projects are easier to build and test. They can be built and tested by using virtual machines such as VMWare, VirtualBox, and Xen. Developers can quickly verify cross-platform projects by making a Local Private Build before the projects are committed for integration.


Native Project


Problem: How to organize platform-specific code?

Solution: Classify implementation code into two types: platform-dependent and platform-dependent. Put platform-dependent code in native projects. Native projects can be built on virtual machines if they depend on operating systems rather than on hardware. For hardware dependent native projects, a Remote Private Build can be used before they are committed for integration.

Patch Project


Problem: How to produce quick fixes to resolve problems without reinstalling the whole software?

Solution: Create a patch project to generate patch files. One way to produce a patch file is to perform a “diff” on the two different software versions and package the difference in the patch file. The patch file also contains a script to upgrade necessary files on the system to be patched.


Local Private Build


Problem: How to prevent a broken build?

Solution: Build a project locally before it is committed. You can make a local build by pressing a build button in your IDE or by running a pre-defined build script. Use the same build script executed by the continuous integration system to make a local build can further reduce the possibility of causing a broken build. 


Remote Private Build


Problem: How to prevent a broken build?

Solution: Use a remote agent to build a project before it is committed. The remote agent’s platform provides an environment that is required to build the project. This pattern is usually used to verify a Native Project that requires a build environment that is different from the local development environment. Continuous integrations systems such as JCIS, CruiseControl, Hudson, Buildbot, TeamCity, and Bamboo support this pattern.


Cross-Platform Integration

Problem: How to build cross-platform products?

Solution: Use a continuous integration system that supports cross-platform integration. Apply Integration Workflow to guide the continuous integration system to dispatch projects on suitable remote platforms for integration. Continuous integration systems supporting this pattern include JCIS, CruiseControl, Hudson, Buildbot, TeamCity, and Bamboo.



Integration Workflow


Problem: How to manage the continuous integration process for a cross-platform product containing interdependent projects?

Solution: Design integration workflows to control the continuous integration process. Two types of essential integration workflows are concerned: intra-project and inter-project. The former decides which integration activities (e.g., compilation, testing, test coverage analyzing, and packaging) to be included in a build and the execution order of each integration activities. The latter decides the build order of all projects according to the relations of project references. 


Single Responsible Person


Problem: How to deal with a broken build?

Solution: Assign a person in your team who will be notified once a build was broken. This pattern prevents broken builds from being ignored; especially those caused by overnight build scripts.


看完這三篇並寫出心得者請向 Teddy 兌換綠色乖乖一包。

友藏內心獨白:To 某學弟 -- 『終於有新文章了,啊你有認真在看嗎?』

2010年12月29日 星期三

持續整合樣式:Single Shared Library Project

Dec. 29 20:41~21:02

昨天才提到 Installation Project 這個 pattern,今天 Teddy 在 Continuous Integration 這本書的 191 頁剛好看到一句話,可以呼應 Installation Project 的重要性 。這句話是這樣滴:

If you can't release your software, then it's almost as if it doesn't exist.

噯呀,辛辛苦苦熬夜爆肝所寫出來的程式如果沒有 release ,就好像女方好不容易懷孕但是男方不肯負責,只好去『夾娃娃』,而這個小生命最後等於不存在一樣的那種感覺。

揮一揮鍵盤,只帶走一個月 N 千塊的研究助理費,這不是 太棒  太可惜了嗎!所以,程式寫幾行不是重點,前人留給你多少 bugs 也不是重點,重點是軟體在你手中有沒有(能不能) release。

今天接這看 paper 裡面個另一個 pattern: Single Shared Library Project 。

Single Shared Library Project

Context: A software product is structured as a number of projects. These projects share some common libraries. For example, a software called ezMonitor includes both Java and C++ projects. In the projects written in Java, Apache Log4J is used. You also develop two common libraries for your application: FileCommons for file manipulation and NetworkCommons for network operation. Some of the ezMonitor projects make use of both libraries; some others make use of one of them and still others make use of none. One way to share the libraries is to manually copy them to the project workspace. However, doing so complicates the version control of the share libraries. For example, once a shared library needs to be upgraded, each of the local copies needs to be upgraded as well. This can be error-prone and tedious for a product that has a number of projects sharing common libraries. 
Problem: How do we make share common third-parity and in-house libraries among projects easy?

  • You want to use a single version of a shared library among the projects that use the library.
  • Shared libraries, either third-parity or in-house, are likely to change over time.
  • The version control mechanism for shared libraries should be as easy as possible. 
Solution: Create a project that acts as a centralized repository for shared libraries. Organize the project structure in a way that third-parity libraries, in-house libraries, native (platform-dependent) libraries as well as system drivers, and source code of the libraries (if available) are placed in different folders. Define rules for each type of the libraries: (1) how should these libraries be referenced by other projects; (2) when and who can update a new version of a library; and (3) how does the library update process get initiated (e.g., manually or automatically).

Figure 2. An example of a Single Shared Library Project

Fig. 2 shows an example to organize a Single Shared Library Project named SharedLibraries. The SharedLibraries project acts as a centralized repository for a cross-platform product written in Java and C/C++. There are six different folders in the SharedLibraries project:
  • driver: This folder contains system drivers, primarily for Windows operating systems. Usually, a Windows system needs to be rebooted to enable the driver.
  • native: This folder contains platform-dependent libraries (usually .dll files for Windows and .so files for Linux-based systems) or executable utility programs (e.g., the cfg_x64 program in Fig. 2).
  • in-house: This folder contains the binary code of common in-house libraries that will be used by other projects. For example, if the MyServer project needs to use the FileCommons.jar file, it does so by directly referencing FileCommons.jar from the SharedLibraries. Whenever the FileCommons.jar is updated to a newer version, the MyServer project (and all projects that use the FileCommons.jar) can get the latest version of the FileCommons.jar by simply issuing an “update” command to sync its local data from the code repository.
  • in-house-src: This folder contains the source code of common in-house libraries. The main purpose of placing library source code in the SharedLibraries project is for debugging and tracing. When everything goes well, developers usually do not want to know the internal implementation of a library. However, when things go wrong and an exception is raised, developers may need to locate the problem by following the stack trace. In this situation, jumping into the source code along the stack trace is necessary. If the stack trace contains an invocation to a method in the library, developers need its source code to explore the method implementation. An IDE (Integrated Development Environment) like Eclipse allows developers to link the source code of a library to its binary code so that Eclipse can jump into the implementation of the library while debugging.
  • 3party: The function of this folder is similar to the in-house folder except that this folder contains libraries from third-parties.
  • 3party-src: The function of this folder is similar to the in-house-src folder except that this folder contains source code of third-party libraries.

Resulting Context: One drawback of sharing libraries via a Single Shared Library Project is the “timing” issue when this pattern is applied in IDEs. Suppose that you use the Eclipse IDE to modify code in project A and project B at the same time and project A uses code in the project B. If project A references code in the project B via a Single Shared Library Project, modification in project B cannot be reflected immediately to project A. Modification in project B can be reflected in project A only after (1) a jar file (i.e., the library of project B) is generated and committed to the Single Shared Library Project; (2) project A syncs with the Single Shared Library Project. Thus, if a set of projects is close related, a Single Shared Library Project may not be suitable. In this situation, use project references in your IDE instead. A project reference example is shown in Fig. 3. In the continuous integration system site, the Single Shared Library Project can still be used since project A is built after project B according to their dependency relationships

Figure 3. A screenshot of the Eclipse project reference.

Related Patterns: The build outcomes of Platform Independent Projects, Interface Projects, and Native Projects are stored in a Single Shared Library Project.


 友藏內心獨白:花不到 30 分鐘又寫了一篇,YES。

2010年12月28日 星期二

持續整合樣式:Installation Project

Dec. 28 22:48~23:11

2010 年就快結束了,12 月到目前為止只寫了一篇,不及格。這原因又是說來話長,還是不說了,藉口講太多 Teddy 都有點心虛了。聽說一般的公司年底都有所謂的『作帳行情』,就算是業績不好看也要想辦法在帳面上動點手腳,粉飾一下太平。以上所說,正是 Teddy 接下來要做的事情。

前一陣子 Teddy 和指導教授寫了一篇關於持續整合的論文,想想 Teddy 也有好一陣子沒談這個主題了,所以就拿點論文中的內容來充數一下,讓本月篇數帳面上不要太難看。這篇論文的題目叫做:

Emerging Patterns of Continuous Integration for Cross-Platform Software Development

這篇論文一共提到 11 個關於跨平台軟體開發的持續整合樣式,其中有兩個樣式有列出詳細的內容,其餘的以 problem-solution 的簡短形式呈現。今天先看兩個詳細樣式中的第一個:Installation Project.

Installation Project

Context: Traditionally, the deployment of a software product is considered at the very late stage of the software development, usually before release. For a project that applies incremental and iterative processes as well as continues integration, working software is expected to be ready at the end of iteration. The working software may be deployed internally for testing and for demonstration. It may also be deployed on the customer site for trial use. Since multiple target platforms are involved in a cross-platform software product, the deployment task is made much more difficult. 
Problem: How to provide an easy-to-use and robust method for users to deploy a cross-platform software product?

  • A software product can fail to attract users if it cannot be easily installed.
  • Different operating systems have their own flavors in installation modes, ranging from text-based to GUI-based modes and using different formats such as the Microsoft MSI and the RedHat RPM.
  • You want to simplify the installation procedures and minimize possible deployment problems.

Solution: At an early stage of software development, create an installation project to produce an installer for the cross-platform application under development. Add the project to your CI system. When the CI system builds the installation project either automatically or by request, an installer is produced. Release software at the end of iteration has become a norm for projects applying incremental and iterative development. Thus, it is reasonable to consider the installation problem at the early stage of a product development so that running software can be provided via the installer. Once the installation project can produce an installer, find a way to automate the testing of the installer on all supported operating systems.

Many commercial and open source tools are available for creating installation programs. Some of them support the creation of cross-platform installers while the others are platform-specific. An example of the former category is InstallAnywhere. By using InstallAnywhere, an Installation Project can produce multiple installers for multiple platforms. For example, InstallAnywhere can produce .exe installers for Windows platforms and .bin installers for Linux-based platforms. The installers can be configured in a way that they run in the GUI mode on Windows platforms and in the text mode on Linux-based platforms. InstallAnywhere also supports a silent installation mode. When an installer is run in the silent mode, users need not (and cannot) to interact with the installer to modify the default behavior of the installer (e.g., to change the installation folder). Instead, the installer accepts a pre-defined configuration file that contains all necessary settings to guide the installer.

Developers can also use platform-specific tools to produce platform-specific installers. For example, InstallShield is a popular tool that prodcues .msi installers for the Windows platforms. For Linux-based systems such as RedHat and Ubuntu, tools to package .rpm and .deb modules are used.

It is also possible to package a cross-platform product as the so-called green software, portable applications, or portable software if the product does not contain low-level native drivers which must be installed in a specific location and does not require the systems to reboot. Green software does not require a sophisticated installation procedure. To use the software, merely copy the software (usually an executable file or a folder) or unzip it to a hard disk or flash disk.

Resulting Context: Using sophisticated tools like InstallAnywhere is very convenient to produce cross-platform installers. However, such a tool is usually very expensive. Also, the produced installers may be larger in size than those produced by platform-specific installation tools. Sophisticated installation tools that support complicated scripts and customization functions produce flexible installers, but can lead developers to experience a sharp learning curve and consequently put off the creation of an Installation Project.

Installation Projects produce installers to deploy a software product from scratch. To install a new version of the software with the installers, the old one usually needs to be uninstalled first and then the new one can be installed. If only a minor part of the product is revised, using Installation Projects to produce an installer to upgrade the software may be taxing. In this situation, use a Patch Project instead.

Related Patterns: Installers package components produced by Platform Independent Projects, Interface Projects, Native Projects, and other components made available through a Single Shared Library Project. Apply Cross-Platform Integration to test an installer on all supported platforms. 


整理持續整合樣式的工作目前 Teddy 還在『持續』進行中,歡迎沒有轉台又能夠把上面內容看完且眼睛沒有扭到的鄉民們給 Teddy 一點建議。

友藏內心獨白:為什麼領錢的都是學弟而寫 paper 的都是『老』學長和老師?

2010年12月26日 星期日


Dec. 26 17:21~19:24

今天到華山藝文中心看幾米的展覽,2009年在華山藝文中心也有幾米的展覽,當時 Teddy 是在展期結束之後才知道有這個展覽,殘念。早上搭捷運來到了熟悉的『忠孝新生站』,從忠孝國小出口走到華山藝文中心大概 10 分鐘左右。到了華山藝文中心之後看到這個就知道是展場的入口:

首先買票入場,單人票 250元, 雙人票450元,四人票880元。看完之後保證物超所值。

除了門票以外,還可以選擇一張上面印有一組號碼的紙卡(五選一),上面這組號碼待會可以用 iPad 留言以及買紀念品打折。

館內是可以拍照的,但是不可以使用閃光燈。入館之後首先看到的是這個由華碩主機版所作成的展品,很有趣。整個展覽的小房間模擬成『雪屋』(當然是用保麗龍球模擬,不是真的雪),小朋友進去超開心(這也是悲劇的開始)。還好 Teddy 去的早,不然就差點看不到。為什麼?耐心看下去...

以下是兩張近拍的照片,用 SATA 接頭當作摩天輪超有意思。



來到另一個房間,有幾張很有 fu 的照片。


接下來就是讓你拍照拍到手斷掉的幾米插畫。Teddy 當場聽到好幾個鄉民說相機沒電了,此時 Teddy 想到一句成語:『相機用時電恨少』。還好 Teddy 有多帶一顆電池出門,否則就要學某位鄉民,把沒電的電池拿出來用手搓一搓看看能不能再多拍幾張(Teddy 內心獨白:賭神看太多了嗎?人家搓牌你老兄搓電池)。

在展場中央有一個比較大的房間,裡面有幾台 iPad 可以在上面留言,待會離開之後在展場出口就可以看到你自己的留言。可以順便在這個地方休息一下。PS:這個留言的軟體好像有 bugs,一直說『ID 卡號錯誤,請重新輸入』,但是又沒有顯示可以重新輸入的地方。


Teddy 又繞回『華碩雪屋』,裡面鬧哄哄的,剛好看到好幾個小朋友在地上玩得不逸樂呼。不久之後,『華碩雪屋』熄燈了。據工作人員氣憤的表示,展覽品被人『蓄意破壞』,正在維修(工作人員內心獨白:來人啊,關門放狗)。下面第二張照片就是工作人員摸黑搶救展品,不知道附近的華碩皇家維修中心是否有可以幫忙... XD。

Teddy 替沒看到『華碩雪屋』的鄉民們感到遺憾,這個展覽廳很棒的說。PS:Teddy 並不知道『華碩雪屋』故障和這群小朋友有沒有關連,也有可能是剛好在裡面的其他鄉民不造成的。總之,好像這批人離開之後不久雪屋也剛好熄燈了。


離開展場馬上看到賣吃的地方,Teddy 點了拿鐵和焦糖瑪奇朵,還不錯喝(肚子還很飽,所以沒有點吃的)。賣咖啡的旁邊就有一個寬敞的地方可以邊喝咖啡,邊看鄉民們的留言。

最後還有賣紀念品的地方 Teddy 忘了拍。紀念品有點貴,Teddy 買了幾張明信片和一盒拼圖。

這個展覽從 2010-12-22 ~ 2011-03-27 ,裡面好像有 10 個還是 12 個不同的房間,各有不同的展品。非常推薦喔。

友藏內心獨白:用 8M/640K ADSL 上載照片好慢啊,難道是到了換光世代的時候了嗎?

2010年11月25日 星期四


Nov. 25 21:38~21:59

Teddy 剛剛才發現,今年已經寫了 100 篇,這一篇是第 101 篇。原本想補上『消除浪費 (7):Defects』這一篇,但是想了想,defects 或是 bugs 的產生,一定是一種浪費啊,沒什麼好扯的,所以就換個口味,寫兩個 Teddy 『原創』的冷笑話... 不過這兩個笑話僅限於經常搭乘 307 公車往來台北與中和的鄉民們才比較容易體會


話說 Teddy 所搭乘的『大有巴士 307 』正以極快的速度行駛在『華中橋』上,此時 Teddy 所搭乘的公車冷不防的突然被另外一部公車所超越。各位看官,到底是那一路公車居然可以贏過『公車之霸』?

答案:另外一輛大有巴士 307。


Teddy 又搭乘『大有巴士 307 』正準備由中和上『華中橋』進入台北市,而在大有巴士 307 前方有兩輛 『台北巴士 307』。『車中有時速(表),心中無速限』的大有巴士司機,高喊著『衝,衝,衝』的口號,一下子就超過了前方這兩台『台北巴士 307』。





2010年11月20日 星期六


Nov. 20 14:48~16:05

這幾天最熱門的新聞,除了可能是全國第一個經過法院證認的『招妓男』事件以外,就屬亞運跆拳道『楊淑君』事件。該事件發生之後,媒體掀起一股反韓潮。今天 Teddy 也來趕個流行,談一下 Teddy 對於韓國的看法。

屬於 Teddy 這個世代的人,大多對韓國沒什麼好感。這可能是因為我們還沈迷於 10 幾 20 年前,台灣還是亞洲四小龍之首的那個年代,多多少少有點看不起韓國。再加上這幾年韓國不斷宣稱許多中國人所發明的東西其實是韓國人發明的,甚至連黃帝,孔子,李白,鄭和這些人也都是韓國人,著實讓全世界的華人都看不下去(怎麼不說 Teddy 也是韓國人..XD)。為了表達內心的不滿,Teddy 就是一個儘可能不買韓貨,不看韓劇,也不去韓國旅遊的人(Teddy 內心獨白:好,我承認,我在 Costco 買過韓國烤魷魚,吃過韓國石鍋拌飯與泡菜鍋,有時無聊會不小心看了 30 分鐘的韓劇...etc.)。

但是,一味的仇外並不會讓台灣變好。從很多跡象顯示,韓國的確已經超過我們了。Teddy 舉幾個印象中的例子:
  • 韓劇與韓國藝人在亞洲受歡迎的程度。
  • 韓國可以出口核電技術。
  • 韓國的 DRAM 和面板產業。
  • 桃園機場的空橋,居然是韓國貨。
  • 韓國的遊戲產業。
  • Teddy 去柬埔寨玩的時候時,到處可以看到 LG 的冷氣。
  • 當 Teddy 買的國產液晶電視與 LCD 螢幕用了兩年多就壞掉時,讓 Teddy 有一股想買 LG 或 Samsung 產品的衝動 (日系的又太貴買不起)。
  • 有時候看電視不小心轉到韓國的古裝歷史劇,有的還不錯看。想起本土的『一枝番仔火,一桶汽油』...XD



以前 Teddy 常聽同事說,『日本人很龜毛』,同事們都很怕接日本人的案子,因為為了一個案子日本人動不動就派 7 - 8 個人來台灣和我們『一個』工程師開會,鉅細靡遺的逐一檢討每一條 issue,有時候從早弄到晚上 1,2 點,隔天一早九點又準時跑來開會。對於具有傳統『差不多先生』良好美德的台灣人而言,當然會不習慣如此嚴謹的做事態度。

Teddy 並沒有和日本人合作的經驗,不過好死不死,一個月前剛好有一個案子和『韓國人』合作,我們需要在短時間內提供一個軟體給對方 。以做軟體來說 Teddy 自認在有限的資源之下,已經盡可能做的很嚴謹了,沒想到就在我們把軟體給對方的兩天之後(包含一份還算詳細的使用手冊),他們回覆了一份很詳細的測試報告,並列出幾點疑問。由對方所回覆的測試報告可以發現這些韓國人做事真的很認真。

插花補充一句:之前這些韓國人還在一份約 200 頁的使用手冊中,找到我們文件的一個 bug,這代表他們真的有先去讀手冊之後才去使用我們的軟體。想一想,如果同樣的工作交到我們身上,聰明的台灣人會怎麼處理?


當然,Teddy 潛意識對於韓國貨,韓劇還是抱持著能免則免的心態(如果口袋夠深,誰不想買 Sony....XD),不過,國貨也要爭氣,不然真的很難毫無理由的一直挺下去(總不能用一句台灣人要選台灣人就打通關吧)。話說回來,咱們做軟體的,也要加油啊。很多時候『自我要求』不夠,談什麼方法論(ISO,CMMI 甚至是 agile methods)都是白搭。


友藏內心獨白:冤枉啊,大人,Teddy 家裡的 LG 冰箱不是 Teddy 買的...

2010年11月18日 星期四


Nov. 18 21:24~22:18

曾經有一陣子 Teddy 受人之託,積極的招募學弟們念博速班,但是卻都以失敗收場。分析其原因,可能有以下三點:
  • Teddy 一念就念了 N 年才畢業,學弟們被嚇到了。
  • 念完博士要那麼多年,投資報酬率不高,還不如早點投入職場。
  • 裝孝帷,我都恨不得效法二分之一個秦始皇(焚書不坑儒),還叫我念。
博速班原本就是『有緣人』才可以念滴,強求不來。再說,念那麼多書有什麼好處,為何把人生最精華的 25 - 35 歲這一段時間浪費在學校?

除了那一張薄的幾乎忘了它的存在的畢業證書以外,要如何具體且簡短的說明念博速班的優點,除了『興趣』二字以外,還真是不太容易。Teddy 想起去年天下雜誌的一篇文章『異數,作家葛拉威爾:創意來自一萬個小時的練習』,覺得這個葛拉威爾(Malcolm Gladwell)講得還真他馬...總統..的好


假設一個博速生一天工作(上課,讀書,讀 papers,找資料,討論,聽演講,做實驗,寫程式...) 6 小時,一年工作 300 天,那麼:

10000 / 6 / 300 = 5.56  年可以畢業,

如果拼一點,每天工作 10 小時,一年工作 300 天,那麼:

10000 / 10 / 300 = 3.3  年可以畢業 。

其實還滿準的耶。所以 Teddy 可以說,念博速班就是給自己一萬個小時的練習,從素人變成達人的一種訓練。Teddy 當年剛念博速班時,指導教授就說過『念個博速起碼要念個 200 - 400 篇 papers』... 至於書就不用說了,多多益善。

路人甲:現在網路那麼發達,任何問題 google 一下不就有答案了?!





友藏內心獨白:彷彿聽到某人說...哼,小 case...拎杯玩 game 早就超過一萬小時。

2010年11月17日 星期三


Nov. 17 22:06~22:59

想當年 Teddy 用 VB 3.0 寫的第一個收錢的軟體,從開發到驗收交貨,程式內容都由 Teddy 一手包辦。既沒寫『單元測試』(這是一個 Teddy 當年聽都沒聽過的名詞),也沒經過『第三方驗證』。最後在客戶那邊吃了好幾天的雞腿便當之後,在『有力人士』的安排之下,糊里糊塗就結案了。

結案之後 Teddy 就再也沒有收到對方回報的任何 bugs,哇...靠...北..邊站,難道當年 Teddy 就那麼強,寫出傳說中『零錯誤的程式』?全錯,依據 Teddy 的猜測,應該是 users 根本沒在使用該軟體,所以 Teddy 寫出的是江湖中人稱『零使用的程式』,翻譯白話文,就是四個字『消化預算』。

儘管當年那個軟體可能存在千百個 bugs,但是只要沒人發現,你(客戶)不說,我(開發人員)不講,那世上就沒有第三者會會知道了。YA... Happy...

以上故事就呼應了本篇的主題:『無知便是福』。很遺憾,Teddy 當年沒領悟到一點,反而因為害怕自己太無知,而跑去唸了一堆書,以至於如今自食惡果。什麼惡果?接著看下去...


最近 Teddy 參與的一個軟體遇到一個問題,就是某項功能在執行了一段時間(例如 2 - 3 小時)之後會出現異常的行為(不是 memory leak),回傳不正確的值。有經驗的鄉民們看到這邊就猜得到,這種『跑了一段時間才出現的 bugs』是不太好解的。該功能的底層用到了前人所開發的 legacy code,該 legacy code 也存在另一個已經 release 多年的軟體中,如果有問題,應該早就被測試出來,或是有使用者回報錯誤才對啊?!可是並沒有,所以應該不是這些 legacy code 的問題... 如果這樣想,就錯,錯,錯,連三錯。

俗話說得好:『前人種樹,後人乘涼。前人擺爛,後人遭殃』。很『帶賽』的 Teddy 總是遇到後者... 在經過一番測試之後,發現相同的問題也會出現在那一個已經 release 多年的軟體上面。所以啦,前人無知便可以享福,而後人沒事學了什麼軟工測試方法,搬了一堆石頭砸自己的腳,就只好幫忙擦屁股了。

還好 Teddy 每次去家X福買衛生紙都是買量販包,一大袋有24小包的那一種(而且是柔柔軟軟的 X 潔,用多了也不會痛喔),所以在擦完自己的屁股之後,還有多餘的衛生紙可以來擦前人的屁股附帶問候前人的親屬

結論就是:前人內心獨白『我選上算我好運要不然你是想怎樣 我軟體能 release 算我好運要不然你是想怎樣。』


2010年11月11日 星期四


Nov. 11 20:28~21:53

各位 Java programmers 有沒有這樣的疑問:跑在同一台電腦上的不同程式,要如何交換資料?有時候寫程式寫到有一種『咫尺天涯』的感覺,明明程式都跑在同一台電腦中,要交換個資料卻是那麼的不容易。

這個問題就是作業系統所講的 Inter-process communication (IPC),學過作業系統的鄉民們應該都知道 IPC 是一個很重要的機制,借用 Wikipedia 的資料幫鄉民們複習一下功課,以下為幾種常用的 IPC 方法:
  • File
  • Signal     
  • Socket
  • Message queue
  • Pipe
  • Named pipe
  • Semaphore
  • Shared memory
  • Message passing (shared nothing)     
  • Memory-mapped file
問題來了,如果你用 Java 開發一個系統,這個系統有好幾支獨立的主程式,這些程式跑在同一台電腦上的不同 VM 中。這些程式要採用哪一種 IPC 方式來交換資料效率會比較好,程式也容易寫?

先去除 Java 沒有『直接』支援的方法:

  • Signal
  • Message queue (JMS 不算...)
  • Named pipe
  • Semaphore
  • Shared memory (JavaSpaces 不算)

對 Teddy 這個『世代』的 programmers 而言,剩下來的方法中,用 socket 可能是最簡單的。但是用 socket 有兩個壞處:
  • 需要佔用一個 port,如果電腦有裝防火牆的話,可能會被擋住,不然就是增加設定的麻煩。
  • 資料傳輸效率較差。明啊明要交換資料的程式都在同一台電腦上,用 socket 還要把傳輸的資料『打包』與『反打包』,速度自然快不起來。
那用 Memory-mapped file,這速度夠快了吧!ㄟ,雖然 Java NIO 有支援,但是 Teddy 還沒試過如何用這種方法來交換資料,所以... 淘汰。那不然用 File 好了。可是要用檔案來交換資料,還要自己處理『同步』的問題(當同時間有多人想讀寫檔案的時候,必須由應用程式自行定義同步機制,以避免資料錯誤),有點麻煩,程式容易出錯也不好測試。



路人甲:裝孝帷,用『資料庫』 overhead 不是更高,要啟動 database server,而且要連到資料庫不也是要建一個 socket,佔用一個 port?

Teddy:Java 有沒有那種類似 Microsoft Access 的資料庫,不需要啟動 database server,可以用『檔案』的方式來開啟資料庫?如果有的話,用『資料庫』來當成 IPC 的方法也許就可行了。

Teddy 找到 H2 這個開放原始碼的資料庫,就具有這種功能。H2 支援三種連線模式:
  • Embedded mode (local connections using JDBC)
  • Server mode (remote connections using JDBC or ODBC over TCP/IP)
  • Mixed mode (local and remote connections at the same time)
其中 embedded mode 不需要啟動 database server,可以直接用以下方式來開啟資料庫。

DriverManager.getConnection("jdbc:h2:data:h2:test", "sa", "sa");

但是問題來了,在 embedded mode 之下,一個資料庫同時間只能被一個 VM (加上 class loader)開啟。H2 會拒絕跑在另一個 VM 的另一支程式用 embedded mode 來開啟同一個資料庫(為了避免資料被搞亂)。

同時間只有一支程式(一個 VM)能夠用 embedded mode 來開啟一個資料庫,那這不就破功了?!還好只要在 connection string 加上 FILE_LOCK=SERIALIZED 就可以允許不同 VM 的程式同時開啟同一個資料庫。

DriverManager.getConnection("jdbc:h2:data:h2:test;FILE_LOCK=SERIALIZED", "sa", "sa");

不過這樣的方便是有代價滴,根據 H2 的文件說明:

This locking mode allows to open multiple connections to the same database. The connections may be opened from multiple processes and from different computers. When writing to the database, access is automatically synchronized internally. Write operations are slower than when using the server mode, and concurrency is relatively poor. The advantage of this mode is that there is no need to start a server.

在 Teddy 的應用中,只有一個 process 會 write,其餘的 processes 絕大部分時間都只會 read,而且同時間大概只會有 2 到 3 processes ,所以 concurrency is relatively poor 也可以接受啦  。當 Teddy 心中正在『暗爽』的時候,居然看到:

This feature is relatively new. When using it for production, please ensure your use case is well tested (if possible with automated test cases).

反正 open source 的東西,用了本來就要自負風險。對於每天工作累到走路必須靠北邊走的鄉民們,能夠少寫一行程式,就少寫一行。所以,用這種方式來達到 IPC 也不失為另一種『聰明』的選擇,至少達到了:
  • 不用建 socket。
  • 應用程式不需要自行設計同步機制。
  • 資料操作方法簡單(SQL)。
  • 速度尚可接受。
最後提醒一點,H2 的 jar 檔需要多站 1.2 MB的空間。 


友藏內心獨白:以前寫 VB 程式同時間連 access 資料庫有慘痛的資料損毀經驗,希望這個 H2 能夠『有檔頭』一點。

2010年11月10日 星期三


Nov. 09 23:19~ Nov. 10 00:06

Teddy 9月20日才說要發憤圖強,結果只持續一個月,從10月21日到現在 Teddy 又偷懶快三個禮拜沒寫部落格了。其實也不是 Teddy 故意要偷懶,應該算是天不從人願,每年年底好像是 Teddy『帶賽』的季節,兩個多禮拜前 Teddy 家裡的 Asus MK241H 螢幕壞掉了,電源完全不亮,前幾天才送回來。數一數 Teddy 今年下半年壞掉的設備:

  • Kyocera FS-1030D 印表機一台
  • 奇美 42吋 TL-42W6000D 液晶電視一部
  • WD 1.5 TB 硬碟一台
  • EN7300GT PCI-E 8X  顯示卡一片
  • Asus MK241H 螢幕一部
好懷念以前那種一台電視機可以看 15-20 年都不會壞的時光。


言歸正傳,今天談一個技術問題,這是最近 Teddy 在工作上遭遇到的『靈異現象』。話說因故 Teddy 和同事臨時被要求要寫一隻程式,透過 SNMP (Simple Network Management Protocol ) 去查詢遠端電腦的若干資料。在程式中我們使用了 snmp4j 這個 open source library 。我們的程式在 Windows 上面跑得很正常,速度很快,但是當執行在 Linux 上面時,速度卻異常的慢,感覺在 Linux 上面程式好像等待某個事件,等了很久(疑似等到 timeout)才繼續執行,有點卡卡的感覺(Teddy 內心獨白:女神卡卡,讚;程式卡卡,爛)。

同事甲:Java 不是跨平台嗎?



既然 SNMP 有用到『網路』,我們一開始『合理懷疑』是不是有甚麼 routing 的問題,或是在 Linux 上面要去得到 host name 之類的資料但是無法取得(以前有類似的經驗),但是經過一番測試之後發現並不是網路的問題。不過還好,既然 snmp4j 是 open source 的軟體,那就把 source 拿出來 trace 一下應該可以看出一些端倪。

在 snmp4j 中,如果要用 SNMP 傳送資料,必須先產生一個 SNMP 物件。在看了 snmp4j 的 source code 之後, 發現產生一個 SNMP 物件的時候,會:

new snmp () ->  initMessageDispatcher() -> SecurityProtocols.getInstance().addDefaultProtocols()

在這個 addDefaultProtocols() method 中,預設會產生下面這六種編碼方式,

        addAuthenticationProtocol(new AuthMD5());
        addAuthenticationProtocol(new AuthSHA());
        /// 下面這幾行是嫌疑犯
        addPrivacyProtocol(new PrivDES());
        addPrivacyProtocol(new PrivAES128());
        addPrivacyProtocol(new PrivAES192());
        addPrivacyProtocol(new PrivAES256());

其中屬於 PrivDES 系列的物件,會產生一個 Salt 物件 singleton, Salt 的 constructor 會執行下列程式:

      SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");    
      sr.nextBytes(rnd);  // 卡在這裡

SecureRandom 是 Java 內建的物件,這一行 sr.nextBytes(rnd) 會呼叫 native code。在 Linux 上面會去讀取 /dev/urandom 這個檔案,以得到一個 byte array。但是 /dev/urandom 檔案的內容被讀走之後,會變空的(或是變少),要再等一段時間才會增加。這裡有一篇文章對於 SecureRandom 的問題有詳細的說明,可以參考。http://lists.agentpp.org/pipermail/snmp4j/2005-January/000273.html


那... 要如何解?答案就在... google 中...參考這一篇提到的 work around (http://bugs.sun.com/view_bug.do?bug_id=6521844),在啟動 JVM 時設定 -Djava.security.egd=file:/dev/./urandom  這個參數就 OK 了。或是到 jre/lib/security 目錄修改 java.security 這個檔案,把 securerandom.source=file:/dev/urandom 改成 securerandom.source=file:/dev/./urandom 也行。

雖然問題暫時解決了,但是 Teddy 還是不知道 /dev/urandom 和 /dev/./urandom 有什麼不一樣?算了,先混過去再說,又不是要出 paper...XD


友藏內心獨白:有 Google 固然好,下對 keywords 才是真本事。

2010年10月21日 星期四

消除浪費 (6):Delays

Oct. 21 22:09~23:22

七浪費之六:Delays,Teddy 覺的用原本 TPS 的用語 Waiting 好像比較容易了解。軟體開發的 delays 情況有:
  • 等待某人有空:例如,等待 DBA (資料庫管理員) 幫忙設定資料庫;等待 technical writer 幫忙寫使用手冊;等待『隊友』幫忙一起解 bugs;等待公司招募到新人。
  • 等待資源:等待測試設備;等待購買的軟硬體設備到貨;等待從 Amazon 買的書寄到台灣。
  • 等待某項知識。例如,等待 Product Owner 明確的告訴開發者所有的需求細節;等待 team leader 告訴你 bugs 要如何解,程式要如何寫;等待新人搞清楚專案狀況。
  • 等待核准。例如,等待老闆核准專案進行;等待法務審核合約;等待客戶畫押需求;等待批准需求變更。
  • 等待功能或產品完成。例如,等待系統分析師生出完整的軟體架構;等待系統設計師畫出全部的 UML 設計圖;等待程式全部完成以便測試;等待程式通過測試。

根據書上的說法,開發人員15 分鐘就會做出一個重要的決定(一秒鐘幾十萬上下?!),如果開發人員對於他正在做的工作有足夠的知識(例如,知道客戶到底要他做什麼),或是當他有問題時馬上就可以獲得解答,那麼開發人員就可以快速做出(較高品質的)決定。如果開發人員缺少足夠的知識或是沒有人可以回答他的問題,那麼聰明的人類只會有三種反應:
  • 停下手邊的工作,試圖去找出答案:原本的工作被中斷,如果找答案的過程很冗長,造成 task switching 的浪費。
  • 停下手邊的工作,找其他事情來做:柿子挑軟的吃,原本的工作可能變成 partially done work。最慘的就是不斷地找新的事情,沒有一件事完成,一直到 stack overflow 為止。
  • 猜測可能的作法,硬著頭皮繼續做下去:蠻幹,最後的成果可能不是客戶所需要的,需要 rework 或 relearning。這個現象常常在很多『有理想,有抱負外加有創意』的開發人員身上發現。


消除 delays 的方法很多,書上提到一個最簡單的做法:

Complete, collocated teams and short iterations with regular feedback can dramatically decrease delays while increasing the quality of decisions.

Teddy 幫鄉民們把上面這句翻成白話文,就是『採用 agile methods 就對了啦』。

Teddy 氣象小叮嚀:鄉民們,不必再等待不可能的『颱風假』,除非你的公司在宜蘭縣。



2010年10月19日 星期二

消除浪費 (5):Task Switching

Oct. 19 21:54~22:42

『七浪費』之五:Task Switching (工作切換)。等一下, 為什麼工作切換是一種浪費?現在這個高科技時代,不管是人,還是機器,不是都強調要具備『多工 (multitasking)』的能力嗎?所以:


消費者:都什麼時代了,iOS 4.x 之前的版本居然膽敢不支援多工。難道我就不能邊玩 game 邊寫 mail 嗎... XD


學過作業系統的人都知道,工作切換便會形成『context switch』,只要有 context switch 就形成浪費。對電腦而言,context switch 可以是很 routine 的工作,對人腦就不同了 如果手邊的工作類型是屬於『不需要大腦也可以搞定的工作』,例如挑大便或是拔草,那麼工作切換所造成的浪費就比較少。但是,對軟體開發而言,大部分的工作卻都是需要『絞盡腦汁』的工作(路人甲:真的嗎?!)。如果時常切換不同的工作,有可能最後花在 context switch 時間比真正去做事的時間還來的多。引用一段書中的話:

When knowledge workers have three or four tasks to do, they will often spend more time resetting their minds as they switch to each new task than they spend actually working on it.


  • 讓兩個人(或兩個小組)每個月(或每個 iteration)輪流負責開發與維護的工作。
  • 每天早上花兩個小時讓整個團隊處理維護的工作,其餘時間專注於新功能開發。
  • 仿效『急診室』的作法,先將每一個客戶所提出的維護需求加以分類,只立即處理『緊急』的維護需求(理論上只有很少量的維護需求是屬於這一類的),然後每一或兩週在看看有哪些維護需求是真正需要處理的(有時候客戶的維護需求放久了會自動消失...^o^)。
  • 把所有不同客戶所使用的軟體版本都放在單一的 code base,然後每週或每一個 iteration(定期)釋出一個更新版本。

結論:在實際的生活中,task switching 是難免的。但是請牢記以下兩點:
  • 不是塞越多的工作給員工就可以得到越多的產出,有時候塞了太多的工作,員工只是在不同的工作間『空轉』而已,最後一事無成。
  • 就算是需要 task switching,也有比較好的工作切換模式。例如,不要每隔 5 分鐘檢查一次 mail,那只會害你分心。最好是採用『定時定量』的方法,例如每天早上一到公司的時間,下午 1:30 以及下班前。

友藏內心獨白:為什麼總是在忙碌的時候,不斷收到 MSN/Skype 的訊息。

2010年10月18日 星期一

敏捷式例外處理設計 (10):自動化更新

Oct. 18 21:29~23:02

這個系列的文章有一陣子沒寫了,最近 Teddy 家裡一堆電子產品壞掉,讓 Teddy 想起了另一個敏捷式例外處理設計原則:自動化更新

先談一下 Teddy 維修的慘痛經驗。

維修奇美 42" 液晶電視

前一陣子 Teddy 買了 2 年多的奇美電視壞了,當初會買奇美,主要是『便宜』,和日系相同尺寸的電視相比,價錢大約只要 1/3 ~ 1/2,而且有三年保固現在電子產品的生命週期都那麼短,與其買一台很貴的日系電視,還不如買國產的用一用先,萬一 3 年後真的壞了,到時候液晶電視價錢一定降很多,再買一台新的也划算。

沒想到還不到三年就真的壞了,電視完全無法開機。Teddy 從網路上查到奇美維修站的電話,打去報修,和維修的師父約了好幾次,都說當天晚上沒有時間不能來,最後只好約了禮拜六(Teddy 的電視是禮拜一壞掉的,此時心中已經略有不爽)。

維修師父來了之後,居然雙手空空,什麼也沒帶。隨便看了一下電視型號與保固書,說了一句令 Teddy 吐血的話:你的電視還在保固期,我們無法維修,請聯絡『原廠』

就這樣,過了一整個禮拜,Teddy 的電視機居然都還沒進入到『維修狀態』。後來好不容易聯絡到『原廠』的維修師父,服務還不錯,當天晚上就帶著一個電路板直接到 Teddy 家裡來更換,當場就修好了,免費。這下子總算讓 Teddy 對奇美的信心指數稍微回升了一點(你看,台灣的消費者是很容易就滿足的)。

  • 為了搶 Time-to-Market (即時上市),很多電子產品的『品質』都只能作到『堪用』。
  • 消費者為了『嘗鮮』,心裡也都預期到『新的東西 bugs  很多』。
那麼消費者是白痴嗎?為什麼要去搶很有可能有問題的 天線 新產品?如果公司的產品『新穎(有賣點)』,『價錢有競爭力 (C/P值高)』加上『售後服務好』,那麼就算產品有問題,甚至有點貴,消費者還是很有可能會買單的(Teddy 內心獨白:iPhone 4 售後服務爛又貴,大家還是搶著買,可見光是『新穎』這一點就可以打死其他因素)

但是,如果『售後服務很爛』,消費者被騙一次之後就不太可能持續購買同一家的產品(除非你是 Apple


以上故事告訴我們,要推出一個成功的產品,至存在兩個互相衝突的力量 (conflicting forces):
  • Time-to-Market (想想 Eee PC, iPad 或 iPhone)
  • Quality (在這裡我們考慮 reliability)
以現在產品開發的趨勢,Time-to-Market 變得越來越重要,先推出產品把錢騙進來再說,那麼品質有問題該怎麼辦?聰明的生意人就想出了『到府維修』,『到府收送,『快速維修』甚至『終身保固』(是誰的終身?產品?消費者?還是廠商?,以降低消費者的『戒心』


鏡頭回到軟體開發。軟體例外處理的最高境界,就是程式中所有可能發生的例外都被妥善的處理,如此一來在 runtime (程式執行時期)就不會因為有『未被處理的例外 (uncaught exceptions)』而導致程式當機或是系統出現一些不預期的行為。例外處理的目的很清楚,但是實施起來卻很難,關於這一點 Teddy  在『敏捷式例外處理設計的第一步:決定例外處理等級』曾經提到三個主要原因:
  • 屬於非功能性需求的例外處理很容易被忽略(時間不夠)
  • 有些例外是需求面看不到的,要到實做時才會出現
  • 真的不知道要怎麼處理(實做知識不足)
就算是以上三點都不成問題(團隊時間很多,實做的例外有人幫忙分析,開發人員清楚各種例外處理的實做技巧...地表上應該不可能有這種團隊...XD),實務上也幾乎不可能把所有的例外都處理好。為什麼?很簡單,因為『程式中可能會發生例外的地方情況太多了』,而軟體專案除非被取消了,總是有 release 的時間(就算是一個 delay N 年的軟體,它還是有 release 的一天),因此就算是一個資源很充裕的專案團隊,在軟體上市之前也很難把所有的例外都處理好。

想像一下,原本你開發的軟體可以順利執行在 Windows 2008 64-bit,但是有一天使用者安裝了 SP2 更新程式,你的軟體就無法再執行。這種『因為執行環境改變而導致系統無法順利執行』的情況實在太多了,當然你可以辯解說『我們的程式出生的時候,SP2 都還沒 受孕 釋出,我們怎麼可能預測未來?這是 SP2 的問題,不是我們的問題』。無論你如何解釋,對於使用者來說,更新 SP2 之後  Windows 跑得好好的,只有你的程式有問題,所以這當然是你的問題。

所以,兩週後產品就要推出了,環境相容性測試還沒做好,程式還有 一堆  一些 bugs,很多 少數例外還沒處理,怎麼辦?別擔心,Teddy 介紹你吃這一帖,保證 藥到 病除 ,就是:『自動化更新』。

對,就是『自動化更新』,明知軟體產品有問題還是要硬著頭皮推出,還好有自動化更新』這個法寶,當作最後的『安全網』。這就好像 奸商 廠商告訴消費者我們提供『到府維修』,『到府收送,『快速維修』甚至『終身保固』。 這麼好的『服務』,就放心給它敗家下去吧(小朋友出走中...)。

這時候,消費者早就已經忘了,『為什麼以前的電視看 20 年都不會壞,現在的電視看兩年就壞了。總之消費者與業者各取所需,


業者:先賺先贏 (股價又漲了)

結論:軟體功能做的爛沒關係,『自動化更新』一定要做的好。多學學人家 M$crosoft,多麼認真的更新啊,還會幫你重新開機喔...(路人甲:他馬總統的,我跑了三天的實驗...XD


2010年10月13日 星期三

這甘A賽減少 Relearning?

Oct. 12 23:00~ Oct. 13 00:18

M. Jwo (應該是先生) 對於 Teddy 胡說八道的『消除浪費 (3):Relearning』有點建言:

M. Jwo :自動化測試等無法減少 relearning 的時間才對。

Teddy:您說『這不是肯德基 自動化測試等無法減少 relearning 的時間才對』,可否說明原因?

M. Jwo :自動化測試甚至TDD等不是減少relearning,而是減少未來bug的發生。因為測試對裡面的細節不會描述,不然重構就無法發生。如果說自動化測試想要減少relearning,不如寫code的時候命名好一點,讓看到程式碼就能知道寫什麼,讓程式碼就是文件,比起測試部份更好。問題是這些都要回去看程式。真的想要減少除了pair programming以外,比如google實行的變形的方式,必須由supervisor才能commit code這些方法我覺得更好,不但有技術傳承更達到code review的功能。


除了虛構的路人甲以外,終於有一個真正的路人對 Teddy 唬爛的內容看不過去了(也許早就有很多...XD),剛好利用這個機會寫一篇文章也好(快沒內容可寫)。

基本上 M. Jwo 的講法 Teddy 完全同意,『寫code的時候命名好一點』,『pair programming』都可以減少 relearning 時間(最後那點關於 google 的作法 Teddy 不了就不加評論)。

大部分的鄉民可能會認為『測試』就是為了『找 bugs』。知道 TDD 的人會說『TDD 是一種設計,不是測試』。不管自動化測試,TDD 的『原意』或是『主要目的』是什麼,Teddy 認為其結果(或是副作用?!)是可以達到減少 relearning 的效果。

想像一下,如果你寫了一個 method X,但是沒有為這個 method 寫 unit tests。一個月後,有人回報你的系統有一個 bug,你花了 5 個小時才找到,原來這個 bug 發生在 method X 中。你『重新學習(重新發現)』到這個 method X 的行為有問題。如果當時有利用自動化測試將這個 method 的『正常行為』記錄下來,而且有頻繁的執行這些自動化測試案例,那麼當問題發生時,便可立即發現(假設你的測試案例可以測出問題),減低『重新學習』的時間。


用白話文解釋,有一個人(小明),從小不學無術,到處做壞事,從 16 歲開始就不斷地進出監獄,卻一直沒有學會教訓。一直到小明 50 歲的時候,遇到一個義工,在這位義工不間斷的勸說與教導之下,小明最後終於改邪歸正。此時小明語重心長的說了一句:

小明:如果早點認識你(義工) 我的人生就不同了。

小明就好比是『一支沒有測試案例的程式』,發生了 bugs 卻渾然不知要如何改正,從何改正。即使是坐牢(程式當機)的時候有點苦悶,但是出獄(重新開機)之後又固態復發(期待下一次的當機?!)。


(Teddy 內心獨白:這個例子有點牽強...一時想不出更好的比方)


每一個自動化測試案例都紀錄著『程式正常行為的某個執行路徑』,從這個角度來看,逐一去執行測試案例便可逐一的了解程式的(片段)行為,可以跟 code reading 互相搭配服用。
依據 Michael C. Feathers 在 『Working Effectively with Legacy Code』的講法,『Legacy code is simply code without tests』。為什麼大家都怕維護別人的系統?因為別人做的東西無法了解啊,就算設計的再好(套用一堆偉大的 patterns),程式的名子取的再棒(Kent Back 附身),只要沒有測試案例,難保改一行產生 N 個 bugs。

換個角度來看,如果鄉民們交接到一個有完整測試案例的系統,你新增了一個功能,跑了全部的測試案例,發現沒有問題,於是你『大膽假設』你沒有把系統改壞。所以,如果你沒有時間,你就不需要去立即被迫去『學習』這個系統的程式碼(延遲決定)。也就是說你可以暫時完全排除 relearning 的需要,這樣應該也算是有給它『減少 relearning 時間』的啦。


阿貶內心獨白:自動化測試有沒有減少 relearning 的時間...有那麼嚴重嗎?!趕快放我出來先。

友藏內心獨白:感謝 M. Jwo 激發 Teddy 另一個瞎掰靈感。

2010年10月10日 星期日

消除浪費 (4):Handoffs

Oct. 10 22:39~23:40


一件工作,轉過一手之後,所剩下來的知識若能有原本的 50% 就算是很不錯了,所以,如果這件工作轉了 5 手,那麼就只剩下 3% 的知識

第一手 50% -> 第二手 25% -> 第三手 12%-> 第四手 6%-> 第五手 3%





交接者內心獨白:東西這麼多,交接時間那麼短,你又講的這麼籠統,我怎麼可能學得會。一定是存心想要留一手不告訴我。(Teddy 補充:套句學弟常常說的話,『學長又沒交接給我!』)



  • 降低交接的次數(Teddy 內心獨白:這不是廢話嗎...XD)。
  • 組織 design-build 團隊(就是 Scrum 所說的 cross-functional teams。關於這一點 Christopher Alexander 早就提出類似的建議,請參考 Teddy 另一篇『Architect-Builder』。
  • 使用『寬頻』溝通方法。盡可能用面對面溝通(face-to-face)取代文件式溝通。(Teddy 內心獨白:Apple 聽到您的心聲,所以開發了 FaceTime。眾鄉民們還不趕快乖乖掏錢去買一隻 iPhone 4。)
  • 儘早且頻繁地釋出部份(先期)作品以便於獲得回饋。這句話 Teddy 要解釋一下,原文比較長:『Release partial or preliminary work for consideration and feedback--as soon as possible and as often as practical.』假設團隊中有 programmers 和 testers,如果 programmers 『自認為』程式已經做完了,所以把程式交給 testers 去測試(這就是一種『交接』)。但是如果在開發的過程中,programmers 從來都沒有跟 testers 討論過,那麼經過交接之後,testers 很可能不知道要如何測試,或是說無法測出真正的問題,甚至會測錯(都算浪費)。如果 programmers 在開發的過程便可以和 testers 討論,那麼便可以減少這樣的問題。

最後補充一點, Teddy 認為用來減少 relearning 的 agile practices,像是 pair programming 或 collective ownership 也都可以減少 handoffs 所造成的浪費。



2010年10月9日 星期六

消除浪費 (3):Relearning

Oct. 09 22:20~23:41

今日談談『七武器 七浪費』之三:Relearning也可以稱為『rework』。如果一次就能做好,就不需要『rework』,所以 『第二次(或以上)』的 work 當然就是一種浪費。但是為什麼不直接說 rework,而要咬文嚼字的說 relearning?

由於軟體開發事實上就是一種『學習新知的過程』,因此減少重新學習已知的知識,就可以減少浪費,所以特別用 relearning 來強調『軟體開發實為學習新識』的特質。例如,團隊中有老鳥跟菜鳥,菜鳥被分配到開發『用 Java NIO 實做非同步檔案讀寫』的某項功能老鳥對於此功能的技術十分熟練,但是被分配到該工作的卻是菜鳥。於是
  • 菜鳥花了一整天搞懂什麼是 Java NIO。
  • 菜鳥再花一天實做非同步檔案讀寫與撰寫單元測試
  • Tester 花了兩小時測出菜鳥所寫的程式有 5 個 bugs
  • 菜鳥解了其中的 3 個 bugs,另外 2 個看不出來問題再哪裡。
  • 菜鳥請老鳥幫忙做 code review,老鳥只花了 10 分鐘就找出 8 個 bugs (原本尚未解的 2 個  bugs 外加 6 個 tester 沒測出來的 bugs)。
  • 菜鳥將這 8 個 bugs 解完。
  • 經過這一番過程,菜鳥獲得 10 點經驗值,菜鳥一級升級為菜鳥二級
以上整個過程花了 6 個工作天,如果可以縮短學習的時間,便可減少時程的浪費。


大量的 relearning 對於軟體開發是一件『很傷』的事情,但是卻很難完全避免 relearning。團隊中幾乎不可能每一個人的知識與經驗都相同(如果能夠找『博格人』來開發軟體就太好了... 什麼,不知道博格人是什麼?來人啊,拖出去...看...Star Trek),因為『派工(分工)』的關係,又不可能把每件工作都交給最懂該工作的人來實做,因此便會造成 relearning 的現象。

另外,人是很『健忘的』,以前做過的事,曾經發生過的問題,日子一久,經常會忘記,因此相同的問題可能一再的發生,這也是 relearning(此時如果能找到『曾子』來開發軟體就好了,因為論語有紀載:『曾子不貳過』,這種人才找來寫程式最好)。


光知道 relearning 是一種浪費,那麼要如何減少 relearning 造成的浪費,這就傷腦筋了。請鄉民們想一下,有沒有哪一個 agile practices 是可以減少 relearning?知道答案的人,請將答案寫在明信片上,來信請寄『台北郵政 5408 號信箱』,前五名答對者本節目將提供神秘小禮物... XD

其實很多 agile practices 都和減少 relearning 有關,例如:
  • 自動化測試:將程式正常行為的『知識』紀錄在自動化測試程式中,當自己或別人不小心產生 bugs 時(破壞程式正常行為),能夠透過紀錄下來的知識立即發現問題(就是這些自動化測試案例),如此便可減少  relearning 所花的時間(可參考 『需求分析書中最重要的資訊是什麼』這篇)。
  • 採用 Design by Contract 或是 assertion。理由類似自動化測試,這些技術在 runtime 都可自動驗證程式的行為是否符合原本的預期。
  • Pair programming:師徒制是傳遞知識最好的方法之一,雖然過程辛苦了點。





2010年10月6日 星期三

消除浪費 (2):Extra Features

Oct. 06 22:27~23:46

Extra Features (多餘的功能)是軟體開發七種浪費行為中,最嚴重的一種浪費。為什麼?道理很簡單,如果某項功能連寫都不需要寫,那就不會因為要開發該功能而產生『Partially Done Work,Relearning,Handoffs,Task Switching,Delays,Defects』這些浪費的行為了。與其做出客戶暫時不需要的功能,而日後需要『時時勤拂拭,勿使惹塵埃』(開發與維護這些功能使其正常工作),還不如採取『本來無一物,何處惹塵埃』的策略,不是省事多了。


Teddy :我也想什麼都不做啊,可是到了這種極端,你的銀行帳戶也會跟著『本來無一物,何處惹塵埃』。畢竟鄉民們大概都還是屬於俗世中人,尚未修煉到不食人間煙火的境界,所以『該做的,還是要做』。至於哪些是該做的,哪些是不該做的,就要靠各位的『智慧』去判斷了..XD。


舉個例子,Teddy 最近看到 Kay 買了 iPhone 4,覺的好心動,不由自主的便稍微研究了幾款智慧型手機,包括 HTC Desire,HTC Desire HDHTC Desire ,Nokia N8...,每一款都好想買。於是,Teddy 心中的小惡魔就不斷地找理由說服 Teddy,『智慧型手機好棒,可以為你的生活帶來極大的便利,趕快買一隻,趕快買一隻

在激情過後,Teddy 發現不管是那一款手機,目前暫時都不需要,先用 Kay 的 iPhone 4 就好了。Teddy 想起『住左邊,住右邊』這齣連續劇,裡面有一句對白,『公家有,用公家,公家沒有用朋友』,這樣最省的啦。如果 Teddy 當時衝動之下跑去買了不需要的手機(Extra Features),那就是大大的浪費了(Teddy 內心獨白:如果口袋夠深的話,好想給它浪費一下...XD)。這種情況在逛大買場的時候也常常發生,就算是事先寫好了購物清單,一不小心還是買了不必要的東西回家。


各位鄉民以前求學的時候,或多或少都有受到傳統軟體開發方法的洗腦,認為軟體專案事前的(需求)分析做的越多越好,系統要很有彈性,以便應付日後未知的新增需求(請參考『你的軟體架構有多軟』),搞得這些做軟體的人好像『算命師』一樣,要能預測未來。這種『過於彈性的軟體架構』或是程式設計師基於『追求使用最新技術的爽度所幻想出來的需求,就好像你的下一隻智慧型手機,下一雙高跟鞋,下一件衣服,下一台 3D 電視下一個女朋友,下一  XXX 一樣,過早投資,通常都是一種浪費。

問題來了,古人有云,要『未雨綢繆』,難道事先準備有錯嗎?不是都說『有備無患』,怎麼現在綢繆』和有備』都變成一種浪費啦,那是不是說每天只要躺著在家裡睡覺就可以當選啦。食神 軟工,我真是猜不透你啊!

長話短說,把握幾個 agile 精神:
  • 最高境界:本來無一物,何處惹塵埃。不需要的功能,就不要做。
  • 撐到最後一刻逼不得已時再做決定。問氣象局一個禮拜後的天氣,準確度可能只有 50%。若是問『今天』的天氣,準確度可能有 90%。如果問『昨天』的天氣,準確度就有 100% 啦。所以,愈晚做決定,通常比較不會出錯。這就是為什麼人人都可以當『事後諸葛亮』的原因。
  • 採用演進式設計。
  • 創造支援『逐步成長 』的開發流程,開發環境,與軟體架構。
  • 對於已經開發完成的功能,要『時時勤拂拭,勿使惹塵埃』。這跟養小孩一樣,要嘛就不生,既然生了,不管長相如何,身體是否健康,都要好好照顧。