新聞中心
但是一直都是開(kāi)發(fā)過(guò)程中的一個(gè)難題,本文旨在探討如何去從容應(yīng)對(duì)復(fù)雜性。

創(chuàng)新互聯(lián)建站科技有限公司專(zhuān)業(yè)互聯(lián)網(wǎng)基礎(chǔ)服務(wù)商,為您提供遂寧托管服務(wù)器,高防主機(jī),成都IDC機(jī)房托管,成都主機(jī)托管等互聯(lián)網(wǎng)服務(wù)。
一、軟件的熵增、構(gòu)造定律
1.熵增定律
熵的概念最早起源于物理學(xué),熱力學(xué)第二定律(又稱(chēng)“熵增定律”),表明了在自然過(guò)程中,一個(gè)孤立的系統(tǒng)總是從最初的集中、有序的排列狀態(tài),趨向于分散、混亂和無(wú)序;當(dāng)熵達(dá)到最大時(shí),系統(tǒng)就會(huì)處于一種靜寂狀態(tài)。
軟件系統(tǒng)亦是如此, 在軟件系統(tǒng)的維護(hù)過(guò)程中。軟件的生命力會(huì)從最初的集中、有序的排列狀態(tài),逐步趨向復(fù)雜、無(wú)序狀態(tài),直到軟件不可維護(hù)而被迫下線或重構(gòu)。
2.構(gòu)造定律
自然界是如何應(yīng)對(duì)這復(fù)雜性?
這在物理中被稱(chēng)為構(gòu)造定律 (Constructal Law), 是由Adrian Bejan于1995提出的:
For a finite-size system to persist in time (to live), it must evolve in such a way that it provides easier access to the imposed currents that flow through it.
對(duì)于一個(gè)有限大小的持續(xù)活動(dòng)的系統(tǒng),它必須以這種方式發(fā)展演進(jìn):它提供了一種在自身元素之間更容易訪問(wèn)的流動(dòng)方式。
這個(gè)定理在自然界中比比皆是,最典型的比如水循環(huán)系統(tǒng),海水蒸發(fā)到大氣,下雨時(shí)降落在地面,一部分滲入地面流入江河,一部分繼續(xù)蒸發(fā),不斷循環(huán)。這種自發(fā)性質(zhì)的設(shè)計(jì)反映了這一趨勢(shì):他們?cè)试S實(shí)體或事物更容易地流動(dòng) - 以最少的能量消耗到達(dá)最遠(yuǎn)的地方,就連街道和道路這些人為地構(gòu)建物體,往往也是有排序的模式,以提供最大的靈活性。
二、如何應(yīng)對(duì)軟件系統(tǒng)的復(fù)雜性?
軟件系統(tǒng)的復(fù)雜性往往是被低估的。復(fù)雜越高,開(kāi)發(fā)人員會(huì)感到不安。對(duì)其的理解認(rèn)知負(fù)荷代價(jià)就越高,我們就更不快樂(lè)。真正的挑戰(zhàn)是在構(gòu)建我們的系統(tǒng)時(shí)要保持其有序以及工程師的生產(chǎn)方式。
Ousterhout教授在《軟件設(shè)計(jì)的哲學(xué)》書(shū)中提到:軟件設(shè)計(jì)的最大目標(biāo),就是降低復(fù)雜度(complexity)。
就是設(shè)計(jì)符合業(yè)務(wù)的構(gòu)造定律的演進(jìn)方式,一種可以以最小的開(kāi)發(fā)維護(hù)成本, 使業(yè)務(wù)更快更好的流動(dòng)發(fā)展的方式。
三、軟件復(fù)雜性來(lái)自哪里, 如何解決?
1.不確定性的來(lái)源
(1)業(yè)務(wù)的不確定性
(2)技術(shù)的不確定性
(3)人員流動(dòng)的不確定性
2.如何面對(duì)不確定性
面對(duì)外部的確定性,轉(zhuǎn)化為內(nèi)核的確定性。
面對(duì)外部的不確定性,找到穩(wěn)定的內(nèi)核基礎(chǔ)。
專(zhuān)注問(wèn)題域
當(dāng)下互聯(lián)網(wǎng)發(fā)展速度是迅猛的, 軟件的形態(tài)也在不斷的變化演進(jìn)。面對(duì)未來(lái)的業(yè)務(wù)及變化,橫向業(yè)務(wù)與縱向業(yè)務(wù)的發(fā)展都是不確定性的。
Robert C. Martin提到的BDUF,永遠(yuǎn)不要想著在開(kāi)始就設(shè)計(jì)好了全部的事情(big design up front),一定要避免過(guò)度設(shè)計(jì)。除非能夠十分確認(rèn)的可預(yù)見(jiàn)變化, 業(yè)務(wù)邊界,否則專(zhuān)注解決當(dāng)前1-2年內(nèi)業(yè)務(wù)變化設(shè)計(jì), 講好當(dāng)下的用戶故事,專(zhuān)注解決眼前的問(wèn)題域。 面向不確定設(shè)計(jì),增量敏捷開(kāi)發(fā)。
確認(rèn)穩(wěn)定的系統(tǒng)內(nèi)核
隨著業(yè)務(wù)的變化、系統(tǒng)設(shè)計(jì)也要持續(xù)演進(jìn)升級(jí)。沒(méi)有一開(kāi)始就完美的架構(gòu), 好的架構(gòu)設(shè)計(jì)一定演化來(lái)的,不是一開(kāi)始就設(shè)計(jì)出來(lái)的。
一個(gè)健康公司的成長(zhǎng),業(yè)務(wù)橫向、縱向會(huì)發(fā)展的會(huì)越來(lái)越復(fù)雜,支持業(yè)務(wù)的系統(tǒng)也一定會(huì)越來(lái)越復(fù)雜。
系統(tǒng)演進(jìn)過(guò)程中的成本,會(huì)受到最開(kāi)始的設(shè)計(jì)、系統(tǒng)最初的內(nèi)核影響的。面對(duì)外部業(yè)務(wù)的不確定性, 技術(shù)的不確定性,外部依賴(lài)的不確定性。一個(gè)穩(wěn)定的內(nèi)核應(yīng)該盡量把外部的不確定性隔離。
- 業(yè)務(wù)與技術(shù)的隔離。
以業(yè)務(wù)為核心,分離業(yè)務(wù)復(fù)雜度和技術(shù)復(fù)雜度。
- 內(nèi)部系統(tǒng)與外部依賴(lài)的隔離;
- 系統(tǒng)中常變部分與不常變部分的隔離;
- 隔離復(fù)雜性(把復(fù)雜性的部分隔離在一個(gè)模塊,盡量不與其他模塊互動(dòng))。
3.無(wú)序性
系統(tǒng)和代碼像多個(gè)線團(tuán)一樣散落一地一樣,混亂不堪,毫無(wú)頭緒。
4.如何面對(duì)無(wú)序性
(1)統(tǒng)一認(rèn)知(秩序化)
(2)系統(tǒng)清晰明了的結(jié)構(gòu)(結(jié)構(gòu)化)
(3)業(yè)務(wù)開(kāi)發(fā)流程化(標(biāo)準(zhǔn)化)
注:這里說(shuō)的流程化并非指必須使用類(lèi)似BPM的流程編排系統(tǒng)。
而是指對(duì)于一個(gè)需求,業(yè)務(wù)開(kāi)發(fā)有一定的順序, 有規(guī)劃的先做一部分事情,開(kāi)發(fā)哪一個(gè)模塊再去做剩下的工作,是可以流程化的。
5.規(guī)模
業(yè)務(wù)規(guī)模的膨脹以及開(kāi)發(fā)團(tuán)隊(duì)規(guī)模的膨脹,都會(huì)帶來(lái)系統(tǒng)的復(fù)雜性提升。
6.如何面對(duì)規(guī)模膨脹帶來(lái)的復(fù)雜性
(1)業(yè)務(wù)隔離, 分而治之;
(2)專(zhuān)注產(chǎn)品核心競(jìng)爭(zhēng)力的發(fā)展;
(3)場(chǎng)景分層。
關(guān)鍵場(chǎng)景
投入更多的開(kāi)發(fā)、測(cè)試資源、業(yè)務(wù)資源(比如單元測(cè)試覆蓋率在90%以上)在關(guān)鍵場(chǎng)景。
普通場(chǎng)景
更快,更低成本、更少資源投入地完成普通場(chǎng)景的迭代。
7.認(rèn)知成本
是指開(kāi)發(fā)人員需要多少知識(shí)才能完成一項(xiàng)任務(wù)。
在引入新的變化時(shí),要考慮到帶來(lái)的好處是否大于系統(tǒng)認(rèn)知成本的提升,比如:之前提到的BPM流程編排引擎,如果對(duì)系統(tǒng)帶來(lái)的好處不夠多也是增加認(rèn)知成本的一種。
不合適的設(shè)計(jì)模式也是增加認(rèn)知成本的一種,前臺(tái)同學(xué)吐槽的中臺(tái)架構(gòu)比較高的學(xué)習(xí)成本, 也是認(rèn)知成本的一種。
8.如何降低認(rèn)知成本
(1)系統(tǒng)與現(xiàn)實(shí)業(yè)務(wù)更自然真實(shí)的映射,對(duì)業(yè)務(wù)抽象建模。
軟件工程師實(shí)際上只在做一件事情,即把現(xiàn)實(shí)中的問(wèn)題搬到計(jì)算機(jī)上,通過(guò)信息化提升生產(chǎn)力。
(2)代碼的含義清晰,不模糊。
(3)代碼的整潔度。
(4)系統(tǒng)的有序性, 架構(gòu)清晰。
(5)避免過(guò)度設(shè)計(jì)。
(6)減少?gòu)?fù)雜、重復(fù)概念, 降低學(xué)習(xí)成本。
(7)謹(jǐn)慎引入會(huì)帶來(lái)系統(tǒng)復(fù)雜性的變化。
四、應(yīng)對(duì)復(fù)雜性的利器
1.領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)——DDD
DDD是把業(yè)務(wù)模型翻譯成系統(tǒng)架構(gòu)設(shè)計(jì)的一種方式, 領(lǐng)域模型是對(duì)業(yè)務(wù)模型的抽象。
不是所有的業(yè)務(wù)服務(wù)都合適做DDD架構(gòu),DDD合適產(chǎn)品化,可持續(xù)迭代,業(yè)務(wù)邏輯足夠復(fù)雜的業(yè)務(wù)系統(tǒng),小規(guī)模的系統(tǒng)與簡(jiǎn)單業(yè)務(wù)不適合使用,畢竟相比較于MVC架構(gòu),認(rèn)知成本和開(kāi)發(fā)成本會(huì)大不少。但是DDD里面的一些戰(zhàn)略思想我認(rèn)為還是較為通用的。
對(duì)通用語(yǔ)言的提煉和推廣
清晰語(yǔ)言認(rèn)知, 比如之前在詳情裝修系統(tǒng)中:
ItemTemplate : 表示當(dāng)前具體的裝修頁(yè)面
ItemDescTemplate、Template,兩個(gè)都能表示模板概概念。
剛開(kāi)始接觸這塊的時(shí)候比較難理解這一塊邏輯,之后在負(fù)責(zé)設(shè)計(jì)詳情編輯器大融合這個(gè)項(xiàng)目時(shí)第一件事就是團(tuán)隊(duì)內(nèi)先重新統(tǒng)一認(rèn)知。
- 裝修頁(yè)面統(tǒng)一使用 —— Page概念
- 模板統(tǒng)一使用 —— Template概念
不將模板和頁(yè)面的概念糅雜在一起,含糊不清,避免重復(fù)和混亂的概念定義。
貧血模型和充血模型
1)貧血模型
貧血模型的基本特征是:它第一眼看起來(lái)還真像這么回事兒。項(xiàng)目中有許多對(duì)象,它們的命名都是根據(jù)領(lǐng)域模型來(lái)的。然而當(dāng)你真正檢視這些對(duì)象的行為時(shí),會(huì)發(fā)現(xiàn)它們基本上沒(méi)有任何行為,僅僅是一堆getter/setter方法。
這些貧血對(duì)象在設(shè)計(jì)之初就被定義為只能包含數(shù)據(jù),不能加入領(lǐng)域邏輯;所有的業(yè)務(wù)邏輯是放在所謂的業(yè)務(wù)層(xxxService, xxxManager對(duì)象中),需要使用這些模型來(lái)傳遞數(shù)據(jù)。
@Data
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年齡
*/
private Integer age;
/**
* 生日
*/
private Date birthday;
/**
* 當(dāng)前狀態(tài)
*/
private Stauts stauts;
}
public class PersonServiceImpl implements PersonService {
public void sleep(Person person) {
person.setStauts(SleepStatus.get());
}
public void setAgeByBirth(Person person) {
Date birthday = person.getBirthday();
if (currentDate.before(birthday)) {
throw new IllegalArgumentException("The birthday is before Now,It's unbelievable");
}
int yearNow = cal.get(Calendar.YEAR);
int dayBirth = bir.get(Calendar.DAY_OF_MONTH);
/*大概計(jì)算, 忽略月份等,年齡是當(dāng)前年減去出生年*/
int age = yearNow - yearBirth;
person.setAge(age);
}
}
}
public class WorkServiceImpl implements WorkService{
public void code(Person person) {
person.setStauts(CodeStatus.get());
}
}
這一段代碼就是貧血對(duì)象的處理過(guò)程,Person類(lèi), 通過(guò)PersonService、WorkingService去控制Person的行為,第一眼看起來(lái)像是沒(méi)什么問(wèn)題,但是真正去思考整個(gè)流程。WorkingService, PersonService到底是什么樣的存在?與真實(shí)世界邏輯相比, 過(guò)于抽象?;谪氀P偷膫鹘y(tǒng)開(kāi)發(fā)模式,將數(shù)據(jù)與業(yè)務(wù)邏輯分離,違反了 OOP 的封裝特性,實(shí)際上是一種面向過(guò)程的編程風(fēng)格。但是,現(xiàn)在幾乎所有的 Web 項(xiàng)目,都是基于這種貧血模型的開(kāi)發(fā)模式,甚至連 Java Spring 框架的官方 demo,都是按照這種開(kāi)發(fā)模式來(lái)編寫(xiě)的。
面向過(guò)程編程風(fēng)格有種種弊端,比如,數(shù)據(jù)和操作分離之后,數(shù)據(jù)本身的操作就不受限制了。任何代碼都可以隨意修改數(shù)據(jù)。
2)充血模型
充血模型是一種有行為的模型,模型中狀態(tài)的改變只能通過(guò)模型上的行為來(lái)觸發(fā),同時(shí)所有的約束及業(yè)務(wù)邏輯都收斂在模型上。
@Data
public class Person extends Entity {
/**
* 姓名
*/
private String name;
/**
* 年齡
*/
private Integer age;
/**
* 生日
*/
private Date birthday;
/**
* 當(dāng)前狀態(tài)
*/
private Stauts stauts;
public void code() {
this.setStauts(CodeStatus.get());
}
public void sleep() {
this.setStauts(SleepStatus.get());
}
public void setAgeByBirth() {
Date birthday = this.getBirthday();
Calendar currentDate = Calendar.getInstance();
if (currentDate.before(birthday)) {
throw new IllegalArgumentException("The birthday is before Now,It's unbelievable");
}
int yearNow = currentDate.get(Calendar.YEAR);
int yearBirth = birthday.getYear();
/*粗略計(jì)算, 忽略月份等,年齡是當(dāng)前年減去出生年*/
int age = yearNow - yearBirth;
this.setAge(age);
}
}
3)貧血模型和充血模型的區(qū)別
/**
* 貧血模型
*/
public class Client {
@Resource
private PersonService personService;
@Resource
private WorkService workService;
public void test() {
Person person = new Person();
personService.setAgeByBirth(person);
workService.code(person);
personService.sleep(person);
}
}
/**
* 充血模型
*/
public class Client {
public void test() {
Person person = new Person();
person.setAgeByBirth();
person.code();
person.sleep();
}
}
上面兩段代碼很明顯第二段的認(rèn)知成本更低, 這在滿是Service,Manage 的系統(tǒng)下更為明顯,Person的行為交由自己去管理, 而不是交給各種Service去管理。
貧血模型是事務(wù)腳本模式
貧血模型相對(duì)簡(jiǎn)單,模型上只有數(shù)據(jù)沒(méi)有行為,業(yè)務(wù)邏輯由xxxService、xxxManger等類(lèi)來(lái)承載,相對(duì)來(lái)說(shuō)比較直接,針對(duì)簡(jiǎn)單的業(yè)務(wù),貧血模型可以快速的完成交付,但后期的維護(hù)成本比較高,很容易變成我們所說(shuō)的面條代碼。
充血模型是領(lǐng)域模型模式
充血模型的實(shí)現(xiàn)相對(duì)比較復(fù)雜,但所有邏輯都由各自的類(lèi)來(lái)負(fù)責(zé),職責(zé)比較清晰,方便后期的迭代與維護(hù)。
面向?qū)ο笤O(shè)計(jì)主張將數(shù)據(jù)和行為綁定在一起也就是充血模型,而貧血領(lǐng)域模型則更像是一種面向過(guò)程設(shè)計(jì),很多人認(rèn)為這些貧血領(lǐng)域?qū)ο笫钦嬲膶?duì)象,從而徹底誤解了面向?qū)ο笤O(shè)計(jì)的涵義。
Martin Fowler 曾經(jīng)和 Eric Evans 聊天談到它時(shí),都覺(jué)得這個(gè)模型似乎越來(lái)越流行了。作為領(lǐng)域模型的推廣者,他們覺(jué)得這不是一件好事,極力反對(duì)這種做法。
貧血領(lǐng)域模型的根本問(wèn)題是,它引入了領(lǐng)域模型設(shè)計(jì)的所有成本,卻沒(méi)有帶來(lái)任何好處。最主要的成本是將對(duì)象映射到數(shù)據(jù)庫(kù)中,從而產(chǎn)生了一個(gè)O/R(對(duì)象關(guān)系)映射層。
只有當(dāng)你充分使用了面向?qū)ο笤O(shè)計(jì)來(lái)組織復(fù)雜的業(yè)務(wù)邏輯后,這一成本才能夠被抵消。如果將所有行為都寫(xiě)入到Service對(duì)象,那最終你會(huì)得到一組事務(wù)處理腳本,從而錯(cuò)過(guò)了領(lǐng)域模型帶來(lái)的好處。而且當(dāng)業(yè)務(wù)足夠復(fù)雜時(shí), 你將會(huì)得到一堆爆炸的事務(wù)處理腳本。
對(duì)業(yè)務(wù)的理解和抽象
限定業(yè)務(wù)邊界,對(duì)業(yè)務(wù)進(jìn)行與現(xiàn)實(shí)更自然的理解和抽象,數(shù)據(jù)模型與業(yè)務(wù)模型隔離,把業(yè)務(wù)映射成為領(lǐng)域模型沉淀在系統(tǒng)中。
結(jié)構(gòu)與防腐層
User Interfaces
- 負(fù)責(zé)對(duì)外交互, 提供對(duì)外遠(yuǎn)程接口。
application
- 應(yīng)用程序執(zhí)行其任務(wù)所需的代碼。
- 它協(xié)調(diào)域?qū)訉?duì)象以執(zhí)行實(shí)際任務(wù)。
- 該層適用于跨事務(wù)、安全檢查和高級(jí)日志記錄。
domain
- 負(fù)責(zé)表達(dá)業(yè)務(wù)概念。
- 對(duì)業(yè)務(wù)的分解,抽象,建模 。
- 業(yè)務(wù)邏輯、程序的核心。
- 防腐層接口放在這里。
infrastucture
為其他層提供通用的技術(shù)能力。如repository的implementation(ibatis,hibernate, nosql),中間件服務(wù)等anti-corruption layer的implementation 防腐層實(shí)現(xiàn)放在這里。
- 防腐層的作用:
- 封裝三方服務(wù)。
- 隔離內(nèi)部系統(tǒng)對(duì)外部的依賴(lài)。
讓隱性概念顯性化
文檔與注釋可能會(huì)失去實(shí)時(shí)性(文檔、注釋沒(méi)有人持續(xù)維護(hù)),但是線上生產(chǎn)代碼是業(yè)務(wù)邏輯最真實(shí)的展現(xiàn),減少代碼中模糊的地方,讓業(yè)務(wù)邏輯顯性化體現(xiàn)出來(lái),提升代碼清晰度。
if (itemDO != null && MapUtils.isNotEmpty(itemDO.getFeatures()) && itemDO.getFeatures().containsKey(ITEM_PC_DESCRIPTION_PUSH)) {
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_PC_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_PC_PUSH, "" + pcContent.hashCode());
} else {
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_PC_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_WL_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_PC_PUSH, "" + pcContent.hashCode());
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_WL_PUSH, "" + content.hashCode());
}
比如這一段代碼就把判斷里的業(yè)務(wù)邏輯隱藏了起來(lái),這段代碼其實(shí)的業(yè)務(wù)邏輯是這樣, 判斷商品是否有PC裝修內(nèi)容。如果有做一些操作, 如果沒(méi)有做一些操作,將hasPCContent 這個(gè)邏輯表現(xiàn)出來(lái), 一眼就能看出來(lái)大概的業(yè)務(wù)邏輯,讓業(yè)務(wù)邏輯顯現(xiàn)化,能讓代碼更清晰??梢愿膶?xiě)成這樣:
boolean hasPCContent = itemDO != null && MapUtils.isNotEmpty(itemDO.getFeatures()) && itemDO.getFeatures().containsKey(ITEM_PC_DESCRIPTION_PUSH);
if (hasPCContent) {
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_PC_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_PC_PUSH, "" + pcContent.hashCode());
} else {
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_PC_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_WL_TEMPLATEID, "" + templateId);
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_PC_PUSH, "" + pcContent.hashCode());
itemUpdateBO.getFeatures().put(ItemTemplateConstant.FEATURE_TSP_SELL_WL_PUSH, "" + content.hashCode());
}
2.簡(jiǎn)單設(shè)計(jì)原則——《Clean Code》
(1)保持系統(tǒng)最大可測(cè)試
只要系統(tǒng)可測(cè)試并且越豐富的單元測(cè)試越會(huì)導(dǎo)向保持類(lèi)短小且目的單一的設(shè)計(jì)方案,遵循單一職責(zé)的類(lèi),測(cè)試起來(lái)比較簡(jiǎn)單。
遵循有關(guān)編寫(xiě)測(cè)試并持續(xù)運(yùn)行測(cè)試的簡(jiǎn)單、明確規(guī)則,系統(tǒng)就會(huì)更貼近OO低偶爾度,高內(nèi)聚度的目標(biāo)。編寫(xiě)測(cè)試越多,就越會(huì)遵循DIP之類(lèi)的規(guī)則,編寫(xiě)最大可測(cè)試可改進(jìn)并走向更好的系統(tǒng)設(shè)計(jì)。
(2)避免重復(fù)
重復(fù)是擁有良好設(shè)計(jì)系統(tǒng)的大敵。它代表著額外的工作、額外的風(fēng)險(xiǎn)和額外且不必要的復(fù)雜度。除了雷同的代碼,功能類(lèi)似的方法也可以進(jìn)行包裝減少重復(fù),“小規(guī)模復(fù)用”可大量降低系統(tǒng)復(fù)雜性。要想實(shí)現(xiàn)大規(guī)模復(fù)用,必須理解如何實(shí)現(xiàn)小規(guī)模復(fù)用。
共性的抽取也會(huì)使代碼更好的符合單一職責(zé)原則。
(3)更清晰的表達(dá)開(kāi)發(fā)者的意圖
軟件項(xiàng)目的主要成本在于長(zhǎng)期維護(hù),當(dāng)系統(tǒng)變得越來(lái)越復(fù)雜,開(kāi)發(fā)者就需要越來(lái)越多的時(shí)間來(lái)理解他,而且也極有可能誤解。
所以作者需要將代碼寫(xiě)的更清晰:選用好名稱(chēng)、保持函數(shù)和類(lèi)的短小、采用標(biāo)準(zhǔn)命名法、標(biāo)準(zhǔn)的設(shè)計(jì)模式名,編寫(xiě)良好的單元測(cè)試。用心是最珍貴的資源。清晰:選用好名稱(chēng)、保持函數(shù)和類(lèi)的短小、采用標(biāo)準(zhǔn)命名法、標(biāo)準(zhǔn)的設(shè)計(jì)模式名,編寫(xiě)良好的單元測(cè)試。用心是最珍貴的資源。
(4)盡可能減少類(lèi)和方法
如果過(guò)度使用以上原則,為了保持類(lèi)的函數(shù)短小,我們可能會(huì)造出太多細(xì)小的類(lèi)和方法。所以這條規(guī)則也主張函數(shù)和類(lèi)的數(shù)量要少。
如應(yīng)當(dāng)為每個(gè)類(lèi)創(chuàng)建接口、字段和行為必須切分到數(shù)據(jù)類(lèi)和行為類(lèi)中。應(yīng)該抵制這類(lèi)教條,采用更實(shí)用的手段。目標(biāo)是在保持函數(shù)和類(lèi)短小的同時(shí),保持系統(tǒng)的短小精悍。不過(guò)這是優(yōu)先級(jí)最低的一條。更重要的是測(cè)試,消除重復(fù)和清晰表達(dá)。
五、最后
總而言之,做業(yè)務(wù)開(kāi)發(fā)其實(shí)一點(diǎn)也不簡(jiǎn)單,面對(duì)不確定性的問(wèn)題域,復(fù)雜的業(yè)務(wù)變化,
如何更好的理解和抽象業(yè)務(wù),如何更優(yōu)雅的應(yīng)對(duì)復(fù)雜性,一直都是軟件開(kāi)發(fā)的一個(gè)難題。
在對(duì)抗軟件熵增,尋找對(duì)抗軟件復(fù)雜性,符合業(yè)務(wù)的構(gòu)造定律的演進(jìn)方式,我們一直都在路上。
參考
[1] 《Domain-Driven Design》 :https://book.douban.com/subject/1629512/
[2] 《Implementing Domain-Driven Design》 :https://book.douban.com/subject/25844633/
[3] 《Clean Code》:https://book.douban.com/subject/4199741/
[4] 《A Philosophy of Software Design》 :https://book.douban.com/subject/30218046/
當(dāng)前標(biāo)題:我們一起聊聊如何從容應(yīng)對(duì)復(fù)雜性
網(wǎng)站路徑:http://fisionsoft.com.cn/article/dhjpsop.html


咨詢(xún)
建站咨詢(xún)
