天天看點

《重構HTML:改善Web應用的設計(修訂版)》——1.3 重構什麼

本節書摘來自異步社群《重構html:改善web應用的設計(修訂版)》一書中的第1章,第1.3節,作者: 【美】elliotte rusty harold 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

諸如java之類的程式設計語言和諸如html之類的标記語言的重構有一個關鍵的差別。與html相比,java變化相對緩慢,c++的變化很少,c就更不用說了。用java 1.0編寫的程式跟java 6的跑起來沒有什麼大的不同。java增加了大量新特性,但大體上能保證一緻性。

然而,html和相應的技術在同樣的時間範圍内卻發生了巨大的變化。今天的html跟1995年的根本不是一碼事。新版不僅剔除了一些關鍵字,也加入了一些新的關鍵字,在文法和解析算法上也有所改變。盡管現代浏覽器如firefox或ie 7通常可以顯示一個過時的頁面,但你會發現很多東西根本無法正常運作。進一步講,浏覽器必須處理css和ecmascript等全新元件。

本書給出的大部分重建構議,将會重點圍繞更新網站以支援web标準,尤其是:

xhtml

css

rest

這有助于将開發人員從以下困境中解救出來:

标簽湯

基于表現的标記

有狀态(stateful)應用

這裡并沒有非此即彼的選擇或是孤注一擲的決定。你總是可以從3個方面入手改善網站的特性,用不着追求盡善盡美。持續改進是重構的重要特征。小改動産生小改善,沒有必要畢其功于一役。你可以在實作有效的xhtml之前先實作良構的xhtml;在轉向css之前也可以先實作有效的xhtml;在進一步考慮消除會話(session)或會話cookie之前,可以先把網站完全符合css的布局做完。

當然不一定得按照這些順序來執行這些改動。你可以從建議清單中選擇能為應用程式帶來最大好處的重構方案。這有可能是不需要xhtml但是急需css的情況;又或者需要把應用程式的架構轉向rest以提升性能,但并不關心把文檔轉為xhtml。不過最終選擇權在你手中。本書給出了各種建議和方案,幫你權衡各種重構方式的代價和收益。

使用标簽湯、基于表格的布局、圖像映射和cookie建構web應用當然是可以的,但擴充它的投入大部分人都擔負不起。橫向(更多使用者)和縱向(更多功能)的擴充均需要一個比較健壯的根基,而這些正是xhtml、css和rest所能提供的。

1.3.1 為何要用xhtml

xhtml隻不過是xml化的html。html至少在理論上基于sgml,而xhtml則基于xml。xml是一個比sgml更簡潔和清晰的規範。是以,xhtml是html簡潔、清晰的一個變體。選擇xhtml還是選擇html,這就像眼前擺着一把槍,你是去扣動扳機,還是去做靶子,那感受可是天壤之别。

對使用者更友好的xhtml頁面是以編寫者更難開發為代價的。html容許犯錯,但xhtml不容許。在html中,如果忽略了結束标簽或是在這裡或那裡留下了多餘的引号,不會發生什麼大事,最多隻是有些文本被标記為粗體了,或者不正确地縮進了。即使是最壞的情況,也隻是在這、在那少了一些詞語而已,頁面的大部分還是能顯示出來的。這種寬容的本性使得html的學習更加容易。因為你編寫的html即使是不正确的,也不至于發生嚴重的問題。

但xhtml非常嚴格。諸如漏掉引号或忽略結束标簽這些細微的錯誤,在html中浏覽器會默默補上,但在xhtml中就會成為嚴重的四級警報。在xhtml文檔中,就算是小小的錯誤,浏覽器也隻能舉手繳械,拒絕顯示頁面,如圖1-2所示。這讓編寫xhtml頁面的工作難度加大,特别是在使用純文字編輯器時。但就跟編寫計算機程式一樣,一個文法錯誤能破壞所有東西。錯誤是沒有商量的餘地的。

《重構HTML:改善Web應用的設計(修訂版)》——1.3 重構什麼

https://yqfile.alicdn.com/6c98d24759dab9b137d06f9054c57ad60b3ae64b.png" >

