日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
系統(tǒng)困境與軟件復(fù)雜度,為什么我們的系統(tǒng)會(huì)如此復(fù)雜

一、前言

建筑師不會(huì)輕易給100層的高樓增加一個(gè)地下室,但我們卻經(jīng)常在干這樣的事,并且總有人會(huì)對(duì)你說(shuō),“這個(gè)需求很簡(jiǎn)單”。到土里埋個(gè)地雷,這確實(shí)不復(fù)雜,但我們往往面臨的真實(shí)場(chǎng)景其實(shí)是:“在這片雷區(qū)里加一個(gè)雷”,而雷區(qū)里哪里有雷,任何人都不知道 。

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括南昌縣網(wǎng)站建設(shè)、南昌縣網(wǎng)站制作、南昌縣網(wǎng)頁(yè)制作以及南昌縣網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,南昌縣網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到南昌縣省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

二、什么是復(fù)雜性

我們一直在說(shuō)系統(tǒng)很復(fù)雜,那到底什么是復(fù)雜性?關(guān)于復(fù)雜的定義有很多種,其中比較有代表的是Thomas J. McCabe 在1976提出的理性派的復(fù)雜性度量,與John Ousterhout 教授提出的感性派的復(fù)雜性認(rèn)知。

1.理性度量

復(fù)雜性并不是什么新概念,早在上世紀(jì)70年代,軟件就已經(jīng)極其復(fù)雜,開(kāi)發(fā)與維護(hù)的成本都非常高。1976年McCabe&Associates公司開(kāi)始對(duì)軟件進(jìn)行結(jié)構(gòu)測(cè)試,并提出了McCabe Cyclomatic Complexity Metric,我們也稱之為McCabe圈復(fù)雜度。它通過(guò)多個(gè)維度來(lái)度量軟件的復(fù)雜度,從而判斷軟件當(dāng)前的開(kāi)發(fā)/維護(hù)成本。

圈復(fù)雜度

代碼狀況

測(cè)性成本

維護(hù)成本

圈復(fù)雜度1 - 10

清晰/結(jié)構(gòu)化

可測(cè)性高

維護(hù)成本低

圈復(fù)雜度10 - 20

復(fù)雜

可測(cè)性中

維護(hù)成本中

圈復(fù)雜度20 - 30

非常復(fù)雜

可測(cè)性低

維護(hù)成本高

圈復(fù)雜度30

不可讀

不可測(cè)

維護(hù)成本非常高

2.感性認(rèn)知

復(fù)雜度高的代碼一定不是好代碼,但復(fù)雜度低的也不一定就是好代碼。John Ousterhout教授認(rèn)為軟件的復(fù)雜性相對(duì)理性的分析,可能更偏感性的認(rèn)知。

Complexity is anything that makes software hard to understand or to modify

-- John Ousterhout 《A Philosophy of Software Design》

譯:所謂復(fù)雜性,就是任何使得軟件難于理解和修改的因素。

50年后的今天,John Ousterhout教授在 A Philosophy of Software Design 書中提到了一個(gè)非常主觀的見(jiàn)解,復(fù)雜性就是任何使得軟件難于理解和修改的因素。

模糊性與依賴性是引起復(fù)雜性的2個(gè)主要因素,模糊性產(chǎn)生了最直接的復(fù)雜度,讓我們很難讀懂代碼真正想表達(dá)的含義,無(wú)法讀懂這些代碼,也就意味著我們更難去改變它。而依賴性又導(dǎo)致了復(fù)雜性不斷傳遞,不斷外溢的復(fù)雜性最終導(dǎo)致系統(tǒng)的無(wú)限腐化,一旦代碼變成意大利面條,幾乎不可能修復(fù),成本將成指數(shù)倍增長(zhǎng)。

三、復(fù)雜性的表現(xiàn)形式

復(fù)雜的系統(tǒng)往往也有一些非常明顯的特征,John教授將它抽象為變更放大(Change amplification)、認(rèn)知負(fù)荷(Cognitive load)與未知的未知(Unknown unknowns)這3類。當(dāng)我們的系統(tǒng)出現(xiàn)這3個(gè)特征,說(shuō)明我們的系統(tǒng)已經(jīng)開(kāi)始逐漸變得復(fù)雜了。

