2008年10月31日 星期五

LINQ to SQL 在 SQL server 2005 與 2000 執行效能大不同

使用一模一樣的資料庫,一個 run 在 SQL Server 2005, 一個則是 SQL Server 2000。
開發時使用 Linq to SQL連線到 2000 的資料庫。
執行時分別連線到  2000 及 2005.

發現執行的結果是一樣的,但使用 profiler 看到的 sql script 卻完全不同。
由於目前測試的是客戶的專案,不能放到這裡來公佈。


只能說,SQL Server 2000 趕快放棄吧。

2008年10月30日 星期四

OOAD(14): OOAD Project Life Cycle

  1. Feature List
  2. Use Case Diagrams
  3. Break Up the Problem
  4. Requirements
  5. Domain Analysis
  6. Preliminary Design
  7. Imlementation
  8. Delivery

2008年10月29日 星期三

OOAD(13): 程式開發方式

所有的程式寫作的開發方式,其實都是下面三個的混合

Use case driven development

一次針對一個 Use case 下一個 scenario 進行開發。再逐步完成該Use case 下所有的scenario。完成該Use case 下所有的scenario後才對下一個 Use case 開發

Feature driven development

一次對針一個系統行為的特色來開發。

Test driven development

針點系統的一個功能寫出 test cases。寫程式的目的就是通過所有的 test cases

2008年10月23日 星期四

OOAD(12): 三種不使用繼承的好方法

如果不透過繼承,又希望從別的類別得到好處。可使用

  1. Delegation (委派)
  2. Composition
  3. Aggreation

Delegation (委派)

一台轎車,如果想要可以欣賞音樂的能力,不是透過繼承(畢竟車子不是音響),而是在車子內加裝汽車音響。
因此,轎車內需要放音樂的能力時,只需要打開汽車音響即可。
class 轎車
{
  private 汽車音響 a汽車音響 = new 汽車音響();
  public void 欣賞音樂()
  {
    a汽車音響.打開();
  }
}

或者,隨時找到一台音響再打開

class 轎車

  public void 欣賞音樂()
  {

    汽車音響 a汽車音響 = new 汽車音響(); //隨時想有就可以有?這大概是軟體世界才有的能力
    a汽車音響.打開();
  }
}

Composition

一個士兵,需要有攻擊的能力,但士兵畢竟不是武器,因此士兵需要有武器。到目前為止就像委派。
但是,武器有許多種,如飛彈、槍、劍,每一種的攻擊方式都不同。

注意到 weapon 是可替換的,只要有實作 IWeapon 的武器就可以。換句話說,一整族IWeapon的武器都可以替換。
另外,weapon 是天生就存在於 Soldier 內的。一旦 Soldier 被 destoryed, weapon 就不存在了。

class Soldier
{
    private IWeapon weapon = new Sword();
    public void Attack()
    {
      weapon.Attack();
    }
  }

  interface IWeapon
  {
    void Attack();
  }

  class Sword : IWeapon
  {
    public void Attack() { }
  }

Aggregation

aggregation 與 Composition 類似,但結構更鬆散,更容易 resuse。上述的例子,weapon 只能生存在 Soldier 的生命週期內,並不合理。如果改成下面的例子,就是 aggregation 了。注意到 weapon 是由建構子傳進去的。當soldier1 被destoryed 後,sword 並不隨之消減。也就是說,可以被 soldier2 再拿去用。

class Soldier
  {
    private IWeapon weapon;
    public Soldier(IWeapon weapon)
    {
      this.weapon = weapon;
    }
    public void Attack()
    {
      weapon.Attack();
    }
  }

  interface IWeapon
  {
    void Attack();
  }

  class Sword : IWeapon
  {
    public void Attack() { }
  }

class Program
  {
    static void Main(string[] args)
    {
      Sword sword = new Sword();
      Soldier soldier1 = new Soldier(sword);
      soldier1.Attack();
    }
  }


在日常生活上,Aggreation 遠較 Composition 多見,這同時也反應到軟體工程上。畢竟物件導向工程是模擬真實的世界。

OOAD(11):Liskov Substitution Principle(LSP)

