2014年7月30日 星期三

在Windows XP設定dir的alias為ls

之前使用Windows的時候常常會打錯指令,在cmd中輸入ls。今天查到方法可以設定dir的alias。只要使用Windows內建的tool叫doskey就可以設定macro。
例如:
doskey ls=dir
不過這個設定並不會自動儲存,下次再開啟cmd後就會消失。因此我們需要把設定存在一個設定檔中,來自動設定,步驟如下:
  1. 把alias存成一個檔案,這邊假設我們把檔案存在c:\bin\cmd_autoruns.cmd,檔案內容格式如下:
    doskey ls=dir
    doskey ..=cd ..
  2. 建立一個batch檔,來設定自動執行剛才我們建立的指令,檔名取為set_cmd_autorun.cmd,檔案內容如下
    reg add "hkcu\software\microsoft\command processor" /v Autorun /t reg_sz /d c:\bin\cmd_autoruns.cmd
  3. 點擊剛才建立的batch檔,完成設定

2014年7月11日 星期五

[C#] Extension Method

C#3.0之後提供extension method這個功能,簡單來說就是讓你在現有的type中加入新的的method。一般是用在內建型態或是sealed class上,一般的type我們可以透過繼承的方式來加入新method,但是我們沒辦法修改內建型態,因此extension method就派上用場了。
Extension會有以下這些特徵:
  1. 必須在非generic的static class中,並且宣告為static method
  2. Method最少要有一個參數
  3. 第一個參數用this關鍵字宣告
  4. 第一個參數不能有this以外的修飾詞,例如out或ref
  5. 第一個參數型態不能是pointer type
以下是一個extension method的範例
public static class StringHelper
{
    public static bool IsCapitalized (this string s)
    {
        if (string.IsNullOrEmpty(s)) return false;
        return char.IsUpper(s[0]);
    }
}
IsCapitalized就是string type的extension method,我們可以這樣使用它:
Console.WriteLine("Test".IsCapitalized());
其實這段呼叫在編譯時候會被修改成去呼叫static method,背後的細節被compiler隱藏起來。
Console.WriteLine(StringHelper.IsCapitalized("Test"));
總結一下,extension method背後會做以下轉換:
arg0.Method(arg1, arg2, ...);  // Extension method call
StaticClass.Method(arg0, arg1, arg2, ...);  // Static method call
Interface也可以被extended,範例如下:
public static T First (this IEnumerable sequence)
{
    foreach (T element in sequence)
        return element;

    throw new InvalidOperationException("No elements!");
}
...
Console.WriteLine("Test".First());   // Output: T

2014年6月27日 星期五

[Python]動態在Object中加入Method

Python這類的動態語言大多提供Run-time時動態修改一個object的方法,這樣的好處是你可以動態的修改某個object,為這個Obejct加入一些新的method。

Ruby要為object加入新method非常簡單:

dog = Object.new

def dog.sit
    print "I'm sitting.\n"
end

dog.sit

Ruby很簡單就能為dog加入一個sit的method。
Python實做起來稍微麻煩一些,主要原因是因為Python的函式有分成bound和unbound。

>>> def foo():
...     print "foo"
...
>>> class A:
...     def bar( self ):
...         print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>

bound method必須被bound到一個instance,在呼叫method時instance才會被當成參數傳入。
由於函式預設都是Unbound,如果直接加入method到object中,Python會丟出exception

>>> def barFighters( self ):
...     print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)

其實只需要手動把method bound到instance上就可以解決這個問題。
這邊我們使用type module中的MethodType來把method bound到instance上。

>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters

可以看到method被bound後就可以在Python中被正確的呼叫,這就是Python動態在object加入method的方法。

2014年5月16日 星期五

[OOP]Law of Demeter(Least Knowledge)

Law of Demeter又叫做Least Knowledge,這其實是一個軟體設計的守則,簡單來說就是要簡單化Object之間的互動,讓多個Object不要互相相依。使得系統太過於複雜,造成未來維護成本較高。

Law of Demeter訂出了四條守則,限制一個Object內的函式只能呼叫以下這些函式:

  1. Object本身的函式(Class內的成員函式)
  2. 當作參數傳遞進來的Object,可以呼叫傳遞進來Obejct所提供的函式
  3. 自行在函式中建立的物件所提供的函式
  4. Object中本來就包含的Object(也就是HAS-A的關係)