那麼為什麼大家都要選擇xhtml呢?這是因為,雖然這些限制加大了編寫xhtml的難度(嚴格的錯誤處理),但卻簡化了xhtml的處理。現在接力棒已經從浏覽器交到了編寫者的手中。浏覽器(或者其他要讀取頁面的裝置)不必再試圖弄懂混亂的标簽湯,并去猜測頁面的真正意圖。隻要頁面有一丁點兒的不清晰,浏覽器就可以(實際上也是有必要的)放棄并拒絕處理。這能讓浏覽器的工作更簡單。目前大多數浏覽器在解析html代碼時,都把精力投入到糾正頁面的錯誤中去了,有了xhtml後就沒有必要這麼費心了。

當然,我們絕大部分人都不是浏覽器開發者,而且可能永遠沒有開發浏覽器的機會。我們能從xhtml及其嚴格的錯誤進行中得到什麼好處呢?自然有好幾條。首先,盡管大多數人不用去開發浏覽器,但大部分人要編寫支援網頁的程式。這些程式可以是混搭(mashup)、web spider、blog聚合器、搜尋引擎、開發工具等,它們都需要讀取網頁。這些程式處理xhtml要比處理html容易得多。

當然,通過web工作或者編寫網頁的大多數人都不是傳統的程式員,而且不會去編寫 web spider或blog聚合器。但有兩樣很有可能需要他們去編寫:javascript以及樣式表。從數量上來說,這是最普遍的一類讀取網頁的程式。所有嵌入到網頁中的javascript程式都需讀取網頁。所有的css樣式表(盡管從傳統的角度來看,它并不是程式)也需讀取頁面。如果javascript和css讀取的是xhtml而不是html,就更容易編寫和除錯。實際上,編寫有效的xhtml所付出的額外代價,在為javascript和css除錯時會獲得更多的時間補償。

修複xhtml錯誤是惱人和花費時間的,但這是一個相當直接的過程,并不是那麼困難。驗證器能列出這些錯誤,你可以浏覽這個錯誤清單并逐一修正它們。事實上,這種層次上的錯誤比較明顯,可以自動修複它,這會在第3章和第4章中介紹。修複xhtml可能得花費些時間,但這些時間總量是可預估的。這樣才不至于讓你在病态的html中,進行javascript或css的跨浏覽器排錯時變得沮喪,看不到完工的盡頭。

使用文本編輯器手工編寫正确的xhtml也是一個不小的挑戰。不過由工具生成标記的話,xhtml會變得更容易。良好的wysiwyg(所見即所得)html編輯器(比如dreamweaver 8)可以(而且應該)被配置為在預設情況下生成有效的xhtml。标記級别的編輯器(如bbedit)也可以設定為使用xhtml規則,盡管編寫者需要小心對待。很多編輯器都有檢查xhtml有效性的選項,可以設定為通過單擊一個按鈕就可自動修正任何錯誤。

保證你已經開啟編輯器的一些必要選項。與良好的cms和wiki類似,blog引擎也可以根據需要生成xhtml。如果你的編寫工具不支援xhtml,盡一切辦法找個更好的工具。在21世紀的今天,html編輯器或web釋出系統不會不支援xhtml。

如果你的網站是手工搭起的模闆系統,有可能得多做些工作,在第3章和第4章中我們會看到這種需求。盡管這種處理手工做得多了一些,但一旦做完就能自動生成有效的xhtml。釋出者通過資料庫或者web表單輸入内容時,或許完全不需要改變他們的工作流程,特别是在使用如markdown或wikitext等非html格式的資料時。系統可以輕松地将它們轉換為xhtml。

使用xhtml而不是html的第二個理由是跨浏覽器相容性。實際上,在今天的浏覽器上xhtml比html更具有一緻性,大量使用css和javascript的複雜網頁更是如此。盡管浏覽器可以修正傳統html的标記錯誤,但并不是總能以相同的方式處理。雖然兩個不同的浏覽器讀取的是相同的頁面,但會産生不同的内部子產品。這給編寫跨浏覽器的樣式表或腳本增加了難度。反之,xhtml并不需要浏覽器做大量解釋,也減少了浏覽器抓狂的機會。誠然,不同的浏覽器對css、javascript和dom(文檔對象模型)相容性的支援不同,但轉向xhtml清除了跨浏覽器相容性的一大障礙。即使不是完整的方案,但也可以修正大量的問題。

第三個理由是在頁面中加入未來的新技術。從上面詳細列出的理由可知,xhtml是更為強大的平台。html善于顯示文本和圖檔,對于簡單的表單來說也還不錯。但除此之外,浏覽器也是flash、java和ajax等其他技術的宿主。很多功能在浏覽器中并不容易實作,比如數學公式和音樂曲譜。有些功能本來就是不難的,比如在表單中輸入錯誤的值時提示使用者。

