架構師到底是做什么的?

summery 7年前發布 | 11K 次閱讀 數據庫 軟件架構

我要成為一個軟件架構師。

對一個年輕的工程師來說,這是一個很好的目標。

我要領導一個團隊,還要做所有關于數據庫、框架和Web服務器的重要決定。

好吧,如果是這樣,你就沒必要成為一個軟件架構師了。

當然有必要了!我要成為一個能夠做所有重要決定的人。

這樣很好,只是你沒有列出哪些才是重要的決定。你剛才說的那些跟重要的決定沒有什么關系。

你說什么?難道數據庫不重要?你知道我們在數據庫上面花了多少錢嗎?

可能很多。不過數據庫仍然不是最重要的。

你怎么能這么說呢?數據庫可是整個系統的心臟啊!所有的數據都保存在這里,它們在這里被排序,被索引,被訪問。如果沒有數據庫,整個系統就無法運作!

數據庫只不過是一個IO設備,它提供了一些有用的工具對數據進行排序、查詢,并生成報表,但這些工具都只是整個系統的附屬品。

附屬品?真是不可思議。

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

好吧,不過如果把這些工具替換掉,我們就要重新實現業務邏輯了。

那是你的問題。

為什么這么說?

你認為業務邏輯依賴數據庫,但實際上不是這樣的。如果你的架構足夠好,最起碼業務邏輯不應該依賴數據庫。

這太瘋狂了。我怎么可能創建出不使用這些工具的業務邏輯?

我并沒有說業務邏輯不要使用數據庫工具,我的意思是它們不應該依賴這些工具。業務邏輯不應該知道使用的是哪一種數據庫。

如果業務邏輯對數據庫一無所知,它怎么使用這些工具呢?

依賴反轉。你要讓數據庫依賴業務邏輯,而不是讓業務邏輯依賴數據庫。

你的話讓人費解。

費解嗎?我講的可是軟件架構。這個就是依賴反轉原則,讓下層策略來依賴上層策略。

那就更加費解了!既然上層策略(假設你指的是業務邏輯)要調用下層策略(假設你指的是數據庫),那么就應該是上層策略依賴依賴下層策略,就像調用者依賴被調用者一樣。這是眾所周知的!

在運行時確實是這樣的,但在編譯時我們要把依賴反轉過來。上層策略的代碼里不要引用任何下層策略的代碼。

拜托!不引用代碼就無法調用它們。

當然可以調用了。面向對象就可以做到。

面向對象對真實世界進行建模,把數據和函數組合到對象里,把代碼組織成直觀的結構。

這是他們告訴你的嗎?

所有人都知道的,這不是很明顯的事情嗎?

確實如此。不過,面向對象是可以做到不引用也能調用的。

好吧,那它是怎么做到的?

你應該知道,在面向對象系統里對象會給其它對象發送消息的,對吧?

是的,當然。

那么你就該知道,消息發送者是不知道消息接收者是什么類型的。

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

是的。不過不管是哪一種情況,發送者都不知道接收者具體的類型。

嗯,是的。

所以發送者可以給接收者傳遞一個函數,讓接收者執行這個函數,這樣發送者就不需要知道接收者是什么類型了。

沒錯。我了解你的意思。不過發送者仍然依賴接收者。

在運行時確實是的,但在編譯時不是這樣的。發送者的代碼里并沒有引用接收者的代碼。實際上,是接收者的代碼依賴了發送者的代碼。

啊!但發送者仍然會依賴接收者的類。

看來需要用代碼來說明了,我用Java來寫些代碼。首先是發送者代碼:

package sender;
public class Sender {
  private Receiver receiver;
  public Sender(Receiver r) {
    receiver = r;
  }
  public void doSomething() {
    receiver.receiveThis();
  }
  public interface Receiver {
    void receiveThis();
  }
}

下面是接收者代碼:

package receiver;
import sender.Sender;
public class SpecificReceiver implements Sender.Receiver {
  public void receiveThis() {
    //這里會做一些有趣的事情
  }
}

可以看到,接收者代碼依賴了發送者代碼,也就是說SpecificReceiver依賴了Sender。同時可以看到,發送者代碼對接收者代碼一無所知。

哈,你作弊了。你把接收者的接口放到了發送者的類里了。

你開始明白了。

明白什么?

當然是架構原則啊。發送者持有接收者必須實現的接口。

如果這意味著我要使用內部類,那么……

使用內部類只是方法之一,還有其它的方法。

請等一下。最開始我們討論的是數據庫,那這些跟數據庫又有什么關系呢?

讓我們來看一下其它代碼吧。首先是一個簡單的業務邏輯

package businessRules;
import entities.Something;
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是用來做什么的呢?

它為業務邏輯提供了所有訪問數據的方法。下面是它的代碼:

package businessRules;
import entities.Something;
public interface BusinessRuleGateway {
  Something getSomething(String id);
  void startTransaction();
  void saveSomething(Something thing);
  void endTransaction();
}

要注意,這個接口是在businessRules包里面的。

好吧。那Something這個類又是用來做什么的呢?

它代表一個簡單的業務對象。我把它放在另一個叫entities的包里。

package entities;
public class Something {
  public void makeChanges() {
    //...
  }
}

最后需要實現BusinessRuleGateway接口,這個實現類會知道相關的數據庫細節:

package database;
import businessRules.BusinessRuleGateway;
import entities.Something;
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設備和框架,這樣他們就可以構建飛速運行的輕量級測試環境。

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

我完全不知道你在說什么了。

好吧,如果在若干年后你還沒有轉做管理,或許會明白的……

 

 

來自:http://www.infoq.com/cn/news/2016/12/What-architect-do

 

 本文由用戶 summery 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!