2014-10-23

[讀書筆記] The art of Unit Testing - ch2 - A first unit test

[讀書筆記] A first unit test

2.1 Frameworks for unit testing

Doing things completely manually would be error-prone and time-consuming, and people would defer doing that as much as possible.

手動出錯的機會很大 又浪費時間
所以請讓Unit-testing framework來協助你寫測試吧

2.1.1 What unit-testing frameworks offer

所以unit-testing framework到底你提供你什麼服務呢?
先想想目前手寫的測試(沒用framework)有怎樣的缺點
  • They were not structured. (

每次測試你可能都是用不同介面來測試 ex. Webform, Winform or WinConsole)

  • They were not repeatable. (無法執行過去的測試)
  • They were not on all your code. (沒有測到所有的code 如果寫UT是很方便的 RD才會盡可能地多寫UT 增加Coverage)
Unit-testing Framework能幫助你解決上述問題

Framework的介入是獨立的 你能在你的TestProject寫完Test Case 再透過統一的介面去執行測試
以下列出了Framework導入後對RD的協助:
1. Write tests easily and in a structured manner.
    Framework都已經定義好結構跟使用方法
    所以寫UT時 只要繼承或是follow API 就能寫出UT
    非常方便且結構化
2. Execute one or all of the unit tests.
    透過GUI或是command 執行所有的tests
    重點是能夠自動化
3. Review the results of the test runs.
    跑完test之後的Report 能夠一目瞭然問題出在哪裡?

2.1.2 The xUnit frameworks

C++ : CppUnit / (GoogleTest)
JAVA : JUnit
.NET : NUnit

2.3 First steps with NUnit

2.3.1 Installing Nunit

先去Nunit官網下載最新的Nunit並安裝
http://www.nunit.org


2.3.2 Loading up the solution

打開NUnit GUI 之後 選擇Open Project 就能將你寫的Test Project 載入 
注意!! 這裡載的是Test Project 不是ProductionCode Project



接下來就能開始執行NUnit了

2.3.3 Nunit attributes

寫UT之前 先來了解NUnit 有哪些attribute可以用
Naming
在寫UT時 最好也follow建議的naming style (潛規則)
Project : 
Create a test project named [ProjectUnderTest].Tests. 

Class : 
For each class, create at least one class with the name [ClassName]Tests.

Method : 
For each method, create at least one test method with the following name: 
[MethodName]_[StateUnderTest]_[ExpectedBehavior]

MethodName : The name of the method you’re testing
StateUnderTest : The conditions used to produce the expected behavior (這個method要執行的動作)

ExpectedBehavior : What you expect the tested method to do under the specified conditions (預期的測試Return Value)

For example:
有個Method叫做 IsValidLogFileName, 這個method的目的是要驗證filename是否合法, 接下來我們要寫一個UT去測這個method, 預期結果為True

所以UT的method name 應該為 :
IsValidFileName_validFile_ReturnsTrue


2.4 Writing our first test

1. Add Reference
    要在Test Project 使用到NUnit必須先using NUnit.Framework
    注意!! 不是加在Production Code    

2. [TestFixture]
    請在每個Test Class上方加上[TestFixture]
    
3. [Test]
    請在每個Test Method上方加上[Test]
    注意!! NUnit的test method都必須為 void 且不帶任何parameters
     ex. public void IsValidFileName_validFile_ReturnsTrue(){...}

4. Arrange, Act, and Assert
    每個Test Method內都需要包含這三個內容:    
  •     Arrange objects, creating and setting them up as necessary.   
  •     Act on an object.  
  •     Assert that something is as expected.
For example:

Create出一些資源 設一些設定
呼叫Production code中待測的這支method
透過Assert 比對結果是否符合自己預期

Assert有很多條件跟API能呼叫
請到官網Document查詢
目前我採用的是NUnit 2.6.3版 
http://www.nunit.org/index.php?p=assertions&r=2.6.3

以下就先列AreEqual跟AreSame的不同點
Assert.AreEqual
這個是值比對
Assert.AreSame
這個是Reference比對

Writing UT Process




2.5 More Nunit attributes

2.5.1 SetUp and TearDown

For unit tests, it’s important that any leftover data or instances from previous tests are destroyed and that the state for the new test is recreated as if no tests have been run before.

一個很重要的原則:
每個測試都像是新的一樣 不要殘留之前的data

所以我們需要SetUp跟TearDown的觀念

[SetUp]

This attribute can be put on a method, just like a [Test] attribute, and it causes NUnit to run that setup method each time it runs any of the tests in your class.



每次執行[Test]之前 就會執行[SetUp]
你可以把[SetUp]想成Constructors

[TearDown]
This attribute denotes a method to be executed once after each test in your class has executed.

每次執行[Test]完之後 就會執行[TearDown]
你可以把[SetUp]想成Destructors

[SetUp]跟[TearDown]是每次執行[Test]都會執行的
那有沒有類似的概念是 for Class [TestFixture]的?

[TestFixtureSetUp]
執行[TestFixtureSetUp] Before all [Test]

[TestFixtureTearDown]
執行[TestFixtureTearDown] After all [Test]

[TestFixtureSetUp]或[TestFixtureTearDown]的用途是當資源setting up 或 cleaning up花太久時 只想執行一次時使用

如下圖:

2.5.2 Checking for expected exceptions

  • The expected exception message is provided as a parameter to the [ExpectedException] attribute.
  • There’s no Assert call in the test itself. The [ExpectedException] attribute contains the assert within it.
  • There’s no point getting the value of the Boolean result from the method because the method call is supposed to trigger an exception.

有時候我們會預期什麼情況下會丟出Exception
此時就能用[ExpectedException]來測試是否有丟出相關Exception

預期要測Exception 就不用Assert (其實已經含在[ExpectedException]中)

For example:

2.5.3 Ignore tests

Sometimes you’ll have tests that are broken and you still need to check in your code to the main source tree.

有時候你不想要Fail的Test中斷你的其他test 可以善用[Ignore]
設定[Ignore]之後 Test就能忽略掉這個TestMethod
在NUnit GUI 看到的顏色就會變成黃色

For example:


如果Ignore內寫了"內容" 
[Ignore("XXX")]
就會在GUI中的Test Property中顯示Reason="XXX"

2.5.4 Setting test categories

我們也能夠透過[Category("A")]將Test分組
如此可透過NUnit測試特定Category

For example:

2.6 Indirect testing of state

State-based testing
State-based testing (also called state verification) determines whether the exercised method worked correctly by examining the state of the system under test and its collaborators (dependencies) after the method is exercised.

有時候狀態的測試不是直接的
如同下列情況

有個Class Calculator 他有
兩個Method :
public void Add(int number);
public int Sum();
一個Property:
private int sum=0;

每次呼叫Add 累加完之後的值會存在sum中

Add return void 這樣我們該如何驗證Add呢?
Solution:
要切兩個Test Case
1. Default Sum應該要為0
2. 呼叫Add之後 Sum應該要正確

注意!! Add_CalledOnce_SavesNumberForSum()
因為這個測試主要還是測試Add的邏輯
所以最好還是以Add來命名

如下圖:

2.7 Summary

