115
Cloud Connected Inc. Front-End Modular & Automated Development 蔣定宇 / josephj / 啊嗚 建立前端團隊開發環境 http://tinyurl.com/coscup-josephj

建立前端開發團隊 - 2011 中華電信訓練所版

Embed Size (px)

DESCRIPTION

 

Citation preview

Cloud Connected Inc.

Front-EndModular & Automated

Development

蔣定宇 / josephj / 啊嗚

建立前端團隊開發環境

http://tinyurl.com/coscup-josephj

嗨!我是啊嗚 /josephj!很開心來到 sfasdf

• 2.5 年:Yahoo! 前端工程師

• 0.5 年:YDN 傳教士

• 1 年:無名小站工程師

• 1.5 年 ~miiiCasa 前端工程師

我的部落格 http://josephj.com

熱愛分享,認為最好的 Solution 是討論出來的

跑步環島在我 29 歲

2008 年 5 月時花了 27 天

跑了 八百多公里達成跑步環島的夢想

没有不可能

在 D-Link 現有的網路設備上建立服務、強化與使用者的關聯性

D-Link 網路服務處

現任職於

•單一網址存取

•分享方便

•私密性高

•容量自己決定

•與家人的 SNS

miiiCasa = WWW + Device = 位於你家裡的雲端

http://josephj.com/entry.php?id=348

miiiCasa Space

不論網內外,以相同介面與網址存取 Device 的檔案 http://www.miiicasa.com/space

miiiCasa Bar

在任何網站皆可存取 miiiCasa 的服務http://*

http://tw.yahoo.com http://www.google.com.tw

因為這些超有趣的概念、決定進入 D-Link當時只想要發揮前端的專長、把產品做出來

卻怎麼也沒想到...

因 D-Link 過去幾乎沒有開發大型網站的經驗,一進去什麼都沒有、得從零開始,我居然就開始去建立開發環境與決定軟體架構。

而這些事情在前一家公司 (Y!) 是没有機會碰的。因為它分工明確、高手多,且很多工具甚至有專門負責的團隊,加上各個服務大都已經有解決方案了,能够真的大刀闊斧地改變現有環境、或注入自己想法的機會相對較少。

Operation Engineer

Service Engineer

QA EngineerFront-end Engineer

System Architect

Software Engineer

System Analyzer

Project Manager

QA Tester

DBA

而在過程之中,我發現自己非常喜歡做前後端整合的工作。若只是單純 HTML/CSS/JavaScript 的撰寫以不能滿足我。結合其它技術讓前端能夠更好 (開發速度、效能、模組化、維護性) 是我現在熱血的方向。

非常鼓勵前端工程師跨往不同的領域因只有前端工程師才知道前端工程師要的是什麼

Server-side Script

Win32

CMS Apache Module

Flash

Embedded System

Firmware

Objective C

I18N/L10N PEAR

Azure

Android

Hardware

本日大綱

• 減少環境差異代碼不判斷環境、設定檔只有一份Fiddler Debugging Proxy 介紹

• 模組化開發:網站的基本單元不管 HTML, CSS, JavaScript 都以模組開發

• 自動化開發:讓犯錯變得困難Nicholas Zakas, “Make it difficult to make mistakes.“

1. 減少環境差異Eliminating environment difference

判斷環境、我做過的蠢事...在 JavaScript 裡判斷 Host、決定圖檔與 AJAX 路徑

在 PHP 也判斷路徑,連接手的 RD 也依樣畫葫蘆

你是否也有類似的判斷程式,或不同環境給不同的設定檔?

環境差異、開發人員數量增加、不同語言與種類、讓這些判斷程式與設定檔越來越多!難以維護、也增加除錯的困難度...

有沒有辦法可以做到?程式不判斷環境、設定檔只寫正式環境

需要克服的議題

• 每種環境伺服器所連結的資料庫 Host Name、數量不一樣。

• 開發機、Alpha 機、QA 機、Staging 機、Production 機的 Host 都完全不一樣。

• 靜態檔案也會有對應的 Host。• 每個工程師習慣的開發環境不同。• CSS/JS 通常在開發以外的環境須做好壓縮與合併,與開發時不同,必須要有不同設定檔作為區隔。

miiiCasa 的作法

• 修改非正式環境上的 /etc/hosts。• 程式碼内只寫正式環境的 Host Name:

www.miiicasa.com, api.miiicasa.com, a.mimgs.com

