剛過去的周五3-14)例行地主持了技術會議,主題正好是《UI層的設計模式——從Script、Code Behind到MVC、MVP、MVVM》,是前一天晚上才定的,中午花了半小時准備了下就開講了。
今天看到了大家在為MVVM knockout.js友(ji)好(lie)地交流,所以就整理下然後更擴展地分享。
主要目的也不是為了爭論,畢竟只是正巧主題相近,原本的打算也就是一次技術分享並且記錄下來。
那麼我們就按照大致的歷史進程將這些概念進行劃分:
我們知道的是現實的歷史發生順序並不如上,因為思想都是相似的,比如MVC很早很早就出現了,解釋型語言至今基本上也有很多分支而且在互聯網時代大行其道。
但我要說的是:不要在意這些細節!
當然了,這是玩笑,我的意思是,這些內容我懶得應該在另外獨立的主題探討,篇幅也有限。
Script
這裡腳本的意思不是指當時是用腳本開發,而是像寫腳本一樣開發。它們都有一個特點:功能單一、管理單一、入口單一。
我們最早的程序是匯編,當時的碼農的工作是兼職,工作內容是編寫一套壽命不長的機器控制指令,有些甚至是命令,比如至今依然保留的Command亮點自尋):
到後來計算機被用於科學計算等,需求推動了需要更高的開發效率,所以我們有了高級語言。
那個時候碼農其實多是數學家,程序的作用很簡單,就是執行一些數學計算,類似今天ICPC的一些算法問題,比如Hello World:
- main()
- {
- printf("hello,world\n");
- }
這時候,程序還可以被歸結為輸入到輸出的過程,我們還能去講講馮諾依曼模型。
在這個時代,開發是指編寫機器指令,甚至都不配用“開發”這個詞來描述這項工作。
軟件、UI和Markup Language
在那個時代講UI等於放屁,根本不存在這種概念。但全賴我們有神器——摩爾定律。
但我個人認為摩爾定律是不足以讓一個敲命令行的時代在幾十年間轉變成這種各類框架技術架構實踐模式的時代,真正推動計算機形成自有的工程學體系的是還有兩樣東西就是:
因為人的能力並沒有“跟上”機器,所以才會出現各種模式、方法、工具等等來補足人的不足,以最大地透支機器性能。就像我前幾天在閃存無聊時突然想到的一句: 架構是對客觀不足的妥協,規范是對主觀不足的妥協。
當我們需要機器做的事情多了起來,我們就沒辦法在一個芯片上解決所有事情,所以才會有馮諾依曼模型、計算機架構,沒辦法用一台機器解決,所以才要互聯網、分布式、雲計算。
同樣,隨著計算機的發展,要做的事情多了,就出現了軟件的概念。當“開發”正式化,我們需求的軟件就變得:功能繁雜、管理統一、多入口。
真正變化的不是客觀本質,而是需求。就像這裡說的“軟件入口”在客觀上我們還是只有一個,原理上始終都只有一個啟動程序、一個啟動代碼片段。但“軟件的入口”,已經從指代Main函數變成了指代起始UI,用戶已經從指代專業人士變成了指代一般消費者,先有軟件的需求,才有軟件的定義,而需求是在變化的。
一個軟件需要比當時多幾個數量級的代碼:
所以我們需要添加索引、用多個文件組織代碼。
機器的發展和軟件的需求擴大和細化,我們開始出現了用戶界面User Interface)的概念和最適合用於界面的語言——標記語言Markup Language)。當然,ML不是為UI而生的,它只是十分適合UI,所以才和UI墜入愛河。
因為有了更高UI的需求,所以代碼才正式被分化為描述做什麼業務邏輯)和有什麼UI)的兩部分,因為我們開發時沒辦法在兩種思維方式下同時工作,開發時的人腦是單線程的。我們所看到的同時進行UI和邏輯開發只不過是我們學會了在兩種模式下快速切換,看起來像同時進行,而不是真正的同時進行。同樣的情況也發生在不同的代碼片段的開發中。
分化的情況除了UI,還發生在方方面面,比如數據操作、UI的對象和樣式分離,我們還是繼續從UI講下去吧。
Code Block和Code Behind其實還有Code Inside,比如onclick="javascript:alert('哎呀我*')")
UI和邏輯分開了兩種語言來寫,但是它們也要放在同一個項目中,因為它們原本就是要一起工作的。即使是分開,也需要相連,因為這是它們本來要解決的問題。
這時候我們出現的通常的)解決方案就是Code Block和Code Behind。雖然從時間上似乎Code Block比Code Behind要早,有種感覺就是越新越好,但實質上它們正交替地發展著,因為誰也沒辦法解決UI和邏輯代碼分化後的一個哲學問題——UI和邏輯是一起的,但是它們卻不是一起的。
Code Block能很好地處理UI和邏輯間在一起的關系,你在同一個地方可以同時維護UI和邏輯:
- @model GM.OA.Finance2.Web.Models.FinancialBase.CurrencyModel
- @{
- ViewBag.Title = "EditCurrencyDrawer";
- Layout = "~/Views/Shared/_DrawerLayout.cshtml";
- }
- @section styles {
- <link href="/Content/base/table-form.css" rel="stylesheet" />
- <link href="/Content/base/drawer.bigtitle.css" rel="stylesheet" />
- }
- <a href="#" class="addcurrency oa-btn" oa-style="green">添加新幣別</a>
- <script type="text/javascript">
- $(document).ready(function () {
- $('.addcurrency').click(function () {
- $.oa.drawer.openUrl('AddCurrencyDrawer/', 'addcurrency', {
- width: 300
- });
- });
- });
- </script>
Code Behind能很好地處理UI和邏輯各自分開的關系,你可以讓UI和邏輯各自做好各自的事情:
- <asp:Button ID="RemoveSelectedCurrency_Button" runat="server" Text="刪除選中幣別" OnClick="RemoveSelectedCurrency_Button_Click" />
- <asp:Button ID="RemoveAllCurrencies_Button" runat="server" Text="刪除所有幣別" OnClick="RemoveAllCurrencies_Button_Click" />
- protected void RemoveSelectedCurrency_Button_Click(object sender, EventArgs e)
- {
- var currencyId = Currencies_ListBox.SelectedItem.Value;
- currencyManager.Remove(currencyId);
- }
- protected void RemoveAllCurrencies_Button_Click(object sender, EventArgs e)
- {
- currencyManager.RemoveAll();
- }
因為存在兩種實現方式,所以就存在了對比,因為存在了對比,所以就存在了爭論。就像是Java和.NET、PHP和.NET、WebForm和MVC、Mac OS和Windows、iOS和Android、騰訊和所有其他互聯網公司,等等。
問題不在哪個更好,而是我們要解決什麼問題。當然,這聽(ben)著(lai)像(jiu)是客氣話了。
真正在UI和邏輯分化後帶來的實質問題是:
至少UI和邏輯剛分化的時代,在軟件上,我們還認為同一項事務是基於同一個UI的一系列操作完成的。
在摩爾定律還持續發揮作用的時候,計算機領域依舊高速發展,所以通常我們還在為一樣事物爭論、思考、辯證的時候,它已經發生了質變了,不變的只是我們要解決的問題。