作者希望大家記住下面四點:

  • It’s common practice to have one test class per tested class, one test project per tested project, and at least one test method per tested method.
  • Name your tests clearly using the following model: [MethodUnderTest]_[Scenario]_[ExpectedBehavior].
  • Use the [SetUp] and [TearDown] attributes to reuse code in your tests, such as code for creating and initializing objects all your tests use.
  • Don’t use [SetUp] and [TearDown] to initialize or destroy objects that aren’t shared throughout the test class in all the tests, because it makes the tests less understandable. Someone reading your code won’t know which tests use the logic inside the setup method and which don’t.

一個Project就對應一個TestProject
一個Class就對應一個TestClass
一個Method至少要對應一個TestMethod

Follow [MethodUnderTest]_[Scenario]_[ExpectedBehavior] 規則

善用[SetUp]及[TearDown]對資源操作
相反地也不要在這兩處放置非所有Test用到的資源

2014-10-22

[讀書筆記] The art of Unit Testing - ch1 - The basics of unit testing

[讀書筆記] The basics of unit testing

1.1 Unit Testing - the classic definition

What is the classic definition?
A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward.
If the assumptions turn out to be wrong, the unit test has failed. 
A "unit" is a method or function.

傳統的Unit Test就是寫另外的code去check你的production code是否正確
一個Unit就是以一個method或function為單位

傳統上大部份公司的現況:
1. Rely on System and Integration Test
    倚靠Integration Test來測
2. Manually testing
    手測
3. Test by using the end product
    利用UI來測

其實我們或多或少都一定寫過測試
如下圖:

我們可能會寫個WinForm或是WebForm透過UI呼叫我們寫的code來驗證正確性

實際上這樣的測試離Good Unit Test 還有一大段距離


1.2 Properties of a good unit test

所以到底Good Unit Test有什麼樣的特性呢?

  • It should be automated and repeatable.
  • It should be easy to implement.
  • Once it’s written, it should remain for future use.
  • Anyone should be able to run it.
  • It should run at the push of a button.
  • It should run quickly.
  • 要能夠自動化
  • 要容易實作
  • 一旦寫好未來都能使用
  • 每個人都能執行它
  • 按個button就能執行
  • 要能夠快速地執行


各位可以問問自己以下的問題:

  • Can I run and get results from a unit test I wrote two weeks or months or years ago?
  • Can any member of my team run and get the results from unit tests I wrote two months ago?
  • Can I run all the unit tests I’ve written in no more than a few minutes?
  • Can I run all the unit tests I’ve written at the push of a button?
  • Can I write a basic unit test in no more than a few minutes?


問問自己 如果有任何一題的答案是no
那麼你寫的test 可能就不屬於Unit Test


1.3 Integration tests

What is the Integration Test?

Integration testing means testing two or more dependent software modules as a group.

Integration test 就是把兩個以上的modules組合起來一起測試

If the test fails, all the parts fail together; if it succeeds, the parts all succeed.

所以Integration Test 面臨的問題是
If the test fails, all of these software components fail as a team, and it can be difficult to figure out what caused the failure of the overall operation.

因為要死就一起死 很難抓出root cause
如下圖:



Integration Test的問題就在於有很多的Failure points你必須一一排除

1.3.1 Drawbacks of integration tests compared to automated unit tests

讓我們回想剛剛自問的問題:
Can I run and get results from a unit test I wrote two weeks or months or years ago?
A: code change是相當常見的 在改完code之後 是否知道有side effect? 所以需要Unit Testing !!!

作者將此稱為 "accidental bugging"

Regression
A regression is a feature that used to work and now doesn’t.
過去可以work 現在不行

Good tests should be easily executed in their original form, not manually.

Can any member of my team run and get the results from unit tests I wrote two months ago?
A:如同第一題 只是這是改別人的code
    大部分人都會擔心Legacy code
    因為會怕改Legacy code又造成side effect

Legacy code
Legacy code is defined by Wikipedia as “source code that relates to a no-longer supported or manufactured operating system or other computer technology,” but many shops refer to any older version of the application currently under maintenance as legacy code. It often refers to code that’s hard to work with, hard to test, and usually even hard to read.

Good tests can be accessed and run by anyone.

Can I run all the unit tests I’ve written in no more than a few minutes?
A:如果test需要很久 那麼你也就不會很常去測試了
    這邊講的是 便利性

Good tests should run quickly.

Can I run all the unit tests I’ve written at the push of a button?
A:如果不行 那代表你必須經過重重難關才能測試(ex.設定 or 雜事) 如果不方便 那麼你也不想去測試了
    這邊講的是 便利性

Good tests should be easily executed in their original form, not manually.


Can I write a basic unit test in no more than a few minutes?
A:測試的scope越大 牽扯的module越多 測試就越難寫
    如果測試越難寫 那麼你也不想去測試了
    這邊講的是 便利性

其實這段也偷偷暗示我們應該要使用Unit-Testing Framework來寫測試才會方便

Good tests against the system should be easy and quick to write.


1.4 Good Unit Test

引言至此 作者終於要帶出他心目中 Good Unit Test的定義了

  • A unit test is an automated piece of code that invokes the method or class being tested and then checks some assumptions about the logical behavior of that method or class.
  • A unit test is almost always written using a unit-testing framework.
  • It can be written easily and runs quickly.
  • It’s fully automated, trustworthy, readable, and maintainable.
好的Unit Testing就是 使用unit-testing framework 自動化地去測logical behavior
必須很方便的實作測試 執行測試也必須很快看到結果

Logical code
Logical code is any piece of code that has some sort of logic in it, small as it may be.

It’s logical code if it has one or more of the following: an IF statement, a loopswitch or case statements, calculations, or any other type of decision-making code.

只有logical code需要測試

反例:
像Java的 get/set 如果沒有內含邏輯的話 其實不用測它


1.5 A simple unit test example

這個章節 作者寫了一個測試範例 但他並沒有使用Unit-testing framework
我們可以看看就算沒有Unit-testing framework 測試的邏輯還是一樣 但是就是麻煩了些 所以有framework的協助 會讓各位更方便地寫Unit Test 才會讓大家有動力去寫


1.6 Test-driven development

大部分的人是在實作完production code之後才開始寫測試
但作者相當推薦先寫測試再寫code
這種方式就稱之為TDD 

傳統的coding process如下圖:
TDD的coding process如下圖:
TDD的流程如下:

1 Write a failing test to prove code or functionality is missing from the end product.
    先寫測試 所以沒有production code的結果就是FAIL

2 Make the test pass by writing production code that meets the expectations of your test.
    接下來我們應該要想辦法讓Test PASS

3 Refactor your code.
    經過幾個Test Pass之後 或許開始發現可以refactor一些code
    此時就能放心地refactoring

Refactoring
Refactoring means changing a piece of code without changing its functionality.
If you’ve ever renamed a method, you’ve done refactoring.
If you’ve ever split a large method into multiple smaller method calls, you’ve refactored your code.
The code still does the same thing, but it becomes easier to maintain, read, debug, and change.

這邊其實帶出一個Unit-testing的優勢就在於我們能夠放心地refactoring 因為改壞馬上就被Unit Test抓出來


1.7 Summary

作者不斷的想強調 什麼是Good Unit Test
因為很重要 所以要一直重複提
What is a good unit testing?
  • It’s an automated piece of code that invokes a different method and then checks some assumptions on the logical behavior of that method or class.
  • It’s written using a unit-testing framework.
  • It can be written easily.
  • It runs quickly.
  • It can be executed repeatedly by anyone on the development team.

