The Clean Architecture in PHP 讀書筆記(一)

本書的目的是解決如何構(gòu)建一個中大型應用应狱,并且滿足:

  1. 可測性
  2. 可重構(gòu)
  3. 易處理
  4. 易維護

而對小的應用,不適合本書的原則捻脖,本書在組織上按照:

  • 先介紹平時寫PHP代碼遇到的共性問題苛坚,然后給出為什么good, solid,clean code是對于應用的健壯和可維護非常重要
  • 接著介紹了一些原則和設計模式
  • 最后使用這些原則,介紹了Clean Architecture

先介紹第一部分:The Problem With Code

Writing Good Code is Hard

If it were easy, everyone would be doing it

框架是非常好的胯究,可以幫助我們快速的開發(fā)稍计,但是前期的學習成本往往很高,特別是如果想要深入理解框架裕循,需要花費大量的經(jīng)歷臣嚣。

框架的選擇上也非常有講究净刮,每年都有新的框架產(chǎn)生、消亡茧球,我們要選擇那些文檔好的庭瑰,活力好的框架,并且框架不應該限制的應用太死抢埋,這樣我們的應用能快速的從一個框架切換到另一個框架弹灭。

另一個重要的議題是:庫函數(shù)的使用。

composer和packagist的出現(xiàn)揪垄,讓我們能更方便的使用各種各樣的庫和函數(shù)穷吮,但是使用庫同樣也會和框架一個問題,當庫做升級和廢棄的時候饥努,我們需要花費精力去遷移捡鱼、升級庫函數(shù)。

以上所有的問題都是本書希望能解決的酷愧,本書會通過架構(gòu)來嘗試解決這些問題驾诈。

What is Architecture?

我們寫任何程序的時候溶浴,都會按照某種形式組織乍迄,而軟件架構(gòu)就是我們組織程序的方式,當然這種組織是為了更好的達成軟件的目標士败。

What does Architecture Look Like?

我們應用的所有特性定義了軟件架構(gòu)闯两,這些特性可能是:

  • 文件的組織方式
  • PHP代碼和Html代碼怎么交互
  • 面向過程 or 面向?qū)ο?/li>
  • 等等....

所以定義架構(gòu)可能非常的冗長,因此我們會針對一些特點給架構(gòu)起個名字谅将,方便彼此交流漾狼,同時運用這些通用的架構(gòu)模式,也能使我們寫出更容易閱讀和理解的代碼饥臂。

舉個具體的例子:你可能只要說我在前端使用MVC模式逊躁,后端使用API web service,別人就能很容易的理解你整個應用的組織方式了隅熙。

Layers of Software

在面向?qū)ο缶幊讨兄疽拢謱蛹軜?gòu)中的層往往是將功能相同的類放到一起,而分層往往是根據(jù)應用的功能進行劃分的猛们。雖然每個應用分層會各不相同,但是一般都會有:數(shù)據(jù)庫交互層狞洋,業(yè)務層弯淘,api交互。

好的分層架構(gòu)中吉懊,彼此間松耦合庐橙,內(nèi)部高內(nèi)聚假勿。

Examples of Poor Architecture

看好的之前,先看看壞的态鳖,通過分析壞的能幫我們更好的理解為什么要這么去做转培。

Dirty,In-line PHP

<body>
  <?php $results = mysql_query(
    'SELECT * FROM customers ORDER BY name'
); ?>
  <h2>Customers</h2>
  <ul>
<?php while ($customer = mysql_fetch_assoc($results)): ?> <li><?= $customer['name'] ?></li>
<?php endwhile; ?>
  </ul>
</body>

問題:

  1. mysql_*函數(shù)已經(jīng)廢棄浆竭,使得我們升級PHP變得困難

    Choosing to use these functions today is choosing heartache tomorrow

  2. 一層就解決了所有的事

    將應用所有的事情都在一層中解決了浸须!應用主要有兩個關(guān)注點:一個是從數(shù)據(jù)庫中獲取數(shù)據(jù),另一個是是對數(shù)據(jù)進行展示邦泄。

  3. 重構(gòu)的噩夢

    考慮下面的變更

    • 表名(customers)或者列名(name)變了怎么辦删窒?有多少文件你需要去修改?如果我們要從mysql_換到PDO怎么辦顺囊?如果數(shù)據(jù)不再是從數(shù)據(jù)庫中肌索,而是從Restful API?
    • 如果我們開始使用模塊語言特碳,如Twig或者Blade诚亚?我們的數(shù)據(jù)庫邏輯深嵌入Html代碼中,我們必須要重寫所有代碼
    • 如果我們想改變名字的顯示方式午乓,我們需要更改多少地方站宗?
  4. 代碼不可測

Poor Man's MVC

看完用PHP裸寫應用后,進一步是使用mvc模式硅瞧,下面是一個例子:

class CustomersController { public function indexAction() {
    $db = Db::getInstance();
    $customers = $db->fetchAll(
      'SELECT * FROM customers ORDER BY name'
);
return [
'customers' => $customers
]; }
}
<h2>Customers</h2>
<ul>
<?php foreach ($this->customers as $customer): ?> <li><?= $customer['name'] ?></li>
<?php endforeach; ?>
</ul>