• 每個 RD 皆在 Linux 開發機開發。• 每個 RD 安裝 Fiddler。• CSS 内的 URL 皆須以 / 開頭的完整路徑。• 在 Deploy 時用 Shell Script 批次取代 Host。

問題 1 : 每個環境的 Host Name 都不一樣

Development

Alpha

Staging

Production

devm1.corp.miiicasa.com:5002*devm1.corp.miiicasa.com:50029

w1.alpha.corp.miiicasa.comimg1.alpha.corp.miiicasa.com

www.staging.miiicasa.coma.staging.mings.com

www.miiicasa.coma.mimgs.com

凡是需 Commit 至版本控管的代碼僅一份組態檔、且只能寫正式環境

對工程師來說只需要做開發機 Host 的對應即可

每個工程師都有自己的環境以 Port 做區隔,像我是 5002*

常見的作法是修改 host 檔但切換麻煩、又不支援 Port 對應

另有 Proxy PAC 檔、FF 或 Chrome 插件可切换但都没辦法做到每種瀏覽器的兼容性

經過一番尋找發現 Fiddler、Charles

這類 Virtual Proxy 軟體最符合我們的需求

對應正式環境

對應正式環境

Charles 是付費軟體、在每種平台上都可以跑。Fiddler 是免費軟體、只能在 Windows 上面跑。

Fiddler 的功能相較強大許多可自訂功能與取得多元的擴充套件開發時會碰到問題也較少

今天就針對 Fiddler 來做介紹!

Charles 與 Fiddler 的差別?

Cloud Connected Inc.

Fiddler Debugging Proxy

蔣定宇 / josephj / 啊嗚

不用不可的 Fiddler Debugging Proxy

http://tinyurl.com/josephj-fiddler

CSS 檔案内的背景圖檔路徑寫法

#mod .bd { background: url(bg_empty.png);}

#mod .bd { background: url(/home/bg_empty.png);}

#mod .bd { background: url(http://a.mimgs.com/home/bg_empty.png);}

實際位置在:/var/www/static/home/style.cssHTTP 請求路徑在:http://a.mimgs.com/home/style.css

三種都可行,你用那一種?

CSS 檔案内的背景圖檔路徑寫法#mod .bd { background: url(bg_empty.png);}

#mod .bd { background: url(/home/bg_empty.png);}

#mod .bd { background: url(http://a.mimgs.com/home/bg_empty.png);}

因為 Performance、CSS 檔案必須最小化且合併通常處理過後的 CSS 檔案會在根目錄產生第一種採用相對路徑的方式就會無法存取第三種雖可行,但過於複雜、容易打錯字

所以我們一律規定使用第二種方式、相容性最好。

檔案合併後 CSS 檔案位置有可能改變,需以 / 開頭/var/www/static/miiicasa/miiicasa.css

http://a.mimgs.com/miiicasa/miiicasa.css

或許可以直接寫 sp_ico_misc.png但若 CSS 在不同的路徑合併就有麻煩了

http://a.mimgs.com/combo?miiicasa/miiicasa.css&foo/foo.css

後端 Server 在不同環境的數量問題只要改主機上的 /etc/hosts 即可

不在這裡做,DB Access 的 Model 就會很複雜

開發以外的環境,因有其他角色需要存取例如 QA 與 Producer 裝 Fiddler 不太適合此時在程式碼中就必須是實際存在的 Host 了

只要在 Package 打包流程中處理掉即可用 Shell Script 動態取代 Host Name

1.1 結語:善用工具與規定、盡可能減少代碼在不同環境的差異性,可以讓程式維護起來更輕鬆!

DIV 模組化開發Modular Development

不再以「頁」為開發邏輯而是開發一個個可獨立運作的的 「DIV 模組」

它有獨立的 HTML、CSS、JS 檔案

Modular Development模組化是現今網站主流

#yhtw_masthead

#ykpmt

#ykpsb

#ykpimt

#ykpimqa #ykpimr

#ykpadv

#ykpug

#ykpiht#ykpiht

<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>

<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>

模組的 HTML 結構

一個 ID 代表一個模組不能重複

.hd, .bd, .ft 分別代表模組的header、body、footer

#ykpsb

•ykp 為知識+ 的 prefix

•sb 為 search box 的縮寫

•檔案:inc/search_box.php

<div id=”ykpsb”> <div class=”bd clearfix”> <form ...> ... </form> <div class=”extra”> ... </div> </div></div>

form .extra