LSP (替換原則) 是談何謂「良好的繼承」。

  • 子類別應該可以使用其基礎類別替代,而不會發生的誤。如果會發生錯誤,就代表使用繼承失敗。
  • Liskov代換原則是繼承之所以能重複使用的基石,只有當衍生類別可以替換掉基礎類別,且軟體的功能不受影響時,其類別才算真正的被重複使用,而衍生類別也才能夠在基礎類別的基礎上增加新的行為。
  • Liskov代換原則要求凡是基礎類別使用的地方,衍生類別一定適用,故衍生類別必須包含全部基礎類別的介面
  • 針對違反LSP設計時可行的重構(Refactoring)方式
    • 當類別A錯誤的繼承類別B時,可建構一個新的抽象類別C,作為2個具體類別A,B的父類別
    • 當類別A錯誤的繼承類別B時,可重構為類別B委派(Delegate)類別A

 

from http://irw.ncut.edu.tw/peterju/se.html

OOAD(10):Open-Closed Principle(OCP)

  • 模組應當敞開擴充大門,但關閉修改之窗。
  • 如何達成開閉原則,關鍵在抽象化。
  • 不允許更改的是系統的抽象層,允許擴充的是系統的實作層。
  • OCP的另一個角度是EVP對可變性的封裝原則(Principle of Encapsulation of Variation)即找到一個系統的可變因素,並將之封裝起來。
  • 可變性必須被封裝,那不同的可變性呢?應用繼承來處理,因此繼承應被視為封裝變化的方法,但繼承的層數避免超過2層以免不同的可變性混和。
  • 應避免將單純的流程控制轉移語句改寫成多型,除非內含了某種商務邏輯。
  • 所有的設計樣式(Design Pattern)都是針對不同的可變性封裝,使系統在不同的角度上達到開閉原則。

from http://irw.ncut.edu.tw/peterju/se.html