癥狀1-變更放大

Change amplification: a seemingly simple change requires code modifications in many different places.

-- John Ousterhout 《A Philosophy of Software Design》

譯:看似簡(jiǎn)單的變更需要在許多不同地方進(jìn)行代碼修改。

變更放大(Change amplification)指得是看似簡(jiǎn)單的變更需要在許多不同地方進(jìn)行代碼修改。比較典型的代表是Ctrl-CV式代碼開(kāi)發(fā),領(lǐng)域模型缺少內(nèi)聚與收攏,當(dāng)需要對(duì)某段業(yè)務(wù)進(jìn)行調(diào)整時(shí),需要改動(dòng)多個(gè)模塊以適應(yīng)業(yè)務(wù)的發(fā)展。

/**
* 銷售撿入客戶
*/
public void pick(String salesId, String customerId) {
// 查詢客戶總數(shù)
long customerCnt = customerDao.findCustomerCount(salesId);
// 查詢銷售庫(kù)容
long capacity = capacityDao.findSalesCapacity(salesId);
// 判斷是否超額
if(customerCnt >= capacity) {
throws new BizException("capacity over limit");
}
// 代碼省略 do customer pick
}

在CRM領(lǐng)域,銷售撿入客戶時(shí)需要進(jìn)行庫(kù)容判斷,這段代碼也確實(shí)可以滿足需求。但隨著業(yè)務(wù)的發(fā)展,簽約的客戶要調(diào)整為不占庫(kù)容。而客戶除了銷售撿入,還包括主管分發(fā)、leads分發(fā)、手工錄入、數(shù)據(jù)采買等多個(gè)場(chǎng)景,如果沒(méi)對(duì)庫(kù)容域做模型的收攏,一個(gè)簡(jiǎn)單的邏輯調(diào)整,就需要我們?cè)诙鄠€(gè)場(chǎng)景做適配才能滿足訴求。

癥狀2-認(rèn)知負(fù)荷

Cognitive load: how much a developer needs to know in order to complete a task.

-- John Ousterhout 《A Philosophy of Software Design》

譯:開(kāi)發(fā)人員需要多少知識(shí)才能完成一項(xiàng)任務(wù)。

認(rèn)知負(fù)荷(Cognitive load)是指開(kāi)發(fā)人員需要多少知識(shí)才能完成一項(xiàng)任務(wù)。使用功能性框架時(shí),我們希望它操作簡(jiǎn)單,部署復(fù)雜系統(tǒng)時(shí),我們希望它架構(gòu)清晰,其實(shí)都是降低一項(xiàng)任務(wù)所需的成本。盲目的追求高端技術(shù),設(shè)計(jì)復(fù)雜系統(tǒng),增加學(xué)習(xí)與理解成本都屬于本末倒置的一種。

TMF是整個(gè)星環(huán)的支柱,也是業(yè)務(wù)中臺(tái)面向可復(fù)用可擴(kuò)展架構(gòu)的核心。但TMF太過(guò)復(fù)雜,認(rèn)知與學(xué)習(xí)成本非常高,我們?nèi)粘V兴媾R的一些擴(kuò)展訴求99%(或者應(yīng)該說(shuō)100%)都不適合TMF,可能通過(guò)一些設(shè)計(jì)模式或者就是一些if else,可能更適合解決我們的問(wèn)題。

除此之外,還包括一些簡(jiǎn)單搜索場(chǎng)景卻用到了blink等流式引擎,簡(jiǎn)單后臺(tái)系統(tǒng)通過(guò)DDD進(jìn)行構(gòu)建,幾個(gè)商品發(fā)布的狀態(tài)機(jī)轉(zhuǎn)換用上了規(guī)則引擎等等,都屬于認(rèn)知負(fù)荷復(fù)雜度的一種。

癥狀3-未知的未知

Unknown unknowns: it is not obvious which pieces of code must be modified to complete a task