[HTML]<style>#ykpsb { margin-bottom:10px;}#ykpsb form { float:left;}#ykpsb .extra { float:right;}</style>

[CSS]

因每個模組有 id,所以 CSS 可以寫得很 namespace

好處就是很安全,不同模組不會互相干擾

照片顯示模組

搜尋模組

列表模組

_photo_view.php_photo_view.css_photo_view.js

_photo_list.php_photo_list.css_photo_list.js

_photo_filter.php_photo_filter.css_photo_filter.js

HTML - 由許多模組所構成

獨立的 HTML 模組檔案

獨立的 CSS 模組檔案

CSS - 由許多模組所構成

獨立的 JavaScript 模組檔案

JavaScript - 由許多模組所構成

模組化的困難

• HTML:很好解決,只要用 include 即可。效能影響不大。

• CSS : 以 ID Selector 作為 CSS 命名空間可以做到。但若每個模組有一個檔案,一頁 30 個模組就會有 30 個檔案,Request 對性能影響很大。

• JavaScript : 跟 CSS 一樣有檔案數量的問題。另外該如何有效率的做跨模組的溝通?

Request 數量的問題

key - 頁面名稱

is_top: 放在 </head> 前或 </body> 前

另外有 is_noscript, media 等屬性可以設定

static.php - 每個頁面要放置哪些 JS/CSS 的組態檔

但 Request 量過多,勢必會造成性能問題

10 個 CSS Request

19 個 JavaScript Request

static.php 把模組的 CSS/JS 檔用一致的方法設定

Mini Tool

將代碼缩小多個 CSS/JS 檔案合併的

開發環境工具

模組檔再多也不需擔心效能的問題

http://www.flickr.com/photos/prettypony/2644225789/

Mini 的 XML 設定檔,把剛剛的設定移往這吧

尋找檔案的路徑、可定義多個。$DEV_ROOT 是在設定 Apache VirtualHost 的環境變數

每個 Mini module 有自己的 CSS 與 JS 檔

module 可以去加入其他的 module,也可以 exclude 某個檔案

index 的 CSS/JS 模組檔案

经过 Mini 合并及压缩的內容:跟線上一致

ㄙ/mini?module=<Mini module>&type=<css|js>

也可以只觀看合併但未壓縮的内容

ㄙ&nominify

這是原本又臭又長的 static.php

29 個 Request

網頁的 Request 量超級多 Orz...

2 個 Request29 個 Request

精簡過後的 static.php... 哇!

網頁的 Request 量大幅減少(大拇指)

透過 Mini 的設定檔,可將原本各自獨立的 CSS/JavaScript 檔案合併且最小化,達到效能最佳最佳化的目的!

但需要注意 Mini 並不適用於正式環境、通常放置 Statif File 的 Web Server 不安裝 PHP、而就算有也會對效能造成影響。

線上的 CSS/JS 在 Deploy 後變成單一檔

s* 用 md5_file() 檢查檔案內容產生的 stamping

可减少 CDN 上有重複內容的檔案

跨模組溝通的問題

JavaScript 跨模組溝通

JavaScript 若以模組為單位區分通常是獨立的 Function 或 Object有系統的跨模組溝通將會是大挑戰

mod A

mod C

mod B

使用者送出表單 取得資料

列表完畢

使用者點選照片

使用者點選大圖

需清空列表

需填滿列表

顯示第一張圖片

顯示點選的圖片

顯示下一張圖、選取框往下張

移動

使用者點選

window.mods[“photo-show”] = { showPhoto : function (src) { .... }}