2014-05-13

[徵合購] Mountain Buggy Nano in maxis-babywelt

大家好 我又來徵合購啦
上次的網站請大家把他忘記 我換另一家購物網站了
maxis-babywelt
http://www.maxis-babywelt.de/index.php?language=gb

為什麼呢? 因為我要的推車這邊還有貨
以下是我要的推車
Mountain Buggy Nano
http://mountainbuggy.com/us/Products/buggies/nano#.U3Hi1PmSySo

你可以把他想成最近很夯的Babyzen YoYo 稍微放大版
但是價格便宜很多 我覺得他很有潛力變成下一個YoYo
目前台灣還沒有人代理 美國也呈現缺貨的狀態

目前我跟這個網站的客服談來談去 終於確定了規格
2個座椅+1台推車 或是 1個座椅+2台推車 再加其他小東西
只要在30KG內 運費都是79.99歐元

我自己會買1個汽座+1台推車
所以有興趣的人合購這台車或是汽座 或是這網站上的其他東西
請聯絡我一下 我們可以再談怎麼share運費
謝謝各位囉

別人的推薦
http://ayz75.pixnet.net/blog/post/40556437-%E7%91%AA%E8%B1%86%E7%9A%84%E6%96%B0%E6%8E%A8%E8%BB%8A---mountain-buggy-nano

Mountain Buggy Nano vs Babyzen YoYo
http://www.bestbuggy.co.uk/2014/03/mountain-buggy-nano-vs-babyzen-yoyo/

Youtube 上的介紹影片
https://www.youtube.com/watch?v=mbvxHoyj13Q

2014-05-08

[讀書筆記] The Practice of Programming - Notation

Notation
SlideShare上的投影片分享



其實這個章節我只有抓到幾個重點

1. 如果你寫很多code去執行一個平庸的工作或是在處理流程上遇到麻煩
    或許你是用錯語言

2. 如果一個適合的語言尚未存在 這就是個機會寫出一個適合的語言

3. Sample : Transit different format data

    假設有兩種不同格式的data
    (1)
 
    (2)

    如果你是針對這兩種格式做pack 與 unpack的處理
    function 大概會長下面這樣
   

    有沒有發現每個type 必須handle parse的邏輯
    所以作者想了一個方法 自訂一種格式format string
    
    c : char
    s : short
    l : long

    如此就能將重複的邏輯抽出 並利用此格式來處理不同type的資料

    
    
    外層是呼叫pack 並給入相對應的format
    外層靠著 "cscl" 告知pack 這次傳入的格式

4. 對於Micros
    作者雖然不推薦使用 但他仍認為Micro有適合的地方 : 
    (1) Micro 適合用在定義文字
    (2) Be practical and be easy to produce.
    (3) Portable

5. 很多問題或許換個方式描述 就能輕易地解決 這就是Notation的魔力

2014-05-07

2014-04-25

2014-04-24

[讀書筆記] The Practice of Programming - Portability

Portability 
SlideShare上的投影片分享



Why do we worry about portability? 
1. Less maintenance and more utility

2. Environments change
    環境會變 OS會升級

3. A portable program is a better designed program
    同意 一個可移植性的程式 本身抽象化的程度也比較高 設計上會比較好

程式語言
1. 照著標準走 

2. 照著主流走

3. 注意各data type的size 但彼此的 size關係不脫離下列
    sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long)
    sizeof (float) <= sizeof (double)

4. 賦值的順序不一定一樣 n = (getchar() <<8) | getchar()
    左邊的getchar()不一定先叫用

5. 注意char的 sign or unsign

6. 注意Struct的size, 計算大小請直接用Struct來計算, 不要用變數相加的方式
    Yes => sizeof (struct X)
    No  => sizeof (char) + sizeof(int)

7. Try several compilers
    既然考慮移植性 就在不同的compiler間 compile看看吧

Headers and Libraries
1. 使用標準lib

2. Header若太肥太亂 請把共同的程式碼抽出來 針對不同環境 把不同的Header集中
   換句話說 共同的程式碼應該在不同環境下都能使用 但是針對不同環境的Header Files 請將它們抽出放到各自的環境上 

3. 如果你取的變數名稱跟標準lib Header定義的一樣 你的名稱會被header汙 染 但是不要跟標準抗爭 請使用別的名字繞過去 

Program Organization
有兩種方法能達到移植性
1. Union
    利用條件式編譯 把所有環境的可能性放在一起
2. Intersection
    抽出共同的部分 根據不同環境塞不同header 作者相當討厭條件式編譯 認為這造成maintain上的困難 

如何避免條件式編譯 看看是否真的有其必要 

Isolation
1. 老話重彈 針對不同環境客製化不同的files
2. Hide system dependencies behind interfaces 盡量抽象化 例如 The I/O Libraries : 我們只會知道Read Write等 最底層最依賴OS的實作放在各語言中
3. 盡量使用Standard Language Library 而不是WINAPI

Data Exchange
作者贊成直接用String做資料交換

Byte Order
有時無可避免使用Binary Data
事實上Binary Data 也比較快比較小 但要注意 little-endian 跟 big-endian的問題
重點是 Sender跟Receiver要講好格式

Portability and Upgrade
1. Change the name if you change the specification 
   若改規格就改名字吧 Name要名副其實
2. Maintain compatibility with existing programs and data 
   要跟舊版保有相容性 就像Java每一版都還會留著舊版API 但在JDK中會註明不建議使用

Internationalization
1. 不要假設ASCII
    用Unicode吧 再用UTF-8轉 c/c++ 就用Wide characters吧
2. 不要假設English
    可以像趨勢的作法 將wording跟UI都抽出 到時方便替換

2014-03-26

[CaseStudy][WinDbg] Hang

[Scenario]
User 發生了Hang Issue 

[開始查案]
根據收到的Dump 通常會發生Hang 應該是resource被佔住 或是deadlock之類的
所以第一步

!locks
0: kd> !locks
**** DUMP OF ALL RESOURCE OBJECTS ****
KD: Scanning for held locks...

Resource @ Ntfs!NtfsData (0x88b01474)    Exclusively owned
     Threads: 84acd020-01<*> 
KD: Scanning for held locks..

Resource @ 0x851d756c    Exclusively owned
    Contention Count = 41
    NumberOfSharedWaiters = 29
     Threads: 84e79d48-02<*> 85c98790-01    863ec940-01    86557030-01    
              84bc9d48-01    8603aa60-01    84e7b8f0-01    861073b8-01    
              8639f5b0-01    84e42648-01    84acd020-01    84c1da58-01    
              84cf3d48-01    84c48030-01    84c54a88-01    84e3f078-01    
              8602ec58-01    86203d48-01    85ecd660-01    86202640-01    
              8620f310-01    862bc030-01    862a9d48-01    84e79410-01    
              86434c78-01    86a5fa60-01    863f82b8-01    8645d998-01    
              8605f030-01    86a46a08-01    
KD: Scanning for held locks..............................................................

Resource @ 0x85d8ae68    Exclusively owned
    Contention Count = 2
     Threads: 8605f030-01<*> 
KD: Scanning for held locks.