-- John Ousterhout 《A Philosophy of Software Design》

譯:必須修改哪些代碼才能完成任務(wù)。

未知的未知(Unknown unknowns)是指必須修改哪些代碼才能完成任務(wù),或者說(shuō)開(kāi)發(fā)人員必須獲得哪些信息才能成功地執(zhí)行任務(wù)。這一項(xiàng)也是John Ousterhout教授認(rèn)為復(fù)雜性中最糟糕的一個(gè)表現(xiàn)形式。

當(dāng)你維護(hù)一個(gè)有20年歷史的項(xiàng)目時(shí),這種問(wèn)題的出來(lái)相對(duì)而言就沒(méi)那么意外。由于代碼的混亂與文檔的缺失,導(dǎo)致你無(wú)法掌控一個(gè)500萬(wàn)行代碼的應(yīng)用,并且代碼本身也沒(méi)有明顯表現(xiàn)出它們應(yīng)該要闡述的內(nèi)容。這時(shí)“未知的未知”出現(xiàn)了,你不知道改動(dòng)的這行代碼是否能讓程序正常運(yùn)轉(zhuǎn),也不知道這行代碼的改動(dòng)是否又會(huì)引發(fā)新的問(wèn)題。這時(shí)候我們發(fā)現(xiàn),那些“上帝類”真的就只有上帝能拯救了。

四、為什么會(huì)產(chǎn)生復(fù)雜性

那軟件為什么越來(lái)越復(fù)雜,是不是減少一些犯錯(cuò)就能避免一場(chǎng)浩劫呢?回顧那些復(fù)雜的系統(tǒng),我們可以找到很多因素導(dǎo)致系統(tǒng)腐化。

  • 想簡(jiǎn)單圖省事,沒(méi)有及時(shí)治理不合理的內(nèi)容
  • 缺少匠心追求,對(duì)骯臟代碼視而不見(jiàn)
  • 技術(shù)能力不夠,無(wú)法應(yīng)對(duì)復(fù)雜系統(tǒng)
  • 交接過(guò)渡缺失,三無(wú)產(chǎn)品幾乎無(wú)法維護(hù)

除了上述內(nèi)容外,還可以想到很多理由。但我們發(fā)現(xiàn)他們好像有一個(gè)共同的指向點(diǎn) - 軟件工程師,似乎所有復(fù)雜的源頭就是軟件工程師的不合格導(dǎo)致,所以其實(shí)一些罪惡的根因是我們自己?

1.統(tǒng)一的中國(guó)與分裂的歐洲

歐洲大陸面積大體與中國(guó)相當(dāng),但為什么歐洲是分裂的,而中國(guó)是統(tǒng)一的。有人說(shuō)他們文化不一樣,也有人說(shuō)他們語(yǔ)言不通是主要原因,也有人說(shuō)他們?nèi)币粋€(gè)秦始皇。其實(shí)我們回顧歐洲的歷史,歐洲還真不缺一個(gè)大一統(tǒng)的帝國(guó)。羅馬帝國(guó)曾經(jīng)讓地中海成為自己的內(nèi)海,拿破侖鼎盛時(shí)期掌管著1300萬(wàn)平方公里的領(lǐng)地。歐洲也曾出現(xiàn)過(guò)偉大的帝國(guó),但都未走向統(tǒng)一。

我們?cè)儆^察地圖,其實(shí)除了中國(guó)、俄羅斯以外,全世界99%的國(guó)家都是小國(guó)。分裂才是常態(tài),統(tǒng)一才不正常。馬老師也曾說(shuō)過(guò),成功都有偶然性只有失敗才存在必然。只有極少國(guó)家才實(shí)現(xiàn)了大一統(tǒng),所以我們不應(yīng)該問(wèn)為什么歐洲是分裂的,而應(yīng)該問(wèn)為什么中國(guó)是統(tǒng)一的。類比到我們的軟件也同樣如此,復(fù)雜才是常態(tài),不復(fù)雜才不正常。

2.軟件固有的復(fù)雜性

The Complexity of software is an essential property, not an accidental one.

-- Grady Booch 《Object-Oriented Analysis and Design with Applications》

