Sunday, September 29, 2013

不要自找麻煩了!小心這六個壞習慣,搞砸你的工作效率

美國總統林肯有句名言:
Most folks are as happy as they make up their minds to be.
「對大多數人來說,他們認定自己有多幸福,就有多幸福。」
要讓一天的工作狀況是充滿效率又積極,或是沉悶又沮喪,其實決定權在你自己身上,今天要和大家分享的是,會讓你在工作中自找麻煩的六大蠢事!想毀了自己一天的工作效率嗎?跟著做就對了!
  • 壞習慣一:批判和衝突
回想一下,上一次被同事或顧客惹惱是什麼時候?在你發火之前,有沒有先停下來想想,對方這樣做是不是有什麼不為人知的原因?
照理說,一個人會生氣、沮喪、不講理、或是惡劣的態度時,通常有一定的原因使他變成這樣,當你要針對當下的態度反擊或批判他們時,或許可以先用同理心探究一下背後的因素,是不是他家的狗剛死掉?或是他現在處於嚴重的偏頭痛?還是接到了什麼不好的消息?
總之你應該要提醒自己,你並不知道他究竟發生了什麼事,用同情的眼光看待這一切吧,才不會讓工作情緒因為衝突而搞砸。
  • 壞習慣二:一直想著還有多少難題要解決
不知道你是否聽過 Marcus Luttrell 的故事,他是美國特種部隊 —— 海豹突擊隊的隊長,曾經深入阿富汗偏遠地區擒獲塔利班重要幹部,他分享自己訓練底下隊員的方式:「學員必須背負重物跑過實彈射擊的場合,還得游過數英里,而在潛水訓練中,我們會把水肺的管子打結,他們必須在緊急的狀況下按照步驟解救自己。」
Candidates who focused on how many days of excruciating training they had left inevitably dropped out. As one of his instructors put it, “The body can take damn near anything. It’s the mind that needs training.”
這之中我發現一件事,所有無法通過訓練的學員,都有個共同點,就是他們會一直去算這個訓練過了多少天,還有多少天,導致意志力越來越薄弱,最後放棄。「其實這些訓練都在身體可以承受的範圍內,最需要被鍛鍊的是心智。」 Marcus 說。
如果你的工作不會像他們那樣危及生命,或許這些難題並沒有那麼可怕,重要的是一個步驟一個步驟去做,不要因為自己嚇自己而被困在原地。
  • 壞習慣三:不斷和別人比較
「人比人,氣死人。」 這個道理你應該就很能體會了,之前〈看朋友一路走向人生勝利組,你就不開心?研究:FB 讓我們善妒、愛比較,感覺空虛感覺冷〉一文中,有談到 FB 會讓人善妒且沮喪,一直看到朋友們精采的照片、生活,實在很容易產生自我質疑:怎麼朋友都是溫拿(Winner),比起來我好像魯蛇(Loser) 一樣。
同樣的道理,在工作中一直和別人做比較,會讓你無法專心在自己的任務上,而且影響工作情緒。
  • 壞習慣四:花費過多時間在會議上
Learn Vest 和 Inc.的執行長 Alexa Von Tobel 曾發表一篇關於會議時間控制的文章,他說:
“Most people think in terms of 30-minute chunks, but I’ve found that when I free up more time, I waste it. Of course, some tasks do require more time so if a meeting needs to take 30 minutes, it will take 30 minutes. But otherwise, I try not to schedule meetings to last that long.”
「大部分人會把開會時間用半小時為單位來做區隔,但就我長久觀察下來,半小時對於許多會議來說都有些太長了,不知不覺中會浪費很多寶貴的時間。當然比較重要的、需要詳細討論的事情會需要半小時以上的時間,但大多數比較小的會議,我建議用 15 分鐘解決,否則常常一天就這樣過了。」
  • 壞習慣五:完美主義者
完美主義是焦慮的根源,它通常來自於小時候所建立起的防禦機制,為了不讓別人批評自己所形成,Shelley Prevost 最近在 Inc. 的一篇文章中指出,完美主義者無謂的堅持經常會讓他們產生焦慮的毛病。
完美的意思是什麼?就是沒有任何人能夠指出你的錯誤或批評你。但你也知道這不可能,因為沒有人是完美的,若你總是在工作上設定不太可能達到的完美標準,只會更容易讓自己鑽牛角尖,走進死胡同。
  • 壞習慣六:感嘆自己的不如意
不要把自己的不開心一直放大,你該放大的是視野和格局,我們都讀過歷史,回想人類在這個世界上所經歷過的一切,戰爭、瘟疫、飢荒…… 都是過往的人們所承受過的苦難,而你現在能坐在辦公室吹冷氣、回家有冰箱用、還能洗個熱水澡,其實都是很幸運的事。
我們必須懂得感恩,能走能跑能思考能呼吸,甚至還可以規劃自己的人生,真的很棒了不是嗎?
(資料來源:Inc.;封面圖片:mugley , CC Licensed)

Reference:
http://techorange.com/2013/09/30/6-ways-to-ruin-your-day/

Excel Fill Down Command hotkey

If you need to input the same data - text or numbers - into a number of adjacent cells in a column, the Fill Down command can quickly do this for you by just using the keyboard.

  • select a cell
  • Press and hold down the Shift key on the keyboard
  • Press and hold down the Down Arrow key on the keyboard to extend the cell highlight from cell D1 to D7 (or press Shift, Ctrl-home to the bottom of the content).
  • Release both keys.
  • press Ctrl-d

