|
任何一位在兩個(gè)領(lǐng)域里——本地應(yīng)用程序和Web應(yīng)用程序——都做過長期開發(fā)的人都會告訴你,web應(yīng)用開發(fā)和傳統(tǒng)的應(yīng)用開發(fā)有很大的不同。這指的并不是編程語言。同樣用Java,或者是Python,甚至C++,你既能開發(fā)本地應(yīng)用,也能開發(fā)出web應(yīng)用。不同之處在于web的載體介質(zhì)。它體現(xiàn)出的是一種完全不同的部署和運(yùn)行環(huán)境。它實(shí)現(xiàn)了一種不同的服務(wù)模式。它使用的是一種不同的應(yīng)用架構(gòu)。它需要程序員采用一種不同的思維方法,因?yàn)閣eb編程所體現(xiàn)出的哲學(xué)體系跟我們傳統(tǒng)的編程派系都相去甚遠(yuǎn)。在此,對于web編程范式,我們有一些有趣的事情需要去認(rèn)識清楚。雖然很明顯,很真實(shí),但卻被現(xiàn)代強(qiáng)勢的編程范式的陰影遮蔽著,被眩目的新技術(shù)和工具的光芒淹沒了。
“究竟是什么?” – 你會問。
我們就來看看。
我們從看看典型的本地應(yīng)用程序的生命周期開始,拿它跟典型的Web應(yīng)用程序的相比較。我將會一直使用“生命周期”這個(gè)詞來表示應(yīng)用程序的活動周期,運(yùn)行時(shí)的,指的不是包括不同開發(fā)和維護(hù)階段的項(xiàng)目周期。
一個(gè)典型的本地應(yīng)用程序的生命周期是什么樣子的?一個(gè)用戶啟動這個(gè)程序,程序被加載到內(nèi)存里,開始運(yùn)行。它能對用戶的輸入起反應(yīng),從磁盤上讀取文件,或通過網(wǎng)絡(luò)傳輸數(shù)據(jù)。它能跟其它的軟件或硬件進(jìn)行交互,調(diào)用其它服務(wù),或響應(yīng)一個(gè)外部調(diào)用。它可以收集數(shù)據(jù),累計(jì)數(shù)據(jù),以某種方式處理這些數(shù)據(jù)。簡言之,這些都是一個(gè)本地應(yīng)用程序啟動后,運(yùn)行時(shí)能做的事情。
一個(gè)典型的web應(yīng)用程序的生命周期是什么樣的呢?用戶在瀏覽器里點(diǎn)擊一個(gè)鏈接。瀏覽器向web服務(wù)器發(fā)送一個(gè)請求,然后會接收到響應(yīng)信息,把它展示給用戶。非常的簡單。但應(yīng)用程序并非是運(yùn)行在用戶機(jī)器上的瀏覽器中的。它運(yùn)行在web服務(wù)器中。在那里,應(yīng)用并不是持續(xù)的運(yùn)行。服務(wù)器只是短暫使應(yīng)用蘇醒來完成處理請求的任務(wù),準(zhǔn)備好要回復(fù)的東西。這些事情發(fā)生在眨眼之間。在兩個(gè)請求之間應(yīng)用并不處于運(yùn)行狀態(tài)。它只是被調(diào)用很短的一段時(shí)間,當(dāng)完成請求服務(wù)后會立即停止運(yùn)行。而且應(yīng)用也不會被整個(gè)的加載到內(nèi)存里,只會加載對于目前的任務(wù)真正有必要的部分。你可以認(rèn)為web應(yīng)用程序只有一個(gè)瞬時(shí)的生命期。只有它的運(yùn)行所在的環(huán)境,也就是web服務(wù)器在持續(xù)的運(yùn)行。事實(shí)上會有一些變通的策略,例如session和數(shù)據(jù)序列化,來幫助在應(yīng)用程序的生命期之間保持?jǐn)?shù)據(jù),來模仿有狀態(tài)的操作,例如某些框架,像ASP.NET的WebForms或JSP就是這樣做的,但畢竟,這都是些技術(shù)上的技巧,跟本文所討論的問題不相干。我們關(guān)注的是普通的web應(yīng)用,關(guān)注它們處理請求的過程。這些web應(yīng)用程序都只享有一個(gè)非常短暫的運(yùn)行存在狀態(tài)。
對于開發(fā)本地應(yīng)用程序,有很多技術(shù)被證明非常有用。面向?qū)ο蟮姆椒梢杂脕順?gòu)造問題環(huán)境,幫助降低問題的復(fù)雜性。一些設(shè)計(jì)模式能體現(xiàn)出一種高效的,而且優(yōu)雅的設(shè)計(jì)方案。分層的架構(gòu)把代碼責(zé)任分離,最小化各層的依賴性。這些全是典型的最佳方案,它們在開發(fā)本地應(yīng)用程序的過程中被充分的證實(shí)過。
而在web應(yīng)用程序里對這些技術(shù)方案的使用卻是另外一種不同的情形了。我們積極的使用面向?qū)ο蟮姆椒▉矶x我們的業(yè)務(wù)模型,我們采用各種設(shè)計(jì)模式,我們實(shí)現(xiàn)分層架構(gòu)。這些幫助我們提高代碼質(zhì)量,增加復(fù)用性,把應(yīng)用程序組織成概念上的各個(gè)模塊。這些都很有效,是我們最常用的技術(shù)路線。但即使如此,我還是忍不住要提醒你,這些東西看起來有些多余,有大炮打蚊子的感覺。時(shí)不時(shí)我會盯著這些精巧而且深思熟慮的代碼,一種無由的想法會襲上我的心頭:干嘛不把這些全都剝離掉,直接做要做的事情呢?
什么是直接做?想想一個(gè)應(yīng)用處理一個(gè)請求的典型處理方式。在主要步驟里發(fā)生了什么?應(yīng)用程序接收用戶輸入,校驗(yàn)它,把它轉(zhuǎn)換成業(yè)務(wù)領(lǐng)域相關(guān)的格式,把它傳進(jìn)一個(gè)SQL語句里,保持到數(shù)據(jù)庫里。下面又發(fā)生了什么?程序從數(shù)據(jù)庫里讀出一些數(shù)據(jù),格式化信息,使之能夠被用戶識別,以一段HTML的形式返回給用戶使用。就是這樣。這就是大多數(shù)web應(yīng)用程序在其幕后所做的事情。在它們的運(yùn)行期里沒有什么特別的對象,它們發(fā)送和接收消息,智能的在其內(nèi)部交互運(yùn)作來實(shí)現(xiàn)高層的行為。不,只是一些數(shù)據(jù)在用戶和數(shù)據(jù)庫之間旅行,送出去,返回來。就是一個(gè)接一個(gè)的數(shù)據(jù)流。實(shí)現(xiàn)這些任務(wù)的程序代碼本質(zhì)上就像一個(gè)函數(shù)式程序,不管它們被構(gòu)造出來的風(fēng)格是什么樣的。
有個(gè)討論直指這個(gè)主題: Is functional programming relevant to web development? 其中一個(gè)雄辯的用戶寫道:
“函數(shù)式編程跟web應(yīng)用開發(fā)非常的匹配。web應(yīng)用接收一個(gè)HTTP請求,生成一個(gè)HTML返回結(jié)果。這應(yīng)當(dāng)被認(rèn)做是一個(gè)從請求到頁面的函數(shù)式功能。”
而我要補(bǔ)充下面的東西。實(shí)現(xiàn)這些功能的代碼本質(zhì)上反映的就是函數(shù)式的風(fēng)格。我們并沒有用真正的對象把應(yīng)用程序的狀態(tài)保存在內(nèi)存里、用它們來實(shí)現(xiàn)應(yīng)用邏輯操作,我們使用的是數(shù)據(jù)庫來保存應(yīng)用程序的狀態(tài),整個(gè)的代碼基本上就是一個(gè)巨大的,復(fù)雜的函數(shù)式功能編碼,它來管理特定數(shù)據(jù)流的走向:數(shù)據(jù)庫或用戶。
從這些討論我們能得到什么?狂熱的強(qiáng)制使用面向?qū)ο蟮娘L(fēng)格、對web應(yīng)用使用復(fù)雜的架構(gòu)未必總會有好處。你不一定就能從這種架構(gòu)方式中獲得有價(jià)值的好處,但從性能和日后維護(hù)的角度看,它們卻能使你的應(yīng)用過于復(fù)雜和效能低下。我們必須針對每個(gè)項(xiàng)目的各自情況來掂量采用某種方式的好處和壞處。
當(dāng)一個(gè)程序員編寫一個(gè)web應(yīng)用程序,如果突然代碼中顯示出了函數(shù)式編程風(fēng)格的印記時(shí),不要馬上批評和嘲笑他。也許他是特意這樣做的。也許這是一種敏銳的感覺到web編程本身就是天生的函數(shù)式編程的潛意識表現(xiàn)。
[英文出處]:Web programming is functional programming
it知識庫:Web編程是函數(shù)式編程,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。