最近有位同事和我聊到他做的幾個案子,都略有差異,但因為這些差異讓原來的程式一改再改,很難共用。
這正是重構存在的真正意義呀!
最簡單的重構是從Rename Varibale和Rename Method開始,接著熟練後便開始Extract Method,進一步則是Pull Up、Push Down,再來則是Generalize Type。
我自己做時只有兩個原則:異中求同、同中求異。
異中求同是指在不同的method裏找出相同的區塊,萃出成一個method或是公用class(例如有關數值運算、轉型、中文數字等等);或是不同的class中找出相同的行為,extract為有相關的class pattern(例如Factory、Abstract Factory等pattern)。
同中求異是指在複製貼上的動作後,找出相同的區塊做Extract Method,若有許多子類別則可以Pull Up,諸如此類的應用。
所有的書都寫得類似,重構就像開車,一點一點地修正方向盤,慢慢地就安全抵達目的。個人的經驗是每天都寫code,經過幾年後就會不知不覺地學到重構的方法。
這只是在下不專業的看法,正統的重構技巧請看重構:改善既有程式的設計 (二版)
P.S. 我不擅長Web重構,高手jaceju有篇非常優秀的簡報。
星期日, 七月 05, 2009
星期三, 七月 01, 2009
今天早上做的怪夢
從小就夢想成為專職的程序員,結果昨天夢到進入一間名為Roogle的公司,辦公室在地下室。
在Roogle必須從實習生幹起,非常辛苦,每個同事都是天才。夢中唯一出現認識的人是一位前公司的朋友,他原本就是天才型的人。其他的同事都是邋遢到不行的超級宅男,帶我介紹公司的是一位身高180cm,約40歲出頭的鮪魚肚男。
在Roogle的第一個任務是學Android程式,從source看起,接下來要靠自己的想像力,寫出一支Android應用。
再看這個應用的好壞,決定去留,所以每天都工作16小時 (其實我在前公司的頭三個月也是每天工作16小時呀),但似乎體力不濟,覺得很辛苦。
後來被鬧鐘吵醒,因為夢太真實了,特此誌之。
在Roogle必須從實習生幹起,非常辛苦,每個同事都是天才。夢中唯一出現認識的人是一位前公司的朋友,他原本就是天才型的人。其他的同事都是邋遢到不行的超級宅男,帶我介紹公司的是一位身高180cm,約40歲出頭的鮪魚肚男。
在Roogle的第一個任務是學Android程式,從source看起,接下來要靠自己的想像力,寫出一支Android應用。
再看這個應用的好壞,決定去留,所以每天都工作16小時 (其實我在前公司的頭三個月也是每天工作16小時呀),但似乎體力不濟,覺得很辛苦。
後來被鬧鐘吵醒,因為夢太真實了,特此誌之。
星期四, 六月 18, 2009
Subversion merge後在commit時發生File not found錯誤
最近遇到好幾次Subversion merge後在commit時發生File not found錯誤,和這裏一樣。
可是在subversion Issue 1673裏早就寫Status: Resolved, Resolution: Fixed,令我非常不滿。
原本svn之外的版本控管軟體沒有Visual Studio整合,剛才再查了一下發現Mercurial已經有VisualHG這樣的好東西可用。還有TortoiseHG的加持,決定再花時間測試一下,如果沒什麼大問題,應該就會報告優秀長官,以Mercurial取代Subversion。
Update:經過兩天的努力....我放棄了。Mercurial在Windows仍舊有中文問題,這不算是成熟的solution,只好繼續當隨call隨到的服務專員。
可是在subversion Issue 1673裏早就寫Status: Resolved, Resolution: Fixed,令我非常不滿。
原本svn之外的版本控管軟體沒有Visual Studio整合,剛才再查了一下發現Mercurial已經有VisualHG這樣的好東西可用。還有TortoiseHG的加持,決定再花時間測試一下,如果沒什麼大問題,應該就會報告優秀長官,以Mercurial取代Subversion。
Update:經過兩天的努力....我放棄了。Mercurial在Windows仍舊有中文問題,這不算是成熟的solution,只好繼續當隨call隨到的服務專員。
星期五, 六月 12, 2009
Chrome設定最小字體大小
最近發現某些網站字體設定得很小,最近又裝了防窺片,完全看不清楚,所以找了一下Chrome定最小字體的方法,在一個設定檔中。
Vista/Win7在
"C:\Users\使用者帳號\AppData\Local\Google\Chrome\User Data\Default\Preferences"
也就是
"%LOCALAPPDATA%\Google\Chrome\User Data\Default\Preferences"
XP在
"C:\Documents and Settings\使用者帳號\Local Settings\Application Data\Google\Chrome\User Data\Default\Preferences"
也就是
"%USERPROFILE%\Local Settings\Application Data\Google\Chrome\User Data\Default\Preferences"
記得先關掉Chrome,再以文字編輯器打開Preferences,尋找webkit的關鍵字,重點是以下紅字這兩行
"webkit": {"webprefs": {"default_fixed_font_size": 16,"default_font_size": 16,"fixed_font_family": "\u7D30\u660E\u9AD4","minimum_font_size": 14,"minimum_logical_font_siz": 14,"sansserif_font_family": "\u65B0\u7D30\u660E\u9AD4","serif_font_family": "\u65B0\u7D30\u660E\u9AD4"}
存檔就完工收兵。
星期四, 六月 11, 2009
我看ASP.NET MVC
本篇有很多錯誤觀念,非請勿入。
最近要幫忙做一個小東西,為了和現有企業架構整合,採用ASP.NET開發。
因為很久沒有寫程式,看了一下ASP.NET MVC,嗯,很好,以前學的WebForm控制項完全派不上用場。
(以下誤)
個人覺得SilverLight一定推不起來,所以ASP.NET 4.0開始讓程度比較好的程序員用MVC,程度差的用WebForm。MVC搭配template和jQuery,不但能夠提昇網頁反應速度,也避免因為使用UpdatePanel帶來的奇怪錯誤。
(以下大誤)
可以預見,未來的趨勢是使用ASP.Net MVC開發Web AP,大量依賴AJAX互動(也就是向Google看齊啦...),所以我要趕緊K jQuery了。
星期五, 六月 05, 2009
鳥毅是畜生的代名詞
今兒個因為雨聲太大04:00醒來,看到以下留言通知:
鳥毅是畜生的代名詞 已針對您的文章「另一顆奇異果」留下新意見:這位老兄文筆不錯呀,是對岸來的吧?老兄都沒看清楚,我在Blog標題就有寫"BLOG就是自已寫爽的",是自爽用的,不是介紹技術呀!而且我也不是T大+MIT,真是一整個無厘頭呀...
呸!!你個x大xx系畢業的就多了不起??
這兒的內容一點技術水平都沒有,可見作者的水準有多麼低下!!
怎不關了乾脆?
還留著污染網民的眼睛.
垃圾.
補充:其實早上我寫到一半就吃包子去了,還有一半沒寫完。
我看到他寫的一點都沒生氣,反而想到禽獸不如的笑話,憑印象大致上如:
一對男女朋友去pub玩,晚上結束後又喝了酒很累,就去Hotel休息。隔天早上女生醒來就啜泣:「嗚~你這個禽獸,對我做了什麼...」男生回說:「昨天太累,我什麼都沒做呀!」女生大怒,生氣地說:「你這個禽獸不如的傢伙!」
所以我寧可當禽獸/畜生也不要禽獸不如呀XD
星期四, 六月 04, 2009
在有TPM的機器啟用VT
一直覺得很奇怪,桌機的CPU明明支援VT,但是xpmode一直說未啟用VT。看了List of Intel Processors that support XPMode,也用SecurAble顯示
,仔細看才發現有個"Click for more"。
於是只好一個個選項去關,發現是Intel TXT這個選項會關掉VT,在這有提到
為什麼這麼簡單的事情,我找了半天都沒人寫呢?反正,現在可以再測看看xpmode了,再來比較有沒有比VirtualBox好用吧...

因此下載了vt.zip,才發現雖然BIOS有啟動VT,但是卻沒生效!
於是只好一個個選項去關,發現是Intel TXT這個選項會關掉VT,在這有提到
如果您選擇了它,任何與以TXT技術存放在TPM中清單不符合的虛擬主機都將無法獲得更高的權限,或甚至根本不能執行。個人猜想在有TPM的機器上,必須要有某種機制將資訊寫入TPM中,TXT才允許執行VT,否則禁用。
為什麼這麼簡單的事情,我找了半天都沒人寫呢?反正,現在可以再測看看xpmode了,再來比較有沒有比VirtualBox好用吧...
星期一, 五月 25, 2009
Windows 2003 x64無法安裝之處理
又一篇個人筆記,最近實在沒有生產力呀...
今天用一台桌上型商用PC灌Windows 2003 Server x64,一直灌不起來,調整BIOS裏各種參數均無效。Windows 2003 Server x64安裝程式無法進入安裝畫面,load driver後就BSoD
,連死在哪個.sys都沒有。這已經是我用nLite做出的整合光碟,沒有更新的driver了。原本用兩顆HD做Raid 1,但似乎有嚴重的問題,不但開機光碟進不去,連TrueImage都只能進Safe Mode,調整回AHCI模式才能使用TrueImage的Full Mode。但是Windows 2003 Server x64安裝程式仍舊是無法進入安裝畫面,幸好有以前同機型的tib備份檔,就使用TrueImage還原到AHCI模式的硬碟。
這件事告訴我們:以後要灌Windows Server,還是買台真正Server吧。(除非灌Linux/FreeBSD)
星期五, 五月 22, 2009
寫.Net程式時慎選專案名稱
小時候我們寫程式時,老師有說過不要亂取變數名稱(誤,我小時候沒上過電腦課),有許多保留字像class等不要用。
今天遇到的非常鳥的錯誤,試著寫一個行事曆,於是把專案名字叫Calendar,變數名稱與Class名稱我都很小心地避開Calendar這種有內建Class的字,但是事情就這麼發生了...
會用Visual Studio寫Asp.net的朋友都知道,Visual Studio會用專案名稱當做namespace,所以編譯時都過了,在有一個叫Site1.master的MasterPage情況下,執行時出現下面的錯誤訊息。
編譯器錯誤訊息: CS0426: 型別 'System.Web.UI.WebControls.Calendar' 中沒有型別名稱 'Site1'這就是在下喜歡Java的命名方式,namespace都會叫com.foo.xxx。唉,我果然不適合寫code呀...
星期二, 五月 19, 2009
Visual Studio連線到 SQL Server Express 2008問題
故事背景:
某個無聊網管在公司把自己工作用PC灌了Ubuntu玩到膩之後,今年開始裝Windows 7 beta 64 bit,前陣子更新到Windows 7 RC build 7100時發現 SQL Express 2008是32bit,於是移掉改裝為SQL Exress 2008 64bit,結果遇到
鳥毅不像VB超人的偶像璉璉有免費點數可用,只好摸摸鼻子換回32bit,結果遇到另一個問題:由於無法啟動使用者執行個體的處理而無法產生SQL Server 的使用者執行個體。此連接將會關閉,幸好有解,在XP把
正當終於用32 bit SQL Express 2008時,又看到SQL Express 2008 x64 Integration with Visual Studio 2008 SP1,原來國外的高手找到方法(hotfixr)可以直接下載patch。可別忘了啟動Named Pipes呀!
連線到 SQL Server 檔案 (mdf) 都需要 SQL Server Express 2005,才能正確運作。 請確認從 URL 下載的元件的安裝:
http://go.microsoft.com/fwlink/?LinkId=49251
過程:
看這裏有官方解說,用白話解說如下:老子不讓你用64bit啦,這是進階功能,要用的話拿小朋友來換。是的,有patch但不能下載。鳥毅不像VB超人的偶像璉璉有免費點數可用,只好摸摸鼻子換回32bit,結果遇到另一個問題:由於無法啟動使用者執行個體的處理而無法產生SQL Server 的使用者執行個體。此連接將會關閉,幸好有解,在XP把
%USERPROFILE%\Local Settings\Application Data\Microsoft\Microsoft SQL Server Data\SQLEXPRESS
目錄刪除就可用,Vista/2008/Win7是在 %USERPROFILE%\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS
。正當終於用32 bit SQL Express 2008時,又看到SQL Express 2008 x64 Integration with Visual Studio 2008 SP1,原來國外的高手找到方法(hotfixr)可以直接下載patch。可別忘了啟動Named Pipes呀!
結論:
64bit Windows之路真是辛苦,此時我真的希望微軟能夠學Mac把程式包成一個package直接用呀!
星期三, 五月 06, 2009
64bit SQLServer無法匯入Excel問題
同事遇到在64bit SQLServer無法在SQLServer直接匯入Excel檔的問題,原因是Jet Engine並沒有64bit版本。
事實上,MS Office並沒有64bit版本,所以Jet Engine也沒有64bit版本呀!
類似 http://www.eggheadcafe.com/software/aspnet/32766378/excel-import.aspx 的情形。
不過,如果選完整安裝的朋友,會在工具列看到「匯出和匯入資料(32位元)」,這個就是32bit版的DTS精靈,產生出來的SSIS封裝可以存在64bit SQLServer上,也可以直接執行。
所以會用Visual Studio寫SSIS封裝的朋友,就可以放心寫了。
什麼?要在Stored Procedure匯入Excel?請參考How to call SSIS package from the stored procedure
參考資料:
64-bit Considerations for Integration Services
how to call a stored procedure in SSIS
事實上,MS Office並沒有64bit版本,所以Jet Engine也沒有64bit版本呀!
類似 http://www.eggheadcafe.com/software/aspnet/32766378/excel-import.aspx 的情形。
不過,如果選完整安裝的朋友,會在工具列看到「匯出和匯入資料(32位元)」,這個就是32bit版的DTS精靈,產生出來的SSIS封裝可以存在64bit SQLServer上,也可以直接執行。
所以會用Visual Studio寫SSIS封裝的朋友,就可以放心寫了。
什麼?要在Stored Procedure匯入Excel?請參考How to call SSIS package from the stored procedure
參考資料:
64-bit Considerations for Integration Services
how to call a stored procedure in SSIS
星期五, 四月 24, 2009
解開intel晶片組driver infinst_autol.exe的方法
又一篇個人筆記。
為了替優秀長官在VAIO Z上安裝Windows Server 2003,之前用nLite做的Windows Server 2003 整合 ich9 driver開機光碟已經不能用,所以只好再找driver來整合。
但是Intel現在已經更新 infinst_autol.exe 的做法,解開安裝後馬上又刪除原始檔,所以我只好輸入infinst_autol.exe /?看有什麼參數可用,最後用infinst_autol.exe -a -f2 C:\temp ,這樣會在C:\temp產生log檔,再從log找到安裝的暫存目錄,這時候就會發現暫存目錄並未刪除。若未加參數時,Log檔會在 C:\Intel\Logs\IntelChipSet.Log,裏面寫的暫存目錄是立即刪除,連安裝過程切換視窗都找不到。
為了替優秀長官在VAIO Z上安裝Windows Server 2003,之前用nLite做的Windows Server 2003 整合 ich9 driver開機光碟已經不能用,所以只好再找driver來整合。
但是Intel現在已經更新 infinst_autol.exe 的做法,解開安裝後馬上又刪除原始檔,所以我只好輸入infinst_autol.exe /?看有什麼參數可用,最後用infinst_autol.exe -a -f2 C:\temp ,這樣會在C:\temp產生log檔,再從log找到安裝的暫存目錄,這時候就會發現暫存目錄並未刪除。若未加參數時,Log檔會在 C:\Intel\Logs\IntelChipSet.Log,裏面寫的暫存目錄是立即刪除,連安裝過程切換視窗都找不到。
星期一, 四月 20, 2009
列舉目錄下所有檔案的C# class
剛在噗浪上看到有人花了不少時間寫列舉目錄下所有檔案的class,記得當初鳥毅也在CodeProject上找了一會兒,以下是鳥毅改寫的Code(原始出處忘了留:P ),授權以原始出處為準(逃~)
Update:我改寫的class似乎太像(十年前的)Java,請看回應laneser寫的版本,這才是.Net風格呀。
Update:我改寫的class似乎太像(十年前的)Java,請看回應laneser寫的版本,這才是.Net風格呀。
using System;
using System.Collections;
using System.IO;
namespace tenyi.io
{
public class FileExplorer
{
public ArrayList FileList = new ArrayList();
public ArrayList extensionLists = null;
private string myPath = null;
private bool recursive = true;
private DateTime lastDateTime = new DateTime(1, 1, 1);
public DateTime LastDateTime
{
get { return lastDateTime; }
}
public FileExplorer(string path)
{
myPath = path;
recursive = false;
FileList = GetFiles(myPath);
}
public FileExplorer(string path, string filter)
{
myPath = path;
recursive = false;
FileList = GetFiles(myPath, filter);
}
public FileExplorer(string path, ArrayList extensions)
{
myPath = path;
extensionLists = extensions;
recursive = false;
FileList = GetFiles(myPath);
}
public FileExplorer(string path, ArrayList extensions, string filter)
{
myPath = path;
extensionLists = extensions;
recursive = false;
FileList = GetFiles(myPath, filter);
}
public FileExplorer(string path, bool recursive)
{
myPath = path;
recursive = recursive;
FileList = GetFiles(myPath);
}
public FileExplorer(string path, string filter, bool recursive)
{
myPath = path;
recursive = recursive;
FileList = GetFiles(myPath, filter);
}
public FileExplorer(string path, ArrayList extensions, bool recursive)
{
myPath = path;
extensionLists = extensions;
recursive = recursive;
FileList = GetFiles(myPath);
}
public FileExplorer(string path, ArrayList extensions, bool recursive, DateTime theTime)
{
myPath = path;
extensionLists = extensions;
recursive = recursive;
FileList = GetFiles(theTime, FileDateCompare.GreatThan);
}
public ArrayList GetFiles(string strPath)
{
return GetFiles(strPath, null);
}
public ArrayList GetFiles(string strPath, string filter)
{
DirectoryInfo dir = new DirectoryInfo(strPath);
FileInfo[] files;
DirectoryInfo[] dirs;
ArrayList List = new ArrayList();
//if the source dir doesn't exist, throw
if (! dir.Exists)
{
throw new Exception("Source directory doesn't exist: " + strPath);
}
if(filter == null)
{
//get all files in the current dir
files = dir.GetFiles();
}
else
{
files = dir.GetFiles(filter);
}
foreach (FileInfo file in files)
{
if (extensionLists == null)
{
List.Add(new FileData(file.FullName, file.Name, file.Extension, file.Length, file.LastWriteTime));
}
else
{
if (checkFile(file.Extension))
{
List.Add(new FileData(file.FullName, file.Name, file.Extension, file.Length, file.LastWriteTime));
}
}
}
files = null;
//if not recursive, all work is done
if (! recursive)
{
return List;
}
//otherwise, get dirs
dirs = dir.GetDirectories();
//loop through each sub directory in the current dir
string tempDir;
foreach (DirectoryInfo subdir in dirs)
{
tempDir = subdir.FullName;
ArrayList temp = new ArrayList();
temp = GetFiles(tempDir);
for (int i = 0; i < temp.Count; i++)
{
FileData TempData = (FileData) temp[i];
List.Add(new FileData(TempData.FullName, TempData.Name, TempData.Extension, TempData.Length, TempData.LastWriteTime));
}
}
dirs = null;
dir = null;
return List;
}
public ArrayList GetFiles()
{
return GetFiles(myPath);
}
public ArrayList GetFiles(DateTime dt, FileDateCompare state)
{
DirectoryInfo dir = new DirectoryInfo(myPath);
FileInfo[] files;
DirectoryInfo[] dirs;
ArrayList aList = new ArrayList();
//if the source dir doesn't exist, throw
if (! dir.Exists)
{
throw new Exception("Source directory doesn't exist: " + myPath);
}
//get all files in the current dir
files = dir.GetFiles();
//loop through each file
foreach (FileInfo file in files)
{
if (extensionLists == null)
{
if (file.LastWriteTime.CompareTo(dt) > 0)
{
aList.Add(new FileData(file.FullName, file.Name, file.Extension, file.Length, file.LastWriteTime));
if (file.LastWriteTime.CompareTo(lastDateTime) > 0)
{
lastDateTime = file.LastWriteTime;
}
}
}
else
{
if (checkFile(file.Extension))
{
if (file.LastWriteTime.CompareTo(dt) > 0)
{
aList.Add(new FileData(file.FullName, file.Name, file.Extension, file.Length, file.LastWriteTime));
}
if (file.LastWriteTime.CompareTo(lastDateTime) > 0)
{
lastDateTime = file.LastWriteTime;
}
}
}
}
//cleanup
files = null;
//if not recursive, all work is done
if (! recursive)
{
return aList;
}
//otherwise, get dirs
dirs = dir.GetDirectories();
//loop through each sub directory in the current dir
string tempDir;
foreach (DirectoryInfo subdir in dirs)
{
tempDir = subdir.FullName;
ArrayList temp = new ArrayList();
temp = GetFiles(tempDir);
for (int i = 0; i < temp.Count; i++)
{
FileData TempData = (FileData) temp[i];
aList.Add(new FileData(TempData.FullName, TempData.Name, TempData.Extension, TempData.Length, TempData.LastWriteTime));
}
}
//cleanup
dirs = null;
dir = null;
return aList;
}
public ArrayList GetDirectories()
{
return GetDirectories(myPath, null, recursive);
}
public static ArrayList GetDirectories(string path, ArrayList filter, bool isRecursive)
{
DirectoryInfo thisDirectoryInfo = new DirectoryInfo(path);
ArrayList arrayList = new ArrayList();
DirectoryInfo[] subDirectoryInfos;
//if the source dir doesn't exist, throw
if (! thisDirectoryInfo.Exists)
{
throw new Exception("Source directory doesn't exist: " + path);
}
//get dirs
subDirectoryInfos = thisDirectoryInfo.GetDirectories();
//loop through each sub directory in the current dir
string tempDir;
if (subDirectoryInfos.Length == 0)
{
if (filter == null)
{
arrayList.Add(thisDirectoryInfo);
}
else
{
if (filter.Contains(thisDirectoryInfo.Name))
{
arrayList.Add(thisDirectoryInfo);
}
}
}
foreach (DirectoryInfo subdir in subDirectoryInfos)
{
tempDir = subdir.FullName;
ArrayList temp = new ArrayList();
//if not recursive, all work is done
if (isRecursive)
{
temp = GetDirectories(tempDir, filter, isRecursive);
for (int i = 0; i < temp.Count; i++)
{
arrayList.Add(temp[i]);
}
}
else
{
if (filter == null)
{
arrayList.Add(subdir);
}
else
{
if (filter.Contains(subdir.Name))
{
arrayList.Add(subdir);
}
}
}
}
subDirectoryInfos = null;
thisDirectoryInfo = null;
return arrayList;
}
private bool checkFile(string strExtension)
{
bool throwaway = true;
for (int j = 0; j < extensionLists.Count; j++)
{
if (extensionLists[j].ToString().ToLower() == strExtension.ToLower())
{
throwaway = false;
}
}
if (throwaway)
{
return false;
}
else
{
return true;
}
}
}
}
Subversion不能merge時的處理
又是一篇個人筆記。
優秀主管帶領的優秀團隊在MCSD.Net Joseph兄的努力之下,目前已經進到coding階段,Joseph兄指導其他同仁把自己開發的模組放到branch避免干擾,但開始發現SVN令人詬病的merge問題。
由於處於開發初期,某些核心程式還不斷地更新,因此Joseph必須常更新trunk上的程式,而其他成員把trunk合併到自己的branch時常遇到問題。
以下為merge的標準步驟:
今天有兩位同事把TortoiseSVN從1.6.0升級到1.6.1後,合併時出現infinite depth的錯誤,個人猜測是.svn裏不知出什麼錯,也是砍掉重練才正常。
結論:終於知道為什麼gslin要把全公司的repository換成Git了。
優秀主管帶領的優秀團隊在MCSD.Net Joseph兄的努力之下,目前已經進到coding階段,Joseph兄指導其他同仁把自己開發的模組放到branch避免干擾,但開始發現SVN令人詬病的merge問題。
由於處於開發初期,某些核心程式還不斷地更新,因此Joseph必須常更新trunk上的程式,而其他成員把trunk合併到自己的branch時常遇到問題。
以下為merge的標準步驟:
- 先commit自己的branch
- 再update自己的branch(這是因為TortoiseSVN的要求,不做不能merge)
- 把trunk合併到自己的branch
- 解決衝突
- 最後commit解決衝突的branch
- 必要時再把branch合併到trunk,方法如1~5。
今天有兩位同事把TortoiseSVN從1.6.0升級到1.6.1後,合併時出現infinite depth的錯誤,個人猜測是.svn裏不知出什麼錯,也是砍掉重練才正常。
結論:終於知道為什麼gslin要把全公司的repository換成Git了。
星期四, 四月 16, 2009
試用多個Subversion GUI Client
為了協助優秀長官的計畫,先協助導入Subversion,我用Apache+SSPI/NTLM整合認證。接著要讓組員們能夠上手svn。要瞭解trunk/branches/tags的用法真是花了不少口水,雖然在公用磁碟有放jserv老大的優秀投影片,但同事們都趕著做案子沒看。我只能個別指導,公司找我這個時薪200元的打雜網管,有些不划算(加班就乘以1.33了呀) =_=
首先建議同事們用TortoiseSVN,在Windows下是首選(我自己用command line),再配合AnkhSVN在Visual Studio整合使用。TortoiseSVN現在有版本圖,與我4年前使用時大不同,穩定性也高。相對之下,RapidSVN就遜多了,在Linux下也會常crash,因此不予考慮。
但是問題來了,有修改目錄性質後,trunk與branch的merge常會發生衝突,TortoiseSVN在這方面雖然有進步,但仍然不強,所以我就試一下其他的Subversion GUI Client。
首先用的是SmartSVN,雖然說功能比較強,但Java的速度就比不上native的client,當然可能與SVNKit實作方式有關,不過時間就是金錢,等到有衝突時再來測,這方面可以參考 http://selainsoft.blogspot.com/2008/01/smartsvn-and-svnkit-javasvn.html 。
接著測eSVN,看來是打算和RapidSVN拼,但從2007年後就沒有新版看來,又是一個無疾而終的專案。再測SubCommander,介面有點類似SmartSVN,但是功能遜多了。
最後一定要提:Subversion的working copy會自動升級,因此若使用最新版的TortoiseSVN後,就無法再使用RapidSVN、SubCommander等GUI,只能與SmartSVN beta合併使用,其實會造成困擾,所以若想同時用多種client,只能用舊版的TortoiseSVN或AnkhSVN。
結論:對大部份的使用者而言,在Windows用TortoiseSVN是最好的選擇;若是idea的瘋狂愛用者,可以選擇SmartSVN。遇到衝突時,就call團隊裏的高手支援吧!
首先建議同事們用TortoiseSVN,在Windows下是首選(我自己用command line),再配合AnkhSVN在Visual Studio整合使用。TortoiseSVN現在有版本圖,與我4年前使用時大不同,穩定性也高。相對之下,RapidSVN就遜多了,在Linux下也會常crash,因此不予考慮。
但是問題來了,有修改目錄性質後,trunk與branch的merge常會發生衝突,TortoiseSVN在這方面雖然有進步,但仍然不強,所以我就試一下其他的Subversion GUI Client。
首先用的是SmartSVN,雖然說功能比較強,但Java的速度就比不上native的client,當然可能與SVNKit實作方式有關,不過時間就是金錢,等到有衝突時再來測,這方面可以參考 http://selainsoft.blogspot.com/2008/01/smartsvn-and-svnkit-javasvn.html 。
接著測eSVN,看來是打算和RapidSVN拼,但從2007年後就沒有新版看來,又是一個無疾而終的專案。再測SubCommander,介面有點類似SmartSVN,但是功能遜多了。
最後一定要提:Subversion的working copy會自動升級,因此若使用最新版的TortoiseSVN後,就無法再使用RapidSVN、SubCommander等GUI,只能與SmartSVN beta合併使用,其實會造成困擾,所以若想同時用多種client,只能用舊版的TortoiseSVN或AnkhSVN。
結論:對大部份的使用者而言,在Windows用TortoiseSVN是最好的選擇;若是idea的瘋狂愛用者,可以選擇SmartSVN。遇到衝突時,就call團隊裏的高手支援吧!
星期三, 四月 15, 2009
用CSS達成BorderColorLight及BorderColorDark的效果
今天在改一個asp的舊網頁,用CSS怎麼都設不出原來用html的BorderColorLight及BorderColorDark畫面好看,後來google找到 http://www.zeali.net/entry/412
原來要放棄CSS的簡單設定法
要設成類似
原來要放棄CSS的簡單設定法
table
{
border: 3px outlet #ade1ff;
}
要設成類似
table
{
border-top: 3px solid #ade1ff;
border-left: 3px solid #ade1ff;
border-right: 3px solid #4284e4;
border-bottom: 3px solid #4284e4;
padding: 0px;
margin: 0px;
border-spacing: 0px;
border-collapse: collapse;
}
星期三, 四月 01, 2009
機瘟
今天真不是個開玩笑的好日子。
星期一早上,正準備開始寫要交給優秀長官的報告時,有人反映網路磁碟不太穩,到了九點多,整台機器完全連不上去。跑到機房去看,根本整台hang住,連ping都沒反應。只好hard reset,經過2小時漫長的check disk後,幸好沒有嚴重的錯誤,等到13:00也重開成功。沒想到才半小時,機器又當掉了,這次不敢再讓機器慢慢的check disk,重開後先停用NOD32。記得在NOD32 3.0剛發布時也有類似的情況,這次有可能是NOD32 4.0惹得禍,不由得懷念起表現得中規中矩的OfficeScan。
昨天下午公司忽然網路出現異狀,查看之下發現有電腦亂發arp資訊,相信是中了arp病毒。
本部落格的忠實讀者應該記得,敝公司和相關企業是class B broadcast的網段,總公司與分公司也透過VPN連線,約有1000台PC在一個Lan...
因此,整個企業的網路就這樣被一台中毒的PC癱瘓。記得十幾年前,中央大學全校走一個gateway,因為某一台電腦把自己的IP設成gateway而造成全校網路不通。
由於Core Switch是相關企業負責,等了2小時後,相關企業資訊部查出來是敝公司的分部殺的人,小弟只好先拔VPN,今天再去擦屁股找出元兇。
早上八點就趕往分部,沒想到遇到白爛司機,說話比史特龍還不清楚,假設史特龍含了一顆蛋,他大概含了兩顆蛋。雖然敝公司分部位於市郊,但好歹也算是台北市,居然有司機路搞不清楚,叫他走平面就硬給我走高架橋,多繞了兩公里;又在單行道開過頭,害我平時150元能到的地方硬是跑到220元。
由於借了部門經理的高檔Notebook出門,當然到了分部就把Notebook接上switch hub,用二分法找出元兇,這部份花不到半小時就搞定。但因為分部的網路線拉得很怪異,本來想用埠號找出元兇實行上很困難,只好在SZ上偷偷地裝了WinPcap和WireShark,其實這個狀況用SmartSniff就夠了,因為我是把連到元兇的網路線直接插上SZ,只要能看到IP或Windows機器名稱即可。找到機器後用Trendmicro提供的好工具iClean去掃毒,可惜沒掃完iClean就hang住,試了幾次無效只好帶回公司重灌。
回到公司已經中午,下午處理些雜事後幫優秀長官的team開了一個Subversion Repository,再把對應網域權限設好(請參考:Subversion+Apache的NTLM/SSPI認證)。正當MCSD.Net同事把他的Rainbow Portal Project丟上去到一半時,就爆炸了當機了。
雖然快下班了但我也只好跑到機房去看發生什麼事情,當KVM切換到那台Subversion Server時出現美麗的藍天白雲....是藍屏死機。重開機兩次都無法啟動,安全模式也進不去。不知道該說幸還是不幸,由於是一般的爛PC,所以就整台抱到我的座位上開始分屍拆機。把硬碟拆下用自費買的usb線接上我的Win7掃描磁碟,掃描在Stage2不到一半就卡住了,Win7確實優秀,若是XP可能會整台hang住,Win7只要把CMD視窗關掉就沒事。
慶幸的是只有系統碟掛點,Subversion Repository依然健在,利用去年備份的tib檔,拿了另一顆80GB IDE硬碟,快速地重建回來。當然得退出網域重新加入,再更新Apache、Subversion和一堆阿里不達的東西,以及最重要的Windows Update。所以整台修好又過了一個多鐘頭,原本預訂今天要交給優秀長官的報告依然一字未動... 答應美麗的MIS小姐要幫她更新的次要SQL Server 也還沒動,又得回家用VPN免費加班。
Today is not my day.
今天真不是個開玩笑的好日子。
星期一早上,正準備開始寫要交給優秀長官的報告時,有人反映網路磁碟不太穩,到了九點多,整台機器完全連不上去。跑到機房去看,根本整台hang住,連ping都沒反應。只好hard reset,經過2小時漫長的check disk後,幸好沒有嚴重的錯誤,等到13:00也重開成功。沒想到才半小時,機器又當掉了,這次不敢再讓機器慢慢的check disk,重開後先停用NOD32。記得在NOD32 3.0剛發布時也有類似的情況,這次有可能是NOD32 4.0惹得禍,不由得懷念起表現得中規中矩的OfficeScan。
昨天下午公司忽然網路出現異狀,查看之下發現有電腦亂發arp資訊,相信是中了arp病毒。
本部落格的忠實讀者應該記得,敝公司和相關企業是class B broadcast的網段,總公司與分公司也透過VPN連線,約有1000台PC在一個Lan...
因此,整個企業的網路就這樣被一台中毒的PC癱瘓。記得十幾年前,中央大學全校走一個gateway,因為某一台電腦把自己的IP設成gateway而造成全校網路不通。
由於Core Switch是相關企業負責,等了2小時後,相關企業資訊部查出來是敝公司的分部殺的人,小弟只好先拔VPN,今天再去
早上八點就趕往分部,沒想到遇到白爛司機,說話比史特龍還不清楚,假設史特龍含了一顆蛋,他大概含了兩顆蛋。雖然敝公司分部位於市郊,但好歹也算是台北市,居然有司機路搞不清楚,叫他走平面就硬給我走高架橋,多繞了兩公里;又在單行道開過頭,害我平時150元能到的地方硬是跑到220元。
由於借了部門經理的高檔Notebook出門,當然到了分部就把Notebook接上switch hub,用二分法找出元兇,這部份花不到半小時就搞定。但因為分部的網路線拉得很怪異,本來想用埠號找出元兇實行上很困難,只好在SZ上偷偷地裝了WinPcap和WireShark,其實這個狀況用SmartSniff就夠了,因為我是把連到元兇的網路線直接插上SZ,只要能看到IP或Windows機器名稱即可。找到機器後用Trendmicro提供的好工具iClean去掃毒,可惜沒掃完iClean就hang住,試了幾次無效只好帶回公司重灌。
回到公司已經中午,下午處理些雜事後幫優秀長官的team開了一個Subversion Repository,再把對應網域權限設好(請參考:Subversion+Apache的NTLM/SSPI認證)。正當MCSD.Net同事把他的Rainbow Portal Project丟上去到一半時,就
雖然快下班了但我也只好跑到機房去看發生什麼事情,當KVM切換到那台Subversion Server時出現美麗的藍天白雲....是藍屏死機。重開機兩次都無法啟動,安全模式也進不去。不知道該說幸還是不幸,由於是一般的爛PC,所以就整台抱到我的座位上開始
慶幸的是只有系統碟掛點,Subversion Repository依然健在,利用去年備份的tib檔,拿了另一顆80GB IDE硬碟,快速地重建回來。當然得退出網域重新加入,再更新Apache、Subversion和一堆阿里不達的東西,以及最重要的Windows Update。所以整台修好又過了一個多鐘頭,原本預訂今天要交給優秀長官的報告依然一字未動... 答應美麗的MIS小姐要幫她更新的次要SQL Server 也還沒動,又得回家用VPN免費加班。
Today is not my day.
今天真不是個開玩笑的好日子。
星期二, 三月 31, 2009
Subversion+Apache的NTLM/SSPI認證
簡單地說明原因,公司的Subversion Repository要用NTLM認證,我在Windows上用Apache架SVN Server。
當然先下載Apache 2.2和對應Apache 2.2的Subversion,接著下載mod_auth_sspi
,modules和bin都放好應該有的檔案後,在 httpd.conf 裏加上
參考資料: http://www.wretch.cc/blog/mogula/22956644
當然先下載Apache 2.2和對應Apache 2.2的Subversion,接著下載mod_auth_sspi
,modules和bin都放好應該有的檔案後,在 httpd.conf 裏加上
LoadModule sspi_auth_module modules/mod_auth_sspi.so接下來要設定權限,找到的範例要用 AuthzSVNAccessFile ,但我怎麼設定都不對,所以把Require user改成Require group,在 httpd.conf 設定如下
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
<Location /projectrepository>若有先進願提供正確的SSPI AuthzSVNAccessFile範例,不勝感激。
DAV svn
SVNPath E:/projectrepository
AuthType SSPI
AuthName "Project Repository"
# Require valid-user
Require group "網域名\群組名" "網域名\群組2"
SSPIAuth On
SSPIAuthoritative On
SSPIDomain 網域名
SSPIOfferBasic On
# AuthzSVNAccessFile E:/projectrepository/svnaccess.txt
</Location>
參考資料: http://www.wretch.cc/blog/mogula/22956644
星期四, 三月 12, 2009
從龍櫻看考試
耶~久違的閒聊文回來了。
最近工作壓力過大,今天出差就看了舊連續劇龍櫻(台灣譯名:東大特訓班),我對這部戲特別有感覺呀!不是因為長澤雅美或是新垣結衣,因為我是社會上的輸家。
如果這部漫畫能夠早個十幾年出現,大概會改變我的人生吧?小時候我老媽每天只會叫我看書,只看書能考上台大嗎?保證不會!
為什麼呢?因為人都有盲點,除了愛聽好話外,人也會不自覺地看自己想知道的知識,對於不喜歡或沒興趣的東西會不自覺地忽略。所以除了看書,要多做題目才會完整地瞭解。和東大特訓班的方法一致,對吧?
我到考完研究所才體會到考試和研究不同,櫻木建二說得沒錯,考試最大的優點就是公平。但是考試有時間限制,必須把自己變成解答機器,才能快速地寫出答案。以前大學時鳥毅的成績不好,因為鳥毅不喜歡做試題,更不看考古題。這種堅持都是屁!不過就是個考試,不代表你的實力好壞,但別人卻用分數衡量你,所以要讓自己機械化。至於如何自我訓練在龍櫻裏都有,我就不多說了。
前幾年考SCJP時,由於教材頗多,我先花一個星期看超級速讀自學教材。平常我看書就不算慢,但是Java相關的細節頗多,所以把看書速度提升,之後再花一個星期看書,並把書後面的題目做兩遍。但是結果並不如我預期,才70幾分,約一年後我考SCWCD時,其實我對那些Pattern並不熟悉,但是直接用超級速讀的方式死背,加上做兩遍考古題,居然考了85分。所以我才說:考試的分數並不代表實力。
在台灣考大學要進台大實在很難,所以鳥毅班主任要告訴各位一個捷徑:考研究所碩士班。就算只有五專畢業,工作滿3年後就可以直接考碩士班,所以鳥毅實在很後悔沒讀五專呀!。但要先聲明不是百分之百有用,這個社會不是努力就會成功。如果不在乎什麼科系,找個冷門報名人數少的,找個十年的考古題做熟,基本觀念都不錯,其實就有很大的希望。但是盡量找不要口試的系所,不然像鳥毅一樣筆試高分卻被某大老以口試30分刷下來。(我當年口試若有60就穩上,他才出此下策,台大口試一般都會打60分,對於想讓他進來的學生都有80分以上。)
若是博士班,聽說要先找好指導教授才去報名,我也沒唸過博士班,所以請另找高明。哦,忘了提,某些工學院的系所缺正妹,除非妳像呂X妮被老師們排擠,否則正妹的口試分數一定高。(這兩天才知道,T大正妹大學也不是讀台大...)
後記:
這篇並不是純唬爛,鳥毅一位朋友就是大器晚成的考試達人。
這位朋友H君,大學重考一年,不但大學四年都補考過關,而且也沒有交到女友,可以說大學時期一事無成。
他當完兵後改名,當年就考上國立中興大學研究所,接著隔年考上高考就跑去當公務員。就這麼結束了嗎?只考兩關怎麼算達人呢?
後來就更猛了,他一年考上一個技師執照,連續三年考完。各位看倌可能有所不知,H君讀的土木系可以考三種技師:土木技師、結構技師、大地技師。技師執照是執業的必要條件,和律師執照、醫師執照、建築師執照等是同等級,難考程度也接近;就算是台大土木系的碩士,也鮮少人同時有三張執照;事實上許多大學土木系的教授連一張執照也沒有。
故事還沒完,隔兩年他又考上檢察官特助,接下來如何呢?我也很期待呀...
我只知道H君靠著考試改變他的人生,開創一條光明大道。
最近工作壓力過大,今天出差就看了舊連續劇龍櫻(台灣譯名:東大特訓班),我對這部戲特別有感覺呀!不是因為長澤雅美或是新垣結衣,因為我是社會上的輸家。
如果這部漫畫能夠早個十幾年出現,大概會改變我的人生吧?小時候我老媽每天只會叫我看書,只看書能考上台大嗎?保證不會!
為什麼呢?因為人都有盲點,除了愛聽好話外,人也會不自覺地看自己想知道的知識,對於不喜歡或沒興趣的東西會不自覺地忽略。所以除了看書,要多做題目才會完整地瞭解。和東大特訓班的方法一致,對吧?
我到考完研究所才體會到考試和研究不同,櫻木建二說得沒錯,考試最大的優點就是公平。但是考試有時間限制,必須把自己變成解答機器,才能快速地寫出答案。以前大學時鳥毅的成績不好,因為鳥毅不喜歡做試題,更不看考古題。這種堅持都是屁!不過就是個考試,不代表你的實力好壞,但別人卻用分數衡量你,所以要讓自己機械化。至於如何自我訓練在龍櫻裏都有,我就不多說了。
前幾年考SCJP時,由於教材頗多,我先花一個星期看超級速讀自學教材。平常我看書就不算慢,但是Java相關的細節頗多,所以把看書速度提升,之後再花一個星期看書,並把書後面的題目做兩遍。但是結果並不如我預期,才70幾分,約一年後我考SCWCD時,其實我對那些Pattern並不熟悉,但是直接用超級速讀的方式死背,加上做兩遍考古題,居然考了85分。所以我才說:考試的分數並不代表實力。
在台灣考大學要進台大實在很難,所以鳥毅班主任要告訴各位一個捷徑:考研究所碩士班。就算只有五專畢業,工作滿3年後就可以直接考碩士班,所以鳥毅實在很後悔沒讀五專呀!。但要先聲明不是百分之百有用,這個社會不是努力就會成功。如果不在乎什麼科系,找個冷門報名人數少的,找個十年的考古題做熟,基本觀念都不錯,其實就有很大的希望。但是盡量找不要口試的系所,不然像鳥毅一樣筆試高分卻被某大老以口試30分刷下來。(我當年口試若有60就穩上,他才出此下策,台大口試一般都會打60分,對於想讓他進來的學生都有80分以上。)
若是博士班,聽說要先找好指導教授才去報名,我也沒唸過博士班,所以請另找高明。哦,忘了提,某些工學院的系所缺正妹,除非妳像呂X妮被老師們排擠,否則正妹的口試分數一定高。(這兩天才知道,T大正妹大學也不是讀台大...)
後記:
這篇並不是純唬爛,鳥毅一位朋友就是大器晚成的考試達人。
這位朋友H君,大學重考一年,不但大學四年都補考過關,而且也沒有交到女友,可以說大學時期一事無成。
他當完兵後改名,當年就考上國立中興大學研究所,接著隔年考上高考就跑去當公務員。就這麼結束了嗎?只考兩關怎麼算達人呢?
後來就更猛了,他一年考上一個技師執照,連續三年考完。各位看倌可能有所不知,H君讀的土木系可以考三種技師:土木技師、結構技師、大地技師。技師執照是執業的必要條件,和律師執照、醫師執照、建築師執照等是同等級,難考程度也接近;就算是台大土木系的碩士,也鮮少人同時有三張執照;事實上許多大學土木系的教授連一張執照也沒有。
故事還沒完,隔兩年他又考上檢察官特助,接下來如何呢?我也很期待呀...
我只知道H君靠著考試改變他的人生,開創一條光明大道。
星期二, 三月 10, 2009
Beyond RTFM
最近協助前單位做的專案,由於舊系統過多,經過一個月仍然停留在瞭解舊系統的階段。這幾天想起十幾年前學到的一個術語:RTFM。
事實上,一個系統經過幾次的修改後,已經多少與原始設計不同,RTFM還不如RTFS。這個專案是敝公司第一次與該公司合作,其他的舊系統均為其他廠商所開發,因此取得源碼亦有困難,多半只拿到簡單的系統手冊與不一定能執行的二進位碼,某些系統連資料庫都不肯給,只給DB Schema的文件。
這幾天優秀長官要鳥毅看一個重要系統的asp,由於只有asp而缺乏可用的DB與VB 6 dll 源碼,讀起來非常痛苦。事實上,如果是可執行的系統,慢慢地trace或許可以找出脈絡。以這個重要系統為例,手上的文件只有操作手冊與DB schema,對於系統分析與設計除了介面外幾乎沒有幫助。但是仔細深入源碼後,卻發現asp內部與許多其他系統連結,而且源碼經過幾個人的修改,以風格及命名方式看來,應該是一間以上外包公司的傑作。
最近又得知為符合法規修正,此系統又要修改。這種時候若得不到客戶的幫助,我只能說:砍掉重練比較快。
當然大部分的長官不會同意全部重寫,因此在這種情況下需要3rd party的協助,我找到Source Insight這個工具,可以試用30天,所以... 小華說SlickEdit也不錯,不過時間有限,所以只試用Source Insight。結果當然不出所料,對於這種近乎純網頁的asp,又大量利用script轉址,Source Insight或SlickEdit根本找不到連結,所以畫不出call graph,其他的API之類就更別提了。
可預見的未來,這個系統一定會砍掉重練,只是遲早的問題。
事實上,一個系統經過幾次的修改後,已經多少與原始設計不同,RTFM還不如RTFS。這個專案是敝公司第一次與該公司合作,其他的舊系統均為其他廠商所開發,因此取得源碼亦有困難,多半只拿到簡單的系統手冊與不一定能執行的二進位碼,某些系統連資料庫都不肯給,只給DB Schema的文件。
這幾天優秀長官要鳥毅看一個重要系統的asp,由於只有asp而缺乏可用的DB與VB 6 dll 源碼,讀起來非常痛苦。事實上,如果是可執行的系統,慢慢地trace或許可以找出脈絡。以這個重要系統為例,手上的文件只有操作手冊與DB schema,對於系統分析與設計除了介面外幾乎沒有幫助。但是仔細深入源碼後,卻發現asp內部與許多其他系統連結,而且源碼經過幾個人的修改,以風格及命名方式看來,應該是一間以上外包公司的傑作。
最近又得知為符合法規修正,此系統又要修改。這種時候若得不到客戶的幫助,我只能說:砍掉重練比較快。
當然大部分的長官不會同意全部重寫,因此在這種情況下需要3rd party的協助,我找到Source Insight這個工具,可以試用30天,所以... 小華說SlickEdit也不錯,不過時間有限,所以只試用Source Insight。結果當然不出所料,對於這種近乎純網頁的asp,又大量利用script轉址,Source Insight或SlickEdit根本找不到連結,所以畫不出call graph,其他的API之類就更別提了。
可預見的未來,這個系統一定會砍掉重練,只是遲早的問題。
訂閱:
文章 (Atom)
