將 ASP.NET 網站移轉至 IIS 7 時碰到的問題

9/28/2009
總算有機會把原本在 IIS 6 上面跑的 Web 專案移轉到 Windows Server 2008 + IIS 7 環境,但部署完成後,瀏覽網站時卻發生錯誤:

Request is not available in this context.


Framework Design Guidelines 筆記 (4): 低門檻原則

9/23/2009
關鍵詞彙
  • Framework(框架;類別庫)
  • The principle of low barrier to entry(低門檻原則)
低門檻原則指的是:
框架必須提供一個較低的入門門檻,讓初學者可以透過簡單的小實驗來學習這套框架。 (p.21)
然而,一套類別庫要做到功能強大、完整,同時又要易學易用,卻不是那麼容易。像 .NET Framework 這類比較大型的類別庫,裡面的類別非常多,為了方便學習、查找,就一定得要有適當、合理的分類和命名,否則可能寫了好多好用的工具,卻藏在類別庫中某個很深層的角落沒人發現。這分類的關鍵,主要就在 namespace 的運用。

因此,若要設計出容易學習的 API,應做到下列幾點(p.22-23):
  • 平常寫程式經常用到的類別要能很容易找到,而且成員的數量要適中。比如說,一個 namespace 裡面包含 500 個型別,結果其中只有少數幾個是真正關鍵或常用的。這種齊頭式平等的分類方式不僅不易學習,在撰寫程式的時候也多少會帶來困擾(IntelliSense 一次列出一拖拉庫的成員清單)。
  • 要讓開發人員隨手捻來就能立即使用。如果使用某個類別之前,還得先建立其他類別的 instances、設定一堆必要的屬性、以及寫很多初始化的程式碼,那麼,初學者為了寫一點實驗用的小程式就得大費周章,可能試個幾次就打退堂鼓了。
  • 要很容易找到錯誤的原因,以便迅速解決問題。例如,API 應該儘量考慮可能發生的 exceptions,並且在例外發生時丟出清楚的錯誤訊息,讓程式設計師能夠從訊息來判斷哪裡出了問題。
關於最後一點,我個人的感受特別深,因為印象中我總是經常重複這樣的牢騷建議。十年前碰到隱藏錯誤或訊息曖昧不明的情況,十年後似乎也沒有太大的改變,還是得不斷拜託寫底層元件的人不要再丟出「發生錯誤了!」這種只有神才知道原因的訊息。(更別提 catch 區塊裡面什麼都沒有的寫法)

據我瞭解,支持「精簡錯誤訊息」的一個主要考量是:end users 根本看不懂那些底層的詳細錯誤訊息;顯示太詳細反而造成使用者的困擾。

我想問題的關鍵在於:錯誤訊息是有分類型或等級的。一般使用者的操作錯誤,應用程式自然很容易顯示最精簡、易懂的訊息(例如:請先選擇這個,再按那個),那是比較偏向 warning、information 之類的告知訊息。而寫底層 API 的設計師要處理的卻是比較特殊的「例外狀況」,這些例外狀況所引發的錯誤訊息雖然對 end users 來說沒太大用處,但卻是維護人員接到電話或 e-mail 時一個非常重要的線索。把這個線索隱藏起來,就像鴕鳥把頭埋進沙堆一樣,對解決問題真的一點幫助也沒有。

詳細描述錯誤訊息只是設計 API 的最基本要求而已,Chris Sells 認為,好的錯誤訊息除了描述 what,還要提示如何解決:
In my own programming, I dearly love error messages that say what I did wrong and how to fix it. All too often, all I get is the former, when all I really care about is the latter. (p.23)

相關文章

審校碎碎念(二):靈活的翻譯?

9/20/2009
例 1:These techniques do not replace other approaches to software testing but can significantly increase testing effectiveness, help identify and reduce redundancy, and also reduce the susceptibility of the testing effort to the pesticide paradox.

Greenfield 是綠海還是綠地?

9/08/2009

Framework Design Guidelines 筆記 (3) : 情節驅動設計

9/04/2009
這是 Framework Design Guidelines 2nd edition 筆記的第 3 篇,基本介紹和表示法請參閱第 1 篇第 2 篇
關鍵詞彙
  • scenario-driven design(情節驅動設計)
  • use cases(使用案例)
  • test-driven development, TDD(測試驅動開發)
以下開始內容摘要,我自己的話用暗橘色標示
==========================================
情節驅動設計的原則

我們建議框架設計師先就框架使用者(按:我們常說的 app programmers)所欲處理的主要情節來撰寫程式碼,之後再根據這些範例程式碼來設計合適的物件模型。