譯:軟件的復(fù)雜性是一個(gè)基本特征,而不是偶然如此。

Grady Booch在 Object-Oriented Analysis and Design with Applications 中提出這樣一個(gè)觀念,他認(rèn)為軟件的復(fù)雜性是固有的,包括問(wèn)題域的復(fù)雜性、管理開(kāi)發(fā)過(guò)程的困難性、通過(guò)軟件可能實(shí)現(xiàn)的靈活性與刻畫離散系統(tǒng)行為的問(wèn)題,這4個(gè)方面來(lái)分析了軟件的發(fā)展一定伴隨著復(fù)雜,這是軟件工程這本科學(xué)所必然伴隨的一個(gè)特性。

Everything, without exception, requires additional energy and order to maintain itself. I knew this in the abstract as the famous second law of thermodynamics, which states that everything is falling apart slowly.

-- Kevin Kelly 《The Inevitable》

譯:世間萬(wàn)物都需要額外的能量和秩序來(lái)維持自身,無(wú)一例外。這就是著名的熱力學(xué)第二定律,即所有的事務(wù)都在緩慢地分崩離析。

Kevin Kelly在 The Inevitable 也有提過(guò)類似的觀點(diǎn),他認(rèn)為世間萬(wàn)物都需要額外的能量和秩序來(lái)維持自身,所有的事物都在緩慢地分崩離析。沒(méi)有外部力量的注入事物就會(huì)逐漸崩潰,這是世間萬(wàn)物的規(guī)律,而非我們哪里做得不對(duì)。

五、軟件架構(gòu)治理復(fù)雜度

為軟件系統(tǒng)注入的外力就是我們的軟件架構(gòu),以及我們未來(lái)的每一行代碼。軟件架構(gòu)有很多種,從最早的單體架構(gòu),到后面的分布式架構(gòu)、SOA、微服務(wù)、FaaS、ServiceMesh等等。所有的軟件架構(gòu)萬(wàn)變不離其宗,都在致力解決軟件的復(fù)雜性。

1.架構(gòu)的本質(zhì)

編程范式指的是程序的編寫模式,軟件架構(gòu)發(fā)展到今天只出現(xiàn)過(guò)3種編程范式( paradigm ),分別是結(jié)構(gòu)化編程,面向?qū)ο缶幊膛c函數(shù)式編程。

  • 結(jié)構(gòu)化編程取消 goto 移除跳轉(zhuǎn)語(yǔ)句,對(duì)程序控制權(quán)的直接轉(zhuǎn)移進(jìn)行了限制和規(guī)范
  • 面向?qū)ο缶幊滔拗?指針 的使用,對(duì)程序控制權(quán)的間接轉(zhuǎn)移進(jìn)行了限制和規(guī)范
  • 函數(shù)式編程以 λ演算法 為核心思想,對(duì)程序中的賦值進(jìn)行了限制和規(guī)范

面向?qū)ο蟮奈宕笤O(shè)計(jì)原則 S.O.L.I.D。依賴倒置限制了模塊的依賴順序、單一職責(zé)限制模塊的職責(zé)范圍、接口隔離限制接口的提供形式。

軟件的本質(zhì)是約束。商品的代碼不能寫在訂單域,數(shù)據(jù)層的方法不能寫在業(yè)務(wù)層。70年的軟件發(fā)展,并沒(méi)有告訴我們應(yīng)該怎么做,而是教會(huì)了我們不該做什么。

2.遞增的復(fù)雜性

軟件的復(fù)雜性不會(huì)憑空消失,并且會(huì)逐級(jí)遞增。針對(duì)遞增的復(fù)雜性有3個(gè)觀點(diǎn):

  • 模糊性創(chuàng)造了復(fù)雜,依賴性傳播了復(fù)雜
  • 復(fù)雜性往往不是由單個(gè)災(zāi)難引起的
  • 我們可以容易地說(shuō)服自己,當(dāng)前變更帶來(lái)的一點(diǎn)點(diǎn)復(fù)雜性沒(méi)什么大不了

