Friday, July 31, 2009

RSS XML Feed

FeedBurner
http://en.wikipedia.org/wiki/FeedBurner
http://feedburner.google.com

Digg
http://en.wikipedia.org/wiki/Digg

Del.icio.us
Del.icio.us

Slashdot - News for nerds, stuff that matters
http://slashdot.org

bloglines
http://www.bloglines.com/

finance trade stock forum

finance trade stock forum

http://www.traderji.com/tools-resources/

resize font size


function resetCurrentsize() {
currentSize = 13;
if(strLocalization == "JP") {
if(typeof(fontOverride) == "undefined") {
currentSize = 16;
} else {
currentSize = fontOverride;
}
}
if(strLocalization == "CN") {
if(typeof(fontOverride) == "undefined") {
currentSize = 14;
} else {
currentSize = fontOverride;
}
}
if (typeof(preDefaultSize) != "undefined") {
currentSize = preDefaultSize;
}
document.getElementById("CurrentSize").value = currentSize;
if (document.getElementById) {
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

function sizeDown() {
if (document.getElementById) {
currentSize--;
document.getElementById("CurrentSize").value = currentSize;
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

function sizeUp() {
if (document.getElementById) {
currentSize++;
document.getElementById("CurrentSize").value = currentSize;
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

resize font size


function resetCurrentsize() {
currentSize = 13;
if(strLocalization == "JP") {
if(typeof(fontOverride) == "undefined") {
currentSize = 16;
} else {
currentSize = fontOverride;
}
}
if(strLocalization == "CN") {
if(typeof(fontOverride) == "undefined") {
currentSize = 14;
} else {
currentSize = fontOverride;
}
}
if (typeof(preDefaultSize) != "undefined") {
currentSize = preDefaultSize;
}
document.getElementById("CurrentSize").value = currentSize;
if (document.getElementById) {
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

function sizeDown() {
if (document.getElementById) {
currentSize--;
document.getElementById("CurrentSize").value = currentSize;
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

function sizeUp() {
if (document.getElementById) {
currentSize++;
document.getElementById("CurrentSize").value = currentSize;
document.getElementById("resizeableText").style.cssText = "font-size:"+currentSize+"px";
}
}

Wednesday, July 29, 2009

兩個人在一起不是為了相互取暖

兩個人在一起不是為了相互取暖
著名的心理學家 弗格姆(E.Fromm)在他的名著(愛的藝術)中有這麼一句名言:
不成熟的愛是--< 因為我需要你 , 所以我愛你 ----
而成熟的愛是--< 因為我愛你 , 所以我需要你 ----
一個人付出的愛是不是成熟,從他最原始的動機與表達得到驗證。

如果是基於需要(例如:因為我孤單、寂寞,所以我需要你陪我與安慰),
那麼他所說的愛其實不是真愛,而是一種條件的需索卻假冒愛的名義。
這假愛的鑑別非常容易,就是當他的需求已得到滿足。
(例如:因為你的陪伴安慰,他已不再感到寂寞),
便會對你的存在覺得多餘與厭煩。

所以,當你的情人打電話給你,訴說他見不著你的日子真是茶不思飯不想,
而求你趕過去給他看看的時候,你且慢高興.因為說穿了,
他只是要你去給他下飯罷了!他只是需要你,那裡是愛你呢!

而真正的愛是無條件的自由付出,所謂需要,其實只是一種邀請:
他需要一個人和他共同完成這樁愛的事實,所以他對你提出邀請了。
而這樣的真愛也很容易鑑別,就是當你對他的邀請婉拒甚至只是沈吟的時候,
他立刻就能尊重你的意願而停步,而不會死追活纏,非要你答應才甘心。

何以故?只因他並不是荏弱的人格需要你去支持,
而是秉其人格的獨立堅強, 願邀你分享他生命的美好時光。
因此我們說愛的第一要義就是自由,
這一方面是指愛的付出應當基於自由意志,而別無潛在的陰暗動機。
一方面則是指對對方人格自由的充分尊重,
而不在付出的愛上面附帶有渴想、期望、要求乃至逼迫的壓力。
而真的相愛是一種愉悅甜美的經驗,而不是互相剝削的債務。

但許多情人的相處卻總是從無私的愉悅始,而以沈重的負擔終。
情人總忍不住想用對方的束縛來保障自己的安全,
卻不知只會帶來更多的煩憂。 而一個願意對方完全自由的人,又有誰捨得離棄?
只是道理雖然簡明,當事到臨頭,總是不容易做到罷了!

有人問:『你為什麼喜歡一個人?』
我只能夠說出為什麼不喜歡一個人,卻說不出為什麼喜歡個人。
喜歡一個人,是一種感覺。
喜歡一個人,卻是事實。
事實容易解釋,感覺卻難以言喻。
愛情是忽然有一個人,我們覺得一見如故,很想靠近他,
我們的內分泌忽然起了翻天覆地的變化,很想擁抱他。
以後,無論快樂或哀愁,我們也想不起當初為什麼愛他。
只有當我們不愛一個人時,才會找出不愛他的原因,
因為我們開始挑剔。
任何一個人,只要你去挑剔,一定找得出缺點。
越去挑剔,缺點越多,我們便可以說出為什麼不喜他。

我們想買一件衣服時,即使發現他有小小瑕疵,埋怨幾句,也肯將就,
因為只有這一件, 而且我們太喜歡它了,瑕不掩瑜嘛!
假使我們根本不想買那件衣服,它的小小瑕疵便是致命傷。
我們更會努力地找出其他缺點,譬如質料不夠挺,顏色太鮮豔,
向售貨員證實,我們不是隨便來逛逛的,我有認真考慮過的呀!

分手可以有很多原因,結合卻只有一個原因,
原因就是: 不需要原因

Subversion 版本控制系統的基礎觀念

Subversion 版本控制系統的基礎觀念

4/06/2009 10:59:00 下午張貼者: Michael Tsai

分類: Subversion, 軟體開發





摘要本文介紹 Subversion 版本控制系統的基礎觀念和術語,以及導入版本控制系統時應考慮的事項。

P.S. 這篇文章原本寫於 2004 年 6 月,之前將部落格搬到 blogger.com 時沒有整理進來,現在補上,順便重新編排、修剪。

簡介

在開發過程中,你是否碰到過以下幾種情形:

檔案被別人(或自己)覆蓋;

檔案遺失(拖放檔案時誤動作...);

想要比對各版本之間的程式碼有何不同;

想要回到之前修改的版本(需求反覆變更、自己改錯了...);

這些 code 不是我改的,是誰碰過我的程式碼?

軟體發行之後,必須凍結共用的程式碼一段時間,免得其他人在改 bug 的同時,因為你修改了共用的程式而增加更多新的問題。

如果有以上情形,你需要的是對專案進行版本控制(version control)。版本控制也有人稱它為原始碼控制(source code control),是 SCM 的一環,其目的即在於解決上述各種問題,讓你可以:

隨時復原錯誤,就好像是專案的時光回溯器,可以將檔案恢復到之前的任何版本;

多人同時修改同一份程式碼,不會有相互覆蓋的情況;

保留所有修改的歷程,如果你發現自己的程式碼有被別人更動過,可以很容易找到是誰更改的,以及何時更改的;

在發行正式版的同時,還能繼續發展新版本,無須下令凍結所有程式碼。

版本控制系統則是提供上述功能的軟體系統,它提供了一個地方讓你集中存放開發過程中的所有程式檔案及文件,以便達到集中控管的目的。

基本觀念

這個小節簡單介紹幾個使用版本控制系統時必須了解的基礎觀念,包括:檔案庫(repository)、工作區(workspace)、取出檔案(checkout)、送交檔案(commit)、分支(branch)等等。

檔案庫

前面提到,版本控制系統有一個集中存放檔案的地方,一般稱之為「檔案庫(repository)」,檔案庫裡面儲存了專案相關產出的所有歷史版本(包括目前開發中的版本)。有的版本控制系統是以資料庫的方式儲存,有的是以檔案的方式儲存;不論儲存的方式為何,對使用者來說,最重要的就是要把檔案庫放在一台穩定、安全的機器上,並且要定期備份。

主從式架構

現在我們知道,檔案庫既然是檔案的集中營,那麼一定是放在某台機器上,供所有開發人員存取,其作業方式如下圖所示,是一種主從式(Client/Server)的架構:







檔案庫所在的機器必須安裝版本控制系統,以提供檔案存取的服務給各個用戶端。圖中的「開發人員A」和「開發人員B」即代表用戶端,而用戶端機器上必須安裝版本控制系統的用戶端工具,才能存取檔案庫。

在連線方式上,用戶端可以透過各種網路協定來存取檔案庫,某些版本控制系統要求你一定要隨時與檔案庫保持連線,才能修改檔案內容;某些版本控制系統(例如 Subversion)則採用比較寬鬆的方式,你可以在沙灘上用筆記型電腦修改程式,等到回辦公室時再將檔案同步。有一個名叫 SVK 的工具甚至可以讓你以完全離線的方式操作檔案庫,此工具是架構在 Subversion 之上。

哪些東西要放進檔案庫?

顯然,專案的程式碼要存放在檔案庫中,以便進行版本控制。那麼,還有哪些東西也要版本控管?

基本上,你在開發一個專案的過程當中,需要用來建置軟體的檔案,都可能要放到檔案庫裡面,例如:建置專案的組態檔或 makefile、測試資料等等。在決定哪些檔案要放進檔案庫時,你可以問自己一個問題:「如果少了這個檔案,能夠建置和發行軟體嗎?」這可以協助你決定至少該把哪些東西放進檔案庫。

視團隊的需要而定,其他專案開過程中的產出,如分析設計文件、團隊成員的討論信件、FAQ、會議記錄等等也都可能納入版本控管。

基本操作和術語本小節簡單介紹幾個使用版本控制工具時必須熟悉的基本術語和操作,包括:工作區(workspace)、取出(check out)檔案、存入/送交(check in/commit)檔案、更新(update)、衝突與合併(conflict and merge)。

工作區(Workspace)

檔案庫存放了專案開發所需的所有檔案及其歷史版本,但是對於團隊成員個人而言,並不需要全部的檔案,我們只需要自己負責的部分就夠了。因此,我們會從檔案庫中取出(複製)一部分自己需要的檔案到自己本機的硬碟裡,這些存放在本機的檔案,就稱為本機複本(local copy),而存放本機複本的地方,則稱為工作區(workspace)。相對於本機複本,儲存在檔案庫中的版本則稱為主要複本(master copy)。

對小型專案而言,本機複本可能就是專案的所有原始碼和文件,而大型專案可能會切割成數個子系統或模組,所以開發人員只要取出自己負責的子系統就行了。

工作區有時候也稱為工作目錄(working directory)或程式碼的工作複本(working copy)。

取出(Check Out)

一開始,我們個人的工作區都沒有任何檔案,因此第一個動作就是要從檔案庫中取出我們需要的工作複本,這個動作稱為:取出(check out)。當你執行 check out 時,版本控制系統就會從檔案庫拷貝一份你需要的工作複本到你的工作目錄,這個工作複本的所有檔案目錄結構都會跟檔案庫裡面的目錄結構一模一樣。

存入/送交(Check In/Commit)

當你取出工作複本之後,就可以修改自己本機的檔案,等到你覺得改得差不多了,或者已經完成某個工作項目了(例如:解決一個 bug),就可以把修改過的檔案存入檔案庫,這個動作稱為:存入或送交(check in or commit)。

更新(Update)

當你修改自己的工作複本時,當然其他團隊成員也可能正在修改一些檔案,每個人的修改作業都是獨立進行且不會相互影響的,別人修改的結果也不會立即反映在你本機的工作複本上。如果你要看到別人修改的最新版本,你就必須執行更新(update)動作。當你的同僚執行 update 時,他們(通常)也會取得你最近 check in 的版本。

Note: Check out 和 update 的行為有些相似,二者皆是從檔案庫把檔案拉回本機,但他們的使用時機和目的並不相同。你必須把檔案 check out 至本機,之後才可以對這些工作複本執行 update 動作。

衝突與合併(Conflict and Merge)

在沒有版本控制的時代,總是偶爾會發生團隊成員彼此互相覆蓋程式碼的意外,有時候,這種意外發生一次就足以釀成大災難。

考慮以下情況:假設 John 取出了 A.java 和 B.java,Mary 也是。兩個人都各自修改了 A.java 的不同部分,而 John 先 check in 了,之後 Mary 如果也執行 check in,版本控制系統便會偵測到 Mary 欲送交的檔案已經有人先一步修改並送交至檔案庫了。

由於兩人修改的是 A.java 中的不同部分,版本控制系統通常可以分辨各自修改的部分,並將兩個人修改的結果合併(merge)。

可是,萬一 John 和 Mary 都修改了 A.java 的同一行程式碼,那麼比較晚執行送交的人就必須處理這個衝突(conflict)。她可能會開啟版本控制系統的差異比對工具,並與對方討論該如何進行合併。這種衝突的情況可能不常見,但萬一發生了,版本控制系統可以確保彼此不會互相蓋掉對方的成果。

在處理檔案取出的動作時,Subversion 採取的是「樂觀鎖定」的作法,也就是完全不鎖定檔案;直到發生衝突時,才由工具進行合併,或由開發人員手動解決。

有些版本控制系統是採取悲觀鎖定的作法,以事先避免衝突發生。換句話說,當某人 check out 某個檔案時,該檔案就會被鎖定成唯讀狀態,此時別人可以讀取這個檔案的內容,或者用它來建置專案,但無法修改,這樣就不會造成衝突了。只是,後來想要修改的人,就必須等到取得鎖定的人 check in 檔案之後才能修改它。

悲觀鎖定可以避免衝突,但實際用起來卻不大方便,因為一個檔案同時間只有一個人能取得修改權,其他人得排隊等候。萬一先取出檔案的人遲遲未送交(例如:休假去了),其他人就只能乾瞪眼。發行版本與修訂版次

就 Subversion 而言,它是將每一次送交動作視為完成一次修訂,並賦予一個修訂版次的編號(revision number),且每送交一次,修訂版次的編號就自動加一。當我向別人提到這點時,總是被問到:「多人開發時,版本編號遞增這麼快,這樣不是很亂嗎?你如何管理軟體的版本?」基本上,這是把軟體的發行版本(release)和修訂版次(revision)混淆了。

簡單地說,我們(開發人員)平常在寫程式時,大都很少處理發行版本的問題,甚至連修訂版次編到幾號了也不在乎;只有當我們要回復到某個歷史版本或進行版本差異比對時,修訂版次對我們來說才有實質作用。至於產品的發行版本,我們可以利用 Subversion 的標記(Tag)功能來做版本的區分;不過,剛開始接觸 Subversion 時應該還不會馬上用到這項功能,這裡就先略過不談。

導入版本控制系統

了解版本控制的基本觀念之後,接著就可以挑選一個版本控制系統,嘗試運用於實際的專案開發工作。如果是一人團隊,應該沒什麼問題;如果是多人團隊,在將版本控制系統導入現行開發流程時,可能就得多花點準備工夫了。以下列出一些準備工作:

選擇合適的工具。目前市面上可以買到或免費取得的版本控制系統有很多,你可能要花一點時間比較一下各種產品的功能,並且根據自己的需求和預算,挑選最適合自己團隊的工具。

安裝並測試版本控制系統的各項功能。

選擇一名管理員。團隊中必須有一個人負責管理檔案庫、建立專案的初始目錄結構、定期備份檔案庫等工作。有時候,他還得協助其他團隊成員解決檔案庫操作的疑難雜症。

教育訓練。教開發人員如何在日常開發工作中使用版本控制系統,讓他們了解跟之前的作業方式有什麼差別、可以獲得哪些好處,以減少因為改變工作習慣而產生的阻力。

正式將專案納入版本控管。

小結

本文介紹了版本控制系統的基本觀念和術語,你應該會發現,這些觀念並不難,而且非常貼近日常軟體開發工作所遭遇的問題。了解這些基礎概念之後,接著便可以開始嘗試將版本控制工具導入實際的軟體開發流程。希望本文提供了足夠的基礎,作為您進一步學習使用版本控制系統的跳板。

術語整理

英文

中文

說明

check out

取出

從檔案庫中取出檔案。

commit/check in

存入

將檔案從本地端存入檔案庫。

export

匯出

把整個模組從檔案庫中取出來,取出來的檔案不包含版本控制系統的管理檔案,也就是匯出的模組將不再由 版本控制系統控管。

import

匯入

把整個目錄結構匯入檔案庫。當你要把一個新的專案放進檔案庫進行版本控管時,就需要執行這個動作。

local copy

本地複本

放在用戶端機器的工作目錄中的專案複本。

master copy

主拷貝

放在檔案庫裡的專案複本。

module

模組

一個目錄階層,通常一個專案就是一個模組。

release

發行版本

軟體產品的一個版本。為了區別產品的版本以及個別檔案的修訂版次,因此不使用 version,而用 release。

repository

檔案庫

存放所有檔案(包含歷史版本)的地方,用戶端執行 check out 時就是從這裡取出檔案。

revision number

修訂版次

一個檔案的修改版本,例如:1.1、1.3.2.2。

tag

標記

在開發過程的某個時間點上,為一組檔案提供的符號名稱。透過 tag 一群檔案,你可以很容易在某個 release 裡面找出這些檔案。

update

更新

從檔案庫中取得其他人修改的檔案,以更新本機的副本(local copy)。

workspace/

working directory

工作區/工作目錄

本機的工作目錄,又稱為沙盒(sandbox)。

參考資料

1]

Pragmatic Version Control with CVS. Dave Thomas and Andy Hunt. The Pragmatic Programmers, LLC. 2003.

[2]

Version Control with Subversion. Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato. http://svnbook.red-bean.com/





3 回應:

dan0605 on 2009年6月24日 下午 5:03 提到...

您好:

想請教您有關subversion在asp.net專案上的運用架構應該如何較為適當,目前有漸漸在導入subversion來管理版本,暫時只有將新專案納入.

  架構上我們有正式主機,測試主機,而專案開發的方式是採用VS remote site 配合frontpage server extensions 來維護,若要採用subversion,是否要先建立一個新的repository ,再將測試主機上的專案import進入repository中.開發人員在自己本機建立working folder,然後checkout repository的內容,之後就是update上測試主機.

請教您,不知這樣子做法對嗎?

Ps.目前是採用TortoiseSVN,預計不會建立SVN SERVER的方式,而是採用檔案的方式.

Michael Tsai on 2009年6月30日 下午 3:50 提到...

您說的那種方式大致上沒問題,其實我也是這麼做的,可能只有一些細節上的差異。

你說不會建立 SVN Server 啊?我不太懂這句話的意思,Subversion 檔案庫不都是放在 SVN server 上面嗎?難道你是用網路共享資料夾的方式?官方文件上有說,絕對不要用這種方式喔!

dan0605 on 2009年7月31日 下午 3:17 提到...

感謝回覆!好像隔很久..呵!

那段有點打錯,應是說目前我們採用檔案的方式,利用TortoiseSVN,並沒有建立SVN SERVER.

只是先前在研究是否要建SVN SERVER時,考量到我們現有的網站是採FSE的方式,感覺中間有點落差及不了解的地方,還請指教!

使用svn/cvs的重要觀念:人的溝通才能花解程式碼的衝突

使用svn/cvs的重要觀念:人的溝通才能花解程式碼的衝突

幾天前跟一個在軟體業界滿長時間的朋友談程式碼管理的技巧,他說:「小專案一定不用版本控制,而大專案也不一定要用。」

這原因出在他們有一個慘痛的教訓。因為一個程設師忽視其他程設師的錯誤修正,強制把他的patch檔送 VSS 儲存庫(我不是故意指名道姓的,因為事實上,他們是用 VSS),於是1個bug,兩個人解決,也就是等於沒人解決。所以他們衍生出使用版本控制器一定要用 lock 動作,單一檔同時間只允許1個程設師修改,而且不可以破壞別人建立的 lock 。這麼作,只是把 VSS 當作高級 cpoy 指令來用而已。

我跟這位朋友提到使用 svn/cvs 的一個重要觀念:每次 commit 前,要先作 update ,且要看看別人所修改的程式碼及註解,如果與自己的程式發生嚴重的邏輯衝突時,不是硬幹別人的程式,而是打個電話跟他聊聊。

如果軟體公司沒有正確地使用版本控制,而是使用老舊的copy思維。為此,他們會衍生出一種與 copy 相輔相成的工作模式:專業分工。把一個軟體專案元件化、模組化,切完再丟給工程師作,每個人專注自己的小區塊,出了問題自己解決,然後再找一位菜鳥程設師來作 SA ,時間到了,就跟大家要要程式碼,兜在一起跑。這麼作看似解決了程式碼衝突的問題,但也帶來新的問題:

1. 程設師漠視團體的效益,專注自己的效益。
2. 認為只要開幾次會,定下模組溝通的介面,就可以不再溝通了。
3. 少了彼此學習的機會。

可是如果你是正確使用版本控制器的,舉個例子( http://chinesetrad.joelonsoftware.com/Articles/TheJoelTest.html )來說說:「約耳老兄在Excel 團隊時有個規定,每天要將專案編譯1次,且導致編譯失敗的人必須從此負責重新編譯的動作(作為處罰), 一直到有其他人出錯為止。這是個讓人不要導致編譯失敗的好誘因,同時是個讓大家輪流處理重新編譯的好方法,這樣大家都會知道怎麼做。」

當你可以綜觀整個專案時,你可以了解模組之間的關係,可以看看別人的程式精華,可以少1個SA(或許軟體公司對這個比較心動),而你只是花1~3個小時,去學1個你未來都用得到的版本控制器,很划算吧!

等等,我聽到有人反應「如果公司不想讓所有人接觸整個專案呢」!這個例子我有遇到過,曾經就遇到一間公司要求1個工程師把商業邏輯都寫在資料庫的預存程序中,而另1個工程師則是撰寫網頁程式來呼叫這些預存程序,這公司希望產品不要讓1個工程師全把握住。遇到這種例子,就善用 subversion 的權限管理,把一個專案中的兩個模組設定1個只有A工程師可讀寫,另1個只有B工程師可讀寫。但我想,這個管 subversion 的人,該是公司老闆來,還是他美貌的秘書呢!

建立 軟體專案 的訊息溝通網絡組織中最基本也最容易被忽視的第一步,就是使用版本控制工具 (Version control tools)。版本控制工具和訊息溝通有什麼關係?很不直覺,但卻是事實。

以 CVS/SVN 這類工具為例,它傳遞與通知訊息的功能其實比電子郵件更有效率。 SVN 的固定動作是 Update → accept change → Commit → add/modify/revert → Update (repeat) 。往往我在 Update 時,就可以透過其他人在 Commit 時留下的訊息,了解到專案的進程或待辦事項...

Friday, July 24, 2009

用 PHP 寫一個噗浪 (Plurk) 機器人

用 PHP 寫一個噗浪 (Plurk) 機器人
2009年7月1日

Plurk 目前已經是時下最流行的微型部落格了,已經有很多的網友都有自己的噗浪帳號,使得目前許多高手開始思考怎麼透過噗浪去產生一些額外的服務。

以下我就簡單說明怎麼寫一個屬於我們自己的噗浪機器人~

基本原理

機器人的原理很簡單,其實就是透過 cURL 來做登入及貼文的動作。已經有高手 Vexed 幫我們寫好程式碼啦,我們只要會改帳號密碼及要貼的訊息即可:

當然在這之前,我們必須先到 Plurk 上為我們的機器人註冊一個帳號。 (這裡假設其帳號密碼為 abc / iamabc)

註:程式碼並非我個人原創,我僅僅為大家說明觀念而已~:D

<?php
/**
* 透過 PHP + cURL 發噗
*
* @author: Vexed
* @see: http://blog.xuite.net/vexed/tech/22023458
*/
define('NICKNAME', 'abc'); // 就是帳號
define('PASSWORD', 'iamabc'); // 就是密碼
define('USER_ID', '123456'); // 登入後,在 HTML 原始碼裡找到 user_id 對應的值

$message = '我是用 PHP + CURL 寫的機器人~';

$ch = curl_init();

// 產生 Cookie ,以便記住登入後的 Session
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');

// 登入
curl_setopt($ch, CURLOPT_URL, 'http://www.plurk.com/Users/login');
curl_setopt($ch, CURLOPT_POSTFIELDS, 'nick_name=' . NICKNAME . '&password=' . PASSWORD);
curl_exec($ch);

// 貼文
curl_setopt($ch, CURLOPT_URL, 'http://www.plurk.com/TimeLine/addPlurk');
curl_setopt($ch, CURLOPT_POSTFIELDS, 'qualifier=says&content=' . urlencode($message) . '&lang=tr_ch&no_comments=0&uid=' . USER_ID);
curl_exec($ch);
curl_close($ch);
?>


然後就是發揮你的創意去更新 $message 裡的內容囉~
機器人的類型

機器人目前我知道的有兩種,一種是定時發噗,一種是看發噗者輸入的內容,然後產生一些相關的回噗。

定時發噗就是利用 crontab (排程執行) ,這個需要自己有伺服器來做這件事。而這種機器人要特別小心,不要一次發出太多訊息,不然會被 Plurk 的防洪機制擋住。

會回噗的機器人則是去解析發噗者該噗的內容,找到關鍵字後加以處理,然後回噗在該噗上。這樣的機器人也分成兩種,一種是需要將它加入朋友的,一種則是它自行尋找 Plurk 的所有內容 (也就是全世界) 。

所以上面的基本原理瞭解之後,我們就可以依照自己的需求與創意,去打造屬於自己的機器人囉~

程式碼與觀念參考:自製 Plurk Bot 定時自動發噗

jaceju PHP, Web 開發, 伺服器安裝與設定 推到Plurk
評論 (3)

1.
Dylan 說道:
2009 年 07 月 01 日 at 20:06:54

我想知道回噗機器人是如何運用這段code來達成:P
2.
Zeuxis 說道:
2009 年 07 月 02 日 at 00:30:37

http://code.google.com/p/rlplurkapi/
比較建議用這個,因為不是每台機械也有 curl 這 Lib
而且上面雖不是出自官方,不過還是實現了比較全面的功能 :)
3.
fillano 說道:
2009 年 07 月 05 日 at 14:33:46

另一種思路是用xmpphp透過gtalk來做:
http://code.google.com/p/xmpphp/

plurk上面有bot的使用說明:
http://www.plurk.com/imhelp

使用前要打開openssl模組。

不過我剛剛測試,直接用example改,中文出不來…再來調調看

Thursday, July 23, 2009

How to make tablesorting work with multiple tables on the same page

With Drupal 5.0 and beyond, it is now possible to provide independent sorting of tables when they appear on the same page.

This is accomplished by inserting a unique label for each table in both the tablesort_sql and theme('table'... calls for each relevant table.

For example, suppose you had two sortable tables on a page, one a list of users, and the other a list of nodes. To make each table sortable independently, you would do something like:

For the user table:
...
$user_sort = tablesort_sql($header, NULL, 'user');

...and then in the user table theme call...
$output = theme('table', $header, $rows, array('class' => 'some-class'), NULL, 'user');

For the node table:
...
$node_sort = tablesort_sql($header, NULL, 'node');

...and then in the node table theme call...
$output = theme('table', $header, $rows, array('class' => 'some-class'), NULL, 'node');

Note that for each table, the label you use for tablesort_sql and theme('table'... must be identical for the independent sorting to be handled properly.

How to write database independent code

In order to ensure that your module works with all compatible database servers (currently Postgres and MySQL), you'll need to remember a few points.

* When you need to LIMIT your result set to certain number of records, you should use the db_query_range() function instead of db_query(). The syntax of the two functions is the same, with the addition of two required parameters at the end of db_query_range(). Those parameters are $from and then $count. Usually, $from is 0 and $count is the maximum number of records you want returned.
* If possible, provide SQL setup scripts for each supported database platform. The differences between each platform are slight - we hope documentation on these differences will be forthcoming.
* Reserved words checker for all database management systems.
* You should test any complex queries for ANSI compatibility using this tool by Mimer.
* If you are developing on MySQL, use it's ANSI compatibility mode.
* If you can install all database servers in your environment, it is helpful to create shell databases in each and then run sample queries in each platform's query dispatch tool. Once your query succeeds in all tools, congratulate yourself.
* Don't use '' when you mean NULL.
* Avoid table and field names that might be reserved words on any platform.
* Drupal 5 and below did not use auto-increment or SERIAL fields. Instead, it used integers and provided a function to generate identifiers: db_next_id(). First you db_next_id needs to be called and then its value can be used where unique identifiers are needed. In Drupal 6 however, you can use auto increment and after insert, it's possible to read the last insert id by using db_last_insert_id($table, $field).
* Use curly brackets when referencing table names in your SQL statements. This ensures that Drupal installations that use a database prefix will work correctly. Example: SELECT * FROM {accesslog} WHERE ... instead of SELECT * FROM accesslog WHERE ....
* Avoid calculating dates/times in the SQL itself. These functions vary widely in different DBMSes and MySQLs performance suffers if you do this. In a lot of cases MySQL won't be able to use indices and will need to calculate these dates/times for every row it scans.

擺脫拙劣,更上一層樓的不二法門,就是先瞭解自己的愚蠢。

古 曹丕
常人貴遠賤近,向聲背實,又患闇於自見,謂己為賢。
今 安西教練
擺脫拙劣,更上一層樓的不二法門,就是先瞭解自己的愚蠢。

FreeBSD 的 security patch 跟 如何 upgrade

剛剛看到 chinsan’s Blog 裡面提到 關於 FreeBSD 的 security patch 是怎麼處理的?,這篇寫的非常不錯,所以順道把手上機器都全部處理了 upgrade 系統了,當然首先是要先習慣閱讀 /usr/src/UPDATING 跟 /usr/ports/UPDATING,當然這兩個其中一個是系統的安全性更新,一個是 ports tree 安全性更新。

裡面 chinsan 大大提到的 SA(Security Advisories)

http://www.freebsd.org/security/advisories.html
相關反應管道請參考 http://security.freebsd.org

這裡的 SA 其實也可以在 /usr/src/UPDATING 這裡面看到,但是網頁版似乎比較好,我提供解法,做起來也不會很困難。

嗯嗯,要升級系統安全性,首先先去修改 /usr/share/examples/cvsup/standard-supfile
把 cvs tag 採 RELENG_7 改成 cvs tag 採 RELENG_7_0

然後再去修改 /etc/make.conf 加上底下:
KERNCONF=GENERIC
SUPHOST=cvsup.tw.FreeBSD.org
SUPFILE=/usr/share/examples/cvsup/standard-supfile

然後更先步驟就如下了:
# 更新 source tree
cd /usr/src; make update
# 或者是
csup -g -L 2 /usr/share/examples/cvsup/standard-supfile
#執行 全套作法?
cd /usr/src; make buildworld; make kernel; make installworld
# 或者是半套?
cd /usr/src; make kernel

這邊我有去查了一下 Makefile:
# buildworld - Rebuild *everything*, including glue to help do upgrades.
# installworld - Install everything built by "buildworld".
# world - buildworld + installworld, no kernel.
# buildkernel - Rebuild the kernel and the kernel-modules.
# installkernel - Install the kernel and the kernel-modules.
# installkernel.debug
# reinstallkernel - Reinstall the kernel and the kernel-modules.
# reinstallkernel.debug
# kernel - buildkernel + installkernel.

所以 make kernel = make buildkernel + make installkernel
make world = make buildworld + make installworld
半套跟全套我不是很懂,可能要去實際去看看,編完之後重新開機就可以了~

更新 ports/ 方面
#
# 也是一樣修改 /usr/share/examples/cvsup/ports-supfile,加到 make.conf
PORTSSUPFILE= /usr/share/examples/cvsup/ports-supfile
SUPHOST= freebsd.csie.nctu.edu.tw
SUP_UPDATE= yes
SUP= /usr/local/bin/cvsup
SUPFLAGS= -g -L 2

這樣
cd /usr/ports; make update
# 或者是
csup -g -L 2 /usr/share/examples/cvsup/ports-supfile

這樣就ok了

mydumper (取代 mysqldump 的工具)

mydumper (取代 mysqldump 的工具)
Published
by
Gea-Suan Lin
on March 4, 2009
in Computer, Database, Murmuring, MySQL and Software
. 2 Comments

mydumper 是取代 mysqldump 的工具,主要的差異在於 mydumper 會同時對多個 table 備份,效率比 mysqldump 好。

作者的說明文章在這裡:「mydumper」,我也順便做成 ports 了。

可以用 --help 看用法,另外我提供常用的範例指令:

mydumper -h [hostname] -u [username] -p [password] -x '^tracdb\.'

備份檔會放在同一個目錄裡 (export-*),看過範例以及 --help 的說明後,應該不太需要講解。

mk-parallel-dump (也是取代 mysqldump 的工具)

mk-parallel-dump (也是取代 mysqldump 的工具)
Published
by
Gea-Suan Lin
on March 5, 2009
in Computer, Database, Murmuring, MySQL and Software
. 0 Comments

maatkit 是一組 MySQL 的工具程式,裡面包括了很多好用的工具。(之前最常用的應該是 mk-table-sync,同步兩台不同機器上的 MySQL 內容)

在「mydumper (取代 mysqldump 的工具)」裡我比較的對象是 mysqldump,但在 mydumper 出來之前,maatkit 就有提供同時 dump 的工具,也就是 mk-parallel-dump。

範例除了在上面的頁面裡就有之外,也可以參考:

mk-parallel-dump -h [hostname] -u [username] --gzip --locktables --numthread=8 --databases='[database]' -p [password]

這樣會把 dump 的結果抓到 default 這個目錄下。

XtraBackup:線上備份 InnoDB 的好東西

XtraBackup:線上備份 InnoDB 的好東西
Published
by
Gea-Suan Lin
on April 24, 2009
in Computer, Database, Murmuring, MySQL and Software
. 1 Comment

XtraBackup 是 Percona 開發的工具,可以線上備份 InnoDB 的資料,而且不太會影響效能,速度比起 mysqldump 快很多。

以往想要線上備份 InnoDB database,會用 InnoDB 所提供的 InnoDB Hot Backup,但這套軟體不是 open source software,除此之外要收費。

Percona 前陣子開始發展 open source 的版本,軟體叫做 XtraBackup,目前寫這篇文章時的最新版是 0.5-beta。

剛剛試著從一台 production database (比較小台,3GB) 的備份,看起來相當順暢:

sudo xtrabackup --defaults-file=/srv/mysql/var/my.cnf --backup --target-dir=/tmp/backup --datadir=/srv/mysql/var

要注意的是參數的順序是有差異的,--defaults-file 一定要在最前面。另外 my.cnf 要記得指定,不然就是把 my.cnf 裡面所有設定值寫在命令列。

--backup 不需要解釋,--target-dir 與 --datadir 也應該很好懂。

直接輸入 xtrabackup 還有不少參數可以調整,像是 --throttle 這種參數可以限制 I/O 速度 (沒有實際用過),有了這個參數,在比較忙碌的 database 上不用擔心過載…

關於 FreeBSD 6 在 VMware 上時間的問題(越來越慢)

關於 FreeBSD 6 在 VMware 上時間的問題(越來越慢),以下方法可解:

Adding

kern.hz=”100″

to

/boot/loader.conf

參考來源:http://communities.vmware.com/message/446496#446496

Revision Control

- Subversion (svn)
- git (Linus Torvalds recommended)

Wednesday, July 22, 2009

Testimonials - 感言

Testimonials - 感言

Tuesday, July 21, 2009

Copying to tmp table

Copying to tmp table
January 26th, 2009

MySQL may use temporary tables during query execution. Ideally you would want to avoid this, since its an expensive and slow operation. It can be avoided by optimizing queries. Sometimes it can’t be completely avoided – in that case you want to make sure the temporary table is created as a “memory” storage engine table, since its very fast, as it is never written to disk and remains, as the name states, in memory. But, as the manual explains, there are some conditions, such as TEXT/BLOB columns, or a combination of GROUP BY/ORDER BY clauses that makes MySQL write the temporary table to disk as a MyISAM table. One can spot these queries by the EXPLAIN output:
[...] Using where; Using temporary; Using filesort
In that case performance depends on disk I/O speed. If there are multiple similar queries running simultaneously, they try to read/write a lot of information to the disk, and will become extremely slow.

Solution? TMPFS!

tmpfs is a filesystem, that resides in RAM/Swap, so if your server has enough available RAM, files written there will bypass disk I/O completely, and will perform significantly faster.

Now, “High Performance MySQL, Second Edition” claims that this solution is still not as good as a MEMORY table, since it requires MySQL to use some expensive OS calls to write & read the temporary table, but it is still faster than the disk based temporary table.

To set it up, just mount a tmpfs system on an empty directory (you should also add this to fstab):
mount tmpfs /tmpfs -t tmpfs
and edit my.cnf to make MySQL use that directory as a temporary directory:
tmpdir = /tmpfs
Be careful though, there is a bug in some versions that prevents this from working properly.

For more information, see this blog.

* Share/Save/Bookmark

Tags: MySQL

This entry was posted on Monday, January 26th, 2009 at 10:25 am and is filed under Programming. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
8 Responses to “Copying to tmp table”
Frank Says:
January 26th, 2009 at 3:43 pm

Good to know!
Ries Says:
February 3rd, 2009 at 8:49 am

I agree that the on disk temporary storage is bad for performance and the first thing to look at is to ‘filter’ data as soon a possible so MySQL has less reason to create such a tmp table.

However your solution posted is very dangerous on buzy databases because what if people run all queries in memory? Then you might end up with out of memory or usage of swap space which slows that down again. Also the solution you provided to store these temp tables on a separate memory HD is dangerous for the similar reasons, what if that space runs out? Will MySQL crash, or happily keep on running and give incorrect or no results back, does anybody know that
behavior?

Usually it’s best to give the RDBM all the memory it can get from the system and let the OS handle disk caching which is more save then create your own tricks.

Ries
Dan Osipov Says:
February 3rd, 2009 at 3:15 pm

Ries,

It depends on the Linux kernel version you’re using. Older kernels will freeze when space runs out, but newer kernels are more safe.

As for giving the DB all the memory it can use – sure, but in the case of a filesort MySQL will create a disk based table no matter what – and that’s slow even if the table is small.

You can also limit the size of a tmpfs partition to make sure it never goes into swap.

FYI – we’ve been running it on a high traffic DB server with 8Gb of RAM, and usage never went into swap space so far.
Ries Says:
February 21st, 2009 at 11:58 am

Dan,

it is still very dangerous to let a DB write that stuff to a limited Disk space because you will never know what happens next. It’s also a bit of a shame that if that ram disk is ‘to large’ you have a lot of memory in use you really don’t use for the DB.

Ries
Dan Osipov Says:
February 21st, 2009 at 12:13 pm

I see your point, but interestingly enough the DB is configured to use all the available memory – it just chooses not to for some reason…
David Abdemoulaie Says:
March 16th, 2009 at 1:25 pm

Dan,

“Using where; Using temporary; Using filesort”

does *not* mean that the temporary table was written to disk. In fact, nothing in EXPLAIN can give you that information. It seems like you’re working under the common assumption that ‘filesort’ means it was written to a file on disk, and then sorted. This is not necessarily the case, filesort is simply the name of the sorting algorithm used, and occurs for in-memory tables as well. It means that the results could not be sorted by an index alone, thus the data was copied to a temporary table, and then the “filesort” algorithm was applied to sort the results.
David Abdemoulaie Says:
March 16th, 2009 at 1:26 pm

In fact, here’s an article that puts it much better than I have:

http://www.mysqlperformanceblog.com/2009/03/05/what-does-using-filesort-mean-in-mysql/
Dan Osipov Says:
March 16th, 2009 at 2:48 pm

Good point Dave – it doesn’t, but like I said, if the table contains a TEXT/BLOB field, or there is GROUP BY/ORDER BY clause in the query, the table will have to be written to disk.

To be sure, you can check the process list while running a query, and you will see the query enter into the “Copying to tmp table on disk” state.

Sunday, July 19, 2009

施比受更有福

幸福建立在錢上面是很脆弱的,

那是一個無底洞,

為了幸福-->就要賺更多錢-->花更多的時間心力在工作-->反而越不幸福

當然我不是說錢不重要,最基本的生活底線是需要一些基本開銷,

但是千萬不要把幸福全部建立在有錢上面,那只會讓你痛苦,不會給你帶來幸福的,


偶爾羨慕人家是難免,無傷大雅

不過如果打從心裡羨慕人家的人多半是對自己的生活不滿意

或是對自己自信心不足

而對於生活的滿意以及自信都只是自己的想法跟態度而已,

你應該想想怎樣調整你的生活,

幸福只是一種感受而已,

有本書叫做「黃金的下半場」(名字不太確定)

內容其實很簡單,就是一個人他在45歲之前,就是為了追求社會上所謂的「成功人生」而努力,

努力賺錢,努力SOCIAL,努力往上爬,

結果45歲那一年他生了一場大病,他的人生完全改觀,

他病癒之後,決定要將人生的下半場,追求一個「有意義」或是「有價值」的人生,

而不是別人眼中所謂的「成功」。

他固定會去當義工,會作一些別人眼裡覺得很傻的事情,

但是他深知道施比受更有福這句話的真正意涵,當自己有能力幫助別人的時候,我是幸福的,

之後他的下半輩子,雖然收入減少,但是他每天都過的很充實,很快樂,很有意義,也幫助了很多人...

很多人總是在預支他的人生,總是計畫著:我要努力拼到45歲或50歲,然後退休享福~

我很冒昧問一句,你怎麼知道你能健健康康活到50歲?

活在當下,把握每一刻,珍惜身邊的人才是你最應該作的,

懂得感恩,每天早上醒來都還有呼吸就要感恩,我想你會是個幸福的人


最後提一個觀念:

錢對你的意義是什麼,你是錢的主人,還是錢是你的主人?

你的每一筆收入都充分的「善用」了嗎?還是「濫用」了呢?

善用你的錢,才是所謂理財的最基本,

錢是最好的僕人(工具),卻是最糟糕的主人,

希望大家都可以有個美好幸福的人生~

The Chair for Programmer

The Chair for Programmer

Herman Miller Aeron Chair
Herman Miller Mirra chair

http://www.hermanmillerred.com/

http://www.codinghorror.com/blog/archives/001146.html

Friday, July 17, 2009

A good programming is 99% sweat and 1% coffee

A good programming is 99% sweat and 1% coffee

Tuesday, July 14, 2009

寫一年的程式要有一年的功力

我一向認為寫一年的程式要有一年的功力, 而不是來一個需求, 就抄上一個改改就完成了, 有時應該停下來想想, 這次的程式設計或專案留下什麼經驗, 可提供下次專案參考, 如何更有效率或更有生產力的完成, 例如:整理可再用的工具模組, 商用模組, 甚至開發自動化工具, 如報表程式產生器, 系統文件產生器, 反向工程工具, 隨著您的創意, 您可以不斷創造出有價值的東西或商品. 當別人要花一天16小時才能完成的工作, 您只要兩小時. 上面我所說的, 我都確實在我的工作生涯中做到了.
因此, 您的經驗得以再用, 您的創意得發揮, 而這些就在於您是不是保有工作的熱誠, 當您有工作的熱誠, 您會在乎如何有效率的完成工作, 如何將經驗分享給團隊, 提升團隊戰力, 如何服務客戶, 提升組織績效及公司業績, 您會在乎如何以最少的成本帶給公司最大的價值.
去年從其他位同仁接下一個失敗的案子, 以較少的人力於一個月內自力完成, 而且得到客戶很好的回應, 關鍵就在於”經驗“
由於人力並不充裕, 在專案中, 我往往除了程式設計外, 也扮演專案管理與系統分析的角色, 另外也扮演內部人員及使用者的教育訓練的講師, 因此資深同仁, 往往負有更多的工作及責任, 在知識經濟的時代, 大家都認知”知識”是組織重要的資產, 能累積知識及經驗並分享與傳承, 我想這更是資深同仁的重要價值所在
年資淺者除了精進技術外, 應該多學習團隊其他成員的優點, 吸收其他人的經驗, 在專案過程中, 學習專案執行的技巧及藝術, 並學習人際的互動與談判或推銷的技巧, 有一天您自然能擔當大任.
而真正瓶頸所在, 是許多人失去年輕時的求知熱誠, 過於計較金錢與名位, 忘記真正工作的價值, 非但不是提升團隊戰力的酵素, 還成為組織成長的阻力, 如此35歲帶來的是成本, 而不是價值了

寫程式要有結構、常數值要先宣告不能在程式中直接用

剛畢業的幾年,總覺得工程師像電容或是手機的電池一樣,就在新技術潮來潮往之間,不斷的充電和放電,直到有一天新知識裝不下去,舊技術沒價值時,就叫做年紀大了。
近不惑之年,經歷了軟體界的各個角色後,看法大不相同,願與大家分享。
阿亮說,凡走過必留下痕跡。充放電之間,到處是值得掌握的當下。
Programmer 隨著年資的增加,經驗心得是不是也跟著累積?例如,我們會不會告訴新來的菜鳥,寫程式要有結構、常數值要先宣告不能在程式中直接用、輸入的引數要先檢查以免問題一再傳播難以追蹤、Naming要有規矩別人才看得懂、軟體要備份和版本控制才不會亂成一團、...?
如果答案是肯定的,資深Programmer的價值當然存在。反之,35歲的工程師做得事情和剛畢業的學生差不多,在功利的角度下衡量,薪水自然也差不多。
又如果,資深Programmer可以把份內的事做得這麼好,有什麼道理不請來Design系統呢?因為這樣子,設計的時候就已經想好,程式要怎麼樣才能被 Programmer順利的寫出來。一路推上去,也不會發生現在我們常抱怨的,『分析師都不懂技術實做,轉換非常困難』之類的問題。
如果做好每一段的工作,未來的方向是可以由自己選擇的。只是,走得順不順利卻是造化,這種問題交給老天爺就好了。

Wednesday, July 8, 2009

五隻猴子的故事

五隻猴子的故事

把五隻猴子關在一個籠子裡,籠子上頭有一串香蕉。實驗人員裝了一個自動裝置,若是偵測到有猴子要去拿香蕉,馬上就會有水噴向籠子,這五隻猴子馬上會被淋濕。

首先有隻猴子想去拿香蕉,馬上水噴出來,每隻猴子都淋濕了。每隻猴子都去嘗試了發現都是如此。於是猴子們達到一個共識:不要去拿香蕉,因為有水會噴出來。

後來實驗人員把其中的一隻猴子換掉,換一隻新猴子(稱為A猴子好了)。關到籠子裡這隻A猴子看到香蕉,馬上想要去拿。結果,被其他四隻舊猴子海K了一頓,因為其他四隻猴子認為新猴子會害他們被水淋到,所以制止這新猴子去拿香蕉。這新猴子嘗試了幾次,被打的滿頭包,還是沒有拿到香蕉。當然,這五隻猴子就沒有被水噴到。

後來實驗人員再把一隻舊猴子換掉,換另外一隻新猴子(稱為B猴子好了)關到籠子裡。這隻B猴子看到香蕉,當然也是馬上要去拿,結果也是被其他四隻猴子K了一頓。那隻A猴子打的特別用力(這叫老兵欺負新兵 呵呵!) B猴子試了幾次總是被打的很慘,只好作罷。

後來慢慢的一隻一隻的,所有的舊猴子都換成新猴子了。大家都不敢去動那香蕉,但是他們都不知道為什麼,只知道去動香蕉會被猴扁。

這就是「傳統」的由來。

call_user_func_array vs $myfunction( &$params )

call_user_func_array vs $myfunction( &$params )

Hi,

I was looking at
http://www.php.net/manual/en/function.call-user-func-array.php and I
was wondering...

Given,
// --
function foo( &$params)
{
echo 'bar';
}
// --

What is the difference between

// --
$params = array( $stuff);
$myFn = 'foo';
$myFn($params)
// --

And

// --
$params = array( $stuff);
$myFn = 'foo';
call_user_func_array( $myFn, $params );
// --

Wont they both achieve the same result?

FFMG
=============================

call_user_func_array is useful when the number of parameters to a called
function is variable or unknown, for example:

function nice_dump() {
$params = func_get_args();
echo "
";
call_user_func_array('var_dump', $params);
echo "
";
}

nice_dump(1, 2, 3);

=============================

Indeed, it's not really function name that's interesting in this
particular example, it's the parameters that particular piece of code
doesn't have to worry about.

Then again, one of it's major advantages is it also supports callbacks, so
you can easily give a class function or object method to it. Your code
would be rather complex to get that otherwise...

Real programmers confuse Halloween and Christmas — because dec(25) = oct(31).)

Real programmers confuse Halloween and Christmas — because dec(25) = oct(31).)

Monday, July 6, 2009

named pipes provider no process is on the other end of the pipe error 233

Can anyone tell me what the cause of the error below is?

I have the client tools installed on XP Pro Svc Pack 2.0. When I try to
connect to the server on the remote machine I get the error message below.

I have set the logins up correctly for the user id I'm using on the client
machine and the remote SQL Server 2005 is setup to accept remote connections.
Naturally, when I go to the info site the error has no information available.

the SQL Server 2005 installation is on a Server 2003 OS.

Thanks...

TITLE: Browse Server for Database
------------------------------

A connection was successfully established with the server, but then an error
occurred during the pre-login handshake. When connecting to SQL Server 2005,
this failure may be caused by the fact that under the default settings SQL
Server does not allow remote connections. (provider: Named Pipes Provider,
error: 0 - No process is on the other end of the pipe.) (Microsoft SQL
Server, Error: 233)

==================================

In SQL Server 2005,
1. use the SQL Server Configuration Manager.
2. Go to the SQL Server 2005 Network Configuration node
3. and under that you will find the protocols.
4. Enable TCP/IP

In SQL Server 2000, use the Server Network Utility. On the
general tab, you select the protocols to enable.
You need to restart the service after enabling protocols.

-Sue

No process is on the other end of pipe

"No process is on the other end of pipe" caused by bad certificate
In this blog, I am focusing on one specific error message which I think a little confusing for you to troubleshoot the connectivity issue against SQL Server 2005.

To be clear, please make sure you saw the following exact same symptom before you apply the resolution that this blog provide since the same error message could also caused by other reasons which is out of scope of this blog.

1) OS on the server could be WinXP/Win 2K/ Win 2K3/ Vista.

2) SQL Server 2005

3) Server was started and from Server ERRORLOG, you can see "The certificate was successfully loaded for encryption."

4) Make local or remote connection over SNAC(SQL 2005 Client) or SqlClient(ADO.NET 2.0) provider, you see any of following error message depends on what protocols enabled on your sql server:

Shared Memory Provider: No process is on the other end of the pipe.


Named Pipes Provider: No process is on the other end of the pipe.


TCP Provider: An existing connection was forcibly closed by the remote host.

5) The problem is consistently not intermitently whenever you make a fresh connection.

6) If you try connection over MDAC( SQLOLEDB.1 provider or {SQL Server} driver) you would get consistent and more descriptable error message like:

[DBMSLPCN]SSL Security error
[DBMSLPCN]ConnectionOpen (SECDoClientHandshake()).

The cause behind would be various such as SQL Server loads the bad cert due to different OS behavior such as between XP/2K and 2K3, later on connection fail since certificate validation does not pass on the server based on validation flag provided by the client.

The resolution here is:

1) If you are not trying encryption, first, see whether you explicitly specify a cert? if so, then delete it; otherwise, go to local machine or user certificate personal store, delete all certificates, and restart sql server, doulbe check Server ERRORLOG, see " A self-signed certificate was successfully loaded for encryption.", then retry connection.

2) If you must use encrypted connection, you need a good certificate for SQL Server 2005. Please see blog: http://blogs.msdn.com/sql_protocols/archive/2005/12/30/508311.aspx

to understand what kind of certificate is qualified for SQL 2k5. Also, you can go to SQL Server Configuration Manager, right click properties for the sql instance, and choose *Certificate* tab, choose any certificate in the drop down list which has already been validated by SQL 2k5, then restarted the sql instance and retry connection.

The error you may hit more frequently when you did not choose a cert and SQL Server load the bad cert from certificate store. There are various bad cert that cause the problem, see kB:http://support.microsoft.com/kb/919710/en-us for one example.

Sunday, July 5, 2009

MySQL Conference Liveblogging: Disaster Is Inevitable - Are You Prepared?

* Suicide
o having no backups
o depending on slaves for backup
o keeping backups on same SAN
o having a single DBA - Frank didn't like this one at all
o not keeping binlogs
* Restoring from backup
o how much time?
o uncompressed backup ready to mount?
o separate network for recovery?
* In Fotolog, 1TB of data was severely hit.
o first problem: backup was highly compressed (tar.gz)
o uncompressing took hours
o so keep uncompressed backups (at least last N days)
o it should be mountable, rather than transferable
* Frank going over recovery modes at http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html
* Row by row recovery
o row by row recovery (get the range of ids)
o custom scripts
o may not be able to use primary key
o foreign key based retrieval faster
o lose 4 seconds for each crashed record (in Fotolog, for some reason some values were crashing mysqld)
* Lessons
o SANs make sense (in some environments)
o try to replicate the whole SAN (in Fotolog, a SAN actually failed because of a bug in its maintenance program)
o everything will fail at some point
o backup everything (cron jobs, my.cnf, custom scripts)
o have backup in a form ready to restore
o don't count replication a backup
o be worried about 'routine' operations
* Peter Zaitsev of Percona takes the stage to talk about his homegrown tools for InnoDB recovery
o innodb-tools - will recover even if mysqld doesn't start, for example if half of RAID0 fails or somebody deleted some data. innodb-tools will recover using InnoDB tablespaces.
* We're out of time

● ● ●

Artem Russakovskii is a San Francisco programmer, blogger, and future millionaire (that last part is in the works). Follow Artem on Twitter (@ArtemR) or subscribe to the RSS feed.

In the meantime, if you found this article useful, feel free to buy me a cup of coffee below.

Thursday, July 2, 2009

CVS Subversion - 版本控制系統的基礎觀念

CVS Subversion - 版本控制系統的基礎觀念

蔡煥麟
huanlin.tsai at msa.hinet.net
Revision: 1.0 (Jun-13-2004)
前言

這是我學習使用 CVS(Concurrent Versions System)和 Subversion 的過程當中,陸續整理的一些筆記,裡面的內容大部分可以在參考文獻中找到。整理這份文件的目的,主要是提供一份比較簡短的觀念說明,讓想要學習使用版本控制系統的人,可以先懂一些必要的觀念和術語,就立刻學習工具的使用,而不是 K 完一堆手冊和 FAQ 之後才有辦法使用工具。我不是說只要閱讀這份文件就夠了,而是當你有了基本的觀念讓你足以使用工具的一些基礎功能之後,就應該去閱讀比較完整的手冊或書籍,以了解其他細節或進階的用法。這時候因為已經有了基礎,再去閱讀其他文件時,就會覺得容易些了。
摘要

本文介紹版本控制系統的基礎觀念及術語,以及導入版本控制系統時應考慮的事項。
1 簡介

在開發過程中,你是否碰到過以下幾種情形:

* 檔案被別人(或自己)覆蓋;
* 檔案遺失(拖放檔案時誤動作...);
* 想要比對各版本之間的程式碼有何不同;
* 想要回到之前修改的版本(需求反覆變更、自己改錯了...);
* 這些 code 不是我改的,是誰碰過我的程式碼?
* 軟體發行之後,必須凍結共用的程式碼一段時間,免得其他人在改 bug 的同時,因為你修改了共用的程式而增加更多新的問題。

如果有以上情形,你需要的是對專案進行版本控制(version control)。版本控制也有人稱它為原始碼控制(source code control),它的目的就在於解決上述的各種問題,讓你可以:

* 隨時復原錯誤,就好像是專案的時光回溯器,可以將檔案恢復到以前的任何時候的版本;
* 多人同時修改同一份程式碼,不會有相互覆蓋的情況;
* 保留所有修改的歷程,如果你發現自己的程式碼有被別人更動過,可以很容易找到是誰更改的,以及何時更改的;
* 在發行正式版的同時,還能繼續發展新版本,無須下令凍結所有程式碼。

版本控制系統則是提供上述功能的軟體系統,它提供了一個地方讓你集中存放開發過程中的所有程式檔案及文件,以便達到集中控管的目的。
版本控制與軟體建構管理

軟體建構管理(Software Configuration Management)簡稱 SCM 或 CM,是軟體工程領域中的一環。SCM 的傳統定義是原始碼的版本管理,後來則逐漸演進擴大,將軟體開發的一些標準和程序納進來。你可以將 SCM 視為軟體演進的過程中,用來管理改變的標準程序,這個改變的來源包括:程式碼的改變、支援多種作業平台、提供多種版本(例如:標準版、專業版)....等等,而版本控制就是用來實現 SCM 的主要工具。

SCM 這個主題很大,這裡主要是點出版本控制與 SCM 的關係,若有興趣進一步了解 SCM,請參考相關的書籍或到 Google 搜尋關鍵字 "software configuration management"。
2 版本控制系統
2.1 檔案庫(Repository)

前面提到,版本控制系統有一個集中存放檔案的地方,這個地方有個正式名稱,叫做「檔案庫(repository)」。檔案庫裡面儲存了專案檔案的所有歷史版本(包括目前開發中的版本),有的版本控制系統是以資料庫的方式儲存,有的是以檔案的方式儲存,不論儲存的方式為何,對使用者來說,最重要的就是要把檔案庫放在一台穩定、安全的機器上,並且還要定期備份。
主從式架構

現在我們知道,檔案庫既然是檔案的集中營,那麼一定是放在某台機器上,供所有開發人員存取,其作業方式如下圖所示,是一種主從式(Client/Server)的架構:

檔案庫所在的機器上,必須要安裝版本控制系統,以便提供檔案存取的服務給各個用戶端;而圖中的「開發人員A」和「開發人員B」則代表了用戶端,用戶端機器上必須安裝版本控制系統的用戶端工具,才能存取檔案庫。

在連線方式上,用戶端可以透過各種網路協定來存取檔案庫,某些版本控制系統要求你一定要隨時與檔案庫保持連線,才能修改檔案內容;某些版本控制系統(例如 Subversion)則採用比較寬鬆的方式,你可以在沙灘上用筆記型電腦修改程式,等到回辦公室時再將檔案同步。
2.2 哪些東西要放進檔案庫?

很顯然的,程式碼當然要存放在檔案庫中,以便進行版本控制,那麼,還有哪些東西也要版本控管?

基本上,你在開發一個專案的過程當中,需要用來建置軟體的檔案,都可能要放到檔案庫裡面,例如:建置專案的組態檔或 makefile、測試資料等等。在決定哪些檔案要放進檔案庫時,你可以問自己一個問題:「如果少了這個檔案,能夠建置和發行軟體嗎?」
衍生的檔案(Generated Artifacts)

有些檔案是建置過程中產生的一些附屬產出文件,例如開發 Java 應用程式時,可以利用 JavaDoc 工具來產生原始碼的說明文件。像這類從某個檔案衍生出來的檔案,該不該放到檔案庫裡面?

簡單的回答是「不要」。因為 :(1) 它不是建置軟體的必備條件;(2) 它是重複的資訊,而且容易造成檔案的不一致,我們經常會修改了程式碼卻沒有立刻產生 JavaDoc 文件;(3) 當我們需要它的最新版本時,可以隨時產生。

以上是針對 JavaDoc 這個例子來說明,但是專案開發過程中,還是有一些其他的衍生檔案,並不像 JavaDoc 文件一樣可以隨時產生。例如,你可能有一些檔案是所有開發人員都要共同存取的,或者需要花數個小時才能重建的,這些檔案還是應該放進檔案庫裡面。
非程式碼的檔案(Non-code Artifacts)

除了建置專案所需的檔案之外,有些非程式碼的檔案也應該納入檔案庫,例如:專案管理的文件、團隊成員的討論信件、會議記錄、FAQ....等等,任何對專案開發有貢獻的資訊都可以放到檔案庫裡。
匯入(Import)

這個動作指的是把一個完整的目錄結構匯入檔案庫。專案一開始的時候,檔案庫裡面並沒有專案的檔案和文件,因此當我們決定要把一個新的專案放進檔案庫進行版本控管時,第一個動作就是建立好一個專案的初始目錄結構(其中可能包含一些必要的檔案),然後執行匯入。
提示

要在 CVS 裡面執行檔案目錄的搬移會有些麻煩,因此最好一開始多考慮一下要放入檔案庫的專案目錄結構,免得造成日後的困擾。Subversion 雖然改善了 CVS 的這個缺點,連目錄的變動都可以進行歷史版本的記錄,但是經常搬動目錄仍然會有些副作用,匯入專案之前還是多想一下比較好。
匯出(Export)

匯出是把整個專案或模組從檔案庫中取出來,取出來的檔案不包含版本控制系統的管理檔案,也就是說,匯出的模組將不再由 版本控制系統控管。
2.3 工作區(Workspace)與管理的檔案
工作區(Workspace)

檔案庫存放了專案開發所需的所有檔案及其歷史版本,但是對於團隊成員個人而言,並不需要全部的檔案,我們只需要自己負責的部分就夠了。因此,我們會從檔案庫中取出(複製)一部分自己需要的檔案到自己本機的硬碟裡,這些存放在本機的檔案,就稱為本地複本(local copy),而存放本地複本的地方,則稱為工作區(workspace)。相對於本地複本,儲存在檔案庫中的版本,則稱為主拷貝(master copy)。

對於小型專案而言,本地複本可能就是專案的所有原始碼和文件,而大型專案可能會切割成數個子系統或模組,所以開發人員只要取出自己負責的子系統就行了。

工作區有時候也稱為工作目錄(working directory)或程式碼的工作複本(working copy)。
取出(Check Out)

一開始,我們個人的工作區都沒有任何檔案,因此第一個動作就是要從檔案庫中取出我們需要的工作複本,這個動作稱為:取出(check out)。當你執行 check out 時,版本控制系統就會從檔案庫拷貝一份你需要的工作複本到你的工作目錄,這個工作複本的所有檔案目錄結構都會跟檔案庫裡面的目錄結構一模一樣。
存入(Commit or Check In)

當你取出工作複本之後,就可以修改檔案內容,等到你覺得修改得差不多了,或者已經改完了,就可以把修改過的檔案存入檔案庫,這個動作稱為:存入(commit,或者 check in)。
更新(Update)

當你修改自己的工作複本時,當然其他的團隊成員也可能正在修改一些檔案,每個人的修改作業都是獨立進行且不會相互影響的,別人修改的結果也不會立即反映在你本機的工作複本上。如果你要看到別人修改的最新版本,你就必須執行更新(update)這個動作。當你的同僚執行 update 時,他們也會取得你最近 check in 的版本。

Check out 和 update 的行為有些相似,儘管他們的使用時機和目的不盡相同,有時候我們還是會交互使用這兩個術語。
2.4 專案、模組、與檔案(Projects, Modules, and Files)

大部分的版本控制系統允許你針對單一檔案進行取出與存入的動作,但是大部分的專案會有數十個到數百個以上的檔案,如果要對每一個檔案執行取出與存入,就太麻煩了,因此版本控制系統提供了不同層級的操作,讓我們能夠以邏輯組成的檔案群組來執行版本控制。

最上層的邏輯單位,就是專案(projects),在專案底下又可分成幾個模組(modules)以及子模組(submodules),你得為這些模組命名,以便團隊成員透過名稱來存取它們。例如一個汽車保養場的資訊系統,可能會分成進廠維護管理模組、庫存零件管理模組、結帳模組...等等,各開發人員只需要取出自己負責的模組就行了。當然,如果你要的話,也可以把整個專案都取回自己的工作區。

你可以把專案看成是某個目錄階層的根目錄,而模組和子模組則是底下的一堆子目錄和檔案。但是記住,模組只是檔案的邏輯組成單位,相同的檔案可以出現在不同的模組裡面,而模組也可以跨專案共享,你只要將一些共享的檔案歸納到一個共用的模組裡面就行了。
2.5 版本從何而來?

到目前為止,我們討論的都是檔案的取出和存入動作,那版本呢?

其實版本控制系統在我們每次執行 check in 時,就會把這次存入的檔案視為一個新的版本,而每個版本都會記錄在檔案庫裡面。也就是說,當你從檔案庫取出一個檔案,修改它,然後存入檔案庫,在檔案庫裡面就會保留一份原始的版本,以及你修改後的版本(註1)。 每次修改的新版本都會被賦予一個修訂版次(revision number),檔案的修訂版次在每次存入檔案庫時就會累加。跟版次號碼一起儲存的 資訊可能還包括了檔案的修改時間,以及由開發人員額外加註的說明。

某些版本控制系統會在你每次 check in 時,為所有的檔案指定一個新的修訂版次;某些工具則是針對個別檔案的變更來記錄版次,例如:

file1.java 1.10
file2.java 1.7
file3.java 1.9

這表示你不能用修訂版次來代表專案的發行版本,而應該用標記(tags)來作為專案的版本號碼。
2.6 標記(Tags)

前面提過,修訂版次(revision numbers)是用來表示個別檔案的版本,它會由版本控制系統自動累加,不適合用來表示專案的發行版本。當我們要為專案訂一個好記的版本名稱時,例如:Pre-Relase2, 應該使用標記(tags)。

標記不只可以作為專案的版本命名,你也可以為特定模組或某些檔案訂一個標記名稱,例如前面舉的例子:file1.java 1.10、file2.java 1.7、file3.java 1.9,你可以為這三個檔案訂一個標記名稱,以後可以使用這個標記名稱來一次取出這三個檔案。

總之,標記代表了專案開發過程中,某一個時間點的狀態,或者里程碑。
2.7 分支(Branches)

在開發過程中,通常所有的程式設計師都是工作在同一個程式碼基礎(code base)上,他們雖然各自負責撰寫不同部分的程式碼,但主要都依循「從檔案庫取出,修改,然後存入」的工作模式,這些目前大家所修改的檔案庫中的程式碼,就稱為專案的主線(mainline)。參考下圖以了解主線的概念(取自 [1])。

然而有些情況不允許我們共同修改主線的程式碼,例如,當專案上線之後,Mary 負責修正使用者陸續反映的程式臭蟲,這段期間可能要維持一兩個月左右,可是這時候負責撰寫程式主架構與共用元件的 John 發現了一些必須改進的地方,John 不能等 Mary 把所有臭蟲都解決了才進行,他必須立刻著手改進現有的主架構和共用元件。如果 John 依照以往的方式,修改了主架構或共用元件之後,執行 check in 的動作,這樣勢必造成其他已經上線的程式產生新的問題,甚至無法運作,而必須全部都修改一遍,如此一來,Mary 的負擔就更重了,她得一邊處理臭蟲,還要應付新的架構和元件所帶來的問題。你或許會想,John 可以一直修改他自己的工作複本,但是都不要執行 check in 就行了,但是這並不符合一般人的工作習慣,我們通常修改程式到某個階段時,就會執行 check in 以確保程式存在一個安全的地方,而且萬一 John 哪天忘了,習慣性地執行 check in,那就糟了。

分支(branches)的用處就在這裡,以上個例子而言,Mary 可以建立一個分支,以繼續修改程式上線後的臭蟲,而 John 則可以繼續維護目前的產品主線。此時 John 和 Mary 都一樣可以執行 check in 的動作,只是 Mary 取出和存入的都是檔案庫中的一個獨立分支,跟 Mary 維護的主線是完全分離的。下圖描繪了上述的作業方式(取自 [1])。

分支就好像是另一個獨立的檔案庫一樣,運用分支的技巧,你就不用因為發行軟體而將目前的的程式碼凍結起來。

關於分支的其他事項:

* 分支是以標記(tag)來識別。
* 即使你的版本控制系統允許你建立分支的分支,但是最好不要這麼做,以免橫生枝節。

提示

對於初學者來說,標記和分支可能不會太快用到,可以先嘗試把一個專案放進版本控制系統,運行順利一陣子之後,再逐漸學習使用這些進階的功能。
2.8 合併(Merging)

當你要 check in 某個檔案時,如果檔案已經先被其他人修改過並且 check in 了,版本控制系統便會偵測到,並且不允許你 check in 這個檔案。此時便需要使用合併(merge)的技術,將兩個人修改的內容進行合併,以確保彼此不會相互覆蓋,又能保留各自修改的內容。由於兩個人修改同一個檔案時,通常不會碰巧都修改到相同的部分,因此版本控制系統會幫我們自動完成合併的動作 ;萬一兩個人修改的部分正好重疊,這種情況稱為衝突(conflict),此時就必須由後來 check in 的那個人手動解決衝突的部分(可能會和另一個修改此檔案的人討論為什麼會發生這種情況,以及應如何修改)。這部分的處理過程在稍後還會有進一步的討論。

除了解決衝突的情況,合併還有另一個用途:用來合併分支和主線。例如當你為正式發行的版本建立一個分支以後,再這個分支裡面修正了一些臭蟲,而你發現這些臭蟲也存在主線的程式裡,此時就可以用合併的方式,讓版本控制系統把你在分支裡面做的修正套用到主線的程式碼。
2.9 鎖定機制(Locking Options)

前面提到過兩個人修改同一個檔案所造成的衝突,是以合併的技術來解決,不過,各種版本控制系統採用的方式可能不盡相同,其相異之處,基本上只是對於檔案鎖定(locking)的處理方式不一樣而已。鎖定機制可分為兩種:嚴格鎖定(strict locking)與樂觀鎖定(optimistic locking)。

採用嚴格鎖定的版本控制系統,採用的是事先避免衝突的態度,也就是當一個人 check out 某個檔案時,該檔案就會被鎖定成唯讀狀態,此時別人可以讀取這個檔案的內容,或者用它來建置專案,但無法修改,這樣就不會造成衝突了 ,只是後來想要修改的人,必須等到取得鎖定的人 check in 檔案之後,才能修改。參考下面的圖例(取自 [2]):

嚴格鎖定可以避免衝突,但實際用起來卻不大方便,因為一個檔案同時間只有一個人能取得修改權,其他人得排隊等候,像上面的例子,Sally 就要等 Harry 執行 check in 之後才能修改檔案,萬一 Harry 一直改不完,或者他忘了,然後渡假去了,Sally 該怎麼辦?

嚴格鎖定還有可能發生死結(deadlock)的情況,例如 A 檔案和 B 檔案兩個是相關的程式,Harry 先取出 A 檔案,且 Sally 取出了 B 檔案;之後 Harry 跟 Sally 又分別要取出 B 檔案和 A 檔案進行修改時,兩個人都無法修改,因為檔案都被對方鎖住了。

樂觀鎖定就沒有這些問題,因為樂觀鎖定根本就不鎖定檔案,任誰都可以同時取出同一個檔案進行修改,當發生衝突時,再使用合併的方式解決。參考下面的圖例(修改自 [1]):

圖中顯示 Fred 和 Wilma 都取出了 File1.java,而 Fred 先修改完並且 check in(commit),當 Wilma 也修改好,要執行 check in 時,版本控制系統會告訴她,她本機上的 File1.java 複本過時了(out-of-date),也就是說,檔案庫裡的 File1.java 從她上次取出後已經被別人更動過了,因此她必須先更新本機的複本,然後再跟本機修改過的複本進行合併,於是最後 check in 的結果就包含了 Fred 和 Wilma 修改的內容。由於兩個人修改的是同一個檔案的不同部分,因此版本控制系統能夠順利完成合併的動作,如果兩個人修改到相同的部分,Wilma 就得自己解決這個衝突了(可能會和 Fred 討論如何修改)。

也許你會覺得樂觀鎖定有可能需要自己手動解決衝突,嫌它太過麻煩,而寧願採用嚴格鎖定的方式。但實際上你並不需要太擔心,因為在開發專案時,通常會事先劃分好個人負責的模組或子系統,因此會發生多人同時修改一個檔案的機會已經不多;即使有這種情況,兩人剛好修改到同一行程式碼的機會更低。所以比較起來,樂觀鎖定還是比嚴格鎖定方便許多。

最後,再將這兩種機制的特性整理成下表,方便參考:
  作業模式 優點 缺點
嚴格鎖定 鎖定-修改-解鎖(lock-modify-unlock) 可避免衝突。 同一時間只有一個人可取得修改權,其他人必須排隊等候,可能造成工作無法順利進行,甚至造成相互鎖住對方要修改的檔案的情況。
樂觀鎖定 複製-修改-合併(copy-modify-merge) 所有人可修改任何檔案。 當兩個人修改同一個檔案的相同部分時,需要手動解決衝突,但發生這種情況的機率很低。
3 導入版本控制系統

在了解版本控制系統的基本觀念之後,就可以挑選一個版本控制系統,把它安裝起來試試看了,如果是一人團隊,應該沒什麼問題;如果是多人團隊,要將版本控制系統導入現行的軟體開發流程,可能就要多花點準備的功夫了。以下簡單說明幾點可能的工作項目:

1. 選擇合適的工具。目前市面上可以買到或免費取得的版本控制系統有很多,你可能要花一點時間比較一下各種產品的功能,並且根據自己的需求和預算,挑選最適合自己團隊的工具。
2. 安裝並測試版本控制系統的各項功能。
3. 選擇一名管理員。團隊中必須有一個人負責管理檔案庫、建立專案的初始目錄結構、定期備份檔案庫等工作。
4. 教育訓練。教導開發人員如何在日常的開發工作中使用版本控制系統,讓他們了解跟之前的作業方式有什麼差別、可以獲得哪些好處,以減少因為改變工作習慣而產生的阻力。
5. 正式將專案納入版本控管。

在選擇工具方面,這裡無法提供什麼有用的建議,因為我只接觸過 Visual SourceSafe、CVS、和 Subversion,不過如果要從這三個工具中挑選,我會選 Subversion,因為:

1. 喜新厭舊;
2. Subveriosn 改進了 CVS 的缺點,連目錄的變更也會記錄版本(檔案和目錄的搬移更方便);
3. 安裝 Subversion 的過程順利(安裝在 Windows 2000 Server 上);
4. 有很方便的用戶端工具:TortoiseSVN,可減少導入 Subversion 的阻力;
5. Subversion 的文件寫得不錯。(感謝 Plasma 提供繁體中文版的 Subverion 電子書)

另外,這裡有一個各家版本控制系統的比較表,也可以參考看看:

http://better-scm.berlios.de/comparison/comparison.html
4 總結

本文介紹了版本控制的一些基本觀念和術語,也大概提了一下導入版本控制系統所需的準備工作,在具備了這些基礎概念之後,便可以開始學習工具的使用,希望本文提供了足夠的基礎,作為您進一步學習使用版本控制系統的跳板。

註1:事實上,大部分的版本控制系統只儲存兩個版本之間有差異的部分,而不是儲存完整的兩份檔案內容。

 
術語整理
英文 中文 說明
check out 取出 從檔案庫中取出檔案。
commit/check in 存入 將檔案從本地端存入檔案庫。
export 匯出 把整個模組從檔案庫中取出來,取出來的檔案不包含版本控制系統的管理檔案,也就是匯出的模組將不再由 版本控制系統控管。
import 匯入 把整個目錄結構匯入檔案庫。當你要把一個新的專案放進檔案庫進行版本控管時,就需要執行這個動作。
local copy 本地複本 放在用戶端機器的工作目錄中的專案複本。
master copy 主拷貝 放在檔案庫裡的專案複本。
module 模組 一個目錄階層,通常一個專案就是一個模組。
release 發行版本 軟體產品的一個版本。為了區別產品的版本以及個別檔案的修訂版次,因此不使用 version,而用 release。
repository 檔案庫 存放所有檔案(包含歷史版本)的地方,用戶端執行 check out 時就是從這裡取出檔案。
revision number 修訂版次 一個檔案的修改版本,例如:1.1、1.3.2.2。
tag 標記 在開發過程的某個時間點上,為一組檔案提供的符號名稱。透過 tag 一群檔案,你可以很容易在某個 release 裡面找出這些檔案。
update 更新 從檔案庫中取得其他人修改的檔案,以更新本機的副本(local copy)。
workspace/
working directory 工作區/工作目錄 本機的工作目錄,又稱為沙盒(sandbox)。

 
參考文獻
[1] Pragmatic Version Control with CVS. Dave Thomas and Andy Hunt. The Pragmatic Programmers, LLC. 2003.
[2] Version Control with Subversion Draft version 9837. Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato. http://svnbook.red-bean.com/(繁體中文版:http://freebsd.sinica.edu.tw/~plasma/svnbook/)
[3] CVS 入門。作者:臥龍小三。http://linux.tnc.edu.tw/techdoc/cvs/book1.html