詳解引擎技術(shù)之約定式編程的實(shí)現(xiàn)理念
原創(chuàng)在前端世界里,我們經(jīng)常會(huì)聽說某某引擎,某某框架,那么到底什么樣子的東西可以稱之為引擎呢?如果我們自己希望編寫引擎應(yīng)該如何做呢?在編寫引擎的時(shí)候,我們至少需要注意哪些方面呢?引擎技術(shù)到底能給我們帶來什么呢?
本文皆旨在平時(shí)的學(xué)習(xí)交流中遇見很多值得討論的問題,抽取部分有價(jià)值的觀點(diǎn),和大家一起談?wù)搶W(xué)習(xí)。
作者簡(jiǎn)介
曲毅,51 CTO WOT峰會(huì)特邀嘉賓,曾為第七屆WOT移動(dòng)互聯(lián)網(wǎng)開發(fā)者大會(huì)的特約講師。從事互聯(lián)網(wǎng)研發(fā)工作11年。曾在高陽,空中網(wǎng),樂蜂網(wǎng)等互聯(lián)網(wǎng)公司擔(dān)任構(gòu)架師,高級(jí)技術(shù)經(jīng)理,技術(shù)總監(jiān)等職位。近4年專注移動(dòng)互聯(lián)網(wǎng),是國內(nèi)資深HTML 5專家和研究者,對(duì)HTML 5技術(shù)有非常深刻的認(rèn)識(shí)和理解,有著豐富的實(shí)踐經(jīng)驗(yàn),是HTML 5引擎Crow 5的創(chuàng)造者。多次受邀在中關(guān)村在線,iweb峰會(huì)和GITC全球互聯(lián)網(wǎng)大會(huì)上擔(dān)任嘉賓和專家。
七樂康高級(jí)技術(shù)總監(jiān)
一、到底什么是引擎?什么是輕量級(jí)框架?什么是重量級(jí)框架?
其實(shí)引擎并沒有我們想的那么神奇,可以理解成封裝的更方便用的框架。引擎技術(shù)其實(shí)也是框架技術(shù)。兩者沒有本質(zhì)上的區(qū)別。前端我們適用的框架,大家熟知的有jquery,zepto,sea,Kissy等都是優(yōu)秀的框架。這些框架使用簡(jiǎn)單,輕量,學(xué)習(xí)門檻很低。這些都是優(yōu)點(diǎn)。這些框架就像小積木一樣,每一種框架都有自己的特點(diǎn),針對(duì)具體的使用場(chǎng)景,解決開發(fā)中遇見的痛點(diǎn)問題。例如jquery封裝了大量的Javascript的方法,解放工程師的重復(fù)編碼,瀏覽器兼容,動(dòng)畫特效處理。但是我們?cè)谧鲆苿?dòng)方面的項(xiàng)目的時(shí)候會(huì)發(fā)現(xiàn)Jquery這樣的庫,不太實(shí)用,很顯然Jquery解決了很多PC瀏覽器兼容方便的事情,相對(duì)移動(dòng)設(shè)備來說體積太大,很多兼容問題不復(fù)存在。那么就出現(xiàn)了zepto框架。zepto定位就是移動(dòng)設(shè)備,這樣它的體積就小了很多。在例如我們處理javascript模塊加載問題的時(shí)候可以使用Sea.js。sea是一個(gè)遵循CommonJS規(guī)范的javascript模塊加載框架,可以實(shí)現(xiàn)javascript的模塊開發(fā)及加載框架。
每一種框架都有自給的一種設(shè)計(jì)理念和針對(duì)痛點(diǎn)給出的解決方法。盡可能的用少的代碼量,去解決更多的問題,同時(shí)給出一個(gè)方便使用的API。這些都是輕量級(jí)框架的優(yōu)點(diǎn)。但是這樣對(duì)于我們開發(fā)工程師來說,就面臨一個(gè)問題。我們?cè)谧鲆粋€(gè)項(xiàng)目的時(shí)候,會(huì)遇見很多很多問題,除了要模塊開發(fā),還要?jiǎng)討B(tài)加載,還要有模版技術(shù),還有動(dòng)畫處理。還有緩存處理,如果做的功能復(fù)雜點(diǎn),還需要調(diào)用地理位置,重力感應(yīng)。需要許許多多的的小框架。如果不使用庫,自己去寫那么就要萬丈高樓從地起,一個(gè)一個(gè)的坑自己填。使用庫就像玩卡牌游戲一樣各種拼湊才能搞定。那么有沒有一個(gè)什么好的框架能一下搞定我們所有呢?
這個(gè)世界就是很奇妙,只要你有需要,就會(huì)有人解決你的需求。答案是有的,在前端的世界,在開源的世界里,想要什么都有現(xiàn)成的東西。說的優(yōu)點(diǎn)絕對(duì)了,但是我們從來不缺少工具。那么就出現(xiàn)了很多重量級(jí)框架,例如YUI,EXT,Anglar.js,Bootstrap等等。這些都屬于重量級(jí)框架,使用他們的好處是,大一統(tǒng)車同軌,書同文,統(tǒng)一度量衡。除了你要加載他們的核心庫以外,你想要什么,這些重量級(jí)框架還給你提供了很多很多插件,讓你用的爽歪歪。但是問題來了,首先這么重的東西,我們真的能用多少功能?而且重量級(jí)框架都有一個(gè)通病就是綁架了碼農(nóng),碼農(nóng)的思維被束縛住了。只能按照他們的方式去編寫代碼。需要什么功能就是機(jī)械的去找插件,沒有完全匹配的就得擴(kuò)展插件,一個(gè)不小心一個(gè)小問題搞半天。運(yùn)氣再差點(diǎn),出現(xiàn)個(gè)什么坑,還很難解決。很多靈活性就這樣的被吞噬了,現(xiàn)在我們都知道,開發(fā)速度意味著什么。還有就是重量級(jí)框架的學(xué)習(xí)無疑像學(xué)了一門語言一樣,對(duì)于團(tuán)隊(duì)的學(xué)習(xí)成本也是很高的。出于種種原因,重量框架在實(shí)際中使用情況并不是特別的多。反正還是拼拼湊湊,不好用了自己換換來的實(shí)際。程序員寧愿自己拼湊,也不太想弄個(gè)套餐。所以才有了包括YUI這樣的重量級(jí)框架已經(jīng)不在更新的事情。
時(shí)代和觀念一直在改變和修正,重量級(jí)框架有太多的優(yōu)點(diǎn)但是不能真正的占據(jù)絕對(duì)份額,除了使用也還受限網(wǎng)絡(luò)等諸多原因。
簡(jiǎn)言之,重量級(jí)框架集成了很多輕量級(jí)框架的特點(diǎn),提供了統(tǒng)一的編碼規(guī)則。集成了很多小框架,避免了拼湊。但是它失去了靈活,綁架了開發(fā),阻礙了擴(kuò)展。增加了學(xué)習(xí)成本。
那么引擎到底是什么呢?首先引擎是框架。然后引擎要具備輕量級(jí)的優(yōu)點(diǎn)小,快,是個(gè)插件,是個(gè)模式。還要具備重量級(jí)框架的思想,可以給出統(tǒng)一的方法論,避免拼湊。同時(shí)引擎不應(yīng)該像重量級(jí)框架一樣去綁架開發(fā),應(yīng)該可以提供靈活的方式去讓開發(fā)人員去使用。
二、引擎技術(shù)是怎么誕生的?
引擎技術(shù)要發(fā)揚(yáng)輕量級(jí)框架的優(yōu)勢(shì)。插件開發(fā)而且是不侵入式開發(fā),是面向切面的,在愿意使用的時(shí)候使用,不愿意的時(shí)候也能較為方便的抽離,引擎要繼續(xù)向重量級(jí)框架學(xué)習(xí)統(tǒng)一的思想,能給出完整的解決方案去盡可能的解決問題。
我們?cè)诰幋a的時(shí)候,最常用的一個(gè)思想就是封裝,這也是框架和引擎技術(shù)的重要思想。我們把操作類的,動(dòng)畫類的,渲染類的,業(yè)務(wù)類的都封裝完,然后看看是否還能再抽取一些更小的粒度,***把這些封裝成一個(gè)一個(gè)類庫,***按照一個(gè)良好的目錄和命名規(guī)則存放。方便引用,然后再給出一個(gè)合適的加載和調(diào)度的方式,去組合代碼。程序員在開放的時(shí)候,會(huì)不斷的擴(kuò)充各種粒度庫。以后的開發(fā)就有點(diǎn)像搭積木了。那么,一個(gè)簡(jiǎn)單的適用于我們項(xiàng)目的小框架就已經(jīng)有了雛形。
但是有這些遠(yuǎn)遠(yuǎn)不夠,因?yàn)檫€至少缺失一個(gè)重要的東西,就是規(guī)則。雖然編寫代碼的時(shí)候可以按照搭積木的方式去壘代碼,已經(jīng)少了很多硬生生的編寫。但是還是有壘代碼的操作。***,我們會(huì)發(fā)現(xiàn),在做一個(gè)功能的時(shí)候,大體上總是會(huì)有加載模版資源,請(qǐng)求數(shù)據(jù),渲染處理,事件處理等等看上去不太一樣,但是方法論無數(shù)遍重復(fù)的工作。試想一下,如果我們能把這些重復(fù)的方式也變成了規(guī)則,讓代碼可以自動(dòng)按照某種關(guān)系去自動(dòng)執(zhí)行這些重復(fù),我們就可以省去很多機(jī)械的重復(fù)的壘代碼的過程。
基于這個(gè)思想,我設(shè)計(jì)了規(guī)則引擎。Crow5就是在這樣的指導(dǎo)思想下誕生的。雖然不能完全實(shí)現(xiàn)代碼自動(dòng)去生成代碼,但是應(yīng)該盡可能的讓代碼趨近于生成更多的代碼。那么代碼憑什么可以自己按照某種邏輯去生成代碼呢?很簡(jiǎn)單,我寫了一個(gè)內(nèi)核,這個(gè)內(nèi)核啥也不干,就是去讀取我下達(dá)的指令,通過我下達(dá)的指令去完成壘代碼的過程。那么,指令是什么呢?就是我給這個(gè)內(nèi)核的一個(gè)配置文件。在這樣的一個(gè)思索過程中就有了以下的設(shè)計(jì)。
按照模塊開發(fā),我們以前是control,service,module,dao分層去處理功能,***模式發(fā)生了改變。分層***是由內(nèi)核去拼裝代碼,***我們只要給出指令就好了。
可以看到上圖,我們?cè)诰帉懘a的時(shí)候,方式發(fā)生了改變,以前需要寫邏輯控制代碼,功能代碼等?,F(xiàn)在只需要提供一個(gè)叫做配置文件的指令。
#p#
三、如何抽取出適用我們的引擎?
對(duì)核心引用的庫抽取,對(duì)邏輯控制抽取,對(duì)展現(xiàn)抽取,對(duì)業(yè)務(wù)進(jìn)行抽取。
四、我們?nèi)绻帉懸妫辽僖瓿赡男┕δ?(能稱之為引擎至少要具備的條件)
雖然沒有明文規(guī)定做一個(gè)引擎到底需要多少東西,但是這里我給出一個(gè)參考方案。如果一個(gè)引擎可以提供給別人使用,至少需要有以下處理機(jī)制,或者說設(shè)計(jì)好以下處理機(jī)制,可以把自己寫的庫很好的給其他人使用。
代碼約定模式,交互抽離模式,數(shù)據(jù)封裝模式,加密混淆機(jī)制,工具類包,插件管理模塊,加載器,攔截器,動(dòng)畫處理模塊,緩存控制器,超時(shí)監(jiān)聽器,模版控制引擎,性能處理模塊(懶加載,按需加載,加速器),業(yè)務(wù)邏輯控制工廠,操作日志管理。
當(dāng)然根據(jù)不同的項(xiàng)目還有很多特殊的模塊,例如做客戶端涉及到解壓縮這樣的,可以設(shè)計(jì)一個(gè)請(qǐng)求代理模塊。
對(duì)外還要提供一個(gè)給開發(fā)人員配置或者編寫的API層。當(dāng)然還需要一個(gè)盡可能完整的使用說明。
五、什么是約定式編程?它和引擎技術(shù)有什么關(guān)系?
我們?cè)诰幊痰臅r(shí)候,如果盡可能的減少代碼量,最直觀的方式就是約定了。例如spring種就有約定模式的影子。所以在設(shè)計(jì)Crow5的時(shí)候,我大量的采用了約定的模式。
簡(jiǎn)單的描述,如果頁面叫index.html,那么控制器的調(diào)用可以叫UI.index。那么,頁面請(qǐng)求的接口可以約定成romote_index。調(diào)用的模版名字可以叫做index_tpl。如果是ajax處理的事件綁定函數(shù)可以約定成 ___index 等等。所有的處理邏輯入口和調(diào)用的名字都是可以約定的。如果有了這個(gè)約定的方式,那么所有類似的編碼就有了規(guī)則,這樣就可以抽象成規(guī)則引擎。那么以后我們只需要傳輸參數(shù),配置。代碼就按照規(guī)則自動(dòng)生成了。
上面的頁面都是用引擎自動(dòng)生成的,我們可以看一下代碼。
編寫的代碼就是配置文件,其余所有代碼由引擎自動(dòng)搞定。所有的性能處理都可以配置。這樣***的減少重復(fù)編碼。
六、你對(duì)引擎技術(shù)的研究后續(xù)會(huì)是什么樣子?
對(duì)于未來繼續(xù)研究的是語義方面的抽取,所有引擎的代碼部分是可以通過云平臺(tái)自動(dòng)實(shí)現(xiàn)按需分配,生成項(xiàng)目的引擎核心。根據(jù)平臺(tái)的配置自動(dòng)實(shí)現(xiàn)配置文件的自動(dòng)生成。這樣在做APP或者demo的時(shí)候,可以實(shí)現(xiàn)自動(dòng)生成。
探索無止境,需要很多靈感,很多設(shè)計(jì)靈感就是從動(dòng)物身上得到的,例如在設(shè)計(jì)心跳保持技術(shù)的時(shí)候,就是觀察青蛙冬眠這個(gè)事情上,抽取總結(jié)心跳加速,減速,停止,蘇醒等。希望能把引擎技術(shù)繼續(xù)往語義方向上突破,可能那個(gè)時(shí)候的編程就變成了問答。