此做法有點類似 TDD 或使用案例驅動的設計方式,但 TDD 算是比較重量級的方法,因為它除了驅動 APIs 的設計之外,還有一些別的目標;使用案例則是從較高的層次來描述情節,而不是從個別 API 呼叫的角度來思考。(scenario、use case、requirement、function,這幾個名詞也許是因為涵義相近或有重疊之處,翻譯成中文時常見有混用的情況,例如把 scenario 稱作「需求」,把 use case 稱作「功能」等等,如此固然「平易近人」,在某些場合卻可能過於含糊籠統。作者在書中對 scenario 和 use case 有比較明確的界定,閱讀時不妨留意一下。)

框架設計原則

設計框架的第一步,必須先從一組使用情節,以及實作這些情節的範例程式碼開始。

Krzysztof Cwalina:對此原則,我有句話要補充:「想要設計一個好框架,除此之外沒別的辦法。」如果這本書只能介紹一個設計原則,我一定會選這個。

框架設計師經常犯的錯誤,是先以各種設計方法論來設計物件模型,然後為這些設計好的 API 撰寫範例程式。問題是,大多數的設計方法(包括物件導向設計)都是以可維護性為主要考量,而未著重在 API 的易用性;它們非常適合用來設計僅供內部使用的程式架構,但不適合用來設計大型框架的共用 API 層。
  • DO 先為主要情節撰寫範例程式碼,然後再從這些範例程式發展出對應的物件模型。