OOAD(9):物件導向類別設計的法則

  • 開閉原則(Open-Closed Principle ; OCP)
  • Liskov代換原則(Liskov Substitution Principle ; LSP)
  • 依賴倒轉原則(Dependency Inversion Principle ; DIP)
  • 介面隔離原則(Interface Segregation Principle ; ISP)
  • 組合/聚合重複使用原則(Composition / Aggregation Principle ; CARP)
  • Demeter原則(Law of Demeter; LoD

2008年10月19日 星期日

OOAD(8): 不確定的事即是風險

當得到需求後,發現有些事情是「不確定」的。這些不確定的事,就是未來的風險。
在專案的過程中,最重要的就是想辦法降低風險。
如果這些風險,仍然是需求不夠清楚時,那還是回頭問客戶吧。

問完客戶後,知道了需求是什麼,記得要技術評估一下,要了解大概該需求未來該如何實作。否則容易引發「技術風險」。
但在技術評估階段時有個重點需要注意,「不要埋頭開始寫程式」。此時的最重要的目的仍是「降低風險」。
過早實作,容易模糊了此時此刻的重點,反而因為尚未了解所有的需求,不但可能做錯了方向,還容易增加專案時程或成本的風險呢。

2008年10月17日 星期五

自訂 assembly 的位置

http://msdn.microsoft.com/en-us/library/yx7xezcf(VS.71).aspx  中有描述當CLR程式執行時,載入 assembly 的順序。
因此,可以使用如下的設定,讓程式執時,除了搜尋執行程式的路徑外,也能搜尋自訂的路徑

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="myBin"/>
    </assemblyBinding>
  </runtime>
</configuration>
以上程式執時,會搜尋 .\myBin 下的所有assembly

WSDL 的主機名稱換成 host name

在取得 web service 的 WSDL 時,發生了一個怪現象

例如, 我要取得 http://server1.domain.com.tw/service1/myService.svc?wsdl,但在其內容,卻包含下面這一段

<xsd:import namespace="http://tempuri.org/" schemalocation="http://host1/service1/myService.svc?xsd=xsd0" />

注意到 server1.domain.com.tw 是對外的 FQDN,而 host1 是該台機器的 host name。

但,host1 對於外部來說,是不可解析的。 怎麼辦呢?

又爬了文,找到 http://blogs.msdn.com/wenlong/archive/2007/08/02/how-to-change-hostname-in-wsdl-of-an-iis-hosted-service.aspx

原來,只需要在 IIS 中設網站的識別碼,如下圖。

image 

按確定後,記得要 IISReset

2008年10月7日 星期二

OOAD(7): 常見的 check

繼承是因為行為發生變化

如果不是行為發生變化,就不值得繼承

善用適合的類別作為屬性

如果子類別只是較父類別多了一些屬性,而非行為發生變化,則可考慮使用Dictionay 作為屬性,而不要子類別了。

舉例來說,下面的程式是不好的。

class Parent
{
   public string Name;
   public void Fly();
}

class Child1 : Parent
{
   public string Color;
   public string AliasName;
}

class Child2 : Parent
{
   public string BackColor;
}

class Child3 : Parent
{
   public string BorderColor;
}

原因是 Child1, Child2, Child3 在行為上根本不會發生變化。還是只有 Parent 的Fly。因此,只需要修改成下面的程式,就不需要子類別了。

class Parent
{
   public string Name;
   public void Fly();
   public Dictionary  OtherProperties {get; set;}
}

2008年10月5日 星期日

Visual Studio 2010

雖然 VS2010看來還要很久才會到來,但有些功能我卻是迫不及待。以下是部份的功能

  • 支援UML
    • Activity Diagram
    • Component Diagram
    • Layer Diagram
    • Logical Class Diagram
    • Sequence Diagram
    • User Case Diagram
  • Requirements management
  • Buttom up design / Top-Down design
  • support .net framework 4.0
  • Layer diagram
  • Debug history
  • jQuery support

2008年10月2日 星期四

ADO.NET Data Service 與 LINQ to SQL

今天在第一次測試時,碰到這樣的訊息

問題

The server encountered an error processing the request. See server logs for more details.

image

測試的過程是這樣的

  1. 建立一個 Web application
  2. 建立一個 Linq to sql dbml file,上頭拖了一個 Company 的 table
  3. 建立一個 ADO.NET Data Service,並修改名稱為 Service.svc
  4. 修改 Service.svc.cs 如下
    public class Service : DataService
    {
        public static void InitializeService(IDataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
        }
    }

解決

頁面上什麼也沒有,只有這一行字。Google了一下。原來加上一行 attribute 即可
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    public class Service : DataService
    {
        public static void InitializeService(IDataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
        }
    }

image

意思是 Company 沒有key

所以在dbml 上加上 partial class, code 如下

  [DataServiceKey("OID")]
  partial class Company
  {
  }
如此一來就解決了問題。

2008年10月1日 星期三

OOAD(6): textual analysis

Textual analysis

  1. 在use case 中尋找名詞與動詞,可用來尋找 class 及其 method
  2. 一個好的 use case 應該精準並清楚地描述系統行為,並容易了解。因此,進行 textual analysis 是快速而容易的。
  3. 當一個 use case 無法或不容易進行 textual analysis 時,就應該進行重寫來重新描述。
  4. 注意到名詞與動詞並非一定是 class 與 method,常常需要逐字檢查。例如「飛機進行轟炸」,不注意的話會以為進行是動詞,而把轟炸當名詞。與客戶重新確認後,發現是客戶描述不正確。經修改後的use case 就會改成「飛機轟炸都市」,就會產生 飛機.轟炸(都市) 的結果。
  5. 即使名詞經分析後並未成為我們需要的 class ,也需要注意。因為這個名詞通常也可能是 actor。

Textual analysis 完畢後,接著可進行更新類別圖 (class diagram)

OOAD(5): Design Principles

Avoid duplicate code

當發現重複的程式碼片斷時,通常代表「設計」有問題。例如責任放錯了類別,或者是否應該delegate到別的類別等等。

Encapsulate what varies

Code to an interface rather than an implementation

Each class in your should have only one reason to change

Classes are about behavior and fuctionlity

在系統中的每個物件只有單一的責任

Share with Facebook