天天看點

一個對話讓你明白架構師到底是做什麼的?

一個對話讓你明白架構師到底是做什麼的?

(程式員:)我要成為一個軟體架構師。

    (資深架構師:)對一個年輕的工程師來說,這是一個很好的目标。

(程式員:)我要上司一個團隊,還要做所有關于資料庫、架構和Web伺服器的重要決定。

    (資深架構師: )好吧,如果是這樣,你就沒必要成為一個軟體架構師了。

(程式員:)當然有必要了!我要成為一個能夠做所有重要決定的人。

    (資深架構師:)這樣很好,隻是你沒有列出哪些才是重要的決定。你剛才說的那些跟重要的決定沒有什麼關系。

(程式員:)你說什麼?難道資料庫不重要?你知道我們在資料庫上面花了多少錢嗎?

    (資深架構師:)可能很多。不過資料庫仍然不是最重要的。

(程式員:)你怎麼能這麼說呢?資料庫可是整個系統的心髒啊!所有的資料都儲存在這裡,它們在這裡被排序,被索引,被通路。如果沒有資料庫,整個系統就無法運作!

    (資深架構師:)資料庫隻不過是一個IO裝置,它提供了一些有用的工具對資料進行排序、查詢,并生成報表,但這些工具都隻是整個系統的附屬品。

(程式員:)附屬品?真是不可思議。

    (資深架構師:)是的,附屬品。你的系統業務邏輯或許會用到這些工具,但這些工具并非業務邏輯固有的組成部分。如果有必要,你可以随時替換掉這些工具,但業務邏輯還是那些業務邏輯。

(程式員:)好吧,不過如果把這些工具替換掉,我們就要重新實作業務邏輯了。

    (資深架構師:)那是你的問題。

(程式員:)為什麼這麼說?

    (資深架構師:)你認為業務邏輯依賴資料庫,但實際上不是這樣的。如果你的架構足夠好,最起碼業務邏輯不應該依賴資料庫。

(程式員:)這太瘋狂了。我怎麼可能建立出不使用這些工具的業務邏輯?

    (資深架構師:)我并沒有說業務邏輯不要使用資料庫工具,我的意思是它們不應該依賴這些工具。業務邏輯不應該知道使用的是哪一種資料庫。

(程式員:)如果業務邏輯對資料庫一無所知,它怎麼使用這些工具呢?

    (資深架構師:)依賴反轉。你要讓資料庫依賴業務邏輯,而不是讓業務邏輯依賴資料庫。

(程式員:)你的話讓人費解。

    (資深架構師:)費解嗎?我講的可是軟體架構。這個就是依賴反轉原則,讓下層政策來依賴上層政策。

(程式員:)那就更加費解了!既然上層政策(假設你指的是業務邏輯)要調用下層政策(假設你指的是資料庫),那麼就應該是上層政策依賴依賴下層政策,就像調用者依賴被調用者一樣。這是衆所周知的!

    (資深架構師:)在運作時确實是這樣的,但在編譯時我們要把依賴反轉過來。上層政策的代碼裡不要引用任何下層政策的代碼。

(程式員:)拜托!不引用代碼就無法調用它們。

    (資深架構師:)當然可以調用了。面向對象就可以做到。

(程式員:)面向對象對真實世界進行模組化,把資料和函數組合到對象裡,把代碼組織成直覺的結構。

    (資深架構師:)這是他們告訴你的嗎?

(程式員:)所有人都知道的,這不是很明顯的事情嗎?

    (資深架構師:)确實如此。不過,面向對象是可以做到不引用也能調用的。

(程式員:)好吧,那它是怎麼做到的?

    (資深架構師:)你應該知道,在面向對象系統裡對象會給其它對象發送消息的,對吧?

(程式員:)是的,當然。

    (資深架構師:)那麼你就該知道,消息發送者是不知道消息接收者是什麼類型的。

(程式員:)這要看使用的是哪一種語言了。在Java裡,發送者最起碼要知道接收者的基本類型。在Ruby裡,發送者知道接收者一定會處理它所發送的消息。

    (資深架構師:)是的。不過不管是哪一種情況,發送者都不知道接收者具體的類型。

(程式員:)嗯,是的。

    (資深架構師:)是以發送者可以給接收者傳遞一個函數,讓接收者執行這個函數,這樣發送者就不需要知道接收者是什麼類型了。

(程式員:)沒錯。我了解你的意思。不過發送者仍然依賴接收者。

    (資深架構師:)在運作時确實是的,但在編譯時不是這樣的。發送者的代碼裡并沒有引用接收者的代碼。實際上,是接收者的代碼依賴了發送者的代碼。

(程式員:)啊!但發送者仍然會依賴接收者的類。

        (資深架構師:)看來需要用代碼來說明了,我用Java來寫些代碼。首先是發送者代碼:

public class Sender {

  private Receiver receiver;

  public Sender(Receiver r) {

    receiver = r;

  }

  public void doSomething() {

    receiver.receiveThis();

  }

  public interface Receiver {

    void receiveThis();

  }

}

        (資深架構師:)下面是接收者代碼:

public class SpecificReceiver implements Sender.Receiver {

  public void receiveThis() {

    //這裡會做一些有趣的事情

  }

}

        (資深架構師:)可以看到,接收者代碼依賴了發送者代碼,也就是說SpecificReceiver依賴了Sender。同時可以看到,發送者代碼對接收者代碼一無所知。

(程式員:)哈,你作弊了。你把接收者的接口放到了發送者的類裡了。

    (資深架構師:)你開始明白了。