曾經(jīng)小李跟我抱怨,說(shuō)這段代碼實(shí)在是太惡心了,花了很長(zhǎng)時(shí)間才看懂,并且代碼非常僵硬,而正好這個(gè)需求需要改動(dòng)到這里,代碼真的就像一坨亂麻。我問(wèn)他最后是怎么處理的,他說(shuō),我給它又加了一坨。

3.編程思維論

戰(zhàn)術(shù)編程

其實(shí)小李的這種做法并非是一個(gè)個(gè)體行為,或許我們?cè)谟龅綇?fù)雜代碼時(shí)都曾這樣茍且過(guò),John教授這種編程方法稱之為“戰(zhàn)術(shù)編程”。戰(zhàn)術(shù)編程最主要的特點(diǎn)是快,同時(shí)具備如下幾個(gè)特點(diǎn)。

  • 當(dāng)前一定是最快的
  • 不會(huì)花費(fèi)太多時(shí)間來(lái)尋找最佳設(shè)計(jì)
  • 每個(gè)編程任務(wù)都會(huì)引入一些復(fù)雜度
  • 重構(gòu)會(huì)減慢當(dāng)前任務(wù)速度,所以保持最快速度
@HSFProvider(serviceInterface = AgnDistributeRuleConfigQueryService.class)
public class AgnDistributeRuleConfigQueryServiceImpl implements AgnDistributeRuleConfigQueryService {

@Override
public ResultModel queryAgnDistributeRuleConfigById(String id) {
logger.info("queryAgnDistributeRuleConfigById id=" + id);
ResultModel result = new ResultModel();
if(StringUtils.isBlank(id)){
result.setSuccess(false);
result.setErrorMsg("id cannot be blank");
return result
}
try {
AgnDistributeRuleConfigDto agnDistributeRuleConfigDto = new AgnDistributeRuleConfigDto();
AgnDistributeRuleConfig agnDistributeRuleConfig = agnDistributeRuleConfigMapper.selectById(id);
if(agnDistributeRuleConfig == null){
logger.error("agnDistributeRuleConfig is null");
result.setSuccess(false);
result.setErrorMsg("agnDistributeRuleConfig is null");
return result
}
this.filterDynamicRule(agnDistributeRuleConfig);
BeanUtils.copyProperties(agnDistributeRuleConfig, agnDistributeRuleConfigDto);
result.setSuccess(true);
result.setTotal(1);
result.setValues(agnDistributeRuleConfigDto);
} catch (Exception e) {
logger.error("queryAgnDistributeRuleConfigById error,", e);
result.setSuccess(false);
result.setErrorMsg(e.getMessage());
}
return result;
}
}

我們看上面這段代碼,是一段查詢分發(fā)規(guī)則的業(yè)務(wù)邏輯。雖然功能能夠work,但不規(guī)范的地方其實(shí)非常多

  • Facade層定義全部邏輯 - 未做結(jié)構(gòu)分層
  • 業(yè)務(wù)與技術(shù)未做分離 - 耦合接口信息與業(yè)務(wù)數(shù)據(jù)
  • Try catch 滿天飛 - 缺少統(tǒng)一異常處理機(jī)制
  • 沒(méi)有規(guī)范化的日志格式 - 日志格式混亂

但不可否認(rèn),他一定是當(dāng)前最快的。這就是戰(zhàn)術(shù)設(shè)計(jì)的特點(diǎn)之一,永遠(yuǎn)按當(dāng)前最快速交付的方案進(jìn)行推進(jìn),甚至很多組織鼓勵(lì)這種工作方式,為了使功能更快運(yùn)作,只注重短期收益而忽略長(zhǎng)期價(jià)值。

戰(zhàn)術(shù)龍卷風(fēng)

Almost every software development organization has at least one developer who takes tactical programming to the extreme: a tactical tornado.

-- John Ousterhout 《A Philosophy of Software Design》

譯:幾乎每個(gè)軟件開(kāi)發(fā)組織都有至少一個(gè)將戰(zhàn)術(shù)編程發(fā)揮到極致的開(kāi)發(fā)人員:戰(zhàn)術(shù)龍卷風(fēng)。

