tag:blogger.com,1999:blog-57111517951602933582024-03-06T06:43:55.103+08:00Sw@y's NotesSw@y的一些讀書心得和筆記Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.comBlogger105125tag:blogger.com,1999:blog-5711151795160293358.post-79240580218723393542014-07-30T20:13:00.001+08:002014-08-26T23:29:50.676+08:00在Windows XP設定dir的alias為ls之前使用Windows的時候常常會打錯指令,在cmd中輸入ls。今天查到方法可以設定dir的alias。只要使用Windows內建的tool叫doskey就可以設定macro。 <br />
例如:<br />
<pre><code>doskey ls=dir
</code></pre>
不過這個設定並不會自動儲存,下次再開啟cmd後就會消失。因此我們需要把設定存在一個設定檔中,來自動設定,步驟如下:<br />
<ol>
<li>把alias存成一個檔案,這邊假設我們把檔案存在c:\bin\cmd_autoruns.cmd,檔案內容格式如下:<br />
doskey ls=dir <br />
doskey ..=cd .. </li>
<li>建立一個batch檔,來設定自動執行剛才我們建立的指令,檔名取為set_cmd_autorun.cmd,檔案內容如下 <br />
reg add "hkcu\software\microsoft\command processor" /v Autorun /t reg_sz /d c:\bin\cmd_autoruns.cmd</li>
<li>點擊剛才建立的batch檔,完成設定</li>
</ol>
Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-573550014018378352014-07-11T14:18:00.001+08:002014-07-11T22:47:27.444+08:00[C#] Extension MethodC#3.0之後提供extension method這個功能,簡單來說就是讓你在現有的type中加入新的的method。一般是用在內建型態或是sealed class上,一般的type我們可以透過繼承的方式來加入新method,但是我們沒辦法修改內建型態,因此extension method就派上用場了。<br />
Extension會有以下這些特徵:<br />
<ol>
<li>必須在非generic的static class中,並且宣告為static method</li>
<li>Method最少要有一個參數</li>
<li>第一個參數用this關鍵字宣告</li>
<li>第一個參數不能有this以外的修飾詞,例如out或ref</li>
<li>第一個參數型態不能是pointer type</li>
</ol>
以下是一個extension method的範例<br />
<pre class="C#" name="code">public static class StringHelper
{
public static bool IsCapitalized (this string s)
{
if (string.IsNullOrEmpty(s)) return false;
return char.IsUpper(s[0]);
}
}
</pre>
IsCapitalized就是string type的extension method,我們可以這樣使用它:<br />
<pre class="C#" name="code">Console.WriteLine("Test".IsCapitalized());
</pre>
其實這段呼叫在編譯時候會被修改成去呼叫static method,背後的細節被compiler隱藏起來。<br />
<pre class="C#" name="code">Console.WriteLine(StringHelper.IsCapitalized("Test"));
</pre>
總結一下,extension method背後會做以下轉換:<br />
<pre class="C#" name="code">arg0.Method(arg1, arg2, ...); // Extension method call
StaticClass.Method(arg0, arg1, arg2, ...); // Static method call
</pre>
Interface也可以被extended,範例如下:<br />
<pre class="C#" name="code">public static T First<t> (this IEnumerable<t> sequence)
{
foreach (T element in sequence)
return element;
throw new InvalidOperationException("No elements!");
}
...
Console.WriteLine("Test".First()); // Output: T
</t></t></pre>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-90767265935113958562014-06-27T16:15:00.001+08:002014-07-04T00:08:11.694+08:00[Python]動態在Object中加入Method<p>Python這類的動態語言大多提供Run-time時動態修改一個object的方法,這樣的好處是你可以動態的修改某個object,為這個Obejct加入一些新的method。</p>
<p>Ruby要為object加入新method非常簡單:</p>
<pre class="ruby" name="code">dog = Object.new
def dog.sit
print "I'm sitting.\n"
end
dog.sit
</pre>
<p>Ruby很簡單就能為dog加入一個sit的method。 <br>
Python實做起來稍微麻煩一些,主要原因是因為Python的函式有分成bound和unbound。</p>
<pre class="python" name="code">>>> 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>>
>>>
</pre>
<p>bound method必須被bound到一個instance,在呼叫method時instance才會被當成參數傳入。 <br>
由於函式預設都是Unbound,如果直接加入method到object中,Python會丟出exception</p>
<pre class="python" name="code">>>> 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)
</pre>
<p>其實只需要手動把method bound到instance上就可以解決這個問題。 <br>
這邊我們使用<a href="https://docs.python.org/2/library/types.html#module-types">type module</a>中的MethodType來把method bound到instance上。</p>
<pre class="python" name="code">>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters
</pre>
<p>可以看到method被bound後就可以在Python中被正確的呼叫,這就是Python動態在object加入method的方法。</p>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-52823463801916373652014-05-16T17:45:00.001+08:002014-05-17T12:14:58.959+08:00[OOP]Law of Demeter(Least Knowledge)<p><a href="http://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter</a>又叫做Least Knowledge,這其實是一個軟體設計的守則,簡單來說就是要簡單化Object之間的互動,讓多個Object不要互相相依。使得系統太過於複雜,造成未來維護成本較高。</p>
<p>Law of Demeter訂出了四條守則,限制一個Object內的函式只能呼叫以下這些函式:</p>
<ol>
<li>Object本身的函式(Class內的成員函式)</li>
<li>當作參數傳遞進來的Object,可以呼叫傳遞進來Obejct所提供的函式</li>
<li>自行在函式中建立的物件所提供的函式</li>
<li>Object中本來就包含的Object(也就是HAS-A的關係)</li>
</ol>
<p>不屬於以上這四種的函式都禁止呼叫。舉例來說,以下這個取得溫度的例子就違反Law of Demeter:</p>
<pre class="c#" name="code">public float getTemp() {
return weatherStation.getThermometer().getTemperature();
}
</pre>
<p>以上的例子呼叫的getTemperature()函式是從getThermometer()中所取得,根據Law of Demeter的定義你不能使用某個透過其他函式回傳的物件中的函式。</p>
<pre class="c#" name="code">public float getTemp() {
Thermometer thermometer = weatherStation.getThermometer();
return thermometer.getTemperature();
}
</pre>
<p>這個例子也同樣違反Law of Demeter,因為thermometer是透過其他Object的函式所取得。</p>
<pre class="c#" name="code">public float getTemp() {
return weatherStation.getTemperature();
}
</pre>
<p>正解是在weatherStation中加入一個getTemperature()函式用來取得溫度。這樣就有符合Law of Demeter,因為weatherStation是此Object中包含的物件(HAS-A的關係)。</p>
<p>Law of Demeter可以減少Object之間的相依程度,可以減少軟體維護的成本。不過有優點就有缺點,使用此守則會產生出一些包裝用的函式,使用不當會導致開發速度增加,甚至會提昇軟體複雜度。</p>
<p>以下是一個過度包裝的例子,改成這樣雖然沒有違反Law of Demeter,但是沒有什麼意義。</p>
<pre class="c#" name="code">public House {
WeatherStation station;
public float getTemp() {
Thermometer thermometer = weatherStation.getThermometer();
return getTempHelper(thermometer);
}
public float getTempHelper(Thermometer thermometer) {
return thermometer.getTemperature();
}
}
</pre>
<p>其實所有守則都不是強制的,守則是要對整體設計有益時才遵守。其實就和Design Pattern一樣,當你有需要時才使用。否則盲目的套用一堆OOP守則以及Design Pattern只會導致系統變得複雜,不容易理解。</p>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-3456989454928849832014-05-14T21:15:00.001+08:002014-05-14T23:58:05.813+08:00Pluggable Object<p>Pluggable Object是最近在<a href="http://en.wikipedia.org/wiki/Kent_Beck">Kent Beck</a>寫得<a href="http://www.amazon.com/Test-Driven-Development-By-Example/dp/0321146530">TDD by example</a>中所看到的Design Pattern。其實就是用多型來處理重複的判斷條件。Kent Beck在書中以圖片編輯器為例,在圖片上按下滑鼠左鍵並移動滑鼠表示拖曳圖片移動。而在空白的地方按下左鍵移動滑鼠會出現方框,讓你一次選取多張圖片。這個流程如果寫成程式碼會長得像這樣: <br>
<pre class="c#" name="code">
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();
}</pre>
<p>你會發現有許多重複的判斷條件,該怎麼避免呢?這時候就可以用Pluggable Object。</p>
<p>首先先定義一個Interface叫做SelectionMode,這個Interface會有兩個函式分別是mouseMove()以及mouseUp(),並且建立兩個class(SingleSelection, MultipleSelection)實做此Interface,分別處理單一選取圖片以及多重選取圖片。如此一來整個程式碼可以被改寫如下:<br>
<pre class="c#" name="code">
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();
}</pre>
<p>程式碼變得乾淨整潔許多,這就是Pluggable Object。</p>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-35406232820922598082014-05-09T18:06:00.001+08:002014-05-12T09:19:34.373+08:00Rework工作大解放:這樣做事反而更成功<div class="separator" style="clear: both; text-align: center;">
<a href="http://pic.eslite.com/Upload/Product/201009/m/634205900565111250.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://pic.eslite.com/Upload/Product/201009/m/634205900565111250.jpg" height="320" width="225" /></a></div>
<br />
<br />
這本書的作者是Ruby on Rails的開發者DHH,他也是知名小公司<a href="http://37signals.com/">37Signals</a>的創辦人。<a href="http://37signals.com/">37Signals</a>是一家很特別的公司,公司的員工不到20人且分布在兩大洲、8個城市。一年雖然見不到幾次面,但是卻能開發出高品質的專案管理軟體<a href="https://basecamp.com/">basecamp</a>,為公司每年帶來數百萬美元的收入。<br />
書中所寫得內容其實就是DHH在創業過程中的一些心得,許多書中的觀念都顛覆了傳統的管理方式。書中花了很大一部份是在講解創業時的一些觀念,從公司發展、人才招募到資金募集都有提到,很適合有心創業或正在創業的人閱讀。以下是幾個書中對工作的看法和大家分享:<br /><br />
<div class="se-section-delimiter">
</div>
<h1 id="工作效率">
工作效率</h1>
<br />
我最喜歡書中探討工作效率的章節,作者認為要提昇工作效率最好的方法就是避免被中斷。在工作時候,我們時常會被一些事情打斷,像是有人找你聊天、電話、電子郵件、噪音……。每次中斷後都需要花一段時間再重新啟動,進入狀況,自然工作效率就低落。作者提到我們應該試著讓自己不被中斷,你會很訝異原來一天可以做這麼多事情。這個論點其實在<a href="http://swaywang.blogspot.tw/2013/01/peopleware-peopleware-productive.html">Peopleware</a>這本書也有提到。<br /><br />
<div class="se-section-delimiter">
</div>
<h1 id="工作狂">
工作狂</h1>
<br />
工作狂是另一個<a href="http://swaywang.blogspot.tw/2013/01/peopleware-peopleware-productive.html">Peopleware</a>也提過得觀念,傳統上我們會認為一個人工作到越晚表示他越認真。這本書用一段經典的話來描述工作狂。<br />
<blockquote>
工作狂不是英雄,真正的英雄已經回家了</blockquote>
作者認為工作狂代表工作效率差,他們習慣用蠻力解決所有問題,而不去思考好的方法幫助自己提昇工作效率。這點也是我這幾年開始工作後的體會,同樣都是寫程式,高手會試著找尋好的方法來提昇自己的效率,像是使用快速鍵、好用的vim外掛,甚至是自己寫一些工具來改善工作效率。而一般人就如同作者寫得,習慣使用蠻力來解決所有問題,而不是動腦想更好的方法。<br /><br />
<div class="se-section-delimiter">
</div>
<h1 id="加班">
加班</h1>
<br />
作者在書中建議讓員工在5點前下班,長時間的加班對企業絕對是弊大於利。這點在很多書都有提到。作者的公司一週只工作40小時,每年還是能創造出上百萬美金的利潤。可見工作效率的重要性絕對大於工作時間。<br /><br />
<div class="se-section-delimiter">
</div>
<h1 id="小公司">
小公司</h1>
<br />
作者也以自身公司為例說明不是所有公司都需要持續擴張規模,小公司的優點是能快速對改變做出應對,擴張成大公司後做任何決定都會傾向保守。作者認為不管是大公司、小公司,只要能持續獲利的公司就是好公司。<br /><br />
<div class="se-section-delimiter">
</div>
<h1 id="結論">
結論</h1>
<br />
這本書的確是一本非常經典的書,書中提到許多創業的心得可能要實際有創業經驗才能有所體會。關於探討工作效率的部份,我認為非常值得一讀。看完這本書後我也檢視了一下自己的工作效率,提醒自己不能變成像書中所寫得工作狂。Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-65353152861337305042014-05-07T17:59:00.001+08:002014-05-07T22:14:15.209+08:00[C]適合使用goto的時機<p>大家都知道goto對程式碼是有害的,會造成程式碼難以被看懂。不過goto並不完全沒有用,有些情況使用goto會讓程式碼看起來比較清楚。</p><div class="se-section-delimiter"></div>
<h1 id="錯誤處理">錯誤處理</h1>
<p>由於C的語法沒有例外處理,在處理錯誤時有很多種寫法,我個人覺得使用goto的這個寫法的可讀性比較好。這也是目前我唯一想到適合使用goto地方,你可以在Linux kernel的程式碼中時常看到這種用法:</p>
<pre class="c#" name="code">
void foo()
{
if (!doA())
goto exit;
if (!doB())
goto error;
if (!doC())
goto error;
/* everything has succeeded */
return;
error:
/* error recovering */
exit:
return;
}
</pre>
<p>另一個常用的範例是用來release resource,以下程式碼當檢查vector中的資料是錯誤時,會使用goto跳到release resource的程式碼。</p><div class="se-section-delimiter"></div>
<pre class="c#" name="code">
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;
}
</pre>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-37656127690830914562014-04-16T23:34:00.000+08:002014-04-16T23:34:08.543+08:00[C#]讓StreamReader從頭開始讀取有時候我們會希望先從檔案讀一部分資料後,再重頭從檔案最前面讀取資料<br>
大部分的程式語言都會提供Seek函式,讓你設定讀取的位置<br>
不過在C#中會根據你使用Stream的不同,作法會有點不一樣<br>
大多數的Stream都只要呼叫Seek函式指回0就可以<br>
比較要注意的是使用StreamReader的時候,你需要多呼叫DiscardBufferedData函式來把cache清空<br>
把cache清掉常常會被忘記,使用StreamReader要多加注意<br>
<pre class="c#" name="code">
fileReader.DiscardBufferedData();
fileReader.BaseStream.Seek(0, SeekOrigin.Begin);
fileReader.BaseStream.Position = 0;
</pre>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-89448513737770413662014-04-15T00:52:00.000+08:002014-04-15T00:52:02.761+08:00翻譯電腦書心得很久沒更新blog<br>
最近除了工作繁忙外,還應出版社邀約翻譯了一本<a href="https://www.tenlong.com.tw/items/9862018887?item_id=889064">Arduino的書</a><br>
實際翻譯書籍後才發現真的沒想像中簡單,最困難的地方應該是在一些專有名詞的翻譯上。<br>
這點這本書還有很大的改善空間,有購買這本書的讀者請多多見諒:P。<br><br>
翻完書之後真的很佩服C++ Primer譯者侯捷大師,能翻譯出這麼多經典的翻譯本。<br>
最後也請大家給這些優秀的譯者們鼓勵鼓勵,要翻譯出一本好書要花的時間絕對比想像中的要多很多。<br>
而且酬勞跟你付出的時間絕對是不成比例的<br><br>
未來有機會還是會想再翻看看其他書,有時候看到一些經典好書沒人翻譯成中文真的蠻可惜的<br>
有了這次經驗相信下次會翻的更好<br><br>
Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com1tag:blogger.com,1999:blog-5711151795160293358.post-3075473075523770162013-05-29T16:42:00.002+08:002013-05-29T16:43:25.456+08:00[C#]?? Operator (null coalescing operator)?? operator可以被用在nullable types以及reference types<br>
語法的意思很簡單:如果operand不是null,把他回傳給我;否則給我一個預設的值。比如說以下例子因為x是null所以y被預設成5。<br />
<pre class="c#" name="code">int? x = null;
int y = x ?? 5; // y is 5
</pre>
first ?? second語法被執行的步驟如下:<br />
<br />
<ol>
<li>檢查first </li>
<li>如果first不是null,回傳first </li>
<li>如果first是null,回傳second</li>
</ol>
<br />
?? operator可以用來串接多個nullable variable以及reference variable。會回傳第一個不是null的變數。以下範例會印出1,因為a是null。<br>
<pre class="c#" name="code">int? a = null, b = 1, c = 2;
Console.WriteLine (a ?? b ?? c); // 1
</pre>
善用?? operator可以讓我們的程式碼變得更簡潔,以下是一個範例程式用來計算使用者的年紀,這個例子沒有使用?? operator。<br>
<pre class="c#" name="code">
DateTime birth;
DateTime? death;
public TimeSpan Age
{
get
{
if (death == null)
{
return DateTime.Now - birth;
}
else
{
return death.Value - birth;
}
}
}
</pre>
使用?? operator我們可以把上面的範例改寫成好懂又精簡的版本。<br>
<pre class="c#" name="code">
DateTime birth;
DateTime? death;
public TimeSpan Age
{
get
{
DateTime lastAlive = death ?? DateTime.Now;
return lastAlive – birth;
}
}
</pre>
Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-49837187407968835932013-05-29T16:23:00.002+08:002013-05-29T16:23:41.534+08:00[C#]Optional parameters and Named arguments<p>C#從4.0版之後開始支援optional parameters以及named arguments,這兩個語法通常會一起使用。他讓我們的程式碼變得更簡潔並增加可讀性。首先先來介紹什麼是Parameters and Arguments。</p>
<h1>Parameters and Arguments</h1>
<p>Parameters和Arguments是兩個很容易搞混的名詞,先來定義這兩者有什麼不同。下面是一段程式碼範例:</p>
<pre name="code" class="C#">void Foo(int x, int y)
{
// Do something with x and y
}
...
int a = 10;
Foo(a, 20);
</pre>
<p>parameters是function定義時所使用的變數,arguments是我們呼叫function時傳進去的變數或值
範例中的x和y是parameters,a和20是arguments。</p>
<h1>Optional parameters</h1>
<p>Optional parameters簡單說就是給parameter一個特定的預設值,當使用者沒有傳入此parameter所對應的arguments時,會自動使用預設值。在C#4.0之前沒有optional parameters,如果要達到這個功能必須使用overloading function,會造成寫一大堆overloading function的情況,並不是很好使用。C#4.0之後使用optional parameters可以免去宣告一堆overloading function的困擾。以下是optional parameters的一個簡單範例:</p>
<pre name="code" class="C#">static void Dump(int x, int y = 20, int z = 30)
{
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
}
...
Dump(1, 2, 3);
Dump(1, 2);
Dump(1);
</pre>
<p>我們設定y和z的預設值為20和30,當我們在呼叫function時,編譯器會根據我們提供的參數去做對應,找出最合適的function。程式執行結果如下:</p>
<pre class="console">x=1 y=2 z=3
x=1 y=2 z=30
x=1 y=20 z=30
</pre>
<p>程式會從parameters list的左邊到右邊一一去對應參數。如果出現無法對應的情況會丟出exception。
<p>由於optional parameters和arguments的對應是按照宣告的順序,因此當我們呼叫Dump(1, 2)時會自動把y對應成2,沒辦法把2對應到z讓y使用預設值。要讓參數能自由對應需要使用接下來要介紹的named arguments。</p>
parameter的預設值必須是一個常數,因此以下範例是錯誤的,因為DataTime.Now並不是一個常數。</p>
<pre name="code" class="C#">Foo(DateTime dt = DateTime.Now)</pre>
<p>Optional parameters也被限制必須放在後面,不能放在非optional parameters之前。</p>
<pre name="code" class="C#">Foo(int x = 0, int y)</pre>
<h1>Name Arguments</h1>
<p>Name arguments讓我們可以不按照順序傳入參數。他的語法是在argument前加入一個對應parameter的名稱。以下是範例:</p>
<pre name="code" class="C#">static void Dump(int x, int y, int z)
{
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
}
...
Dump(1, 2, 3);
Dump(x: 1, y: 2, z: 3);
Dump(z: 3, y: 2, x: 1);
Dump(1, y: 2, z: 3);
Dump(1, z: 3, y: 2);
</pre>
<p>不管argument的順序是如何,編譯器會自動幫我們對應到正確的parameters名稱。</p>
<pre class="console">x=1 y=2 z=3
x=1 y=2 z=3
x=1 y=2 z=3
x=1 y=2 z=3
x=1 y=2 z=3
</pre>
<h1>Abusing argument evaluation order</h1>
<pre name="code" class="C#">int i = 0;
Dump(z: ++i, x: ++i, y: ++i);
</pre>
<pre class="console">
x=2 y=3 z=1
</pre>
<p>上面這行程式碼輸出的結果可能會和你想的不一樣,這是因為傳進去的argument還是根據他宣告的順序做計算,而不是patameters的順序。我們應該要避免寫出這種程式碼。</p>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-76848359102474904542013-05-23T21:19:00.001+08:002013-06-04T11:04:25.840+08:00C# in Depth(精通C#)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcDMaIbQ1Kwn4ZQl63NAE_QQqrXaPm2X9ga-5K9NjEXixbKxmxPqit24yZWZlI6kHDkz4t-UWvHsenUd4hc-bEeAMczRTlBIpJc7TavYDO3ORNWIOPcGBdfKC59OGBeBJ4m5kEVjr0mDg/s1600/41vMVJPzNBL.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcDMaIbQ1Kwn4ZQl63NAE_QQqrXaPm2X9ga-5K9NjEXixbKxmxPqit24yZWZlI6kHDkz4t-UWvHsenUd4hc-bEeAMczRTlBIpJc7TavYDO3ORNWIOPcGBdfKC59OGBeBJ4m5kEVjr0mDg/s320/41vMVJPzNBL.jpg" width="254" /></a></div>
這是一本想更深入瞭解C#的人必讀的一本書。作者完整的交代了C#1.0到C#4.0之間的改變,這樣的寫法讓讀這本書有點像在念C#的歷史。書中詳細的說明C#每次改版新增了哪些功能,以及為什麼要新增這些功能,是為了解決什麼樣的問題。<br><br>
我一直覺得要瞭解一個程式語言的語法最重要的事情就是瞭解語法演進的過程。其實就像學習數學和物理一樣,只會死背公式是沒有用的。程式語言作者設計某種語法一定是有他的原因。如果我們不懂背後設計的原由,就很難活用這個語法。學習程式語言另一個重要事情是此語法實際的用途和例子,比如說使用某種語法可以改善程式的可讀性,讓程式看起來更精簡。這兩點作者都有完整的解釋,這也是這本書為什麼被這麼多人推薦的原因。<br><br>
書中甚至提到一些compiler相關的東西,像是compiler如何推論匿名型別的正確型別,LINQ和extension methods是如何被compiler轉譯。這些東西在其他C#的書幾乎沒有被解釋。雖然說不用懂這些也能寫程式,不過我相信要寫出好程式多瞭解這些東西是會有幫助的。<br><br>
這本書雖然有中文版,但是我覺得翻譯不是很理想。在閱讀過程中常常可以看到錯字或缺字,句子翻譯起來不太通順(書中很常出現"然而"有點妨礙閱讀),甚至會有少翻的情況發生。因此還是建議有能力的讀者可以閱讀原文本。另外第二版沒有中文版是蠻可惜的,中文版只有介紹到C#3.0。<br><br>
總而言之,這是一本C#的經典書籍,很適合學完基本語法後當C#的第二本書,看完之後一定會對C#有更深入的體認<br><br>
最近看到C# in Depth要出<a href="http://www.amazon.com/C-Depth-Jon-Skeet/dp/161729134X/ref=sr_1_1?s=books&ie=UTF8&qid=1369314606&sr=1-1&keywords=C%23+in+Depth%2C+third">第三版</a>,內容涵蓋了C#5.0的語法。有興趣的人可以到Amazon網站注意出版訊息。Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-78724384907207398022013-05-20T20:53:00.000+08:002013-05-21T17:45:34.109+08:00在Visual Studio 2012的C++ Projects中設定target frameworkVisual Studio 2012沒有UI可以設定C++ Project的Target Framework<br>
唯一的方法就是去修改.vcxproj裡頭的TargetFrameworkVersion <br>
可以用常用的文字編輯器直接把.vcxproj打開,直接修改TargetFrameworkVersion就可以了<br>
C++ project新建立時候預設會使用v4.0,在.vcxproj裡頭有可能會找不到TargetFrameworkVersion<br>
這時候可以自己加入TargetFrameworkVersion tag到PropertyGroup Globals中<br>
下面是一個範例,此設定檔的Target Framework是v4.5<br>
<pre class="html" name"code">
<PropertyGroup Label="Globals">
...
<RootNamespace>...</RootNamespace>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
</pre>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-34655757505202548072013-05-07T18:44:00.000+08:002013-05-07T18:45:43.567+08:00[Python]如何disassemble Python程式碼大家都知道Python程式碼會被編譯成Python bytecode並執行在Python的VM上。有沒有什麼方法可以把Python程式碼變成bytecode印出來呢?Python有個disassembler module可以幫助你把Python code轉成bytecode。<br />
以下是一段範例。<br />
<pre class="console">>>> import dis
>>> def foo():
... a = 1
... b = 2
... c = a + b
...
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)
3 6 LOAD_CONST 2 (2)
9 STORE_FAST 1 (b)
4 12 LOAD_FAST 0 (a)
15 LOAD_FAST 1 (b)
18 BINARY_ADD
19 STORE_FAST 2 (c)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
</pre>
dis module中的dis method可以幫助你把Python code轉成byte codeSway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-65759094834185147352013-05-03T11:40:00.001+08:002013-05-03T11:40:40.680+08:00[C]#if和#else,切換程式碼的小技巧在寫程式時當我們修改程式碼時通常會把舊有的程式碼註解起來,再加入新的程式碼。有沒有什麼方法能快速在新舊程式碼之間切換呢?C裡頭的#if和#else是一個好方法。下列是一個常見的新舊程式碼範例,我們用註解把程式碼分開:<br>
<pre class="C" name="code">
newCode();
/*
someOtherCode();
*/
</pre>
<pre class="C" name="code">
/*
newCode();
*/
someOtherCode();
</pre>
其實可以用C裡頭preprocessor的小技巧來快速切換程式碼<br>
<pre class="C" name="code">
#if 1
newCode();
#else
test(); /* FIXME: please don't to that. */
someOtherCode();
#endif
</pre>
<pre class="C" name="code">
#if 0
newCode();
#else
test(); /* FIXME: please don't to that. */
someOtherCode();
#endif
</pre>
如此一來我們只要切換1和0就可以快速切換不同區塊的程式碼,就算裡頭有註解也不用擔心<br>
要註解一大塊程式碼也可以使用這個技巧<br>
<pre class="C" name="code">
#if 0
newCode();
test();
#endid
</pre>
Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com1tag:blogger.com,1999:blog-5711151795160293358.post-36002024307144926202013-04-10T15:12:00.000+08:002013-06-06T20:51:15.124+08:00Static Typing, Dynamic Typing, Strong Typing, Weak Typing<h1>Static Typing</h1>
<p>如果一個程式語言中的每個變數型別在編譯時期就完全決定好,我們稱這個程式語言屬於static type。這類的程式語言在使用變數時通常都需要先宣告變數,編譯器會在編譯時期去做type checking。比如說Java, C, C++, C#。以下是一段C的範例:</p>
<pre class="C" name="code">
int num, sum; // explicit declaration
num = 5; // now use the variables
sum = 10;
sum = sum + num;
</pre>
<p>變數使用前需要宣告是static type的特徵之一</p>
<h1>Dynamic Typing</h1>
<p>Dynamic type和static type相反,一個屬於dynamic type的程式語言不需要宣告變數,因此編譯器無法對型別做檢查在編譯時找出型別上的錯誤。在執行期間存取變數時,會透過適當的機制來判斷此變數可能的型別。Dynamic type不需要事先宣告變數就能直接使用,比如說Python, PHP, Ruby, Perl。以下是一段Python的範例程式:</p>
<pre class="python" name="code">
sum = 1 // directly using the variable
sum += 2
</pre>
<p>上面的範例我們直接使用變數sum而沒有事先宣告,這是dynamic type的其中一個特徵。
簡單來說,Static typing會在編譯時去做type checking。而dynamic type會在run-time時做check。</p>
<h1>Strong Typing</h1>
<p>Strong typing很常會和static typing以及dynamic typing搞混。Strong typing是指變數會被綁定到某個型別,除非經過明顯的型別轉換,不然型別不會任意改變。比如說Python就是strong typing,以下是個範例:</p>
<pre class="console">
>>> x = 3
>>> y = '4'
>>> print(x+y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
</pre>
<p>Python不允許int和string相加,除非我們主動去做型別轉換,不然x和y變數不會經過隱藏的型別轉換加在一起。這就是Strong typing的主要特徵。Python是dynamic typing同時也是strong typing</p>
<h1>Weak Typing</h1>
<p>Weak typing是指型別的概念比較弱,變數的型別可能隨時會經過隱性的轉換。比如說JavaScript,以下是JavaScript的範例:</p>
<pre class="javascript" name="code">
var x = 3
var y = '4'
alert(x + y) //Produces "34"
</pre>
<p>不同於Python,JavaScript允許這種語法並且會自動幫你做型別轉換。這就是weak typing的特徵之一。</p>
<h1>Strong Typing v.s. Weak Typing</h1>
<p>其實這兩者並沒有一個約定成俗的定義,很多程式語言都同時有兩種的特性。只能說偏向某一邊比較多。比如說C,大部分人認為C偏向Weak Typing,因為C有pointer可以做任意轉型,同時也有void *這種變數可存取任意型別。</p>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com1tag:blogger.com,1999:blog-5711151795160293358.post-41226280130216508782013-04-09T21:22:00.000+08:002013-04-23T17:05:57.736+08:00Type-safe v.s. Type-Unsafe某一些程式語言比較自由,允許我們去做一些危險的動作。比如說C和C++的Pointer就允許我們直接對記憶體做操作。這類的功能讓程式語言變得很強大,但是一不小心有可能會讓程式整個當掉。這種允許我們任意存取記憶體位置的程式語言就不能算是Type-safe。比如說以下的C程式讓我們access超過int boundary的位置:<br>
<pre class="C" name="code">
int i = 10;
char *s = (char*)i;
print(*(s+10));
</pre>
這種問題不會發生在C#身上,因為C#是Type-safe的程式語言。以下範例在C和C++合法,但是在C#會丟出錯誤訊息:
<pre class="C#" name="code">
double d = 10.59;
int i = 5;
i = d; //this causes an Error
</pre>
在C#中不能隨便把某個型別的資料當作是另外一種型別,如果編譯器認為這樣轉型是不合法的,在編譯的時候就會丟出錯誤。<br>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-58381123347597773812013-04-09T20:56:00.000+08:002013-04-09T20:56:55.095+08:00[C#]Delegate如果你有學過C,C#的delegate其實很類似C的function pointer。delegate讓我們可以把function透過參數的形式來傳遞,也就是說delegate可以讓我們把function當作<a href="http://swaywang.blogspot.com/2012/01/first-class-function.html">first class opject</a>來操作。下列是一個delegate的簡單範例:<br>
<pre class="C#" name="code">
using System;
delegate void StringProcessor(string input);
class Person
{
string name;
public Person(string name) { this.name = name; }
public void Say(string message)
{
Console.WriteLine("{0} says: {1}", name, message);
}
}
class SimpleDelegateUse
{
static void Main()
{
Person jon = new Person("Jon");
Person tom = new Person("Tom");
StringProcessor jonsVoice, tomsVoice;
jonsVoice = new StringProcessor(jon.Say);
tomsVoice = new StringProcessor(tom.Say);
jonsVoice("Hello, son.");
tomsVoice.Invoke("Hello, Daddy!");
}
}
</pre>
此範例中我們建立了宣告了兩個delegate的instance,分別是jonsVoice以及tomsVoice。最後用兩種不同的方式呼叫function<br>
使用delegate要有以下三個步驟:<br><br>
<b>1. 宣告delegate type</b><br>
<pre class="C#" name="code">
delegate void StringProcessor(string input);
</pre>
這行就是我們宣告delegate type的地方,這個delegate的type是含有一個string參數且回傳值為void的function。此delegate type只能接受回傳值以及參數個數一模一樣的function。不過有一種特殊情況:
<pre class="C#" name="code">
void Test(object x);
</pre>
此function也可以被assigned給此delegate的instance,因為string是繼承自object<br><br>
<b>2. 建立delegate instance</b><br>
<pre class="C#" name="code">
StringProcessor jonsVoice, tomsVoice;
jonsVoice = new StringProcessor(jon.Say);
</pre>
用new可以建立剛才宣告好得delegate instance,建立傳入的參數是之後要透過delegate呼叫的function<br><br>
<b>3. 呼叫delegate instance的function</b><br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguCfUrMGwwSxCD6DXAjWxuX_TCymfvjRA6w3eBqbardR_luab9PkTSsderwsgqZMEo5fsqI6c1Pj7exz45PFWCWsQRIQW5Ig1fvMr6q_FAdRAJRWksqqC-Uj_ek8SE7Uza9tAR5HtpsKU/s1600/test.PNG" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguCfUrMGwwSxCD6DXAjWxuX_TCymfvjRA6w3eBqbardR_luab9PkTSsderwsgqZMEo5fsqI6c1Pj7exz45PFWCWsQRIQW5Ig1fvMr6q_FAdRAJRWksqqC-Uj_ek8SE7Uza9tAR5HtpsKU/s320/test.PNG" /></a><br>
編譯之後會把jonsVoice("Hello, son.")轉成jonsVoice.Invoke("Hello, son.")<br>
最後又會透過delegate呼叫原本assigned的function jon.Say("Hello, son.")<br>
<br>
delegate很常用在UI Button的click,我們會事先宣告EventHandler的delegate instance。當button被按下時,執行對應的處理function。有點類似call back function。<br><br>
每個delegate instance內部都有一個invocation list用來紀錄function,也就是說一個delegate instance可以紀錄不只一個function。當有多個function時,delegate會一一呼叫invocation list中所儲存的function。我們可以透過<b>+=</b>以及<b>-=</b>運算子來新增移除function。以下是個簡單的範例:<br><br>
<pre class="C#" name="code">
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
void HowAreYouToday(string sender) {
Console.WriteLine("How are you today, " + sender + '?');
}
Notifier greetMe;
greetMe = new Notifier(HowAreYou);
greetMe += new Notifier(HowAreYouToday);
greetMe("Leonardo"); // "How are you, Leonardo?"
// "How are you today, Leonardo?"
greetMe -= new Notifier(HowAreYou);
greetMe("Pereira"); // "How are you today, Pereira?"
</pre>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-58154318428907352352013-04-03T14:48:00.000+08:002013-04-03T14:51:53.257+08:00[C#]快速讀取、寫入檔案的方法C#提供一些快速的Method可以直接寫入或是讀取檔案,善用的話可以節省一些時間<br>
以下三個static methods只需要一個步驟就可把資料從檔案讀到記憶體中,傳入參數都是讀取檔案的路徑<br>
<pre class="C#" name="code">
File.ReadAllText(path) // (回傳string)
File.ReadAllLines(path) // (回傳array of strings)
File.ReadAllBytes(path) // (回傳一個byte array)
</pre>
<br>
下列四個static methods同樣只需要一個步驟就可把資料寫入到檔案中,傳入參數是路徑以及寫入的資料<br>
<pre class="C#" name="code">
File.WriteAllText(path, string)
File.WriteAllLines(path, array of strings)
File.WriteAllBytes(path, bytes)
File.AppendAllText(path, string) // (適合用在log file)
</pre>
File.ReadAllLines和File.ReadLines看起來很像,但是ReadAllLines會一次把所有資料讀到記憶體中<br>
ReadLines會回傳一個IEnumerable<string>,不會一次把所有資料讀到記憶體中<br>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-12170349863285479742013-04-02T21:22:00.000+08:002013-04-03T14:59:36.748+08:00如何讓Visual Studio 2012中compile的程式可在Windows XP上執行最近發現一個問題,Visual Studio 2012預設並不支援Windows XP。也就是說Compile出來的程式沒辦法在XP上執行。花了一點時間上網找解決方法,發現微軟在去年年底出的<a href="http://go.microsoft.com/?linkid=9821199">Visual Studio 2012 Update 1</a>已經可以支援XP了。程式開發人員可以在Visual Studio 2012上撰寫程式並compile成XP可執行的執行檔。<br />
<br />
安裝好更新檔之後還需要設定專案所使用的toolset為Visual Studio 2012 – Windows XP (v110_xp)<br />
<br />
詳細步驟如下:<br />
<br />
1. 在Solution Explorer中的Project上按右鍵並點選Properties<br />
<br />
2. 在左手邊樹狀目錄中選取Configuration Properties, General,把Platform Toolset property設定成Visual Studio 2012 – Windows XP (v110_xp)<br />
<br />
3. 重新編譯後會產生可在XP上執行的執行檔Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com2tag:blogger.com,1999:blog-5711151795160293358.post-80113449726762626182013-03-28T18:18:00.001+08:002013-05-23T18:57:37.228+08:00無瑕的程式碼-敏捷軟體開發技巧守則 (Clean Code: A Handbook of Agile Software Craftsmanship)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-MX47IeDEinJOxCvrOOpOX0JmYPpkoRi1koO-WriKuMgjVr-3R6RjIa2fC3Zh_RBK3YWnIgtUGeoCNB1jrL_sLzf_iSqjrfvkKqEZC7ngnmC2EfSgRZrwjOKoAHu-G9K8eT9wVjAXjZQ/s1600/PG21219.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-MX47IeDEinJOxCvrOOpOX0JmYPpkoRi1koO-WriKuMgjVr-3R6RjIa2fC3Zh_RBK3YWnIgtUGeoCNB1jrL_sLzf_iSqjrfvkKqEZC7ngnmC2EfSgRZrwjOKoAHu-G9K8eT9wVjAXjZQ/s320/PG21219.jpg" width="264" /></a></div>
<br />
最近發現<a href="http://swaywang.blogspot.tw/2012/01/clean-code-handbook-of-agile-software.html">Clean Code</a>總算出中文翻譯書了,去書局翻了一下內容發現翻譯品質還不錯。害怕原文書的朋友們可以考慮買這本翻譯書。前陣子也看到O'reilly最近要出<a href="http://swaywang.blogspot.tw/2013/01/the-art-of-readable-code.html">The Art of Readable Code</a>的中文翻譯本,這本書和Clean Code主題類似,有興趣的人可以注意一下出版的消息。<br />
<br />
很高興看到有越來越多好書被翻譯成中文,也希望未來能夠有更多經典書能被翻譯成中文讓更多人閱讀。<br />
<br />
原文板的讀書心得和筆記如下:<br /><br />
心得 : <a href="http://swaywang.blogspot.tw/2012/01/clean-code-handbook-of-agile-software.html">Clean Code</a><br><br>
筆記 :
<ul>
<li><a href="http://swaywang.blogspot.com/2011/12/clean-code-meaningful-names.html">Meaningful Names</a></li>
<li><a href="http://swaywang.blogspot.com/2012/01/clean-code-functions.html">Functions</a></li>
<li><a href="http://swaywang.blogspot.com/2012/01/clean-code-comments.html">Comments</a></li>
</ul>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com2tag:blogger.com,1999:blog-5711151795160293358.post-75745610321259349892013-03-28T18:05:00.002+08:002013-04-03T14:52:23.418+08:00寫入資料到txt檔,用Notepad打開顯示亂碼今天碰到一個奇怪的問題,我有一個程式會產生一個.txt檔。內容為上千個0~255的數字由空白隔開。寫檔成功後在Windows XP底下用Notepad打開發現顯示為亂碼,但是用Notepad++以及Wordpad打開都可正常顯示。很明顯這是編碼的問題,不過為什麼會這樣讓我找了一陣子。最後發現是Notepad的問題。<br />
<br />
Windows XP的Notepad有Unicode Detection的功能,Notepad使用一個Windows API叫<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd318672(v=vs.85).aspx">IsTextUnicode()</a>來偵測目前文字檔是不是Unicode編碼。但是這個API並沒辦法完美的辨認出Unicode,有時後會把ASCII text誤認為是Unicode編碼。比如說這段字串"<b>aaaa aaa aaa aaaaa</b><span style="font-family: sans-serif; font-size: x-small;"><span style="line-height: 19.1875px;">",</span></span>如果你把他貼在Notepad上存起來再重新打開,你會發現他變成一團亂碼。原因就在於IsTextUnicode()把全部都是此ASCII text誤認為UTF-16。除了此case以外還有很多其他的case會造成誤判。而Wordpad以及Notepad++不會有此誤判的現象,因此可正常顯示。Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-41633711519365594952013-02-05T20:32:00.004+08:002013-02-06T11:54:05.889+08:00Coding Style Guide以下網址是google以及llvm所制定的C++ coding standars,提供給想改善程式碼品質的人參考看看<br />
<br />
LLVM Coding Standards<br />
<a href="http://llvm.org/docs/CodingStandards.html#include-style">http://llvm.org/docs/CodingStandards.html#include-style</a><br />
<br />
Google C++ Style Guide<br />
<a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml">http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml</a><br />
<br />
<br />
Google同時還有制定Python Coding Style Guide<br />
Google Python Style Guide<br />
<a href="http://google-styleguide.googlecode.com/svn/trunk/pyguide.html">http://google-styleguide.googlecode.com/svn/trunk/pyguide.html</a><br />
<br />
Python Code Style<br />
<a href="http://docs.python-guide.org/en/latest/writing/style/">http://docs.python-guide.org/en/latest/writing/style/</a><br />
<br />
PEP 8 -- Style Guide for Python Code<br />
<a href="http://www.python.org/dev/peps/pep-0008/">http://www.python.org/dev/peps/pep-0008/</a>Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-57031430346323964942013-01-20T15:49:00.001+08:002013-01-20T15:49:34.580+08:00Peopleware:腦力密集產業的人才管理之道 (Peopleware: Productive Projects and Teams, 2/e)<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Gfvb6zm46H_e76NGwMX47NJPp1QfzWsFcV3jdu3cAONzyzjsdcm8Amw33RfZcADr9GSFXDDW5XFwzqFbYCTuLbTeSqrw3kvIFwh0S8-10jn8oaPTXZHHTr9HAfDUw44P1bb2NhHbyak/s1600/9789867889645.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Gfvb6zm46H_e76NGwMX47NJPp1QfzWsFcV3jdu3cAONzyzjsdcm8Amw33RfZcADr9GSFXDDW5XFwzqFbYCTuLbTeSqrw3kvIFwh0S8-10jn8oaPTXZHHTr9HAfDUw44P1bb2NhHbyak/s320/9789867889645.jpg" width="228" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
就如同封面所寫,這是一本軟體專案管理的聖經本,和<a href="http://swaywang.blogspot.tw/2011/12/blog-post.html">人月神話</a>齊名。雖然這是一本26年前出版的書籍,但是書中觀念現在同樣還是適用。甚至現在還有許多軟體公司使用書中所寫得錯誤方法來管理員工。</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
書中一開始就講到,軟體業和一般製造業完全不同。軟體業比較像是藝術創作。老闆如果把員工當成可替換的零件,那這家公司註定是要失敗的。Peopleware提到幾個成功的關鍵,例如管理底下的軟體工程師的方式會決定這家公司會成功還是失敗。書中提了許多實際案例以及有趣的實驗,一一破解傳統主管的迷思。舉例來說,書中提到強迫員工加班的成效並沒有一般人想的這麼大,長久下來反而會造成員工效率低落。書中也提到環境對員工的影響,優秀的程式設計師大多數都來自於安靜不易受干擾的工作環境,但是老闆往往為了省小錢而造成工程師效率低落。</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
我最喜歡書中做的一個實驗,作者把不同公司的工程師們安排在自己的工作環境進行程式競賽。結果發現最優秀的工程師和最差的工程師效率可以差到10倍。同時最優秀的那群工程師們大多數擁有良好的工作環境。</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Peopleware這本書不只適合給主管閱讀,也很推薦一般工程師去閱讀這本書。書中提到許多改善工作效率的方法。讀者可一一檢視,改善自己的工作效率。</div>
Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com0tag:blogger.com,1999:blog-5711151795160293358.post-57022762580275929672013-01-10T19:30:00.000+08:002013-01-10T19:31:34.113+08:00[C]函式指標陣列用法(Array of Function Pointers)在寫程式時候,我們常常會碰到根據不同狀態去執行不同函式的情況。比如說下列範例,根據state變數的狀態去呼叫對應的函式。<br><br>
state: 0,執行run()<br>
state: 1,執行stop()<br>
state: 2,執行exit()<br><br>
<pre class="c" name="code">
void run() {
printf("start\r\n");
}
void stop() {
printf("stop\r\n");
}
void exit() {
printf("exit\r\n");
}
</pre>
<pre class="c" name="code">
bool OnStateChange(uint state) {
if (state == 0) {
run();
}
else if (state == 1) {
stop();
}
else if (state == 2) {
exit();
}
else {
printf("Wrong state!\n");
return false;
}
return true;
}
</pre>
用if判斷式是最簡單的方法。不過如果state變多。整段code就會變得很冗長。<br>
<pre class="c" name="code">
int OnStateChange(uint state) {
switch (state) {
case 0:
run();
break;
case 1:
stop();
break;
case 2:
exit();
break;
default:
printf("Wrong state!\n");
return false;
}
return 0;
}
</pre>
改用switch看起來有比較乾淨一點。不過state變多,程式碼也會變得冗長。有沒有什麼更精簡的作法呢?這時候函式指標陣列就派上用場了。<br>
<pre class="c" name="code">
static void (*command[])(void) = {run, stop, exit};
int OnStateChange(uint state) {
if (state > 3) {
printf("Wrong state!\n");
return false;
}
command[state]();
return 0;
}
</pre>
這種寫法比前兩個例子都來的精簡。函式指標陣列宣告的第一個void表示函式的回傳值,第二個void表示函式的參數。所以這是一個帶有三個函式指標的陣列,陣列中函式的回傳值以及參數都是void。Sway Wanghttp://www.blogger.com/profile/02092125692002667124noreply@blogger.com2