Resource @ 0x85d88840    Exclusively owned
    Contention Count = 1
    NumberOfExclusiveWaiters = 1
     Threads: 8605f030-01<*> 
     Threads Waiting On Exclusive Access:
              860d88d8       

KD: Scanning for held locks...................................................................................................................................................................................................................................

Resource @ 0x84d8ff34    Shared 1 owning threads
    Contention Count = 2
    NumberOfExclusiveWaiters = 1
     Threads: 84acd420-01<*> 
     Threads Waiting On Exclusive Access:
              84e79d48       

KD: Scanning for held locks..............................
10293 total locks, 5 locks currently held

Threads: 84e79d48-02<*> 打*代表 這條Thread 佔了這個resource
從上面資訊來看
最下面的Resource
Resource @ 0x84d8ff34    Shared 1 owning threads
卡住了Thread 84e79d48

而Thread 84e79d48 的Resource
Resource @ 0x851d756c    Exclusively owned
卡住了Thread 8605f030
Resource @ 0x85d88840    Exclusively owned
Resource @ 0x85d8ae68    Exclusively owned

所以才造成System Hang

讓我們來看看罪魁禍首 Thread 84e79d48到底在幹嘛


0: kd> !thread 84acd420
THREAD 84acd420  Cid 0004.001c  Teb: 00000000 Win32Thread: 00000000 WAIT: (WrQueue) UserMode Non-Alertable
    82948600  QueueObject
Not impersonating
DeviceMap                 89a088d8
Owning Process            84a41a20       Image:         System
Attached Process          N/A            Image:         N/A
Wait Start TickCount      23593          Ticks: 1024 (0:00:00:15.974)
Context Switch Count      1966           IdealProcessor: 0             
UserTime                  00:00:00.000
KernelTime                00:00:00.483
Win32 Start Address nt!ExpWorkerThread (0x8288999e)
Stack Init 8ad0bfd0 Current 8ad0bc10 Base 8ad0c000 Limit 8ad09000 Call 0
Priority 14 BasePriority 13 UnusualBoost 1 ForegroundBoost 0 IoPriority 2 PagePriority 5
ChildEBP RetAddr  Args to Child              
8ad0bc28 8288a69d 84acd420 8293af08 82937d20 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8ad0bc60 828894f7 84acd4e0 84acd420 82948600 nt!KiSwapThread+0x266
8ad0bc88 8288a1ed 84acd420 84acd4e0 00000000 nt!KiCommitThreadWait+0x1df
8ad0bcec 82889a83 82948600 00000001 00000000 nt!KeRemoveQueueEx+0x4f8
8ad0bd50 82a15f5e 00000000 a9364519 00000000 nt!ExpWorkerThread+0xe5
8ad0bd90 828bd219 8288999e 00000000 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19
結果看來很正常 看不出什麼東西
這時候來看看Resource吧

對Resource @ 0x84d8ff34位置下dt
dt 0x84d8ff34 _eresource
Why _eresource 我想應該是ntdll的變數吧
總之 我們看第7個變數
 +0x018 OwnerEntry       : _OWNER_ENTRY
所以一樣對它下dt
dt 0x84d8ff34 _eresource OwnerEntry.
要記得打"." 才能看更多資訊

//
// Checking of resource of 0x84d8ff34.
//
0: kd> dt 0x84d8ff34 _eresource
ntdll!_ERESOURCE
   +0x000 SystemResourcesList : _LIST_ENTRY [ 0x84d8f884 - 0x84d8fed4 ]
   +0x008 OwnerTable       : 0x84d8e158 _OWNER_ENTRY
   +0x00c ActiveCount      : 0n1
   +0x00e Flag             : 4
   +0x010 SharedWaiters    : (null) 
   +0x014 ExclusiveWaiters : 0x84d8f838 _KEVENT
   +0x018 OwnerEntry       : _OWNER_ENTRY
   +0x020 ActiveEntries    : 1
   +0x024 ContentionCount  : 2
   +0x028 NumberOfSharedWaiters : 0
   +0x02c NumberOfExclusiveWaiters : 1
   +0x030 Address          : (null) 
   +0x030 CreatorBackTraceIndex : 0
   +0x034 SpinLock         : 0
//
// no thread exclusively owns this resource.
//
0: kd> dt 0x84d8ff34 _eresource OwnerEntry.
ntdll!_ERESOURCE
   +0x018 OwnerEntry  : 
      +0x000 OwnerThread : 0
      +0x004 IoPriorityBoosted : 0y0
      +0x004 OwnerReferenced : 0y0
      +0x004 OwnerCount  : 0y000000000000000000000000000000 (0)
      +0x004 TableSize   : 0

沒東西
來看看OwnerTable吧

dt 0x84d8e158 _OWNER_ENTRY
看到TableSize = 7 所以後面可能有7個Entry
我們可以先用 ?? sizeof(_OWNER_ENTRY) 看OWNER_ENTRY的size

unsigned int 8

所以我們知道下一個Entry 就要再+8

dt 0x84d8e160 _OWNER_ENTRY



0: kd> dt 0x84d8e158 _OWNER_ENTRY
ntdll!_OWNER_ENTRY
   +0x000 OwnerThread      : 0
   +0x004 IoPriorityBoosted : 0y1
   +0x004 OwnerReferenced  : 0y1
   +0x004 OwnerCount       : 0y000000000000000000000000000001 (0x1)
   +0x004 TableSize        : 7
0: kd> dt 0x84d8e160 _OWNER_ENTRY
ntdll!_OWNER_ENTRY
   +0x000 OwnerThread      : 0x84acd420  ---> thread of 0x84acd420 shared owns this resource 
   +0x004 IoPriorityBoosted : 0y0
   +0x004 OwnerReferenced  : 0y0
   +0x004 OwnerCount       : 0y000000000000000000000000000001 (0x1)
   +0x004 TableSize        : 4
從第二個Entry看到了 OwnerThread 0x84acd420
結果還是這條System Thread呀

所以案子到這邊查不下去了
我們僅知道System Thread這個Resource沒有釋放
所以Lock住 其他需要Exclusively owned的Resource 也造成了Hang

2014-03-22

[CaseStudy][WinDbg] Crash - Break instruction exception

[Scenario]
User 從Agent打開log 立即發生了Crash

[開始查案]
根據收到的Dump


0:000> !analyze -v

FAULTING_IP: 

+ff79600

00000000`00000000 ??              ???

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)

ExceptionAddress: 0000000000000000

   ExceptionCode: 80000003 (Break instruction exception)

  ExceptionFlags: 00000000

NumberParameters: 0

STACK_TEXT:  

00000000`0011f9f8 000007fe`fd8b1430 : 00000000`01e975d0 00000000`7752300a 00000000`01e975d0 00000000`01e9d868 : ntdll!NtWaitForMultipleObjects+0xa

00000000`0011fa00 00000000`77511220 : 00000000`0011fb40 00000000`0011fb30 00000000`00000000 00000000`00000000 : KERNELBASE!WaitForMultipleObjectsEx+0xe8

00000000`0011fb00 00000001`40034e09 : 00000000`00000000 7fffffff`fffffffe 00000001`4012d390 00000000`00000000 : kernel32!WaitForMultipleObjects+0xb0

00000000`0011fb90 00000001`4002afc7 : 00000001`40137fc0 00000000`00000000 00000000`00000000 00000000`001c3a00 : XXX!CWindowManagerClient::Run+0xe9

...(Ignore)
只知道原因是Break instruction exception 但是從這個Stack看起來卻沒有幫助 因為這條Stack就是顯示主程式起來之後在等結束


正常我們會從FOLLOWUP_IP來看 預計下一步會執行的點
FOLLOWUP_IP: 

XXX!CWindowManagerClient::Run+e9 
00000001`40034e09 3d81000000      cmp     eax,81h