為改善這些問題的技術在不斷發展,而且還有更多的技術正在開發當中,包括為數學公式準備的mathml,為樂譜準備的musicxml、為動畫準備的svg(scalable vector graphics,可伸縮矢量圖形)和為強大用戶端程式準備的xforms等。所有這些都是以xhtml為基礎的,但它們都不能正确地基于傳統的html使用。把頁面重構為xhtml可以利用即将到來的新技術。在某些情況下,新技術可以讓你做到原先做不到的事。在其他情況下,讓你做到現階段技術所能做到的,而且更快更容易。無論是哪一種情況,隻要是其中之一,都值得你去把html重構成xhtml。

1.3.2 為何要用css

把表現從内容中分離出來是html的基本設計原則。這讓你可以為不同的用戶端提供相同的内容,但可以由用戶端來決定樣式,最大程度上适應它們所需要的環境。手機浏覽器不具備firefox等桌面浏覽器一樣的性能。實際上,手機浏覽器很可能根本不去可視化地顯示内容,而是隻把文檔内容讀給使用者聽。

是以,html文檔應該側重表達的是文檔的意義而不是文檔的表現。更重要的是,這種編寫風格尊重使用者的偏好。通路者可以選擇适合自己的字型和顔色,而不是編寫者提供的預設值。一種尺碼并不能适合所有人。擁有正常視力的30歲飛行員非常容易看清的網站,可能對于一位85歲的老奶奶來說就是模糊不清的;一個漂亮的藍綠設計對于一個色盲使用者來說可能就是很費解的;一個精心設計的表格布局,對于正在花園州高速公路(garden state parkway)上兜風時使用手機收聽網頁的司機來說,隻不過是一些雜亂無序的詞組。

在html中,你不應将一些段落格式css化為左對齊的11點的加粗arial字型,而應該指定它是一個h2标題。自從netscape出現并發明了font标簽和其他一些表現性元素後,人們就馬上開始使用——恐怕你也沒少用吧。雖然之後w3c以css作為回應,但是這種破壞業已産生。網頁到處充斥着font、frame、marquee以及其他表現性元素。語義元素如blockquote、table、img和ul的本身意義都被颠覆了,隻用來達到布局的目的。坦白地說,雖然運作并不是那麼好,但很長一段時期内,這是我們所能做到的最好狀态。

但現在不一樣。今天的css不僅僅是簡單的重複,比起使用frame、占位gif以及圖檔隐藏文本等做法實作的布局和表現相比,它要優秀得多。css布局不僅更精美,而且更少偏差、更高效、更好用,而且頁面加載變得更快,顯示得更好。多做些努力,css就能讓頁面在多平台多浏覽器上運作得更好。

把表現标記挪出頁面并放到分離的樣式表中去,你就可以從一個簡單的頁面開始,這種簡單性對所有通路者都是清晰的,即使使用的是10年前的浏覽器。然後可以為這些頁面賦予漂亮的外觀效果,改善使用它們的使用者的體驗。這麼一來不會有任何人被拒之門外,頁面實作了優雅降級(degrade gracefully)。

這種方式也對開發者有利。首先,它讓掌握不同技術的不同開發者可以發揮自己的長處:内容作者不用顧忌最終格式而奮筆直書,設計者可以不了解内容作者的語句就組織和重排頁面,程式員可以不妨礙頁面的表現而開發腳本,為頁面添加功能。css讓每個人在互不幹擾的情況下各司其職發揮所長。

如果css對于内容作者和設計者來說是小恩小惠的話,那麼對開發者來說簡直是天大的恩賜。從程式員的角度來看,把所有的布局和樣式挪出來放到一個分離的css樣式表中後,頁面會變得非常簡潔。文檔樹内的元素更少,嵌套深度也更低,編寫與頁面有關的互動腳本的難度也大幅度下降。

最後的赢家莫過于勤勤懇懇管理整個網站的站長(web master)了。移除表現性标記和分離樣式表,可以組合通用的樣式,并保持整站一緻的觀感。把預設字型從arial修改為helvetica不再需要編輯上千個html文檔,現在隻需在一個獨立的樣式檔案中修改一行就能搞定。

css讓web開發者、站長和web設計者都能遵從dry原則:别自我重複(don’t repeat yourself)。把通用的規則組合成獨立的、可複用的檔案,可以簡化維護、更新和編輯。甚至最終使用者也能從中得益,因為他們隻需載入一次網站的樣式規則,而不是每個頁面都得重新下載下傳一遍。更輕量的頁面載入得更快,顯示得更流暢。這真是一個共赢的局面。