將戰(zhàn)術(shù)編程發(fā)揮到極致的人,叫戰(zhàn)術(shù)龍卷風(fēng)。戰(zhàn)術(shù)龍卷風(fēng)以腐化系統(tǒng)為代價(jià)換取當(dāng)前最高效的解決方案(或許他自己并未覺(jué)得)。戰(zhàn)術(shù)龍卷風(fēng)也有如下幾個(gè)特點(diǎn):

  • 是一位多產(chǎn)的程序員,沒(méi)人比龍卷風(fēng)更快完成任務(wù)
  • 總能留下龍卷風(fēng)后毀滅的痕跡留給后人去清理
  • 是真的很卷

一些組織甚至?xí)?zhàn)術(shù)龍卷風(fēng)視為英雄,為什么能干得又多又快?因?yàn)樗麑⒊杀痉诺搅宋磥?lái)。軟件工程最大的成本在于維護(hù),我們每一次代碼的改動(dòng),都應(yīng)該是對(duì)歷史代碼的一次整理,而非單一的功能堆積。龍卷風(fēng)能贏得現(xiàn)在,但終將失去未來(lái),而這個(gè)失敗的未來(lái)或許需要全團(tuán)隊(duì)與他一起買單。

戰(zhàn)略編程

John教授提出與戰(zhàn)術(shù)編程相對(duì)的是戰(zhàn)略編程,戰(zhàn)略編程更注重長(zhǎng)期價(jià)值,不滿足于功能work,致力于制作出色的設(shè)計(jì),以滿足對(duì)未來(lái)擴(kuò)展的訴求(注意,不要過(guò)度)。戰(zhàn)略設(shè)計(jì)有如下4個(gè)特點(diǎn)

  • 工作代碼遠(yuǎn)遠(yuǎn)不夠
  • 引入不必要的復(fù)雜度不可接受
  • 不斷對(duì)系統(tǒng)設(shè)計(jì)進(jìn)行小幅改進(jìn)
  • 投資心態(tài)(每位工程師都需要對(duì)良好的設(shè)計(jì)進(jìn)行連續(xù)的少量投資 10~20%)

John Ousterhout教授在 A Philosophy of Software Design 書中提到了戰(zhàn)略設(shè)計(jì)與戰(zhàn)術(shù)設(shè)計(jì)的總成本投入。隨著時(shí)間的流逝,戰(zhàn)略設(shè)計(jì)可以有效控制軟件成本,但戰(zhàn)術(shù)設(shè)計(jì)會(huì)隨著時(shí)間的推移線性遞增。這與Martin Fowler在 Patterns of Enterprise Application Architecture 這本書中所提的關(guān)于數(shù)據(jù)驅(qū)動(dòng)與領(lǐng)域驅(qū)動(dòng)關(guān)于復(fù)雜度的治理是同樣的含義,要致力于長(zhǎng)期的價(jià)值投資。

4.系統(tǒng)的困境與演進(jìn)

沒(méi)有系統(tǒng)是天然復(fù)雜的,為了快速完成任務(wù)不斷引入新的復(fù)雜度至系統(tǒng)逐漸腐化,無(wú)限增長(zhǎng)與無(wú)限傳遞的復(fù)雜度讓軟件需求越來(lái)越難“快速完成”。當(dāng)有一天我們意識(shí)到系統(tǒng)的復(fù)雜性時(shí)再試圖通過(guò)戰(zhàn)略設(shè)計(jì)進(jìn)行軟件的迭代,你會(huì)發(fā)現(xiàn)舉步維艱,一處很小的修改需要投入大量的基建修復(fù),最終我們不得不向成本低頭,不斷再通過(guò)戰(zhàn)術(shù)設(shè)計(jì)無(wú)限的茍且。

A condition that is often incorrectly labeled software maintenance. To be more precise, it is maintenance when we correct errors; it is evolution when we respond to changing requirements; it is preservation when we continue to use extraordinary means to keep an ancient and decaying piece of software in operation. Unfortunately, reality suggests that an inordinate percent- age of software development resources are spent on software preservation.

