星期日, 七月 05, 2009

不專業之重構心得分享

最近有位同事和我聊到他做的幾個案子,都略有差異,但因為這些差異讓原來的程式一改再改,很難共用。
這正是重構存在的真正意義呀!

最簡單的重構是從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有篇非常優秀的簡報

星期三, 七月 01, 2009

今天早上做的怪夢

從小就夢想成為專職的程序員,結果昨天夢到進入一間名為Roogle的公司,辦公室在地下室。
在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隨到的服務專員。

星期五, 六月 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醒來,看到以下留言通知:
鳥毅是畜生的代名詞 已針對您的文章「另一顆奇異果」留下新意見:

呸!!你個x大xx系畢業的就多了不起??
這兒的內容一點技術水平都沒有,可見作者的水準有多麼低下!!
怎不關了乾脆?
還留著污染網民的眼睛.
垃圾.
這位老兄文筆不錯呀,是對岸來的吧?老兄都沒看清楚,我在Blog標題就有寫"BLOG就是自已寫爽的",是自爽用的,不是介紹技術呀!而且我也不是T大+MIT,真是一整個無厘頭呀...

補充:其實早上我寫到一半就吃包子去了,還有一半沒寫完。
我看到他寫的一點都沒生氣,反而想到禽獸不如的笑話,憑印象大致上如:
一對男女朋友去pub玩,晚上結束後又喝了酒很累,就去Hotel休息。
隔天早上女生醒來就啜泣:「嗚~你這個禽獸,對我做了什麼...」
男生回說:「昨天太累,我什麼都沒做呀!」
女生大怒,生氣地說:「你這個禽獸不如的傢伙!」
所以我寧可當禽獸/畜生也不要禽獸不如呀XD

星期四, 六月 04, 2009

在有TPM的機器啟用VT

一直覺得很奇怪,桌機的CPU明明支援VT,但是xpmode一直說未啟用VT。看了List of Intel Processors that support XPMode,也用SecurAble顯示
,仔細看才發現有個"Click for more"。
因此下載了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,結果遇到
連線到 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

星期五, 四月 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,裏面寫的暫存目錄是立即刪除,連安裝過程切換視窗都找不到。

星期一, 四月 20, 2009

列舉目錄下所有檔案的C# class

剛在噗浪上看到有人花了不少時間寫列舉目錄下所有檔案的class,記得當初鳥毅也在CodeProject上找了一會兒,以下是鳥毅改寫的Code(原始出處忘了留:P ),授權以原始出處為準(逃~)
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的標準步驟:
  1. 先commit自己的branch
  2. 再update自己的branch(這是因為TortoiseSVN的要求,不做不能merge)
  3. 把trunk合併到自己的branch
  4. 解決衝突
  5. 最後commit解決衝突的branch
  6. 必要時再把branch合併到trunk,方法如1~5。
講起來容易做起來難,尤其是遇到奇怪現象時需要靠經驗解決,有時候設定了svn:ignore的性質變動,會造成每次merge都有衝突,此時砍掉重練branch似乎比較快呀Orz

今天有兩位同事把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後,就無法再使用RapidSVNSubCommander等GUI,只能與SmartSVN beta合併使用,其實會造成困擾,所以若想同時用多種client,只能用舊版的TortoiseSVNAnkhSVN

結論:對大部份的使用者而言,在Windows用TortoiseSVN是最好的選擇;若是idea的瘋狂愛用者,可以選擇SmartSVN。遇到衝突時,就call團隊裏的高手支援吧!

星期三, 四月 15, 2009

用CSS達成BorderColorLight及BorderColorDark的效果

今天在改一個asp的舊網頁,用CSS怎麼都設不出原來用html的BorderColorLight及BorderColorDark畫面好看,後來google找到 http://www.zeali.net/entry/412
原來要放棄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上偷偷地裝了WinPcapWireShark,其實這個狀況用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硬碟,快速地重建回來。當然得退出網域重新加入,再更新ApacheSubversion和一堆阿里不達的東西,以及最重要的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 裏加上
LoadModule sspi_auth_module modules/mod_auth_sspi.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
接下來要設定權限,找到的範例要用 AuthzSVNAccessFile ,但我怎麼設定都不對,所以把Require user改成Require group,在 httpd.conf 設定如下
<Location /projectrepository>
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>
若有先進願提供正確的SSPI AuthzSVNAccessFile範例,不勝感激。
參考資料: 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君靠著考試改變他的人生,開創一條光明大道。

星期二, 三月 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 InsightSlickEdit根本找不到連結,所以畫不出call graph,其他的API之類就更別提了。

可預見的未來,這個系統一定會砍掉重練,只是遲早的問題。