(程式員:)明白什麼?

    (資深架構師:)當然是架構原則啊。發送者持有接收者必須實作的接口。

(程式員:)如果這意味着我要使用内部類,那麼……

    (資深架構師:)使用内部類隻是方法之一,還有其它的方法。

(程式員:)請等一下。最開始我們讨論的是資料庫,那這些跟資料庫又有什麼關系呢?

        (資深架構師:)讓我們來看一下其它代碼吧。首先是一個簡單的業務邏輯

public class BusinessRule {

  private BusinessRuleGateway gateway;

  public BusinessRule(BusinessRuleGateway gateway) {

    this.gateway = gateway;

  }

  public void execute(String id) {

    gateway.startTransaction();

    Something thing = gateway.getSomething(id);

    thing.makeChanges();

    gateway.saveSomething(thing);

    gateway.endTransaction();

  }

}

(程式員:)這個業務邏輯沒有做什麼事情啊。

    (資深架構師:)這隻是個例子。在實際實作業務邏輯的時候,不會有很多類似這樣的類的。

(程式員:)好吧。那麼Gateway是用來做什麼的呢?

        (資深架構師:)它為業務邏輯提供了所有通路資料的方法。下面是它的代碼:

public interface BusinessRuleGateway {

  Something getSomething(String id);

  void startTransaction();

  void saveSomething(Something thing);

  void endTransaction();

}

        (資深架構師:)要注意,這個接口是在businessRules包裡面的。

(程式員:)好吧。那Something這個類又是用來做什麼的呢?

        (資深架構師:)它代表一個簡單的業務對象。我把它放在另一個叫entities的包裡。

public class Something {

  public void makeChanges() {

    //...

  }

}

        (資深架構師:)最後需要實作BusinessRuleGateway接口,這個實作類會知道相關的資料庫細節:

public class MySqlBusinessRuleGateway implements BusinessRuleGateway {

  public Something getSomething(String id) {

    // 從MySQL裡讀取一些資料

  }

  public void startTransaction() {

    // 開始一個事務

  }

  public void saveSomething(Something thing) {

    // 把資料儲存到MySQL

  }

  public void endTransaction() {

    // 結束事務

  }

}

    (資深架構師:)可以看到,業務邏輯是在運作時對資料庫進行調用的。而在編譯時,是database包引用了businessRules包。

(程式員:)好吧,我想我明白了。你用多态性隐藏了資料庫實作。不過在業務邏輯裡,仍然引用了資料庫的工具接口。

    (資深架構師:)不,不是這樣的。我們并沒有打算為業務邏輯提供所有的資料庫工具接口,而是業務邏輯建立了它們所需要的接口。在實作這些接口的時候,可以調用相應的工具。

(程式員:)嗯,這樣的話,如果業務邏輯需要所有的工具,那麼你必須把所有工具都放到Gateway接口裡。

    (資深架構師:)哈,我覺得你還是沒有明白。

(程式員:)不明白什麼?我覺得已經很清楚了。

    (資深架構師:)每個業務邏輯隻定義它所需要的接口。

(程式員:)等等,什麼意思?

    (資深架構師:)這個叫作接口分離原則。每個業務邏輯隻使用一部分資料庫工具,是以每個業務邏輯隻定義能夠滿足需要的接口。

(程式員:)這樣的話,你就會有很多接口,而且有很多實作類。

    (資深架構師:)哈,是的。你開始明白了。

(程式員:)這樣子很浪費時間!我為什麼要這樣做呢?

    (資深架構師:)這樣做是為了讓代碼更幹淨,并且節省時間。

(程式員:)算了吧,這樣隻會增加更多的代碼。

    (資深架構師:)相反,這其實是很重要的架構決定,這跟你之前所說的那些所謂的重要決定是不一樣的。

(程式員:)什麼意思?

    (資深架構師:)還記得你剛開始說你要成為一個軟體架構師嗎?你還想要做所有重要的決定?

(程式員:)是啊,我是這麼想過。

    (資深架構師:)你想做所有關于資料庫、Web服務和架構的決定。

(程式員:)是啊,而你卻說它們都不重要,還說它們其實跟重要的決定不相幹。

    (資深架構師:)沒錯,它們确實跟重要的決定不相幹。一個軟體架構師真正要做的重要決定都在資料庫、Web伺服器和架構之外。

(程式員:)但首先要先決定用什麼資料庫、Web伺服器或架構啊!

   (資深架構師:)實際上應該在開發後期才開始做這些事情——在你掌握了更多資訊之後。

   (資深架構師:)當架構師草率地決定要使用一個資料庫,後來卻發現使用檔案系統效率更高。

   (資深架構師:)當架構師草率的決定使用一個Web伺服器,後來卻發現團隊需要的不過是一個socket借口。

   (資深架構師:)當架構師草率地決定使用一個架構,後來卻發現架構提供的功能是團隊不需要的,反而給團隊帶來了諸多限制。

   (資深架構師:)當架構師在掌握了足夠多的資訊後才決定該用什麼資料庫、Web伺服器或架構。

   (資深架構師:)當架構師為團隊鑒别出運作緩慢、耗費資源的IO裝置和架構,這樣他們就可以建構飛速運作的輕量級測試環境。

   (資深架構師:)當架構師把注意力放在那些真正重要的事情上,并把那些不重要的事情放在一邊。

(程式員:)我完全不知道你在說什麼了。

    (資深架構師:)好吧,如果在若幹年後你還沒有轉做管理,或許會明白這一切的……

文檔來源:IT蝦米網

一個對話讓你明白架構師到底是做什麼的?