-- Grady Booch 《Object-Oriented Analysis and Design with Applications》

譯:我們總是說(shuō)我們需要“維護(hù)”這些老系統(tǒng)。而準(zhǔn)確的說(shuō),在軟件發(fā)展過(guò)程里,只有我們修正錯(cuò)誤時(shí),才是維護(hù);在我們應(yīng)對(duì)改變的需求時(shí),這是演進(jìn);當(dāng)我們使用一些極端的手段來(lái)保持古老而陳腐的軟件繼續(xù)工作時(shí),這是保護(hù)(茍且)。事實(shí)證明我們更多的時(shí)間是在應(yīng)對(duì)最后一種狀況。

如同Grady Booch在 Object-Oriented Analysis and Design with Applications 中所提到的觀點(diǎn),當(dāng)我們使用一些極端的手段來(lái)保持古老而陳腐的軟件繼續(xù)工作時(shí),這確實(shí)是一種茍且。我們小心翼翼、集成測(cè)試、灰度發(fā)布、及時(shí)回滾等等,我們沒(méi)有在“維護(hù)”他們,而是以一種丑陋的方式讓這些丑陋的代碼繼續(xù)能夠成功茍且下去。當(dāng)代碼變成意大利面條時(shí),將幾乎是不可能修復(fù),成本將成指數(shù)倍增長(zhǎng),并且似乎我們的系統(tǒng)已經(jīng)存在這樣的代碼,并且可能還在持續(xù)增加中。

六、架構(gòu)偽論

在架構(gòu)設(shè)計(jì)中,總有一些軟件工程師所堅(jiān)信的詩(shī)和遠(yuǎn)方,但到不了的烏托邦不一定就是遙不可及的美好圣地,實(shí)則也可能是對(duì)系統(tǒng)無(wú)益甚至有害的架構(gòu)設(shè)計(jì)。這里列舉其中2條可能存在的架構(gòu)偽論。

1.好的代碼自解釋

Comments do not make up for bad code

-- Martin Fowler 《Clean Code》

譯:注釋不是對(duì)劣質(zhì)代碼的補(bǔ)救

Martin Fowler在 Clean Code 書中提到注釋不是對(duì)劣質(zhì)代碼的補(bǔ)救,以前我也一直堅(jiān)信如果代碼足夠好是不需要注釋的。但實(shí)則這是一個(gè)偽命題,John教授這么評(píng)價(jià)它 ‘good code is self-documenting’ is a delicious myth。

/**
* 批量查詢客戶信息
*/
public List queryCustomerList(){
// 查詢參數(shù)準(zhǔn)備
UserInfo userInfo = context.getLoginContext().getUserInfo();
if(userInfo == null || StringUtils.isBlank(userInfo.getUserId())){
return Collections.emptyList();
}
LoginDTO loginDTO = userInfoConvertor.convert(userInfo);
// 查詢客戶信息
List customerSearchVOList = customerRemoteQueryService.queryCustomerList(loginDTO);
Iterator it = customerSearchVOList.iterator();
// 排除不合規(guī)客戶
while(it.hasNext()){
CustomerSearchVO customerSearchVO = it.next();
if(isInBlackList(customerSearchVO) || isLowQuality(customerSearchVO)){
it.remove();
}
}
// 補(bǔ)充客戶其他屬性信息
batchFillCustomerPositionInfo(customerSearchVOList);
batchFillCustomerAddressInfo(customerSearchVOList);
return customerSearchVOList;
}

這段代碼我們可以很輕松的在5秒內(nèi)看明白這個(gè)函數(shù)是做什么的,并且知道它內(nèi)部的一些業(yè)務(wù)規(guī)則。無(wú)限的私有方法封裝會(huì)讓代碼鏈路過(guò)深,無(wú)限類的拆解會(huì)造成更多網(wǎng)狀依賴,至少有3點(diǎn)內(nèi)容,讓我們絕不能拋棄注釋。

無(wú)法精準(zhǔn)命名

命名的含義是抽象實(shí)體隱藏細(xì)節(jié),我們不能在一個(gè)名字上賦予它全部的信息,而必要的注釋可以完美的進(jìn)行輔佐。