我們讓顯示邏輯和控制邏輯分離了份乒,但是仍然有問題:

  1. 仍然是硬編碼Querys
  2. 和Db類強耦合
  3. 仍然很難測試
  4. 分了兩個非常大的層

Poor Usage of Database Abstraction

使用Repository設計模式進行重構(gòu):

class CustomersController { 
  public function usersAction() {
    $repository = new CustomersRepository(); 
    $customers = $repository->getAll();
    return [
        'customers' => $customers
    ]; 
   }
}
<h2>Customers</h2>
<ul>
<?php foreach ($this->customers as $customer): ?> <li><?= $customer['name'] ?></li>
<?php endforeach; ?>
</ul>

通過使用CustomersRepositoryusersAction不需要關(guān)心數(shù)據(jù)從哪來腕唧,怎么獲取數(shù)據(jù)或辖。

但是上面的架構(gòu)仍然會有些問題:

  1. CustomersRepository強耦合

    仍然直接實例化出CustomersRepository類,意味著依賴于具體實現(xiàn)枣接,而不是抽象颂暇。

  2. 依賴問題

    由于我們?nèi)匀灰蕾囉诰唧w的類,因此在測試時候但惶,不適合單元測試耳鸯。

So how Should this Code Look?

class CustomersController extends AbstractActionController { 
  protected $customerRepository;
public function __construct(CustomerRepositoryInterface $repository) { 
  $this->customerRepository = $repository;
}
public function indexAction() { 
  return [
      'users' => $this->customerRepository->getAll()
    ];
} 
}

上面的代碼解決了幾個問題:

  1. 通過聲明依賴于接口,我們再也不依賴于具體實現(xiàn)了
  2. 可測性好膀曾,通過實現(xiàn)不同的CustomerRepositoryInterface,我們就能模擬各種case
  3. 沒有地方會影響我們升級新的PHP或者函數(shù)庫
  4. 數(shù)據(jù)來源的變化再也不會影響我們了

Coupling The Enemy

耦合是我們遇到的問題中最普遍的县爬,我們?yōu)榱烁玫睦斫怦詈希磧蓚€例子:

Spaghetti Coupling

<body>
<?php $users = mysqli_query('SELECT * FROM users'); ?>
<ul>
<?php foreach ($users as $user): ?> <li><?= $user['name'] ?></li> <?php endforeach; ?>
  </ul>
</body>

上面的代碼耦合非常嚴重添谊,高耦合意味著一旦離開另一個類或功能财喳,將無法工作。上面的例子:一旦離開database,我們不能正常工作了耳高,一旦離開瀏覽器扎瓶,我們也無法正常顯示用戶信息。

OOP Coupling

class UsersController {
public function indexAction() {
  $repo = new UserRepository(); 
  $users = $repo->getAll();
  return $users; 
}
}

UsersController離開UserRepository能工作嗎泌枪?不能概荷,因此UsersController強依賴于UserRepository

低耦合誰特別關(guān)心碌燕?

  • Developers who refactor their code.
  • Developers who like to test their code
  • Developers who like to reuse their code

How do we Reduce Coupling?

那怎么減少耦合呢误证?有下面4個方法

  1. 減少依賴:盡可能將類的職責設計的最少,減少對外部的依賴
  2. 使用依賴注入(DI)
  3. 使用接口陆蟆,而不是具體的類
  4. 使用適配器:不直接依賴于第三方庫雷厂,而是使用適配器的方式,減少對于不可控類的依賴
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叠殷,一起剝皮案震驚了整個濱河市改鲫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌林束,老刑警劉巖像棘,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異壶冒,居然都是意外死亡缕题,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門胖腾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烟零,“玉大人,你說我怎么就攤上這事咸作∠前ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵记罚,是天一觀的道長墅诡。 經(jīng)常有香客問我,道長桐智,這世上最難降的妖魔是什么末早? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮说庭,結(jié)果婚禮上然磷,老公的妹妹穿的比我還像新娘。我一直安慰自己刊驴,他們只是感情好样屠,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般痪欲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攻礼,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天业踢,我揣著相機與錄音,去河邊找鬼礁扮。 笑死知举,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的太伊。 我是一名探鬼主播雇锡,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼僚焦!你這毒婦竟也來了锰提?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芳悲,失蹤者是張志新(化名)和其女友劉穎立肘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體名扛,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡谅年,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肮韧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融蹂。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弄企,靈堂內(nèi)的尸體忽然破棺而出超燃,到底是詐尸還是另有隱情,我是刑警寧澤桩蓉,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布淋纲,位于F島的核電站,受9級特大地震影響院究,放射性物質(zhì)發(fā)生泄漏洽瞬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一业汰、第九天 我趴在偏房一處隱蔽的房頂上張望伙窃。 院中可真熱鬧,春花似錦样漆、人聲如沸为障。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳍怨。三九已至呻右,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞋喇,已是汗流浹背声滥。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侦香,地道東北人落塑。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像罐韩,于是被迫代替她去往敵國和親憾赁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容