最後,不要忽略了css對網絡管理者和會計師的重要性。雖然每個頁面中純表現性的資訊可能隻占1kb到2kb,但對于上千個頁面和百萬之巨的使用者,總量就會大得驚人。隻載入一次樣式,不用每個頁面都載入額外的表現性标記,就可以節省帶寬。espn在轉向css标記時,每天節省了2tb的流量。從這個層次上說,這能轉化為實實在在的收益,節省程度大緻上是可以估量的。誠然,我們開發的絕大多數站點都不能跟espn相提并論,隻能幻想着每天能先有2tb的日流量,而我們能夠節省日流量則遠遠少于2tb。但不管怎麼說,如果你正經曆着流量超載,或是有希望被digg首頁推介而流量大漲,把樣式挪到外部的css樣式表中肯定會大有幫助。

1.3.3 為何要用rest

rest(representational state transfer,表述性狀态轉移)是本書提出的出現最早但可能知道的人最少的重構目标。盡管本書側重于html,但也不會忽視html的傳輸協定http,rest是http的架構。

了解http和rest對如何設計web應用程式非常重要。在頁面中放置表單,或使用ajax在javascript程式中傳遞資料時,使用的就是http。正确使用http可以開發健壯、安全和可擴充的應用程式。但使用不慎的話,你能祈禱的最好結果隻是一個功能勉強可用的系統,但可能會發生的最壞情況是非常不妙的:web spider會删掉整個站點、購物中心在聖誕購物期間由于繁忙的業務而當機或者搜尋引擎無法索引導緻使用者無法找到你的網站。

盡管基本的靜态html頁面有着内在的rest方式,但大部分更為複雜的web應用程式并不是。特别是在應用程式涉及以下常見的特性時,必須考慮使用rest:

表單

使用者驗證

cookie

會話

狀态

人們很容易在這些特性上犯錯,現在很多應用程式使用它們的方式也是錯比對多。web不是lan,那種為少數而且有限c/s系統服務的技術,都不能擴充為可以容納千萬級使用者的web系統。基于會話和持久連接配接技術的c/s架構對web并不适用。試圖重建它們會敗在擴充上,通常會導緻損失慘重的後果。

使用http實作的rest擁有一些關鍵的概念,這會在接下來的内容中讨論。

所有的資源通過url定位

使用不同的url給不同的資源打上标簽,讓它可以被收藏、連結,被搜尋引擎索引或印到廣告牌上。

别抵觸url,大部分資源都應該隻通過url定位。就是說,每個客戶都應該有一個獨立的url直接連結到他的記錄(當然有密碼保護),而不是所有客戶都共享同一個url,通過不同的登入cookie才能改變這個url下的内容。

通過get進行諸如查詢或浏覽等安全無副作用的操作

google隻能索引通過get通路的頁面,使用者隻能收藏通過get通路的頁面,其他網站隻能連結使用get的頁面。如果想提升網站的流量,應該讓使用者盡可能以get方式通路網站。

通過post進行諸如購買或添加評論等非安全的操作

web spider按慣例在頁面上抓取的是通過get通路的連結,即使有時被告知是不應抓取的。使用者在浏覽器位址欄中鍵入url,然後修改它們就能看到發生的結果。浏覽器預抓取連結頁面也是通過get。如果存在如删除内容、簽署合同或重新排序等通過get執行的操作,有些程式某種程度上并不會征求真實使用者的同意就開始執行,這有時會産生十分嚴重的後果。當google發現并抓取“删除此頁”之類的連結時,整個站點可能就會是以消失,這都是因為使用get取代了post。

各個請求彼此獨立

用戶端和伺服器端都可以有自己的狀态,而且互不依賴對方。所有必要的資訊都在每一次通信中傳遞。無狀态讓擴充得以通過緩存和代理伺服器來實作,在有必要時同樣也支援伺服器群代替單台伺服器。同樣,伺服器對相同用戶端沒有必要連續響應兩次。

健壯、可擴充的web應用程式應該使用http而不是抵觸http。常見的c/s應用程式是可以做到的,rest風格的應用程式也可以照單全收,而且能做到充分的可擴充性。但是,這樣的實作可能要求系統進行巨大的改動。盡管如此,如果你擅于解決擴充性問題,那麼這就可以成為一項重要的重構技術。