工程设计论——如何写好工程代码
簡(jiǎn)介:設(shè)計(jì)是在對(duì)需求的認(rèn)知不完整的情況下,對(duì)被設(shè)計(jì)對(duì)象進(jìn)行求解的一個(gè)過(guò)程。這就迫使我們需要一邊認(rèn)識(shí)被設(shè)計(jì)對(duì)象,一邊進(jìn)行求解。為了并行化地進(jìn)行這一過(guò)程,也為了使得對(duì)被設(shè)計(jì)對(duì)象地認(rèn)識(shí)有初步的研究工具和基礎(chǔ),我們總結(jié)出了一套利用分拆提供弱約束,并基于這種分拆,來(lái)并行進(jìn)行不同組件之間的設(shè)計(jì)的流程。
作者 | 任增
來(lái)源 | 阿里技術(shù)公眾號(hào)
一 內(nèi)容概述
二 理論基礎(chǔ)
三 什么是設(shè)計(jì)——設(shè)計(jì)和計(jì)算與認(rèn)知之間的聯(lián)系
一門(mén)科學(xué)的建立,應(yīng)當(dāng)首先明確本學(xué)科的局限性,確定本學(xué)科最基本的問(wèn)題與框架。明確的基本框架應(yīng)能夠迅速得到一門(mén)學(xué)科的基礎(chǔ)結(jié)論與研究方法;明確的基本問(wèn)題可以用于檢驗(yàn)上述的結(jié)論與方法。指出自然界中每一杯水中都有金元素并不能對(duì)金礦的發(fā)現(xiàn)起到什么促進(jìn)作用。設(shè)計(jì)科學(xué)的現(xiàn)在的發(fā)展應(yīng)該做減法而不是做加法。對(duì)于設(shè)計(jì)所具備的特征,有很多描述。這些描述最基本的共同點(diǎn)是設(shè)計(jì)是需要達(dá)到一定的目標(biāo)的(即需求)。其他特征并不是設(shè)計(jì)最基本的特征。例如最優(yōu)化設(shè)計(jì)中就沒(méi)有需求變更,logo設(shè)計(jì)中就沒(méi)有系統(tǒng)故障。
如果認(rèn)同需求是設(shè)計(jì)的共同點(diǎn),那么搞清楚需求是什么則是重要的。 大部分人都認(rèn)為,在我們的實(shí)際工作中,需求是不明確的,不完整的。那我們不妨用辯證的思維來(lái)考慮這個(gè)問(wèn)題的反面,什么是明確的,完整的需求?一份完整的需求,對(duì)于所有人而言都是清晰的,不會(huì)產(chǎn)生什么不一樣的理解。那么對(duì)于什么樣的產(chǎn)品能夠滿足相應(yīng)的需求,也應(yīng)該是清晰的。用集合論的話來(lái)說(shuō),一個(gè)集合被其外延所完全確定。換句話說(shuō),如果需求能夠被一個(gè)確定的驗(yàn)收方式來(lái)定義,比如說(shuō)單元測(cè)試,那么這份需求可以說(shuō)是明確和完整的。
我們還需要更進(jìn)一步地探討什么是驗(yàn)收。以單元測(cè)試為例,我們用單元測(cè)試來(lái)輸出一個(gè)True或是輸出一個(gè)False;如果認(rèn)為單元測(cè)試本身是一個(gè)函數(shù),那驗(yàn)收就是要求被設(shè)計(jì)對(duì)象在該函數(shù)下的相必須為T(mén)rue。那么,如果我們的需求足夠簡(jiǎn)單,會(huì)發(fā)生什么情況?比如說(shuō)我們的需求是找到一個(gè)x,使其滿足x+1=0,我們一般稱這種問(wèn)題為求解,或者是逆運(yùn)算。可以看到,當(dāng)我們對(duì)需求及其實(shí)現(xiàn)方式的認(rèn)識(shí)完全清晰的時(shí)候,需求將退化成為一個(gè)函數(shù),設(shè)計(jì)將退化成為逆運(yùn)算的過(guò)程。
設(shè)計(jì)的過(guò)程中,我們對(duì)于需求及實(shí)現(xiàn)方式的認(rèn)識(shí)是不全面的,這是其與逆運(yùn)算不同的核心點(diǎn)(而不是需求不明確或者是需求會(huì)發(fā)生變更)。例如化工產(chǎn)品的合成路線設(shè)計(jì),例如高效排序算法的設(shè)計(jì),都不存在需求本身不明確的問(wèn)題。認(rèn)知的不全面迫使我們需要在設(shè)計(jì)的過(guò)程中,一邊對(duì)需求及其實(shí)現(xiàn)方式進(jìn)行認(rèn)知,獲取更多的知識(shí),一邊進(jìn)行求逆運(yùn)算,找到能夠滿足需求的實(shí)現(xiàn)方式。
四 工程設(shè)計(jì)的過(guò)程
在進(jìn)行工程設(shè)計(jì)的過(guò)程中,對(duì)于認(rèn)知和計(jì)算的交替流程,我們總結(jié)了一套行之有效的經(jīng)驗(yàn),即對(duì)需求的拆分和組合。
我們剛剛已經(jīng)說(shuō)過(guò),需求本質(zhì)上是要求一個(gè)對(duì)象,在某個(gè)函數(shù)下的像具備某些特征,這本質(zhì)上是一種約束。而“被設(shè)計(jì)對(duì)象由A,B兩個(gè)組件構(gòu)成,A具備123特征,B具備456特征”,這和需求的描述方式?jīng)]有什么不同,本質(zhì)上也是一種約束。也就是說(shuō),分拆本身也是對(duì)被設(shè)計(jì)對(duì)象的一種約束,只不過(guò)滿足分拆約束的對(duì)象并不一定滿足需求的約束。因此我們不妨把分拆的約束當(dāng)作一種對(duì)被設(shè)計(jì)對(duì)象的弱約束。
因而工程設(shè)計(jì)可以被總結(jié)成為如下的流程:
我們剛剛已經(jīng)說(shuō)明了,分拆本質(zhì)上也是一種約束。第二步中的求解結(jié)果,仍舊有可能是一種對(duì)子系統(tǒng)需求,此時(shí)就需要我們繼續(xù)進(jìn)行更加細(xì)化的設(shè)計(jì)。
引入弱約束這個(gè)概念,是因?yàn)樵谖覀儗?duì)被設(shè)計(jì)對(duì)象一無(wú)所知的情況下,研究如何實(shí)現(xiàn)相應(yīng)的需求是相對(duì)困難的。那么我們不妨假設(shè)被設(shè)計(jì)對(duì)象具備某些性質(zhì)(這種假設(shè)往往也強(qiáng)依賴于個(gè)人經(jīng)驗(yàn)),并將這些假設(shè)性質(zhì)(比如說(shuō)接口)作為研究如何實(shí)現(xiàn)的一種工具和框架。
例如在代碼設(shè)計(jì)中,拆分為A,B兩個(gè)模塊并進(jìn)行并行設(shè)計(jì)時(shí),如果在A模塊的實(shí)現(xiàn)流程完全不知道B模塊的信息,那么將會(huì)對(duì)A模塊的設(shè)計(jì)產(chǎn)生巨大的阻礙(比如前端完全不知道后端的數(shù)據(jù)格式)。但是,B模塊的具體實(shí)現(xiàn)方式還未確定,此時(shí)A模塊也不可能對(duì)B模塊的信息由完整的了解,且并不是每一個(gè)B模塊的信息對(duì)于其他模塊都是有用的(比如后端選用的數(shù)據(jù)庫(kù)格式,后端部署的位置,后端的實(shí)現(xiàn)方式)。所以我們需要折中的對(duì)B模塊進(jìn)行約束(比如規(guī)定接口),使得A模塊能夠獲得必要的相關(guān)信息。了解過(guò)認(rèn)知論的同學(xué)也應(yīng)該知道,這種接口本身就是一種對(duì)B模塊的認(rèn)知(參照羅素的感覺(jué)材料或是我在前序文章中所述的“關(guān)系”)。我認(rèn)為這是依賴注入的底層邏輯,也是面向接口設(shè)計(jì)將成為軟件設(shè)計(jì)的最終形態(tài)的底層依據(jù)。
在這個(gè)例子中,工程設(shè)計(jì)與科學(xué)研究后進(jìn)行計(jì)算的最大區(qū)別即在于,第二步中的具體實(shí)現(xiàn)過(guò)程是并行的。各個(gè)組件的實(shí)現(xiàn)的并行在軟件工程中是常見(jiàn)的(前后端分別編碼,最后進(jìn)行調(diào)試即是如此)。我們當(dāng)然可以在完全研究清楚J(X)的性質(zhì)下,再去進(jìn)行設(shè)計(jì)。限制我們不去這么做的條件,并非是這樣得到的產(chǎn)品效果一定不好,而是設(shè)計(jì)需要投入的工期與人力有限制。完全設(shè)計(jì)好前端之后,再去進(jìn)行后端設(shè)計(jì),當(dāng)然是可以的,但是這種串行化的工作模式,顯而易見(jiàn)的會(huì)對(duì)工期造成負(fù)面影響。
為了使得這種拆分方式可行,獨(dú)立職責(zé)的原則就需要被引進(jìn)以保證最后的組裝工作順利完成。在上一步中,我們的工作是并行的,意味著我們并不知道f(X),g(X),m(X)所需要取得的值是多少。如果我們最終研究得到
那我們顯然是找不到相應(yīng)的解的。這就需要我們保證f({X}),g({X}),m({X})之間的相互獨(dú)立。我們對(duì)拆分地獨(dú)立性及其負(fù)面影響進(jìn)行進(jìn)一步地探討:
這一規(guī)則對(duì)應(yīng)于軟件領(lǐng)域中的單一職責(zé)原則,有人評(píng)論這一原則是較為難以運(yùn)用和掌握的(“單一職責(zé)原則是最簡(jiǎn)單但又最難運(yùn)用的原則”)。事實(shí)確實(shí)如此,接下來(lái)我們將對(duì)這一點(diǎn)進(jìn)行探討。
我們換一種看起來(lái)正確的模棱兩可的表述更方便我們發(fā)現(xiàn)問(wèn)題在哪。這個(gè)陳述是:獨(dú)立的功能應(yīng)當(dāng)由獨(dú)立的類來(lái)實(shí)現(xiàn)。那么,問(wèn)題出現(xiàn)了。我們?cè)趺慈ヅ袛鄡蓚€(gè)功能之間相互獨(dú)立?熟悉哲學(xué),并對(duì)哲學(xué)中對(duì)“Free”的討論有接觸的人會(huì)很快反應(yīng)過(guò)來(lái),“Free”這個(gè)詞必然是建立于某種映射之上,單獨(dú)說(shuō)A與B“Free”沒(méi)有任何意義。家庭教育和學(xué)校教育是否獨(dú)立?道德教育和智力教育是否獨(dú)立?從不同的角度會(huì)有不一樣的答案。從時(shí)間上,家庭教育和學(xué)校教育相互獨(dú)立;從評(píng)分標(biāo)準(zhǔn)上,道德教育和智力教育也相互獨(dú)立。如果把教育也作為一種設(shè)計(jì),我們是應(yīng)該把教育劃分成為家庭教育和學(xué)校教育,還是劃分成為道德教育和智力教育?劃分的依據(jù)究竟應(yīng)該是什么?
顯而易見(jiàn)的事情是,我們所能夠接受的判斷功能之間的相互獨(dú)立的依據(jù),應(yīng)該是從其實(shí)現(xiàn)方式上相互獨(dú)立。那么上面那句話,就可以改寫(xiě)成為:實(shí)現(xiàn)上獨(dú)立的功能應(yīng)當(dāng)被獨(dú)立地實(shí)現(xiàn)。這有點(diǎn)像一句政治正確的廢話,其具體的運(yùn)用強(qiáng)依賴于設(shè)計(jì)人員對(duì)于相關(guān)領(lǐng)域的事前經(jīng)驗(yàn)與判斷。不具備相關(guān)領(lǐng)域的經(jīng)驗(yàn),進(jìn)行功能劃分必然會(huì)出現(xiàn)一些搞笑的結(jié)果。這就是單一職責(zé)原則是最簡(jiǎn)單,也最困難的原則的原因。
五 總結(jié)與局限
設(shè)計(jì)是在對(duì)需求的認(rèn)知不完整的情況下,對(duì)被設(shè)計(jì)對(duì)象進(jìn)行求解的一個(gè)過(guò)程。這就迫使我們需要一邊認(rèn)識(shí)被設(shè)計(jì)對(duì)象,一邊進(jìn)行求解。為了并行化地進(jìn)行這一過(guò)程,也為了使得對(duì)被設(shè)計(jì)對(duì)象地認(rèn)識(shí)有初步的研究工具和基礎(chǔ),我們總結(jié)出了一套利用分拆提供弱約束,并基于這種分拆,來(lái)并行進(jìn)行不同組件之間的設(shè)計(jì)的流程。由于分拆只能提供關(guān)于被設(shè)計(jì)對(duì)象的較弱認(rèn)識(shí),因此依賴倒置和面向接口設(shè)計(jì)是必須的。為了使得并行化的設(shè)計(jì)最終可以被組裝,單一職責(zé)原則(獨(dú)立原則)是必須的。
可以看到,整個(gè)設(shè)計(jì)理論是必須基于對(duì)需求的認(rèn)知不完整,且需要低成本(首要的是時(shí)間成本)地完成設(shè)計(jì)這一條件。對(duì)于設(shè)計(jì)周期比較長(zhǎng),認(rèn)知較為充分的領(lǐng)域,設(shè)計(jì)理論并不適用。完全只用設(shè)計(jì)模式來(lái)衡量設(shè)計(jì)的好壞,也是不可取的。這方面的反例有很多,LeetCode上面的題目,恐怕沒(méi)有哪一個(gè)符合了設(shè)計(jì)模式,比如說(shuō)找鏈表倒數(shù)第k個(gè)節(jié)點(diǎn)中的雙指針就是一個(gè)典型。對(duì)于人體而言,也并不遵循什么單一職責(zé)原則,甚至可以說(shuō)耦合地不像,人在饑餓的時(shí)候,可以分解蛋白質(zhì)來(lái)供能;我們?cè)陲w機(jī)設(shè)計(jì)過(guò)程中,有考慮過(guò)在液壓油泄露時(shí),拿燃油來(lái)充當(dāng)液壓油么?一些經(jīng)典設(shè)計(jì)也并不遵循設(shè)計(jì)理論與原則,例如活塞環(huán)既能夠防止漏氣,又能夠降低摩擦磨損,這顯然也不是符合獨(dú)立公理的。
只有對(duì)設(shè)計(jì)科學(xué)的底層邏輯有著深入的研究,才能使得這門(mén)科學(xué)發(fā)揮其真正的作用。雖然本文盡可能地對(duì)這個(gè)領(lǐng)域進(jìn)行了一些減法地操作,略去了一些不核心的要素,但是無(wú)論在理論上,還是例子上,都沒(méi)有能夠提供一個(gè)真正能夠被驗(yàn)證成為正確或是錯(cuò)誤的想法或是命題。本文甚至連錯(cuò)誤都算不上,這無(wú)論如何都是讓人不滿意的。
六 附——利用分拆來(lái)設(shè)計(jì)系統(tǒng)的一個(gè)例子
很多設(shè)計(jì)領(lǐng)域的文章提出的例子,都是一些已有的設(shè)計(jì);或是拿著根本沒(méi)有市場(chǎng)的需求來(lái)設(shè)計(jì)一款產(chǎn)品。這種先射箭后畫(huà)靶的行為并不能促進(jìn)科學(xué)的發(fā)展。因此找一個(gè)大家都熟知的領(lǐng)域,提出解決起來(lái)較為有難度,但是需求明確的問(wèn)題來(lái)作為探討的例子。很幸運(yùn)的是,我的確解決了我自己提出的問(wèn)題。
在機(jī)械領(lǐng)域,平面桿件機(jī)構(gòu)的設(shè)計(jì)是最基本的問(wèn)題。例如對(duì)下圖中這種四桿機(jī)構(gòu),我們經(jīng)常會(huì)進(jìn)行擺角的設(shè)計(jì)等工作。那么,我們能不用勻速的電機(jī)和平面桿件,使得平面桿件上的某一點(diǎn)有著指定的軌跡?例如用平面桿件畫(huà)一只兔子?
對(duì)于這個(gè)問(wèn)題,我們梳理我們已經(jīng)知道的知識(shí),來(lái)給出一些弱約束:
那么,我們?cè)儆刹鸱纸o出另外的弱約束,以解決這一問(wèn)題:
在這樣一個(gè)弱約束下,我們的問(wèn)題就變?yōu)榱?#xff1a;
如何通過(guò)一些圓周運(yùn)動(dòng),及建立在其上的加法體系,擬合任意一個(gè)周期運(yùn)動(dòng)。
問(wèn)題二可以由如下桿組完成,轉(zhuǎn)動(dòng)副2始終為轉(zhuǎn)動(dòng)副1,3的中點(diǎn):
最終的設(shè)計(jì),我用了16個(gè)主動(dòng)件,及16個(gè)連接組,共計(jì)80個(gè)桿件,得到的結(jié)果已經(jīng)在上圖中展示了。
誠(chéng)實(shí)而言,我認(rèn)為這個(gè)例子在說(shuō)明弱約束和強(qiáng)約束,以及拆分對(duì)于工程設(shè)計(jì)的必要性方面,仍舊難以擺脫先射箭后畫(huà)靶的嫌疑。但是至少,我不認(rèn)為我設(shè)計(jì)的機(jī)構(gòu),就是本問(wèn)題的最優(yōu)解;我想本問(wèn)題用以說(shuō)明工程設(shè)計(jì)并不能得到最好的設(shè)計(jì)這一點(diǎn),還是足夠的。
原文鏈接
本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。?
總結(jié)
以上是生活随笔為你收集整理的工程设计论——如何写好工程代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 量化感知训练实践:实现精度无损的模型压缩
- 下一篇: 阿里巴巴代码平台架构的演进之路