window.mods[“photo-list”] = { init : function () { ... $(“img”).on(“click”, function(e) { window.mods[“photo-show”].showPhoto(this.src); } }

九成的人會用全域變數解決問題

當照片顯示模組没有一起在同一頁時,列表模組就會出現 Bug!

http://www.flickr.com/photos/vincentteeuwen/2816245519/

我們都希望球員 (模組) 們扮演好自己的角色在球場 (頁面) 上合作有場好比賽 (功能)

http://www.flickr.com/photos/acaben/2477822120/

但是缺乏紀律 (無架構、使用全域變數) 最後必將造成 (模組) 之間的衝突

雅虎首頁前端架構師 Nicholas Zakas 的啟發

JavaScript 應用程式架構

http://www.slideshare.net/nzakas/scalable-javascript-application-architecture

當頁面上多了一個模組它將不會破壞其他模组的結構、樣式與行為

它將提供新的功能、讓其他的模组可以與它溝通互動拿掉它時不需修改、也不會影響與其溝通模組的原有功能

Loose Coupling 鬆散耦合與其他模組的關係是鬆散的

http://www.thesoftwaredevotional.com/images/coupling_train.jpg

Broadcast & Listen模組溝通的方式類似 Hub 的概念

一台電腦出任何訊息,所有電腦都會收到但是其他電腦只處理它有興趣的訊息

模組是獨立運作的,類似插件的概念放在任何頁面上都不需修改、即可提供功能

http://www.flickr.com/photos/nadesign/4324782791/

Module - 獨立運作的個體

• 模組之間不知道彼此的存在• 模組只在意自己本身的功能

Static

Instance Instance Instance

Module Module ModuleStatic Static Static

Core - 整個架構的核心Core

• 接受模組註冊 (register)

• 控制模組啟動關閉 (start, stop)

• 所有廣播訊息的傳遞與對應 (match)

Static Class

Module Module ModuleStatic Static Static

Static

Sandbox - 模組 API 介面Core

• 以 Instance 的方式讓模組不受污染• 模組與 Core 溝通都需要透過 Sandbox

• 模組只能使用 Sandbox 提供的方法• 提供模組 broadcast 與 listen 功能

Static

Sandbox Sandbox SandboxInstance Instance Instance

Module Module ModuleStatic Static Static

broadcast(“need-love”, object)listen(“need-love”)

match(caller, object)

_photo_list.js 照片列表模組Y.Core.register("photo-list", { // 此模組的初始化 init: function (api) { // 這個模組有興趣聽取的兩種訊息 api.listen("photo-filter-submit"); api.listen("photo-filter-response"); this.api = api; }, // 此模組在頁面上 ContentReady onviewload: function () { // 告訴 Core 照片列表完畢,並且把第一張照片路徑一起提供 this.api.broadcast("photo-list-rendered", img.src); }, // 此模組收到訊息時 onmessage: function (eventType, callerName, data) { switch (eventType) { case "photo-filter-response" : this._updateUI() // 填滿列表 break; case "photo-filter-submit" : // 清空列表 break; } }, _updateUI: function (data) { // 告诉 Core 照片列表完畢,並把第一張照片路徑一起提供 this.api.broadcast("photo-list-rendered", img.src); }});

需清空列表

需填滿列表取得資料

使用者送出表單

顯示第一張照片列表完畢

`

範例 Demo

http://josephj.com/project/javascript-platform-yui-demo

miiiCasa 使用 CodeIgniter 作為 PHP Framework也利用了 HMVC Library 達成模組化

http://www.miiicasa.com/my 我的個人檔案頁

http://www.miiicasa.com/my 我的個人檔案頁

CodeIgniter 應用程式

CodeIgniter 模組

controller

views

~/miiicasa/index/my/controllers/index.php

~/miiicasa/index/my/views/index.php

「共用」頁首模組

「我的」選單模組

「我的」功能列表頁首模組

「共用」頁尾模組

http://www.miiicasa.com/my 裡有哪些模組?

http://www.miiicasa.com/my 的共用頁首模組

Controller

Views

JavaScript

CSS

~/miiicasa/index/common/controllers/_masthead.php

~/miiicasa/index/common/views/_masthead.php

~/miiicasa/static/index/common/_masthead.js

/miiicasa/static/index/common/_masthead.css

有底線 _ 的表示是 div 模組檔也有人叫 partial 或 component

http://www.miiicasa.com/my 的共用頁首模組

Controller

Views

JavaScript

CSS

~/miiicasa/index/common/controllers/_masthead.php

~/miiicasa/index/common/views/_masthead.php

~/miiicasa/static/index/common/_masthead.js

/miiicasa/static/index/common/_masthead.css

模組化會讓檔案變多且分散、要找到檔案變得很麻煩...

我們在開發機提供了好用的 Shell Script $ codeigniter open <CI Module>/_<div Module> #批次開啟$ codeigniter create <CI Module>/_<div Module> #批次建立

vim -p /home/dev/joseph_chiang/miiicasa/index/modules/common/controllers/_masthead.php /home/dev/joseph_chiang/miiicasa/index/modules/common/views/_masthead.php /home/dev/joseph_chiang/miiicasa/static/common/_masthead.js /home/dev/joseph_chiang/miiicasa/static/common/_masthead.css

codeigniter open common/_masthead 等於下面的指令:

好處:模組化開發讓各別團隊成員能專注在單一功能的開發上、不需要煩惱整頁複雜的架構、或共用 API 後面複雜的邏輯 (剛的多國語系不好搞)。另外在測試上也可以以模組為單位單獨測試、符合 Unit Test 的精神

自動化:讓犯錯變得困難Make it difficult to make mistakes

到從零開始公司的好處就是先搶先贏

http://www.flickr.com/photos/eye1/3184963395/by Ivan Mlinaric

josephj我第一個來的!老子說了算!

一開始我就制定了許多 Guidelines

在前家公司時最難忘的話一位主管對我們的品質提出質疑

「As a team,你們的價值究竟在哪裡?」

軟體開發團隊必須要有規範的制定基本框架的設計

代碼品質才能得到提升

任何規範或框架都是開發人員的限制但若不設限制的情況就會像...

Winchester Househttp://www.crockford.com/codecamp/quality.ppt

煙囪上架屋頂?這就是疊床架屋

有 Guideline 不錯,但是老祖宗形容地很貼切:「積習難改」、「陽奉陰違」,每個人對於自己的習慣與理念有所不同,有意無意地 Guideline 放到一旁。

久而久之,當初大家同意的 Guideline 就會被遺忘、整個團隊的程式品質開始陷入混亂...

Code Review 是一個好方法,但得花許多時間、没辦法常辦,即使發現了問題,也只能用妥協的方式做小部分的修改...

軟體開發不應該存在的妥協電腦的世界不就是 0 跟 1 嗎?

1. Commit/Push 時的作法

• 執行 JSLint : 必須符合 JavaScript Good Parts

• 執行 PHP CodeSniffer : 可自訂 Code Convention 檢查 PHP、JavaScript、CSS

• 執行 OptImg:提示圖檔尚未最佳化、是否要用程式自動最佳化?

若沒通過檢查就無法 Commit !

每次 Commit/Push 以 Hook 對變動檔案做檢查

JSLint

document.write can be form of eval

PHP CodeSniffer (a.k.a phpcs)

.rule { attr: value; }

敝公司的 Visual Designer 只負責製作 PSD 檔案

F2E 得自己處理圖檔最佳化的問題

PNG8 是目前公認在 Web 最好的格式

但是只有 Fireworks 支援轉換 Alpha Transparency (索引色透明)

每次切圖都超痛苦,先用 Photoshop 打開 PSD

再開 Firework 轉換成索引色透明

生命就這樣浪費在没有意義的事物上了

Image Optimization

圖檔占網站總頻寬的 46%

OptImg: 一個指令按下去幫你搞定

不修改就不给 Commit

1. Commit/Push 時的作法

唯有將檢查放入每天的開發流程中Guideline 才能真正地被落實

2. Packaging 時的作法我深深認為...

F2E 寫程式最重要的就是 Maintenance你的程式必須很容易地被其它成員看懂

其它像是 Performance 或 Security 的議題大多有機會交由工具或架構處理掉

打包 (Packaging) 就是一個很好的機會

2. Packaging 時的作法• 執行 JS/CSS 的最小化與合併 例如:miii_index_d38eba51136ed0bf6d159770853b393b.css 是首頁所有 CSS 合併最小化產生的

• 執行 Static 設定檔的取代是首頁所有 CSS 合併最小化產生的

• 執行 CSS 背景圖檔取代為 DataURI/MHTML不再使用超手工的 CSS Sprites

打包 pkg_create & pkg_deploy

合併 JS/CSS 檔案與最小化檔案合併後、檔名也會改變(不再使用 Mini 工具)

pkg_create

pkg_deploy

2. Packaging 時的作法

版本控制中不應該有無法維護的檔案,例如:

合併或最小化的 CSS/JSCSS Sprites 圖檔

DataURI/MHTML 字串

就讓打包流程去產生、以其它環境做驗證

以自動化的方式、讓妥協與錯誤不會重複地發生

Review• 減少環境差異善用工具、制定規定,減少環境產生的差異,代碼的品質自然高!

• 模組化開發將每個模組檔案獨立、用工具減少 Performance 爭議、用架構讓模組相互溝通。

• 自動化開發透過流程整合自動化機制、減少每天浪費的時間、及每個人犯錯的機率、提昇 Performance。

相關連結

• JavaScript Module Platform @ GitHubhttp://github.com/josephj/javascript-platform-yui

• Online Demo http://josephj.com/project/javascript-platform-yui-demo

• Demo Source @ GitHub http://github.com/josephj/javascript-plaform-yui-demo