不屬於以上這四種的函式都禁止呼叫。舉例來說,以下這個取得溫度的例子就違反Law of Demeter:

public float getTemp() {
    return weatherStation.getThermometer().getTemperature();
}

以上的例子呼叫的getTemperature()函式是從getThermometer()中所取得,根據Law of Demeter的定義你不能使用某個透過其他函式回傳的物件中的函式。

public float getTemp() {
    Thermometer thermometer = weatherStation.getThermometer();
    return thermometer.getTemperature();
}

這個例子也同樣違反Law of Demeter,因為thermometer是透過其他Object的函式所取得。

public float getTemp() {
    return weatherStation.getTemperature();
}

正解是在weatherStation中加入一個getTemperature()函式用來取得溫度。這樣就有符合Law of Demeter,因為weatherStation是此Object中包含的物件(HAS-A的關係)。

Law of Demeter可以減少Object之間的相依程度,可以減少軟體維護的成本。不過有優點就有缺點,使用此守則會產生出一些包裝用的函式,使用不當會導致開發速度增加,甚至會提昇軟體複雜度。

以下是一個過度包裝的例子,改成這樣雖然沒有違反Law of Demeter,但是沒有什麼意義。

public House {
    WeatherStation station;

    public float getTemp() {
        Thermometer thermometer = weatherStation.getThermometer();
        return getTempHelper(thermometer);
    }

    public float getTempHelper(Thermometer thermometer) {
        return thermometer.getTemperature();
    }
}

其實所有守則都不是強制的,守則是要對整體設計有益時才遵守。其實就和Design Pattern一樣,當你有需要時才使用。否則盲目的套用一堆OOP守則以及Design Pattern只會導致系統變得複雜,不容易理解。

2014年5月14日 星期三

Pluggable Object

Pluggable Object是最近在Kent Beck寫得TDD by example中所看到的Design Pattern。其實就是用多型來處理重複的判斷條件。Kent Beck在書中以圖片編輯器為例,在圖片上按下滑鼠左鍵並移動滑鼠表示拖曳圖片移動。而在空白的地方按下左鍵移動滑鼠會出現方框,讓你一次選取多張圖片。這個流程如果寫成程式碼會長得像這樣:

Figure selected; 
public void mouseDown() { 
    selected= findFigure(); 
    if (selected != null)
        select(selected);
}
public void mouseMove() {
    if (selected != null) 
        move(selected); 
    else 
        moveSelectionRectangle(); 
}
public void mouseUp() { 
    if (selected == null) 
        selectAll(); 
}

你會發現有許多重複的判斷條件,該怎麼避免呢?這時候就可以用Pluggable Object。

首先先定義一個Interface叫做SelectionMode,這個Interface會有兩個函式分別是mouseMove()以及mouseUp(),並且建立兩個class(SingleSelection, MultipleSelection)實做此Interface,分別處理單一選取圖片以及多重選取圖片。如此一來整個程式碼可以被改寫如下:

SelectionMode mode; 
public void mouseDown() { 
    selected = findFigure(); 
    if (selected != null)
        mode = SingleSelection(selected);
    else
        mode = MultipleSelection();
}

public void mouseMove() {
    mode.mouseMove();
}

public void mouseUp() {
    mode.mouseUp();
}

程式碼變得乾淨整潔許多,這就是Pluggable Object。

2014年5月9日 星期五

Rework工作大解放:這樣做事反而更成功



這本書的作者是Ruby on Rails的開發者DHH,他也是知名小公司37Signals的創辦人。37Signals是一家很特別的公司,公司的員工不到20人且分布在兩大洲、8個城市。一年雖然見不到幾次面,但是卻能開發出高品質的專案管理軟體basecamp,為公司每年帶來數百萬美元的收入。
書中所寫得內容其實就是DHH在創業過程中的一些心得,許多書中的觀念都顛覆了傳統的管理方式。書中花了很大一部份是在講解創業時的一些觀念,從公司發展、人才招募到資金募集都有提到,很適合有心創業或正在創業的人閱讀。以下是幾個書中對工作的看法和大家分享:

工作效率


我最喜歡書中探討工作效率的章節,作者認為要提昇工作效率最好的方法就是避免被中斷。在工作時候,我們時常會被一些事情打斷,像是有人找你聊天、電話、電子郵件、噪音……。每次中斷後都需要花一段時間再重新啟動,進入狀況,自然工作效率就低落。作者提到我們應該試著讓自己不被中斷,你會很訝異原來一天可以做這麼多事情。這個論點其實在Peopleware這本書也有提到。