0:000> uf 00000001`40034e09
XXX!CWindowManagerClient::Run+0xd1 [XXX\windowmanagerclient.cpp @ 168]:
  168 00000001`40034df1 41b901000000    mov     r9d,1
  168 00000001`40034df7 4533c0          xor     r8d,r8d
  168 00000001`40034dfa 488d542468      lea     rdx,[rsp+68h]
  168 00000001`40034dff 418d4901        lea     ecx,[r9+1]
  168 00000001`40034e03 ff1537080a00    call    qword ptr [XXX!_imp_WaitForMultipleObjects (00000001`400d5640)]
  169 00000001`40034e09 3d81000000      cmp     eax,81h
  169 00000001`40034e0e 7775            ja      XXX!CWindowManagerClient::Run+0x165 (00000001`40034e85)


可以看出就是在00000001`40034e03 Call _imp_WaitForMultipleObjects時出了問題

但是這樣還是看不出什麼端倪

所以先列出所有的thread 看是否有異狀
0:000> ~*knb
...(Ignore)
...
22  Id: 6b98.1eb0 Suspend: 0 Teb: 000007ff`fff7c000 Unfrozen
 # Child-SP          RetAddr           Call Site
00 00000000`09cb89c8 000007fe`fd8b1430 ntdll!NtWaitForMultipleObjects+0xa
01 00000000`09cb89d0 00000000`77522ce3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
02 00000000`09cb8ad0 00000000`77599105 kernel32!WaitForMultipleObjectsExImplementation+0xb3
03 00000000`09cb8b60 00000000`77599287 kernel32!WerpReportFaultInternal+0x215
04 00000000`09cb8c00 00000000`775992df kernel32!WerpReportFault+0x77
05 00000000`09cb8c30 00000000`775994fc kernel32!BasepReportFault+0x1f
06 00000000`09cb8c60 00000000`60201ad5 kernel32!UnhandledExceptionFilter+0x1fc
07 00000000`09cb8d40 00000000`60203547 XXX!_invalid_parameter+0xc5 [f:\sp\vctools\crt_bld\self_64_amd64\crt\src\invarg.c @ 88]
08 00000000`09cb9300 00000000`6006758b XXX!wcscpy_s+0x97 [f:\sp\vctools\crt_bld\self_64_amd64\crt\src\tcscpy_s.inl @ 30]
09 00000000`09cb9340 00000000`600502d7 XXX!CLogQueryEntry::FillDlpData+0x11bb [XXX\logcl_logquery.cpp @ 3211]
0a 00000000`09cb9510 00000000`60049349 XXX!CLogQueryEntry::OnLogviewVirus+0x17f7 [XXX\logcl_logquery.cpp @ 900]

結果在第22條thread 發現了UnhandledException
很明顯
在做wcscpy_s 時 參數錯誤
來看看定義
errno_t wcscpy_s(
   wchar_t *strDestination,
   size_t numberOfElements,
   const wchar_t *strSource 
);



這題的答案是
wcscpy_s 時的Src size 比Des大 所以造成Crash

2014-03-17

Compile Error when we build the GoogleTest in VS2012

我嘗試要在VS2012上試試Unit Test

Step 1 :
去googletest 網站download googletest project
https://code.google.com/p/googletest/

目前版號是gtest-1.7.0

Step 2:
解壓縮zip

Step 3 :
用VS2012 開啟專案
.\gtest-1.7.0\msvc\

Step 4 :
Rebuild projects

根據Primer上的說明 欲先玩googletest 必先compile之
To write a test program using Google Test, you need to compile Google Test into a library and link your test with it. 

但是正常情況下會compile error
錯誤原因為 :
Error 5 error C2977: 'std::tuple' : too many template arguments d:\coding\gtest-1.7.0\include\gtest\gtest-printers.h

[Root Cause]
http://stackoverflow.com/questions/12558327/google-test-in-visual-studio-2012
VC++ 2012 does not (and will never) support variadic templates; consequently, its standard library implementation attempts to fake them using preprocessor-generated overloads and specializations. As this blog post notes, the number of faux variadic template parameters defaults to 5 – the problem is that gtest is trying to instantiate std::tuple<> with as many as 10 template arguments.
As the blog post goes on to mention, you can define the _VARIADIC_MAX macro project-wide to support up through 10 parameters; you'll probably want to do this by way of your project's preprocessor definitions setting.

[Solution]
打開4個Project的Property
properties -> C\C++ Preprocessor -> Processor Definitions -> <edit...>

Add "_VARIADIC_MAX=10"
Save and Rebuild all projects





2014-03-07

2014-02-14

[讀書筆記] Clean Code Part 1 (Ch1 to Ch3)

Chapter 1 : Clean Code

(1) 童子軍規則 - 讓營地比你來時更乾淨!!
     儘管Legacy code很多 但每一次比每一次乾淨也是件好事

Chapter 2 : Meaningful Names

(1) 名副其實
       Bad : int d;
       Good : int elapsedTimeInDays;

(2) 避免誤導
       如果你的變數型態不是List
       Bad : accountList
       Good : accountGroup or accounts

(3) 做有意義的區分
       不使用意義含混的廢話(Info, Data, a, an, the)
       ex. ProfuctInfo, aProduct

(4) 避免把類型或者變數範圍編碼進名稱    
      如果未來類別改變 還要記得改變數會很麻煩
      如果變數未改 又會造成誤導
      ex. 原本宣告 PhoneString phoneString
           後來改類別 PhoneNumber phoneString
           phoneString這變數名稱會誤導下一個開發者

(5) Interface
      不對介面類別名稱作編碼
        IShapreFactory
      寧可針對實作類別名稱作編碼
        ShapreFactory
ShapreFactoryImp

(6) Class
      類別名稱應該是名詞或名詞短語

(7) Function or Method
      函式名稱應該是動詞或動詞短語

Chapter 3 : Functions

(1) Small & Do one thing
       函數應該做一件事情,做好這件事情,只做這一件事情
       所以Function應該要短

(2) Function Arguments
       參數數量越少越好
       如果參數數量無法降低 那代表你必須要開始封裝參數
       ex.
       Circle makeCircle(double x, double y, double radius)
       Circle makeCircle(Point center, double radius)

(3) Boolean Arguments
       如果你想要用一個Boolean值去當開關
       Ex. SetJugService(true) // Start Jug Service
             SetJugService(false) // Stop Jug Service

       上面作法的缺點在於:
       1. 參數僵化成2選1
       2. Function內必須有if邏輯

       你倒不如設計成
       StartJugService()
       StopJugService()

(4) Command Query Separation
       The real solution is to separate the command from the query so that the ambiguity cannot occur.

       if( set("username","jug"))...
       Function 應該一次做一件事 要嘛回答問題 要嘛執行動作
       上述 function 會讓reader混淆
     
      有些人會將 set 改成 setAndCheckIfExists
      但是對於閱讀仍舊沒有幫助
 
      比較適合的作法是 :
      if(attributeExists(“username”))
          setAttribute(“username”, “jug”);

(5) Don’t Repeat Yourself
        Duplication may be the root of all evil in software.
       如果code一再重複 表示你可以將code抽出來處理

2014-02-11

[收藏] 15 hot programming trends -- and 15 going cold

Peter Wayner 近日在InfoWorld寫了一篇
15 hot programming trends -- and 15 going cold

原文

Javeworld上有比較方便閱讀的版面

InfoQ 翻譯版

15个热门的编程趋势及15个逐步走向衰落的编程方向(上)


15个热门的编程趋势及15个逐步走向衰落的编程方向(下)


[重點筆記]
1. Hot: JavaScript MV* frameworks
    Not: JavaScript files
    請利用JavaScript Framework幫你做事
    Ex. Kendo, Sencha, jQuery Mobile, AngularJS, Ember, Backbone, Meteor JS

2. Hot: SVG + JavaScript on Canvas
    Not: Flash
    Flash封閉且退燒了 請改用SVG + JavaScript on Canvas

3. Hot: Mobile Web apps
    Not: Native mobile apps
    優點 : 跨平台 (不需每個平台都得投入開發)
    PS. HTML運行的速度不輸Native apps
       
    我個人蠻質疑這一點的 記得當初Facebook就是想走Web apps模式行不通才轉為Native應用 不過Startup team的話 在資源不足的初期也許適用

4. Hot: GitHub
    Not: Résumés
    身為一個programmer 沒有比真的有作品更有代表性了

5. Hot: Renting
    Not: Buying
    這就是AWS紅的原因 Startup team可以考慮
 
6. Hot: Node.js
    Not: JavaEE, Ruby on Rails, PHP
    不了解Node.js 要研究看看


2014-02-10

2014-02-09

2013 NABU Business Trip in San Francisco (景點篇) Part 2

[封面故事]
個人最愛的一張照片 富有生命力
千飛萬鳥 攝於 舊金山Crissy Field 2013.12.04 — at Crissy Field.

日期: 2013.11.29 to 2013.12.04

[2013.12.03]
今天的計畫是衝到需要一小時車程的Great Mall 去購買老婆的禮物Coach包包 一早我先去Boudin Sourdough Bakery & Cafe 吃著名的Sourdough bread clam chowder 這濃湯是倒在麵包裡面 我個人是覺得還好 吃完濃湯之後 便搭了Bart前往Green Line的最後一站Fremont 其實老實說SF的Bart路線眾多 車廂裡也不會告訴你這台車往哪裡 唯一的線索是月台上的電子佈告 所以要先確定一下是哪條線再上車比較保險 到了Fremont之後 出站前記得去按一下轉乘優惠券 這樣搭180公車才有$2優惠 公車有固定時間 所以建議去回都要先盯一下時間 免得沒搭到車又得等一陣子 Great Mall 是眾多Outlet 聚集的地方 個人認為這地方是我出差以來 最值得來shopping的地方 商品真的都便宜非常多 就拿Coach來說吧 大概打了4折多的價格 來美國不帶一個回去真的說不過去 好便宜阿 晚上則是去Oracle Arena去看NBA 也是在同一條Bart路線上 所以相當方便 

這是我第一次進場看NBA 昨天工作結束之後 查了一下官網售價 超級貴 還好找到Stubhub這個網站 讓我用$35就買到下層的座位 勇士隊的主場是Oracle Arena 下了Bart Station沿著天橋走就能走到球場 進入球場前球場檢查人員會要求你先寄放包包 只能帶隨身包包進場 相機鏡頭太長也不能帶 進場之後 在外圍地區隨便繞繞 有賣吃的 喝的 球隊商品 你也可以跟Warriors Girl 拍照 進場找到座位坐下之後 發現後方一大堆小朋友 問了一下原來是勇士隊的慈善活動 招待他們來球場看球 他們雖然是小朋友 比賽時還是超級High 一直在又吼又叫的 賽前還有小朋友的籃球表演賽 不要小看小朋友們 他們動作還蠻扎實的 其實整場比賽看下來 前半段勇士打得很差 當地酸民也是毫不留情地狂噓 到了第四節勇士才瘋狂大逆轉 三分雨一直下 全場超HIGH 看NBA真的很爽阿阿阿阿~~~~

[2013.12.04]
今天的計畫是前往Alcatraz Island 原本上星期六就要去的 才知道惡魔島的票要先上網買 所以只好買12/4的門票 一個成人要價$30美元 早上我們搭著F line bus 前往PIER33 這裡是搭乘渡輪前往Alcatraz Island的地方 渡輪有三層 你可以選擇坐在室內 或是頂層露天 當然是選頂層 View比較好啊 不過吹著太平洋的海風 超~級~冷~ 到了惡魔島之後 就開始島上觀光 島上有許多廢棄的建築 或是改裝成觀光客可以瀏覽的博物館 進入主監獄之後 可以選擇聲音導覽 每個點都會有介紹 不過比較不方便的是 導覽不能用點的 所以只能按下暫停 到了下個點之後再繼續聽 老實說主監獄真的蠻陰森的 Kiko很喜歡進到牢獄裡面拍照 我可是敬謝不敏 中午Kiko帶我到傳說中的螃蟹路邊攤 原來是在PIER42 難怪星期六我們在PIER39找半天找不到 我選了一隻清蒸螃蟹 $13 就在小販前面嗑了起來 味道很不錯 就是麻煩了點 吃完飯Kiko心血來潮 想要騎腳踏車去金門大橋 雖然我已經去了兩次了 不過在港區這邊騎腳踏車 好像也不賴 所以就捨命陪君子再去一趟囉 我們租了腳踏車 沿著港灣一路騎去金門大橋 吹著海風 沿路看到美麗的景點就停下來拍照 中間經過Crissy Field 這裡有一大片草皮跟大型藝術裝置 你也能看到有許多人溜著一大堆狗 也很多人選擇在這裡慢跑 總之這裡真的很悠閒 這也是旅遊有趣的地方 下午還車的時候 我們超過了10分鐘 但這邊老美實在很一板一眼 超過10分鐘算我們一小時 我跟老闆講了很久 都沒辦法妥協 不過幸好沒跟他撕破臉 因為當我們返回市區時 我才熊熊發現我的相機還放在腳踏車的前袋裡 趕快搭了公車回去請老闆幫我拿回相機 老闆的店跟租車處有段差距 不過他還是騎著腳踏車去幫我拿回相機 幸好最後相機還是有拿回來 晚上要搭飛機回台灣了 我拉著很重的行李去Bart Station搭車到SFO機場 結果刷卡進去月台時 發現他們唯一一台電扶梯壞了 所以我得很吃力的提著兩個行李下樓 就在這個時刻 有個墨西哥女生很熱情的來幫我拿另一件行李 到了月台我直向她道謝 她就向我問路 沒想到我在SF6天 也是能幫別人指路阿 不過很剛好的是 我們的目的地都是機場 所以我就叫她跟我走就是 我們在車廂裡聊著聊著 話題不外乎就是台灣是不是中國的 我想大部分的老外都會這麼認為>< 突然旁邊的老美 就跟我說 Hi 我媽也是台灣人 我會說一點中文(這句是用國語說) 有沒有這麼剛好阿?

2013 NABU Business Trip in San Francisco (景點篇) Part 1


[封面故事]
這組情侶來自澳洲 今天第一天到舊金山 他們像我一樣被破地圖所害 不過最後還是順利抵達Golden Gate Bridge 後來我們又一起去了Golden Gate Park 在那邊他們看到松鼠很興奮 直說它們這是第一次看到松鼠 問我有沒有看過 我說台灣公園裡很多松鼠 就像澳洲袋鼠一樣多 — feeling funny at Golden Gate Bridge.

日期: 2013.11.29 to 2013.12.04

[2013.11.29]
下午抵達SFO 一如往常我們叫了Taxi前往Hotel 我原本有先查好 從機場出發到飯店大概20分鐘左右
結果沒想到在沒塞車的情況之下司機還開了30幾分鐘 而且要價45鎂 不曉得他有沒有偷繞路
我們住的hotel就在市區 離Union Square很近 所以晚上就晃過去逛逛 廣場剛好有演唱活動 聚集大量人潮
廣場中間有棵大型聖誕樹大家爭相合照 旁邊有個溜冰場 看得我心癢癢也想去溜一下 不過太多人排隊了 當場是客滿
下個session要等到晚上10點 只好放棄了 廣場附近則是一堆知名品牌店面 這裡真的是個購物天堂阿
我真的覺得女生一定超愛這裡的

[2013.11.30]
今天跟在美國工作的人生勝利組 Tom Chih-Chung Liu來個SF一日遊 坐著他的新車 我們暢遊了 AT&T Park, 漁人碼頭, 藝術宮跟金門大橋
早上第一個點是AT&T Park 雖然現在休季 不過球場還是維護的很漂亮 而且可以免費進場 我們從外野進入 拍了球場著名的可樂跟大手套 意外發現外野居然還有一個縮小版兒童小球場 小朋友們是真的可以進去打球的 下一個點是漁人碼頭 在這裡我們犯了一個錯誤 明明PIER39停車場只有兩台車在排隊 我們卻繞過去停更遠一點的停車場 重點是在PIER39停車 如果有用餐的話可以抵兩個小時 而我們後來停的停車場每15分鐘3美元 只能說花錢買個經驗 我們在漁人碼頭想要找同事口中的便宜大螃蟹 結果都找不著(後來發現我們找錯區域) 所以就挑一個好像還蠻多人排隊的餐廳去吃飯 我點了SF經典的Cioppino 簡單來說就是海鮮大雜燴Pasta 新鮮又好吃 用餐完我們便前往金門大橋 沒想到今天下午的金門大橋大霧瀰漫 什麼都拍不到 晚點繞去附近的藝術宮 沒想到晚上的藝術宮挺有氣氛的

[2013.12.01]
昨天去Golden Gate Bridge時充滿神祕的大霧 所以固執的我 今天還是決定再去一次 從Union Square附近搭上MUNI公車38號 再轉28號 就到了Golden Gate Bridge 我在橋上充當好多遊客的攝影師 看來遊客們對這個景點是特別興奮阿 我徒步走上橋面 只完成了2/3就往回走了 因為實在太遠了 我還想撥點時間去其他地方 下一個景點是Golden Gate Park 這點是一組澳洲情侶推薦我一定要去看看的地方 這公園真的是超~ 級 ~ 大 ~ 我都覺得我快把台北市走完了一圈了

[2013.12.02]
工作日 今天的客戶藏身在郊外工廠中 我們一度還懷疑司機有沒有走錯路 工作結束之後 其中一位女客戶邀請我們跟她一起坐電車回家=.= 也不錯啦 一路上聊著聊著就搭著公車轉Bart 回到Hotel

2014-02-05

2013 NABU Business Trip in Salt Lake City (景點篇)


[封面故事]
11/28 Thanksgiving 下午騎著腳踏車在Salt Lake City Downtown亂騎亂晃亂拍照 在神聖的Temple Square的見證下 這位男子請我幫他跟女友拍照 私底下卻偷偷跟我講 他等下要跟他女友求婚 請我幫他錄影跟拍照 這是我第一次幫人家求婚 哈哈 感覺很特別 也恭喜他們了 — feeling special at Temple Square.

日期: 2013.11.26 to 2013.11.29
Salt Lake City in Utah
SLC 是個方便的城市 有摩門教莊嚴的大教堂 有免費的電車可以載你趴趴走 也有腳踏車可以讓你運動一下 雖然outlet在很遠的地方 不過這邊的Mall也不賴 我們剛好趕上Thanksgiving 在傳說中的Black Friday 確實也不少折扣
但這邊讓我最感到特別的 就是靜電 我們外地三人組在SLC最常講的話 就是Oh~ Shit了 因為又被電了

2013.11.26
今天的午餐在Market Grill Street 是個有肉有海鮮的地方 我們點了Chesapeake的oyster以及推薦的fresh fish 重點是便宜又好吃
Salt Lake City 這邊有免費的電車可以搭乘 相當方便 我晚上就搭著電車前往City Creek Mall 跟Gateway Mall 採買老婆需要的禮物 City Creek Mall 據說是摩門教建立的商場 比Gateway好逛多了 Gateway是在戶外 頂著寒風在外面逛是很冷的

2013.11.27
今天的客戶是End user 他們本身也是間Security的公司 這就是所謂的Security中的Security
總經理是Richard 南韓人 非常年輕 才32歲 非常精實且有企圖心的人 一般Thanksgiving 老美都不想工作 在家陪家人看足球 他卻是自己跑來上班 親自測試我們家產品 甚至還想變成我們的reseller 一個超級積極的人
中午我們跑去吃best pie in America 當天點餐都能免費得到一小塊Pie 晚餐Richard招待我們去吃日本料理 這家壽司都附上濃濃的美奶滋 甜甜的 跟台灣吃的日本料理有點差別 吃飯不開車就能啤酒喝到爽啦 司機們還真是滴酒不沾因為他們酒駕罰很重

2013.11.28
Thanksgiving的一天 大部分的店家都沒營業 我原本預計要搭著電車去The University of Utah 但是連電車都休息是要怎麼去 所以我只好在飯店附近繞繞拍拍 這邊街道都整理的很乾淨整齊 隨便拍都很有fu 中午返回飯店的餐廳吃thanksgiving特餐 要價$45 不便宜 不過難得碰上感恩節 就給他吃下去吧 下午騎著腳踏車 前往摩門教的大本營 Temple Square 碰巧見證了一對情侶求婚的經過 傍晚騎著騎著突然看到山丘上有個漂亮的建築 念頭一轉 立馬騎車上山 汗流浹背地騎到山頭上之後 終於見到了這漂亮的建築 - Utah State Capitol

2013.11.29
Black Friday , 到處都在打折 所以我就趁早上去City Creek Mall 採買一番 中午就要跟Utah說掰掰了

2014-02-03

2013 NABU Business Trip in Toronto (景點篇)


[封面故事]
晚上9:30走在下雪的街頭 就是為了拍攝他 CN Tower — at CN Tower / La Tour CN.

日期: 2013.11.24 to 2013.11.26

Toronto 是出差行程裡面最緊的一個城市 加上飛機誤點 抵達Toronto之後已經下午5點多 當天是星期天 所以晚上任何店家幾乎都不營業了 所以我選擇在隔天的晚上前往Downtown 這裡交通算便利 只是繁複了些 先要從Hotel搭shuttle至TTC Station, TTC是類似地鐵或是捷運的玩意 然後就搭著TTC到Union Station 沒想到走在Toronto的街頭 竟飄著小雪 我頂著寒風 就是為了今天的重點行程 ~ CN Tower ~

2014-02-01

2013 NABU Business Trip in Virginia (景點篇)

[封面故事]
USS Wisconsin BB-64 超級戰艦 真的超壯觀— at USS Wisconsin (BB-64).

日期: 2013.11.21 to 2013.11.24


[2013.11.21]

吃完KFC之後 便從LOUISVILLE出發 中間行經CHARLOTTE再到Virginia的NORFOLK INTERNATIONAL Airport 這段航程是搭乘US Airways 的小飛機 非常幸運地 這是我第一次坐在第一排的座位 到了 NORFOLK機場之後 這邊有很多裝置藝術可以拍攝 今晚又是入住Norfolk Marriott Chesapeake


[2013.11.22]

今天拜訪一家在Chesapeake的客戶 離我們飯店非常的近 但他們還是派車過來接送 老闆娘是德國人 可以感覺得出來她相當嚴謹 中午出來一起吃飯時 接待的客戶推薦我們吃一家當地有名的餐廳 Cotton Southern Bistro (2012 Best Winner) 我本著來Virginia就要吃海鮮的精神 點了Riverwalk Shrimp 份量超級十足 根本就吃不完 回到客戶公司之後 下午老闆娘休假了 所以Doug開始輕鬆了起來 介紹我們它們公司賣的其他產品 其中一個是小小的bluetooth speaker 聲音聽起來確實還蠻不錯的 晚上回到飯店 Lounge星期五晚上不開 所以我們只好在Hotel的餐廳吃飯 至少比Room Dining 便宜多了


[2013.11.23]

Virginia 一日遊 景點
Virginia Beach -> The MacArthur Memorial -> Norfolk Fire-Rescue Museum -> Moses Myers House

-> Saint Paul's Episcopal Church -> USS Wisconsin -> Grand Illumination and Parade


今日休兵 所以我們在Virginia一日遊 早上先去Virginia Beach 中午到Norfolk觀光 看博物館 看教堂 看海軍 Phil一直要找在Saint Paul's Church的cannonball 這邊的教堂實在太漂亮了 每個都很像很有名的樣子 所以我們共走錯了兩次 中午在當地相當著名的Freemason Abbey吃龍蝦配白酒 雖然有點貴 但是值得一嘗阿 晚上聽計程車司機說有聖誕節遊行 就跑去參加了 遊行7:00才開始 我們5:00就到那邊搶第一排的位子 果然早到是值得的 不僅有位子可以坐下 遊行也看得很清楚 這遊行相當盛大 幾乎當地學校 公司都有組隊參加 參加者跟觀眾熱情狂歡 我身旁的黑人媽媽整場又叫又跳的 超嗨



[2013.11.24]

這間Marriott的早餐是點餐式的 可以吃到飽 品質也不賴 我們用完早餐之後便前往機場 我們下個點要去加拿大囉

2014-01-28

2014-01-19

2013 NABU Business Trip in Kentucky (景點篇)

[封面故事]
來到了肯德基的故鄉Kentucky 就是要吃一下原版的肯德基阿
照片中的人物都是這次出差一起同行的同事


日期: 2013.11.19 to 2013.11.21

[2013.11.19]
下午從MSP機場出發至CHICAGO轉機再到LOUISVILLE 到了飯店已經接近晚上10點 Phil 帶我們衝到頂樓Lounge去吃免費的餐點 有他的點數真的還蠻省的 吃東西都不用錢

[2013.11.20]
今天前往客戶公司 今天的客戶Kevin 是個超級High且熱情的人 中午他帶我們去吃當地超級推薦的Mussel & Burger Bar 果然是超級好吃 這邊的Mussel 有機會來的話 一定要嘗嘗 下班時 Kevin帶我們去看看它們公司的環境 每個人都有一個小玩具 公司也大辣辣擺一個高爾夫球Game在工作環境 過了五點 他們Parter開了一瓶wine來喝 實在是太酷了

[2013.11.21]
今天中午就要飛Virginia 所以很可惜沒有時間可以逛一下Louisville 但是來到Kentucky就是要吃一下原版的肯德基阿 所以我們在機場嗑了肯德基 結果沒想到機場這家店居然沒有賣炸雞!!!

2014-01-06

2013 NABU Business Trip in Minnesota (景點篇)

[封面故事]
11/19 早上6:00起床,頂著-4C的低溫,從旅館徒步20多分鐘,就是為了拍攝莊嚴的Cathedral of St. Paul

日期: 2013.11.17 to 2013.11.19

這次入住的旅館是The Saint Paul Hotel位於 St. Paul據說是Snoopy作者Charles M. Schulz的故鄉。所以旅館外頭的Rice Park立了許多Snoopy相關的雕像。

[2013.11.17]
今天從桃園國際機場搭Delta至日本成田機場與同事Kiko會合之後 再一起轉機去MN. 坐飛機的時間約14hr 很久!! 屁股很痛!! 到了Minneapolis 海關針對kiko問蠻久的 我在後面也有點擔心 不過輪到我的時候 居然問一下公司跟目的就放行了 究竟是男女生有差呢 還是國籍有差? 接下來我們就直接前往The Saint Paul Hotel. Kiko說她累了要去補眠 而我卻因為有安安這兩個月來的訓練 居然沒什麼時差 所以整個下午我就自己在Saint Paul這邊亂走亂晃亂拍囉

[2013.11.18]
今天去客戶那邊onsite 早上跟Beta Manager Phil會合之後就一起搭Taxi前往客戶公司 今天基本上都還蠻順利的 客戶也跟我們喇低賽了
一整天 其中最酷的就屬獵鹿了 中午我們點了號稱freaky fast的Jimmy John's
據說比subway好吃 客戶大力推薦. 大約4:30 MN這邊就天黑了 客戶就說要準時回家了=.= 晚上回到Hotel之後 因為還要寫報告 + 討論 + 開會 所以就不出去吃了 點了Room Dining的 Turkey Burger 想不到還蠻好吃的

[2013.11.19]
今天6:00就起床 為的就是去拍攝莊嚴的Cathedral of St. Paul 頂著-4度C的低溫 徒步20分鐘後抵達 之後回到Hotel跟Phil與Kiko會合 今天早上的行程是Minneapolis市區雙腳萬能 所以我們幾乎把市區所以景點都走光了 中午前往機場 離飛機起飛還有2個多小時 所以我又跑去號稱全美最大的Mall, Mall of America, 因為是臨時起意 機場也沒wifi能讓我再查一下地址 不過幸好路是長在嘴上 也感謝熱情的老美 讓我這個沒準備的傢伙能夠順利抵達

2013-12-04

[FB] 千飛萬鳥 攝於 舊金山Crissy Field 2013.12.04

2013-07-14

2012-12-29

[FB] 清境之巔 觀山觀光 攝於清境農場觀山牧區 2012.12.29