How to Avoid Producing Legacy Code at the Speed of Typing
英語不好翻譯很爛。英語好的去看原文。
About the Author
I am a software architect/developer/programmer.
I have a rather pragmatic approach towards programming, but I have realized that it takes a lot of discipline to be agile. I try to practice good craftsmanship and making it work.
lars.michael.dk, 2 Mar 2015 CPOL
?
原文地址:http://www.codeproject.com/Articles/882165/How-to-Avoid-Producing-Legacy-Code-at-the-Speed-of
This article provides a recipe on how to avoid producing legacy code at the speed of typing by using a proper architecture and unit testing.
Introduction
作為一個(gè)企業(yè)軟件開發(fā)者,你經(jīng)常和產(chǎn)出遺留代碼(legacy code)做斗爭(zhēng)-那種不值得維護(hù)或支持的代碼。你在不斷努力避免重寫重復(fù)的東西抱著微弱的希望以期下次你能剛好做的正確。【原文:You are constantly struggling to avoid re-writing stuff repeatedly in a faint hope that next time you will get it just right.】
遺留代碼(legacy code)的特征是,其中,不好的設(shè)計(jì)和建造模式或者依賴于過時(shí)的框架或第三方組件。一下是你可能認(rèn)識(shí)的幾個(gè)典型例子:
你或者你的團(tuán)隊(duì)產(chǎn)出了一個(gè)漂亮的,功能豐富的Windows應(yīng)用。之后,你意識(shí)到真正的需求是一個(gè)瀏覽器(web應(yīng)用)或者移動(dòng)應(yīng)用。你意識(shí)到為你的應(yīng)用替換UI將需要付出更加大量的努力,因?yàn)槟闱度肓颂囝I(lǐng)域功能(domain functionality)在它的UI里面。
另一個(gè)情景可能是你編寫了一個(gè)后端,它是深度滲透在某一個(gè)特定的ORM-例如Nhibernate或者Entity Framework-或者高度依賴與某一個(gè)RDBMS。在這一個(gè)點(diǎn)上,你想要改變策略來讓后端避免使用ORM和使用文件存儲(chǔ)的持久化數(shù)據(jù)庫(kù),但是很快你就意識(shí)到這幾乎是不可能完成的,因?yàn)槟鉪omain functionality 和data layer 是緊緊耦合。
在上述兩種情況下,你以打字的速度來生產(chǎn)遺留代碼(legacy code)。
?
然而,那還是有希望的。通過采用一些簡(jiǎn)單技巧和原則,你可以永遠(yuǎn)改變這一已經(jīng)注定的局面。
?
The Architectural Evolution
下面,我將描述三個(gè)階段標(biāo)準(zhǔn)商業(yè)軟件開發(fā)的三個(gè)典型模式。幾乎所有開發(fā)者都處于第二階段,但關(guān)鍵是要進(jìn)入第三階段,你將最終成為一個(gè)建筑模式的忍者。
?
Phase 1 - Doing it Wrong
大多數(shù)開發(fā)者聽過分層設(shè)計(jì)模式,所以很多第一次嘗試設(shè)計(jì)模式就像下面一樣-把前后端進(jìn)行功能責(zé)任分離的兩層結(jié)構(gòu):
?
到目前為止還好,但是很快你就意識(shí)到那有一個(gè)極大的問題,也就是引用程序的業(yè)務(wù)邏輯和前端以及后端糾纏在一起,并且依賴于它們。
?
Phase 2 – A Step Forward
因此,下一個(gè)嘗試是引入一個(gè)中間層-一個(gè)domain layer-由你應(yīng)用程序的真正的業(yè)務(wù)邏輯組成:
?
這種模式看起來具有迷惑性的良好結(jié)構(gòu)和解耦性。然而,事實(shí)并非如此。問題是紅色的依賴箭頭表明domain layer對(duì)后端具有天生的依賴-典型的,因?yàn)槟阍赿omain layer使用new(c#或者java)來創(chuàng)建后端類(backend classes)的實(shí)例。domain layer 和后端是緊緊耦合的。這有許多缺點(diǎn):
- domain layer 功能不能再其他的上下文環(huán)境中單獨(dú)重用。你需要把他的依賴項(xiàng)(the backend)一并引入。
- domain layer 無法單獨(dú)的進(jìn)行單元測(cè)試。你需要關(guān)聯(lián)它的依賴項(xiàng),后端代碼
-
一個(gè)后端的實(shí)現(xiàn)(例如一個(gè)使用RDMBS數(shù)據(jù)庫(kù))無法簡(jiǎn)單的被另一個(gè)后端(使用文件數(shù)據(jù)庫(kù))實(shí)現(xiàn)替換
All of these disadvantages dramatically reduces the potential lifetime of the domain layer. That is why you are producing legacy code at the speed of typing.
所有這些缺點(diǎn)都在減少domain layer的聲明周期。這是為什么你在以打字的速度產(chǎn)生遺留代碼的原因
Phase 3 – Doing it Right
你要做的其實(shí)很簡(jiǎn)單。你只需調(diào)轉(zhuǎn)代表依賴關(guān)系的紅色箭頭。這是一個(gè)微小的調(diào)整,但是結(jié)果大不同:
?
這一設(shè)計(jì)模式堅(jiān)持依賴倒置原則【Dependency Inversion Principle 】(DIP)-面向?qū)ο笤O(shè)計(jì)最重要的原則之一。重點(diǎn)是,一旦這一模式被確立-依賴關(guān)系立刻調(diào)轉(zhuǎn)-領(lǐng)域?qū)拥臐撛谏芷诘玫酱蠓仍黾?。UI需求或者轉(zhuǎn)變從Windows窗口到瀏覽器或者移動(dòng)設(shè)備,或者你的持久化存儲(chǔ)可能從關(guān)系型數(shù)據(jù)庫(kù)(RDBMS)轉(zhuǎn)換到文件型存儲(chǔ),但是現(xiàn)在所有改變都可以很容易在不修改領(lǐng)域?qū)拥那闆r下實(shí)現(xiàn)。因?yàn)檫@樣的實(shí)現(xiàn)前端和后端很好的與領(lǐng)域?qū)咏怦睢R虼?#xff0c;領(lǐng)域?qū)泳幊桃粋€(gè)代碼庫(kù)理論上你幾乎永遠(yuǎn)不用去替代-至少持續(xù)到你的業(yè)務(wù)改變或者整體框架發(fā)生改變的時(shí)候。現(xiàn)在,你可以有效地和你的遺留代碼戰(zhàn)斗了
另一方面來說,讓我給你一個(gè)簡(jiǎn)單的示例來演示如何在實(shí)踐中提升DIP:
也許你有一個(gè)product service在領(lǐng)域?qū)?#xff0c;它可以對(duì)定義在后端的products repository執(zhí)行CRUD操作。這樣經(jīng)常導(dǎo)致像下圖一樣的錯(cuò)誤指向的依賴關(guān)系:
?
這樣是因?yàn)槟悴坏貌辉趐roduct service的某處使用”new“,這就產(chǎn)生了對(duì)product repository的依賴:
var repository = new ProductRepository();?應(yīng)用DIP原則來倒轉(zhuǎn)這樣依賴關(guān)系,你必須在領(lǐng)域?qū)右越涌诘姆绞揭胍粋€(gè)product repository的抽象并且讓product repository 實(shí)現(xiàn)這個(gè)接口(implementation of this interface):?
?
現(xiàn)在,作為使用New產(chǎn)生product repository 實(shí)例的替代方案,你可以注入repository 到service 通過一個(gè)構(gòu)造參數(shù)(constructor argument):
private readonly IProductRepository _repository; public ProductService(IProductRepository repository){ _repository = repository;}
?
這是依賴注入的知識(shí)(Dependency injection DI)。我以前已經(jīng)在一篇博客中做過詳細(xì)介紹見:Think Business First.
?
一旦你正確的應(yīng)用了全部設(shè)計(jì)模式,對(duì)抗遺留代碼的目標(biāo)顯而易見:把盡量多個(gè)功能引入domain layer(領(lǐng)域?qū)?#xff09;,讓前端和后端不斷收縮同時(shí)讓domain layer(領(lǐng)域?qū)?#xff09;不斷豐滿:
這一設(shè)計(jì)模式產(chǎn)出的一個(gè)實(shí)用的副產(chǎn)品,它使它自己很容易對(duì)domain functionality(領(lǐng)域功能)進(jìn)行單元測(cè)試。因?yàn)閐omain layer 的耦合特性以及面對(duì)所有的依賴都是表現(xiàn)為抽象的(如一個(gè)接口或者一個(gè)抽象基類)。這樣很容易為他們的抽象偽造出一個(gè)對(duì)象來實(shí)現(xiàn)單元測(cè)試。所以它是”在公園散步“來守衛(wèi)整個(gè)domain layer和單元測(cè)試(unit tests)【注:原文 So it is “a walk in the park” to guard the entire domain layer with unit tests.? 】.你要做的無外乎就是努力提供超過100%覆蓋率的單元測(cè)試來保證你的domain layer足夠健壯并且堅(jiān)如磐石。這有增加了你domain layer的生命周期。
你可能已經(jīng)了解到這不僅僅是傳統(tǒng)的前端和后端,但是所有其他的組件-包括單元測(cè)試或者一個(gè)http-based 的Web API-會(huì)擔(dān)當(dāng)一個(gè)domain layer的消費(fèi)者角色。因?yàn)?#xff0c;這樣的設(shè)計(jì)模式描述起來像一個(gè)onion layers:
?
最外層的組件消費(fèi)領(lǐng)域庫(kù)代碼(domain library code)-通過提供領(lǐng)域抽象(接口或者基類)具體實(shí)現(xiàn)或者作為領(lǐng)域方法(domain functionality)的直接用戶(domain model 和services)。
無論如何,要記住:耦合的方向總是指向中心的-指向domain layer。
在這一點(diǎn)上,它看起來好像太理論化,and,well…,有點(diǎn)抽象。不過,它原則上不需要做很多。在另一篇文章中(CodeProject article of mine ),我描述和提供了一些遵從所有原則的簡(jiǎn)單的代碼。那個(gè)示例的代碼非常簡(jiǎn)單,但是非常接近于正式的產(chǎn)品代碼。
?
Summary
作為一個(gè)商業(yè)軟件開發(fā)者避免產(chǎn)生遺留代碼(legacy code)是一場(chǎng)持久的戰(zhàn)斗。想獲勝的話,執(zhí)行下列操作:
- 確保所有的依賴箭頭通過應(yīng)用依賴倒置原則(DIP)和依賴注入(DI)而指向中央和獨(dú)立的domain layer
- 不斷地健壯domain layer,通過盡可能多的把functionality移動(dòng)到domain layer,使domain layer 變得豐滿而是外層(onion layer 中的outer layer)逐漸萎縮。
-
使用單元測(cè)試(unit tests)覆蓋領(lǐng)域?qū)?#xff08;domain layer)的每個(gè)的單個(gè)功能。
?
遵循這些簡(jiǎn)單原則也許最終將匯合到一起。你的code也許將比以前擁有一個(gè)超乎想象的長(zhǎng)生命周期,因?yàn)?#xff1a;
- 領(lǐng)域?qū)拥墓δ?#xff08;domain layer functionality)可以在許多不同的上下文環(huán)境中復(fù)用。
-
100%覆蓋率的單元測(cè)試(unit test)可以使domain layer 非常健壯和堅(jiān)如磐石。
-
領(lǐng)域?qū)拥某橄?#xff08;例如持久化機(jī)制)實(shí)現(xiàn)可以輕松的替換成其他的實(shí)現(xiàn)方式
-
領(lǐng)域?qū)邮侨菀拙S護(hù)的。
?
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
轉(zhuǎn)載于:https://www.cnblogs.com/buyixiaohan/p/4627803.html
總結(jié)
以上是生活随笔為你收集整理的How to Avoid Producing Legacy Code at the Speed of Typing的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用软件测试路由器性能报告,小米路由器网
- 下一篇: Tomcat 打开一闪而过