工作狂


工作狂是另一個Peopleware也提過得觀念,傳統上我們會認為一個人工作到越晚表示他越認真。這本書用一段經典的話來描述工作狂。
工作狂不是英雄,真正的英雄已經回家了
作者認為工作狂代表工作效率差,他們習慣用蠻力解決所有問題,而不去思考好的方法幫助自己提昇工作效率。這點也是我這幾年開始工作後的體會,同樣都是寫程式,高手會試著找尋好的方法來提昇自己的效率,像是使用快速鍵、好用的vim外掛,甚至是自己寫一些工具來改善工作效率。而一般人就如同作者寫得,習慣使用蠻力來解決所有問題,而不是動腦想更好的方法。

加班


作者在書中建議讓員工在5點前下班,長時間的加班對企業絕對是弊大於利。這點在很多書都有提到。作者的公司一週只工作40小時,每年還是能創造出上百萬美金的利潤。可見工作效率的重要性絕對大於工作時間。

小公司


作者也以自身公司為例說明不是所有公司都需要持續擴張規模,小公司的優點是能快速對改變做出應對,擴張成大公司後做任何決定都會傾向保守。作者認為不管是大公司、小公司,只要能持續獲利的公司就是好公司。

結論


這本書的確是一本非常經典的書,書中提到許多創業的心得可能要實際有創業經驗才能有所體會。關於探討工作效率的部份,我認為非常值得一讀。看完這本書後我也檢視了一下自己的工作效率,提醒自己不能變成像書中所寫得工作狂。

2014年5月7日 星期三

[C]適合使用goto的時機

大家都知道goto對程式碼是有害的,會造成程式碼難以被看懂。不過goto並不完全沒有用,有些情況使用goto會讓程式碼看起來比較清楚。

錯誤處理

由於C的語法沒有例外處理,在處理錯誤時有很多種寫法,我個人覺得使用goto的這個寫法的可讀性比較好。這也是目前我唯一想到適合使用goto地方,你可以在Linux kernel的程式碼中時常看到這種用法:

void foo()
{
    if (!doA())
        goto exit;
    if (!doB())
        goto error;
    if (!doC())
        goto error;

    /* everything has succeeded */
    return;

error:
    /* error recovering */

exit:
    return;
}

另一個常用的範例是用來release resource,以下程式碼當檢查vector中的資料是錯誤時,會使用goto跳到release resource的程式碼。

double sum_vector(double *vector1, double *vector2, int *error) {
    double sum = 0;
    *error = 1;
    if(!checkVectorValid(vector1)) goto invalidVector;
    if(!checkVectorValid(vector2)) goto invalidVector;

    /* sum of vectors */

    *error = 0;

invalidVector:
    free(vector1);
    free(vector2);
    return 0;
}

2014年4月16日 星期三

[C#]讓StreamReader從頭開始讀取

有時候我們會希望先從檔案讀一部分資料後,再重頭從檔案最前面讀取資料
大部分的程式語言都會提供Seek函式,讓你設定讀取的位置
不過在C#中會根據你使用Stream的不同,作法會有點不一樣
大多數的Stream都只要呼叫Seek函式指回0就可以
比較要注意的是使用StreamReader的時候,你需要多呼叫DiscardBufferedData函式來把cache清空
把cache清掉常常會被忘記,使用StreamReader要多加注意
fileReader.DiscardBufferedData(); 
fileReader.BaseStream.Seek(0, SeekOrigin.Begin); 
fileReader.BaseStream.Position = 0;

2014年4月15日 星期二

翻譯電腦書心得

很久沒更新blog
最近除了工作繁忙外,還應出版社邀約翻譯了一本Arduino的書
實際翻譯書籍後才發現真的沒想像中簡單,最困難的地方應該是在一些專有名詞的翻譯上。
這點這本書還有很大的改善空間,有購買這本書的讀者請多多見諒:P。

翻完書之後真的很佩服C++ Primer譯者侯捷大師,能翻譯出這麼多經典的翻譯本。
最後也請大家給這些優秀的譯者們鼓勵鼓勵,要翻譯出一本好書要花的時間絕對比想像中的要多很多。
而且酬勞跟你付出的時間絕對是不成比例的

未來有機會還是會想再翻看看其他書,有時候看到一些經典好書沒人翻譯成中文真的蠻可惜的
有了這次經驗相信下次會翻的更好