舉例來說,假設要設計一個 API 來計算某段程式的執行時間,你會先寫出類似下面的情節程式範例(有點像虛擬碼,注意裡面同時有 C# 與 VB 語法):
// scenario #1: 計算執行時間
Stopwatch watch = Stopwatch.StartNew();
DoSomething();
Console.WriteLine(watch.Elapsed);

// scenario #2: 重複使用 stopwatch
Dim watch As Stopwatch = Stopwatch.StartNew()
DoSomething();
Console.WriteLine(watch.ElapsedMilliseconds)

watch.Reset()
watch.Start()
DoSomething()
Console.WriteLine(watch.Elapsed)

然後,根據這些程式碼發展出以下物件模型:
public class StopWatch
{
public static StopWatch StartNew();

public void Start();
public void Reset();

public TimeSpan Elapsed { get; }
public long ElapsedMilliseconds { get; }
...
}

也就是說,情節驅動設計就是從 API 使用者的角度出發,先想想看會怎麼用這些 API,並寫下範例程式碼。這些範例程式碼等於是 API 物件模型的需求規格,而接下來的工作就是根據這些範例程式碼來設計符合該需求的物件模型(類別)。

這種設計方式,也可以說是由上而下,從外(外部需求)到內(內部實作)吧!

相關文章

.NET Framework 4.0 新功能:Code Contracts

9/03/2009
MSDN Magazine 2009 年 8 月號CLR Inside Out 專欄主題是 .NET Framework 4.0 的新功能:Code Contracts,由 Melitta Andersen 執筆。正如其名稱所揭示的,這項新功能的目的即在於進一步支援合約式設計(design by contract)的概念。


Framework Design Guidelines 筆記 (2) : 漸進式框架

9/01/2009
摘自:Framework Design Guidelines 2nd edition by Krzysztof Cwalina & Brad Abrams
Key Terms
  • progressive framework: 漸進式框架
表示法
  • DO: 表示強烈建議、務必遵守的設計原則。
  • CONSIDER: 建議考慮這麼做。
  • DO NOT: 禁止事項。
  • AVOID: 儘量避免的做法。
=============================
  • DO 設計框架時要兼顧功能強大與容易使用。

    如 Alan Kay 所說:「簡單的東西就要有簡單的設計,而碰到複雜的情況時也應該要能應付。」(Simple things should be simple and complex things should be possible.)
  • DO 設計時應考量廣大開發人員的各種程式設計風格、需求、以及不同的技術水平。
  • DO 設計時應考量支援各種程式語言。
Krzysztof Cwalina:設計框架給跟你相似的使用者是很簡單的,而要設計給跟你不同的使用者就非常困難了。許多 APIs 都是由領域專家所設計,但老實講,只有領域專家覺得它們好用。

Brad Adams:我們在設計 APIs 時往往只考慮到自己,而非客戶的需要。
漸進式框架

一套框架要能同時兼顧各類開發人員、需求、和程式語言,是相當困難且昂貴的事業。以往,開發軟體元件的廠商是針對特定開發族群和特定需求來提供多種解決方案,例如微軟的 Visual Basic、MFC、ATL 等等。

這些特定用途的 APIs 雖然強大好用,卻有個主要缺點:當開發人員要從目前的技術領域移向另一塊領域時,學習曲線會非常陡峭,因為那等於是要學習另一套新的東西。

比較好的解決方式,是提供所謂的漸進式框架(progressive framework)。這種框架的特色是兼顧各類型的開發人員,且適用範圍較廣,從比較簡單的需求到進階的應用都能應付。

.NET Framework 即屬於漸進式框架,它有單一的程式撰寫模型,支援廣泛類型的應用需求與技術層次,學習曲線也較為緩和,能夠由簡入繁、循序漸進。

相關文章

Framework Design Guidelines 筆記 (1) : 優良框架的特徵

8/31/2009

小引
網路上有不少人推薦這本書,我也覺得是本內容紮實的好書。原以為應該很快就能看到中文版了,但一直到第二版都沒看到影子(中國大陸有出第一版的簡體版)。我想,這多少是因為從書名來看,它似乎是專門寫給 framework designers 看的,目標讀者的市場太小了。

其實,在目前的程式設計環境,開發人員多少都得碰觸到共用類別/元件的撰寫,即便是元件的使用者(或 app programmers),瞭解好的程式寫法與設計原則,對提升軟體品質也大有幫助。

另一個原因,也許和書中所提的類別設計原則與程式寫法(如命名規則、exception 的處理建議等)比較細緻有關。撰寫一般的 app code 時,多以結果導向,即程式能跑、功能正確就行,至於 end users 看不到的程式碼,自己想怎麼寫就怎麼寫。尤其在專案時程很趕,與時間賽跑的情況下(哪個案子不是這樣?),哪還有閒功夫去琢磨:這個變數怎麼命名比較好、那些 code 是否要抽離成共用類別或函式、有哪些 patterns 可以 reuse 呢?

但我一直覺得,就像人品一樣,程式碼的品質會反映在軟體系統的外在行為上,使用者必定能感受到。也許他們看不到程式碼寫得怎麼樣,但是操作介面難用、執行效能差、不易擴充(要求稍微改一點東西就說程式很難改)、大小 bug 不斷...等等,都顯示出軟體系統的內在(架構與設計)出了問題。

我打算節譯部分內容,放在部落格上。一方面作筆記,一方面也向大家推薦這本書。至於會寫多少篇,倒也沒認真去想,若有時間的話,看到哪兒就寫到哪兒吧。

以下開始內容摘要,我自己的話是用暗橘色標示

優良框架的特徵
  1. 優良的框架一定很精簡

    大部分的框架都不缺功能,因為只要需求明確,增加功能就很容易。
    另一方面,當開發過程中出現時程壓力、功能蔓延(feature creep)等問題,或想要滿足每一項枝微末節的需求時,簡單性(simplicity)通常就會被犧牲掉。
    如果多考慮一下設計的複雜性,你會發現,把目前版本的一些功能砍掉,並將時間花在思考下一個版本該如何設計才適當,這麼做通常會有比較好的結果。
    如框架設計師常說的:「功能隨時可以加,但要將它移除可就難了。」
  2. 優良的框架須付出較高的設計成本

    框架設計應該是開發流程中的一項明確且專屬的工作,因為這項工作需要謹慎規劃、組織人力、並有效執行,它不應流於實作過程中的附屬產品。

    (問題是有多少軟體公司願意聘用專職的 framework designer?看他好像閒閒沒事在看書的時候,可能還是忍不住叫他去打雜吧。正所謂物盡其用..... >_<|||)
  3. 優良的框架充滿權衡取捨

    沒有所謂「完美設計」這種東西。設計其實就是一連串的權衡取捨,然後做出正確決定。你得瞭解各種選項的優點和缺點。如果在設計時都沒有碰到需要取捨的情況,那不是你發現銀彈了,而是可能很多重要的地方都沒考慮到。
  4. 優良的框架會善用既有成果
  5. 優良的框架能持續演進
  6. 優良的框架易於整合
  7. 優良的框架具備一致性
===================
說到設計的簡單性,還真的不簡單。
碰到需要處理大量資料的情況就直接開個超大陣列,這種寫法簡單嗎?簡單,而且通常過於天真。

我曾看過一個 .NET 類別庫裡面有個工具類別提供一個叫做 CreateDirectory 的 method。好奇它跟 System.IO.Directory 的 CreateDirectory 有甚麼不同,挖出原始碼一看:

public void CreateDirectory(string path)
{
  If (!System.IO.Directory.Exists(path))
  {
    System.IO.Directory.CreateDirectory(path);
  }
}

這函式設計得簡單嗎?簡單,但是多餘。這種連雞肋的價值都談不上的 method,除了增加類別庫的體積和重量之外,別無益處。

也許設計者希望使用此類別的程式設計師少寫一些 code,但問題是,當欲建立的目錄已經存在時,System.IO.Directory.CreateDirectory 本來就不會發生錯誤,何必多此一舉呢?

元件或框架設計師必須非常瞭解基礎類別庫的行為,才不會為了提供方便的工具而重新發明一堆輪子。增加 methods 時若未審慎考量,一旦使用類別庫的程式設計師用慣了,專案中到處充斥這些 method calls,將來要拿掉可就麻煩了。

請神容易送神難。框架設計師豈可不慎?

相關文章
技術提供:Blogger.
回頂端⬆️