Reference:
http://spreadsheets.about.com/od/tipsandfaqs/qt/81130filldown.htm

Thursday, September 26, 2013

Optional Parameters in C#

A parameter is optional if it specifies a default value in its declaration.

The default value of an optional parameter must be specified by a constant expression, or a parameterless constructor of a value type. Optional parameters cannot be marked with ref or out.

default value examples:

// use default() keyword to obtain the default value of any type.
public void Problem(Guid optional = default(Guid)) {
}

or

// a parameterless constructor of a value type.
public void Problem(Guid optional = new Guid()) {
}

Note: new Guid(), which is equivalent to default(Guid).

Note: the new Guid() value is only applicable when:

  • You're really calling the parameterless constructor
  • Foo is a value type

Mandatory parameters must occur before optional parameters in both the method declaration and the method call (the exception is with params arguments, which still always come last).

Reference:
C# 5.0 in a Nutshell: The Definitive Reference
http://stackoverflow.com/questions/5117970/how-can-i-default-a-parameter-to-guid-empty-in-c

copy mode in tmux

  1. Use ctrl-b [ to enter copy mode in tmux
  2. Use h j k l keys to move around.
  3. Use space key to start selection.
  4. Use enter key to copy the selected text.
  5. Use ctrl-b ] to paste the copied text.

# man tmux

http://www.openbsd.org/cgi-bin/man.cgi?query=tmux&sektion=1

Monday, September 23, 2013

TOOLS - 透過LINUX指令取得全中國大陸 IPV4, IPV6 IP address range 網段

工作上,有時需要判斷IP來源是否為中國大陸的IPv4網段,分享一行簡單的Shell Script:

資料來源:http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest

我們使用 Linux 來抓取及分類:

cat delegated-apnic-latest |grep 'apnic|CN|ipv4|' $FILE | cut -f 4,4 -d'|'

取得的 IPv4 網段就是全中國大陸的 IPv4 網段,如果需要其他格式,請自行轉換。

那如果是要全中國大陸 IPv6 網段呢?看一下資料來源,裡面就有答案了。

Reference:
http://blog.kkbruce.net/2011/10/tools-linuxipv4-ipv6.html#.UkDP4oakqT4

軟體測試(SOFTWARE TESTING)超快速入門筆記

軟體測試(SOFTWARE TESTING)超快速入門筆記

測試的目的

軟體測試(Software Testing)是一個大題目,不過其目標都是一樣的,例如,提早發現缺陷,提高軟體品質,產生可靠的程式碼…等。軟體測試的方法論中,測試的範圍可大可小,以程式碼的測試為例,小的單元測試(Unit Testing)、大的整合測試(Integration Testing)。除了對程式碼進行相關測試外,我們還可以對整個網站、資料庫、I/O … 等進行壓力測試。測試可是一門大學問,當然不可能在這小小一篇裡寫完,這一篇只是前言,讓大家對於測試有個初步的瞭解,先有初步瞭解,接下來再介紹 ASP.NET MVC 裡單元測試(Unit Testing)。

手動測試

  1. 了解需求
  2. 手動進行基本驗證
例如,我們寫了一段驗證 Email Address 的 Regular Pattern,我們很順的把網頁執行起來,開始在表單的 Email 欄位亂打一通,【abc@abc】、【abc@abc.】、【abc@abc.abc】 … 看不正常資料是否能通過驗證。很多寫的不好的 Regular Expression 到第三個 abc@abc.abc 就 … 過了。這樣對嗎?這就稱【手動測試】,我們日常的 Debug 就常做這種事,但你能瞭解或記得多少組的測試組合呢?

自動化測試

  1. 介面測試(UI Testing)
  2. 單元測試(Unit Testing)
  3. 整合測試(Integration Testing)
簡單說就是透過程式軟體去進行測試,沒有人的介入去進行測試。舉例來說,字母o與數字0,如果我不要加【字母 | 數字】只單純打【o/0】,你分得出來嗎那個是"ㄛ"那個是"零"嗎?我們常用密碼組合中有一組是 w0rd,透過程式 w0rd 是字串,對就是對,透過人工加老花眼,很容易輸入為 word。自動化測試就是要去除人工介入而可能產生的錯誤,進而提升測試的可信度、可靠度。例如手動測試的例子中,我們的測試資料有一組 abc@abc.c0m (c零m),驗證程式要能正確抓出錯誤才是對的,結果很順手的輸入成 abc@abc.com,然後跑去罵寫這支 Regular Expression 的人,事後又模擬出不來(又輸入了正確的測試資料),然後被冠上"你的程式一定有Bug."的臭名,青天大人這冤不冤?

ASP.NET MVC 單元測試(UNIT TESTING)

我們開發人員在 ASP.NET MVC 專案通常只做單元測試(Unit Testing),我們注重在 Controller 內的 Action 是否正確無誤,而且進行單元測試(Unit Testing)程式碼的撰寫也可以順便進行 Code review 與 Refactory (非Test-driven development, TDD開發),進行一些物件導向基本原則檢查。
寫單元測試(Unit Testing)就是要讓一切有憑有證有據。讓單元測試(Unit Testing)幫你說話,在《軟體構築美學》在第「4-2-2 為什麼需要測試」一節提到需要測試的幾個原因:
  • 確保臭蟲不會反覆出現
  • 確保新的程式碼達到可接受的品質水準
  • 建立與保持開發團隊和用戶的信心
  • 最重要的,加速回饋循環