設(shè)計(jì)思想的闡述

代碼只能實(shí)現(xiàn)設(shè)計(jì)不能闡述設(shè)計(jì),這也是為什么一些復(fù)雜的架構(gòu)設(shè)計(jì)我們需要文檔的支撐而非代碼的‘自解釋’,在文檔與代碼之間的空隙,由注釋來(lái)填補(bǔ)。

母語(yǔ)的力量

這點(diǎn)尤其適合我們中國(guó)人,有時(shí)并不是因?yàn)樽⑨屔俅a多,所以我們下意識(shí)會(huì)首先看代碼。而是我們幾十年感受的文化,讓我們對(duì)中文與ABC具有完全不一樣的感觀。

2.永遠(yuǎn)追求最優(yōu)雅

雷布斯曾自夸自己寫的代碼像詩(shī)一樣優(yōu)雅,追求優(yōu)雅的代碼應(yīng)該是每個(gè)軟件工程師的心中的圣地。但有時(shí)存在一些不優(yōu)雅,存在一些‘看似不合理’并不代表就不對(duì),反而有時(shí)在追求更優(yōu)雅的路上我們持續(xù)跑偏。

The goal of software architecture is to minimize the human resources required

to build and maintain the required system.

-- Robert C.Martin 《Clean Architecture》

譯:軟件架構(gòu)的終極目標(biāo)是,用最小的人力成本來(lái)滿足構(gòu)建和維護(hù)該系統(tǒng)的需求

Robert C.Martin在 Clean Architecture 一書中提到了架構(gòu)終極目標(biāo),用最小的人力成本來(lái)滿足構(gòu)建和維護(hù)該系統(tǒng)的需求。架構(gòu)始終是我們解決復(fù)雜度的一個(gè)工具,如果當(dāng)前系統(tǒng)并不復(fù)雜,我們不需要為了所謂的優(yōu)雅去過(guò)分改造與優(yōu)化它,持續(xù)將成本置在一個(gè)較低水位,就是軟件最好的解決辦法。

業(yè)務(wù)簡(jiǎn)單的系統(tǒng)不應(yīng)用DDD架構(gòu),弱交互場(chǎng)景也無(wú)需進(jìn)行前后端分離,哪怕是鄧總設(shè)計(jì)師在規(guī)劃新中國(guó)的發(fā)展上,也是制定了一套‘中國(guó)特色社會(huì)主義’制度。不要盲從一些教條的觀念,選擇適合自己的,控制在可控制范圍內(nèi),既不過(guò)度也不缺失。畢竟沒(méi)有絕對(duì)的優(yōu)雅,甚至沒(méi)有絕對(duì)的正確。

七、寫在最后

很多人認(rèn)為做業(yè)務(wù)開(kāi)發(fā)顯得沒(méi)那么有挑戰(zhàn)性,但其實(shí)正好相反。最難解決的bug是無(wú)法重現(xiàn)的bug,最難處理的問(wèn)題域是不確定性的問(wèn)題域。業(yè)務(wù)往往是最復(fù)雜的,面向不確定性設(shè)計(jì)才是最復(fù)雜的設(shè)計(jì)。軟件工程學(xué)科最難的事情是抽象,因?yàn)樗鼪](méi)有標(biāo)準(zhǔn)、沒(méi)有方法、甚至沒(méi)有對(duì)錯(cuò)。如何在軟件固有的復(fù)雜性上找到一條既不過(guò)度也不缺失的路,是軟件工程師的終身課題,或許永遠(yuǎn)也無(wú)法達(dá)到,或許我們已經(jīng)在路上了。

參閱書籍

《A Philosophy of Software Design》《Object Oriented Analysis and Design with Applications》《Clean Code》《Clean Architecture》《Patterns of Enterprise Application Architecture》


文章標(biāo)題:系統(tǒng)困境與軟件復(fù)雜度,為什么我們的系統(tǒng)會(huì)如此復(fù)雜
分享路徑:http://m.5511xx.com/article/coggejp.html