如果你連單元測試(Unit Testing)都過不了(也許是他人寫,也許是自己寫),那【加速回饋循環】的時間會短的讓你驚訝!

單元測試(UNIT TESTING)撰寫注意事項

  1. 測試程式碼不應接觸任何外部資源(External Resources),舉例來說:
    1. File I/O
    2. Database Access
    3. RESTful Service (Web Service/WCF/...)
    接觸外部資源的單元測試(Unit Testing)可能造成結果的不信任,以資料庫存取來說,合理的資料庫裡資料是隨時在變動的,對於不斷變動的資料,你要如何測試?另一點是,會讓執行單元測試(Unit Testing)的時間過長,我在《解析极限编程:拥抱变化》的《推薦序》中看到一個數字 Eclipse 這套軟體必須通過21000個單元測試(Unit Testing),這本書的原文是在2004年寫的,現在是2012年,我相信現在的數字會大非常多,你試想這些外部資源都是非常耗時耗資源的,假如每次執行都必須執行21000次 File I/O,我想你會"起瘋"!
    就以上理由,ASP.NET MVC 的 Model Class (或 DAL, data access layer) 通常不太寫單元測試(Unit Testing)。
    以上說明會讓人誤解,比較嚴謹應該改為:如果MVC的Model裡只有"LINQ to SQL類別"或"ADO.NET實體資料模型"或"*.tt"等,實在沒有什麼好寫的。因為那些都是用工具產生的。
  2. 類別(Class)的靜態物件(例如,VB Shared, C# static)可能受其他方法(Method)而改變狀態(state)。此時無法在單一個方法內驗證其 State 的正確性,在此情況下,就不合適在單元測試(Unit Testing)中驗證靜態物件的 State。反之,執行之後靜態物件會成為"特定 State",就可以寫單元測試(Unit Testing)來驗證。

整合測試(INTEGRATION TESTING)

針對專案的一部分全部進行測試。
  1. 需配合情境設計
  2. 需先設置測試所需環境
例如,
  1. 建立測試資料庫
  2. 建立測試資料
  3. 建立測試檔案
  4. 建立測試服務(Web Service / WCF / Web API / ...)
  5. 執行整合測試
  6. 刪除所有測試相關資料與服務
單元測試(Unit Testing)是一個點的測試,整合測試(Integration Testing)是面與線的測試

測試驅動開發(TEST-DRIVEN DEVELOPMENT)

測試來驅動軟體開發
  1. 先寫測試程式碼(通常是單元測試)
  2. 開發被測試的程式碼
  3. 讓開發的程式碼通過條件(1)的測試程式碼
由於我們必須先寫測試程式碼,開發團隊必須先瞭解需求為前提來寫測試程試碼,然後才進行實際程式碼的開發工作。整體流程大致:
  1. Test Coding (Unit Testing)
  2. Test fail
  3. Developer Coding
  4. Test Success
  5. Refactory (Run 3 → 4 → loop )
條件(2)是正常的,因為寫完測試程式碼後,根本就沒有實際程式可以測試,所以一定失敗。有了測試程式碼,接下來就是寫能通過測試程式碼的實際程式碼,以通過測試為前提。如果實際程式需要重構(Refactory)就必須重跑一次條件(3)(4),以確保重構後的程式碼也能通過測試。雖然 TDD 看起來很不錯,但 TDD 還是有先天上的限制,一是需求不清,二是架構不明。不清不明的內容,如何撰寫測試程式碼,即條件(1)都無法執行了,那還談什麼 TDD,對吧。

Reference:
http://blog.kkbruce.net/2012/07/software-testing.html#.Uj4YaYakqT7

Top 10 things which make your code hard to test

So you decided to finally give this testing thing a try. But somehow you just can’t figure out how to write a unit-test for your class. Well there are no tricks to writing tests, there are only tricks to writing testable code. If I gave you testable code you would have no problems writing a test for it. But, somehow you look at your code and you say, “I understand how to write tests for your code, but my code is different “. Well your code is different because you violated one or more of the following things. (I will go into the details of each in a separate blog posts)
  1. Mixing object graph construction with application logic: In a test the thing you want to do is to instantiate a portion (ideally just the class under test) of your application and apply some stimulus to the class and assert that the expected behavior was observed.  In order to instantiate the a class in isolation we have to make sure that the class itself does not instantiate other objects (and those objects do not instantiate more objects and so on). Most developers freely mix the “new” operator with the application logic. In order to have a testable code-base your application should have two kinds of classes. The factories, these are full of the “new” operators and are responsible for building the object graph of your application, but don’t do anything. And the application logic classes which are devoid of the “new” operator and are responsible for doing work. In test we want to test the application logic. And because the application logic is devoid of the “new” operator, we can easily construct an object graph useful for testing where we can strategically replace the real classes for test doubles. (see: How to Think About the “new” Operator with Respect to Unit Testing)
  2. Ask for things, Don’t look for things (aka Dependency Injection / Law of Demeter): OK, you got rid of your new operators in you application code. But how do I get a hold of the dependencies. Simple: Just ask for all of the collaborators you need in your constructor. If you are a House class then in your constructor you will ask for the Kitchen, LivingRoom, and BedRoom, you will not call the “new” operator on those classes (see 1). Only ask for things you directly need, If you are a CarEngine, don’t ask for FuelTank, only ask for Fuel. Don’t pass in a context/registry/service-locator. So if you are a LoginPage, don’t ask for UserContext, instead ask for the User and the Athenticator. Finally don’t mix the responsibility of work with configuration, If you are an Authenticator class don’t pass in a path of the configuration information which you read inside the constructor to configure yourself, just ask for the configuration object and let some other class worry about reading the object from the disk. In your tests you will not want to write a configuration into a disk just so that your object can read it in again. (see:Breaking the Law of Demeter is Like Looking for a Needle in the Haystack)
  3. Doing work in constructor: A class under tests can have tens of tests. Each test instantiates a slightly different object graph and than applies some stimulus and asserts a response.  As you can see the most common operation you will do in tests is instantiation of object graphs, so make it easy on yourself and make the constructors do no work (other than assigning all of the dependencies into the fields). Any work you do in a constructor, you will have to successfully navigate through on every instantiation (read every test). This may be benign, or it may be something really complex like reading configuration information from the disk. But it is not just a direct test for the class which will have to pay this price, it will also be any related test which tries to instantiate your class indirectly as part of some larger object graph which the test is trying to create.
  4. Global State: Global state is bad from theoretical, maintainability, and understandability point of view, but is tolerable at run-time as long as you have one instance of your application. However, each test is a small instantiation of your application in contrast to one instance of application in production. The global state persists from one test to the next and creates mass confusion. Tests run in isolation but not together. Worse yet, tests fail together but problems can not be reproduced in isolation. Order of the tests matters. The APIs are not clear about the order of initialization and object instantiation, and so on. I hope that by now most developers agree that global state should be treated like GOTO.
  5. Singletons (global state in sheep’s clothing): It amazes me that many developers will agree that global state is bad yet their code is full of singletons. (Singletons which enforce their own singletoness through private constructor and a global instance variable) The core of the issue is that the global instance variables have transitive property! All of the internal objects of the singleton are global as well (and the internals of those objects are global as well… recursively). Singletons are by far the most subtle and insidious thing in unit-testing. I will post more blogs on this topic later as I am sure it will create comments from both sides. (see:Singletons are Pathological Lairs)
  6. Static methods: (or living in a procedural world): The key to testing is the presence of seams (places where you can divert the normal execution flow). Seams are essentially polymorphism (Polymorphism: at compile-time the method your are calling can not be determined). Seams are needed so that you can isolate the unit of test. If you build an application with nothing but static methods you have procedural application. Procedural code has no seams, at compile-time it is clear which method calls which other method. I don’t know how to test application without seams. How much a static method will hurt from a testing point of view depends on where it is in you application call graph. A leaf method such as Math.abs() is not a problem since the execution call graph ends there. But if you pick a method in a core of your application logic than everything behind the method becomes hard to test, since there is no way to insert test doubles (and there are no seams). Additionally it is really easy for a leaf method to stop being a leaf and than a method which was OK as static no longer is. I don’t know how to unit-test the main method!
  7. Favor composition over inheritance: At run-time you can not chose a different inheritance, but you can chose a different composition, this is important for tests as we want to test thing in isolation. Many developers use inheritance as code reuse which is wrong. Whether or not inheritance is appropriate depends on whether polymorphism is going on. Inheriting from AuthenticatedServlet will make your sub-class very hard to test since every test will have to mock out the authentication. This will clutter the focus of test, with the things we have to do to successfully navigate the super class. But what if AuthenticatedServlet inherits from DbTransactionServlet? (that gets so much harder)
  8. Favor polymorphism over conditionals: If you see a switch statement you should think polymorphisms. If you see the same if condition repeated in many places in your class you should again think polymorphism. Polymorphism will break your complex class into several smaller simpler classes which clearly define which pieces of the code are related and execute together. This helps testing since simpler/smaller class is easier to test.
  9. Mixing Service Objects with Value Objects: There should be two kinds of objects in your application. (1) Value-objects, these tend to have lots of getters / setters and are very easy to construct are never mocked, and probably don’t need an interface. (Example: LinkedList, Map, User, EmailAddress, Email, CreditCard, etc…). (2) Service-objects which do the interesting work, their constructors ask for lots of other objects for colaboration, are good candidates for mocking, tend to have an interface and tend to have multiple implementations (Example: MailServer, CreditCardProcessor, UserAthenticator, AddressValidator). A value-object should never take a service object in its constructor (since than it is not easy to construct). Value-objects are the leafs of your application graph and tend to be created freely with the “new” operator directly in line with your business logic (exception to point 1 since they are leafs). Service-objects are harder to construct and as a result are never constructed with a new operator in-line, (instead use factory / DI-framework) for the object graph construction. Service-objects don’t take value-objects in their constructors since DI-frameworks tend to be unaware about the how to create a value-object. From a testing point of view we like value-objects since we can just create them on the fly and assert on their state. Service-objects are harder to test since their state is not clear and they are all about collaboration and as a result we are forced to use mocking, something which we want to minimize. Mixing the two creates a hybrid which has no advantages of value-objects and all the baggage of service-object.
  10. Mixing of Concerns: If summing up what the class does includes the word “and”, or class would be challenging for new team members to read and quickly “get it”, or class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns. These classes are hard to tests since there are multiple objects hiding inside of them and as a resulting you are testing all of the objects at once.
So here is my top 10 list on testability, the trick is translating these abstract concepts into concrete decisions in your code.

Reference:
http://misko.hevery.com/2008/07/30/top-10-things-which-make-your-code-hard-to-test/

Saturday, September 21, 2013

Top Five (Wrong) Reasons You Don't Have Testers

In 1992, James Gleick was having a lot of problems with buggy software. A new version of Microsoft Word for Windows had come out, which Gleick, a science writer, considered to be awful. He wrote alengthy article in the Sunday New York Times Magazine which could only be described as a flame, skewering the Word team for being unresponsive to the requests of customers, and delivering an enormously buggy product.
Later, as a customer of a local Internet provider Panix (which also happens to be my Internet provider), he wanted a way to automatically sort and filter his mail. The UNIX tool for doing this is called procmail, which is really arcane and has the kind of interface that even the most hardcore UNIX groupies will admit is obscure.
Anyway, Mr. Gleick inadvertently made some kind of innocent typo in procmail which deleted all his email. In a rage, he decided that he was going to create his own Internet access company. Hiring Uday Ivatury, a programmer, he created Pipeline, which was really quite a bit ahead of its time: it was the first commercial provider of Internet access with any kind of graphical interface. 
Now, Pipeline had its problems, of course. The very first version didn't use any kind of error correction protocol, so it had a tendency to garble things up or crash. Like all software, it had bugs. I applied for a job at Pipeline in 1993. During the interview, I asked Mr. Gleick about the article he wrote. "Now that you're on the other side of the fence," I asked, "do you have a bit more of an appreciation for the difficultly of creating good software?"
Gleick was unrepentant. He denied that Pipeline had any bugs. He denied that it was anything as bad as Word. He told me: "one day, Joel, you too will come to hate Microsoft." I was a little bit shocked that his year of experience as a software creator, not merely a software user, hadn't given him a smidgen of appreciation for how hard it is to really get bug-free, easy to use software. So I fled, turning down the job offer.  (Pipeline was bought out, by PSI, the strangest Internet provider on earth, and then unceremoniously taken out and shot.)
Software has bugs. CPUs are outrageously finicky. They absolutelyrefuse to deal with things that they weren't taught to deal with explicitly, and they tend to refuse in the most childish of ways. When my laptop is away from home, it tends to crash a lot because it can't find the network printer it's used to finding. What a baby. It probably comes down to a single line of code somewhere with a teensy tiny almost insignificant bug in it.
Which is why you positively, absolutely, need to have a QA department. You are going to need 1 tester for every 2 programmers (more if your software needs to work under a lot of complicated configurations or operating systems). Each programmer should work closely with a single tester, throwing them private builds as often as necessary.  
The QA department should be independent and powerful, it must not report to the development team, in fact, the head of QA should have veto power over releasing any software that doesn't meet muster.
My first real software job was at Microsoft; a company that is not exactly famous for its high quality code, but which does nonetheless hire a large number of software testers. So I had sort of assumed that every software operation had testers.
Many do. But a surprising number do not have testers. In fact, a lot of software teams don't even believe in testing.
You would think that after all the Quality mania of the 80s, with all kinds of meaningless international "quality" certifications like ISO-9000 and buzzwords like "six-sigma", managers today would understand that having high quality products makes good business sense. In fact, they do. Most have managed to get this through their heads. But they still come up with lots of reasons not to have software testers, all of which are wrong.
I hope I can explain to you why these ideas are wrong. If you're in a hurry, skip the rest of this article, and go out and hire one full-time tester for every two full-time programmers on your team. 
Here are the most common boo-hoo excuses I've heard for not hiring testers:

1. Bugs come from lazy programmers.

"If we hire testers", this fantasy goes, "the programmers will get sloppy and write buggy code. By avoiding testers, we can force the programmers to write correct code in the first place."
Sheesh. If you think that, you either have never written code, or you are remarkably dishonest about what writing code is like. Bugs, by definition, leak out because programmers did not see the bug in their own code. A lot of times it just takes a second set of eyes to see a bug.
When I was writing code at Juno, I tended to exercise my code the same way every time ... I used my own habits, relying on the mouse a lot. Our marvelous, vastly overqualified tester had slightly different habits: she did more things with the keyboard (and actually rigorously tested the interface using every possible combination of inputs). This quickly uncovered a whole slew of bugs. In fact at times she actually told me that the interface flatly didn't work, 100% did not work, even though it always worked for me. When I watched her repro the bug I had one of those whack-your-forehead moments. Alt! You're holding down the Alt Key! Why didn't I test that?

2. My software is on the web. I can fix bugs in a second.

Bwa ha ha ha ha! OK, it's true, web distribution lets you distribute bug fixes much faster than the old days of packaged software. But don't underestimate the cost of fixing a bug, even on a web site, after the project has already frozen. For one thing, you may introduce even more bugs when you fix the first one. But a worse problem is that if you look around at the process you have in place for rolling out new versions, you'll realize that it may be quite an expensive proposition to roll out fixes on the web. Besides the bad impression you will make, which leads to:

3. My customers will test the software for me.

Ah, the dreaded "Netscape Defense". This poor company did an almost supernatural amount of damage to its reputation through their "testing" methodology:
  1. when the programmers are about halfway done, release the software on the web without any testing.
  2. when the programmers say they are done, release the software on the web without any testing.
  3. repeat six or seven times.
  4. call one of those versions the "final version"
  5. release .01, .02, .03 versions every time an embarrassing bug is mentioned on c|net.
This company pioneered the idea of "wide betas". Literallymillions of people would download these unfinished, buggy releases. In the first few years, almost everybody using Netscape was using some kind of pre-release or beta version. As a result, most people think that Netscape software is really buggy. Even if the final release was usually reasonably unbuggy, Netscape had so doggone many people using buggy versions that theaverage impression that most people have of the software was pretty poor.
Besides, the whole point of letting "your customers" do the testing is that they find the bugs, and you fix them. Unfortunately, neither Netscape, nor any other company on earth, has the manpower to sift through bug reports from 2,000,000 customers and decide what's really important. When I reported bugs in Netscape 2.0, the bug reporting website repeatedly crashed and simply did not let me report a bug (which, of course, would have gone into a black hole anyway). But Netscape doesn't learn. Testers of the current "preview" version, 6.0, have complained in newsgroups that the bug reporting website still just doesn't allow submissions. Years later! Same problem!
Of those zillions of bug reports, I would bet that almost all of them were about the same set of 5 or 10 really obvious bugs, anyway. Buried in that haystack will be one or two interesting, difficult-to-find bugs that somebody has gone to the trouble of submitting, but nobody is looking at all these reports anyway, so it is lost.
The worst thing about this form of testing is the remarkably bad impression you will make of your company. When Userland released the first Windows version of their flagship Frontier product, I downloaded it and started working through the tutorial. Unfortunately, Frontier crashed several times. I was literally following the instructions exactly as they were printed in the tutorial, and I just could not get more than 2 minutes into the program. I felt like nobody at Userland had even done theminimum amount of testing, making sure that the tutorialworks. The low perceived quality of the product turned me off of Frontier for an awfully long time. 

4. Anybody qualified to be a good tester doesn't want to work as a tester.

This one is painful. It's very hard to hire good testers. 
With testers, like programmers, the best ones are an order of magnitude better than the average ones. At Juno, we had one tester, Jill McFarlane, who found three times as many bugs asall four other testers, combined. I'm not exaggerating, I actually measured this. She was more than twelve times more productive than the average tester. When she quit, I sent an email to the CEO saying "I'd rather have Jill on Mondays and Tuesdays than the rest of the QA team put together".
Unfortunately, most people who are that smart will tend to get bored with day-to-day testing, so the best testers tend to last for about 3 or 4 months and then move on.
The only thing to do about this problem is to recognize that it exists, and deal with it. Here are some suggestions:
  • Use testing as a career move up from technical support. Tedious as testing may be, it sure beats dealing with irate users on the phone, and this may be a way to eliminate some of the churn from the technical support side.
  • Allow testers to develop their careers by taking programming classes, and encourage the smarter ones to develop automated test suites using programming tools and scripting languages. This is a heck of a lot more interesting than testing the same dialog again and again and again.
  • Recognize that you will have a lot of turnover among your top testers. Hire aggressively to keep a steady inflow of people. Don't stop hiring just because you temporarily have a full manifest, 'cause da golden age ain't gonna last.
  • Look for "nontraditional" workers: smart teenagers, college kids, and retirees, working part time. You could create a stunningly good testing department with two or three top notch full timers and an army of kids from Bronx Science (a top-ranked high school in New York) working summers in exchange for college money.
  • Hire temps. If you hire about 10 temps to come in and bang on your software for a few days, you'll find a tremendous number of bugs. Two or three of those temps are likely to have good testing skills, in which case it's worth buying out their contracts to get them full time. Recognize in advance that some of the temps are likely to be worthless as testers; send them home and move on. That's what temp agencies are for.
Here's one way not to deal with it:
  • Don't even think of trying to tell college CS graduates that they can come work for you, but "everyone has to do a stint in QA for a while before moving on to code". I've seen a lot of this. Programmers do not make good testers, and you'll lose a good programmer, who is a lot harder to replace.
And finally. The number one stupid reason people don't hire testers:

5. I can't afford testers!

This is the stupidest, and it's the easiest to debunk.
No matter how hard it is to find testers, they are still cheaper than programmers. A lot cheaper.  And if you don't hire testers, you're going to have programmers doing testing. And if you think it's bad when you have testers churning out, just wait till you see how expensive it is to replace that star programmer, at $100,000 a year, who got sick of being told to "spend a few weeks on testing before we release" and moved on to a more professional company. You could hire three testers for a yearjust to cover the recruiter's fee on the replacement programmer.
Skimping on testers is such an outrageous false economy that I'm simply blown away that more people don't recognize it.

Reference:
http://www.joelonsoftware.com/articles/fog0000000067.html

Thursday, September 19, 2013

to control the behavior of the [] associative array

to control the behavior of the [] associative array

public class MyClass
{
    public string this[string someArg]
    {
        get { return "You called this with " + someArg; }
    }

}

class Program
{

    void Main()
    {
        MyClass x = new MyClass();
        Console.WriteLine(x["something"]);
    }
}

Reference:
http://stackoverflow.com/questions/12391745/does-c-sharp-have-array-with-index-is-a-string-like-php

Monday, September 16, 2013

在 Linux 下開發 C/C++ 的新手指南

新加入一個專案,最先面對的課題是如何正確地編譯和執行專案,可從 "It works on my machine" 如此地風行,印證這件事的困難性;再來則是閱讀負責工作相關的程式碼。至於發揮程式語言的特性,運用高階設計模式等,都是另開新專案或熟悉狀況後才有機會發揮。
過去數年沉浸在愉快的 scripting language 和開發新專案中,一直沒踏入這殘酷的世界。這篇記錄在這樣的情境下,可能需要的技能,結算一下這一個多月的心得,全都是血淚談啊 ...。

系統工具

熟悉作業系統的安裝套件是首要之務,這樣才知道如何補足需要的 header、library,或是安裝含 debug symbol 版的函式庫以執行 gdb 觀察程式或除錯。參見《自行編譯含 debug symbol 的套件 (package)》了解 Ubuntu/Debian 下的套件命名規則。
在未安裝套件的情況下,可用
  • aptitude search SUBSTRING # 找套件
  • aptitude show PACKAGE # 顯示套件用途
  • apt-file search X # 找出 X 包在那個套件裡,找 header 時很有用。
注意在用 apt-file 前要先跑 sudo apt-file update,不然搜不出東西來。
對於已安裝套件,可用
  • dpkg --search SUBSTRING # 找出安裝在那個套件,已知 header 時,適合用來找 library
  • dpkg -L PACKAGE # 列出套件內容,可用來找 header、library
  • locate SUBSTRING # 我比較常用它找 header 的位置,再觀看 header 內容
執行 locate 前記得先執行 sudo updatedb,原因同 apt-file。

編譯

連結

這一塊讓我卡了一陣子。一些粗淺心得:

執行

光只是讀程式碼就像大海撈針一樣,不太有效率。可從動態執行過程找出主要執行的路徑,再專注相關的程式碼。
1. strace 和 ltrace
srace 是分析執行行為的強大工具,google 一下會看到很多別人的個案心得,看看再自己試一試,很快能上手,不知能發揮它多少功能。這裡列自己用的兩個小案例:
反而是 ltrace 一直都想不到使用它的時機,也沒找到好的個案心得文。
2. gdb
gdb 的重要性不需多說明,之前的幾則心得:
強烈建議使用 cgdb,簡易安裝 + 無痛上手,瞬間省下大量操作和讀碼的時間。
3. 打開除錯功能
依照開發者的習性,一定會留後門讓自己方便除錯,從這角度下手也可省下不少時間:
4. 載入函式庫
除以上所言外,我另外有找過畫出程式流程的靜態和動態分析工具,像是畫 call graph 或是 C 的 cflow。不過 C++ 的靜態分析效果很糟,就沒花太多時間研究。目前用 strace 和 gdb 覺得已夠用了,不知用工具產生 call graph、class 相依圖或其它東西,是否會更有幫助。待有需求看整體的程式時再來試試。

閱讀程式碼

聽了大家的建議後,做了一些實際操作,而有些心得:
Eclipse CDT 雖然方便,後來我還是用 gj 居多。原因有幾點:
  • 我已很習慣用 vim + screen 做事,gj 最合這個情境
  • id-utils 真的是超級快
  • 我針對自己的需求更新 gj 多次,愈用愈順手
另外 ack 也滿方便的,懶得建 index 或是想比對子字串時,可直接使用。當然 id-utils 也支援子字串比對,只是暫時懶得為此修改 gj 的程式,目前大部份需求是找完整的 symbol。

熟悉 Linux 系統程式

在基本工具都上手後,打算每天抽一點時間加減讀一點相關知識。一兩年下來應該會有不錯的成果。目前打算讀《The Linux Programming Interface》,年假時試看看效果如何。
這一個月的心得以了解 /proc 為主,對觀察 CPU 用量、RAM 用量、載入那些函式庫、multi-thread、程式執行狀態等都很有幫助:

結論

即使大概知道有那些東西,還是需要實際動手的經驗,才會真的學進去。一個月下來進步了不少,不過對於要面對的戰役,還有一大段路要趕上,還有很多很多要學的。

2012-01-29 更新

補上一些後來新寫的連結。此外,《The Linux Programming Interface》 相當實用,讀 ch1 ~ 3 讓我補足不少基礎知識。ch41、42 講解 shared library 也相當值得一看。相關心得見《The Linux Programming Interface 讀書心得》

2013-07-13 更新

備忘效能分析相關的工具:

2013-07-20 更新

將後半部份內容抽出來,另寫了一篇比較完整的文章:《了解 C/C++ 程式行為的技巧》。

Reference:
http://fcamel-fc.blogspot.tw/2012/01/linux-cc.html

My Unified Theory of Bugs

I think of bugs as being classified into three fundamental kinds of bugs.

Logical: Logical bug is the most common and classical “bug.” This is your “if”s, “loop”s, and other logic in your code. It is by far the most common kind of bug in an application. (Think: it does the wrong thing)
Wiring: Wiring bug is when two different objects are miswired. For example wiring the first-name to the last-name field. It could also mean that the output of one object is not what the input of the next object expects. (Think: Data gets clobbered in process to where it is needed.)
Rendering: Rendering bug is when the output (typical some UI or a report) does not look right. The key here is that it takes a human to determine what “right” is. (Think: it “looks” wrong)
NOTE: A word of caution. Some developers think that since they are building UI everything is a rendering bug! A rendering bug would be that the button text overlaps with the button border. If you click the button and the wrong thing happens than it is either because you wired it wrong (wiring problem) or your logic is wrong (a logical bug). Rendering bugs are rare.

Typical Application Distribution (without Testability in Mind)

The first thing to notice about these three bug types is that the probability is not evenly distributed. Not only is the probability not even, but the cost of finding and fixing them is different. (I am sure you know this from experience). My experience from building web-apps tells me that the Logical bugs are by far the most common, followed by wiring and finally rendering bugs.



Cost of Finding the Bug

Logical bugs are notoriously hard to find. This is because they only show up when the right set of input conditions are present and finding that magical set of inputs or reproducing it tends to be hard. On the other hand wiring bugs are much easier to spot since the wiring of the application is mostly fixed. So if you made a wiring error, it will show up every time you execute that code, for the most part independent of input conditions. Finally, the rendering bugs are the easiest. You simply look at the page and quickly spot that something “looks” off.

Cost of Fixing the Bug

Our experience also tells us how hard it is to fix things. A logical bug is hard to fix, since you need to understand all of the code paths before you know what is wrong and can create a solution. Once the solution is created, it is really hard to be sure that we did not break the existing functionality. Wiring problems are much simpler, since they either manifest themselves with an exception or data in wrong location. Finally rendering bugs are easy since you “look” at the page and immediately know what went wrong and how to fix it. The reason it is easy to fix is that we design our application knowing that rendering will be something which will be constantly changing.

Logical Wiring Rendering
Probability of Occurrence High Medium Low
Difficulty of Discovering Difficult Easy Trivial
Cost of Fixing High Cost Medium Low
How does testability change the distribution?

It turns out that testable code has effect on the distribution of the bugs. Testable code needs:

Clear separation between classes (Testable Seems) –> clear separation between classes makes it less likely that a wiring problem is introduced. Also, less code per class lowers the probability of logical bug.
Dependency Injection –> makes wiring explicit (unlike singletons, globals or service locators).
Clear separation of Logic from Wiring –> by having wiring in a single place it is easier to verify.
The result of all of this is that the number of wiring bugs are significantly reduced. (So as a percentage we gain Logical Bugs. However total number of bugs is decreased.)



The interesting thing to notice is that you can get benefit from testable code without writing any tests. Testable code is better code! (When I hear people say that they sacrificed “good” code for testability, I know that they don’t really understand testable-code.)

We Like writing Unit-Tests

Unit-tests give you greatest bang for the buck. A unit test focuses on the most common bugs, hardest to track down and hardest to fix. And a unit-test forces you to write testable code which indirectly helps with wiring bugs. As a result when writing automated tests for your application we want to overwhelmingly focus on unit test. Unit-tests are tests which focus on the logic and focus on one class/method at a time.

Unit-tests focus on the logical bugs. Unit tests focus on your “if”s and “loop”s, a Focused unit-test does not directly check the wiring. (and certainly not rendering)
Unit-test are focused on a single CUT (class-under-test). This is important, since you want to make sure that unit-tests will not get in the way of future refactoring. Unit-tests should HELP refactoring not PREVENT refactorings. (Again, when I hear people say that tests prevent refactorings, I know that they have not understood what unit-tests are)
Unit-tests do not directly prove that wiring is OK. They do so only indirectly by forcing you to write more testable code.
Functional tests verify wiring, however there is a trade-off. You “may” have hard time refactoring if you have too many functional test OR, if you mix functional and logical tests.
Managing Your Bugs

I like to think of tests as bug management. (with the goal of bug free) Not all types of errors are equally likley, therefore I pick my battles of which tests I focus on. I find that I love unit-tests. But they need to be focused! Once a test starts testing a lot of classes in a single pass I may enjoy high coverage, but it is really hard to figure out what is going on when the test is red. It also may hinder refactorings. I tend to go very easy on Functional tests. A single test to prove that things are wired together is good enough to me.

I find that a lot of people claim that they write unit-tests, but upon closer inspection it is a mix of functional (wiring) and unit (logic) test. This happens becuase people wirte tests after code, and therefore the code is not testable. Hard to test code tends to create mockeries. (A mockery is a test which has lots of mocks, and mocks returning other mocks in order to execute the desired code) The result of a mockery is that you prove little. Your test is too high level to assert anything of interest on method level. These tests are too intimate with implementation ( the intimace comes from too many mocked interactions) making any refactorings very painful.

Reference:
http://misko.hevery.com/2008/11/17/unified-theory-of-bugs/

SLOPE function excel formula

Returns the slope of the linear regression line through data points in known_y's and known_x's. The slope is the vertical distance divided by the horizontal distance between any two points on the line, which is the rate of change along the regression line.
Syntax
SLOPE(known_y's,known_x's)
Known_y's     is an array or cell range of numeric dependent data points.
Known_x's     is the set of independent data points.
Remarks
  • The arguments must be either numbers or names, arrays, or references that contain numbers.
  • If an array or reference argument contains text, logical values, or empty cells, those values are ignored; however, cells with the value zero are included.
  • If known_y's and known_x's are empty or have a different number of data points, SLOPE returns the #N/A error value.
  • The equation for the slope of the regression line is:
where x and y are the sample means AVERAGE(known_x’s) and AVERAGE(known_y’s).
  • The underlying algorithm used in the SLOPE and INTERCEPT functions is different than the underlying algorithm used in the LINEST function. The difference between these algorithms can lead to different results when data is undetermined and collinear. For example, if the data points of the known_y's argument are 0 and the data points of the known_x's argument are 1:
    • SLOPE and INTERCEPT return a #DIV/0! error. The SLOPE and INTERCEPT algorithm is designed to look for one and only one answer, and in this case there can be more than one answer.
    • LINEST returns a value of 0. The LINEST algorithm is designed to return reasonable results for collinear data, and in this case at least one answer can be found.
Example
The example may be easier to understand if you copy it to a blank worksheet.
1
2
3
4
5
6
7
8
AB
Known yKnown x
26
35
911
17
85
74
54
FormulaDescription (Result)
=SLOPE(A2:A8,B2:B8)Slope of the linear regression line through the data points above (0.305556)

Reference:
http://office.microsoft.com/en-us/excel-help/slope-HP005209264.aspx
http://office.microsoft.com/en-us/mac-excel-help/linest-function-HA102927823.aspx?CTT=1
http://en.wikipedia.org/wiki/List_of_mathematical_symbols
http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient