Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
JavaScript Code Quality
Search
Joseph Chiang
May 18, 2013
Technology
59
4.2k
JavaScript Code Quality
關於 JavaScript 品質,我想說的是...
Joseph Chiang
May 18, 2013
Tweet
Share
More Decks by Joseph Chiang
See All by Joseph Chiang
不断归零的前端人生 - 2016 中国软件开发者大会
josephj
1
350
Let's Redux!
josephj
4
250
Automatic Functional Testing with Selenium and SauceLabs
josephj
2
220
From Hacker to Developer
josephj
1
86
tmuxinator
josephj
0
170
JavaScript Promise
josephj
0
160
Be an Internet Person
josephj
9
510
F2E Evolution
josephj
55
3.2k
F2E for Enterprise
josephj
42
5.6k
Other Decks in Technology
See All in Technology
DynamoDB でスロットリングが発生したとき/when_throttling_occurs_in_dynamodb_short
emiki
0
260
アジャイルでの品質の進化 Agile in Motion vol.1/20241118 Hiroyuki Sato
shift_evolve
0
180
複雑なState管理からの脱却
sansantech
PRO
1
160
個人でもIAM Identity Centerを使おう!(アクセス管理編)
ryder472
4
240
アプリエンジニアのためのGraphQL入門.pdf
spycwolf
0
100
ExaDB-D dbaascli で出来ること
oracle4engineer
PRO
0
3.9k
Security-JAWS【第35回】勉強会クラウドにおけるマルウェアやコンテンツ改ざんへの対策
4su_para
0
180
Storybook との上手な向き合い方を考える
re_taro
2
300
エンジニア人生の拡張性を高める 「探索型キャリア設計」の提案
tenshoku_draft
1
130
AI前提のサービス運用ってなんだろう?
ryuichi1208
8
1.4k
あなたの知らない Function.prototype.toString() の世界
mizdra
PRO
1
200
OCI Vault 概要
oracle4engineer
PRO
0
9.7k
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
250
21k
Rails Girls Zürich Keynote
gr2m
94
13k
Building a Scalable Design System with Sketch
lauravandoore
459
33k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Bash Introduction
62gerente
608
210k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
A Modern Web Designer's Workflow
chriscoyier
693
190k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
A Philosophy of Restraint
colly
203
16k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Transcript
JAVASCRIPT CODE QUALITY 講者 josephj 關於 JavaScript 品質,我想說的是...
當談到 JavaScript 品質... 大家心裡的重要性就好像左邊那一本 XD
JavaScript 的興起... 讓開發者覺得 JavaScript 就是要複製貼上
Bad JavaScript = 違章建築 寫程式應該是被維護的,而不是一看就想要拆掉的 6000 ⾏行 JavaScript!
Agenda cᄝ:BIPP⇥֥֞࢝⇪ cླေࡹ৫భ؊ↀộ֥ࡏἧ cᄝNJJJ$BTB⇥֥֞࢝⇪ cླေ༵℟ίa؟Ԏ cໃῲॖӻ⇟୭৯֥ٚཟ cሱọ߄1MVT 成長 = 從過去的錯誤反省!
第 1 課 from Yahoo! 前端⼯工程師必須成為真正的團隊、⽽而⾮非只是資源
中央游泳池 當時「前端⼯工程師」不屬於任何產品線 專案 1 專案 2 F2E Pool 不會有閒置資源
中央游泳池 當時「前端⼯工程師」不屬於任何產品線 專案 1 專案 2 F2E Pool 基本上都在專案 任務導向、缺少團隊機制
大家只管自己的眼前的案子 缺少水平的機制去管理品質
久了必會發生慘案 • 由新人負責、跟其他專案成員關在小房間 (沒有其他 F2E) • View 全部用 JS 組、後端只給
JSON • 不支援 NoJS、沒法上一頁 • 重複程式碼非常多,沒人敢大改 • 專案結束沒多久,新人離職 • 2012 年底,此服務關閉
永遠在我心裡的一句話 “As a team, F2E 的價值究竟在哪裡?” 好不容易培訓⼀一個新⼈人、卻⼜又因制度不健全害了他
開始去思考「團隊」這件事 • Code Convention 團隊規範 • Code Review 定期 Review
程式碼 • Checklist 上線前需達成的清單 ⾮非常重視⼀一致性、維護性
規範一些最基礎的小事情 一致性、像同一個人寫的 https://github.com/josephj/f2e-styleguide
Code Review http://programmers.stackexchange.com/questions/170211/php-data-access-layer 程式碼接受所有⼈人檢驗
比 JSLint 更傷感情 XD https://github.com/miiicasa/youtube-iframe/issues/1
需要比較正面的態度 每次 Code Review 都能學到很多東⻄西!
Pair Programming http://en.wikipedia.org/wiki/File:Pair_programming_1.jpg ⼀一個⼈人寫程式、⼀一個⼈人當觀察員
導入正確的模式 模組化 (Module) 與觀察者 (Observer) 模式
模組:寫法一致、避免全域變數 welcome/_notification.js ⼀一個模組即有⼀一個 JS 檔
模組:寫法一致、避免全域變數 YUI.add("welcome/_notification", function (Y) { var trans = {},
module; module = new Y.Module({ selector: "#notification", init: function () { }, on: { viewload: function (node) { } } }); }, "0.0.1", {"requires": [ "module" ] }); welcome/_notification.js 以 CLI ⾃自動從樣板建⽴立模組 ⼀一個模組 (Partial) 配⼀一個 JavaScript 檔 好⽤用⽅方法與屬性都圍繞在此 instance ⼀一旦當此模組存在於 DOM 之中 相依模組 此模組的 Selector 或物件參考
模組:寫法一致、避免全域變數 YUI.add("welcome/_notification", function (Y) { var trans = {},
module; module = new Y.Module({ selector: "#notification", init: function () { }, on: { viewload: function (node) { } } }); }, "0.0.1", {"requires": [ "module" ] }); module.broadcast("greeting", trans.greeting); module.listen("need-‐love", function (e) { /* do something */ }); new Y.ScrollPagination({node: node}); welcome/_notification.js 所有的功能都圍繞著模組化開發 多國語系 送廣播 聽廣播 加上其他相依模組 trans.greeting = module.getTrans("greeting", "Hello World"); ,"module-‐popup", "module-‐intl", "gallery/scroll-‐pagination"
模組:寫法一致、避免全域變數 YUI.add("welcome/_notification", function (Y) { var trans = {},
module; module = new Y.Module({ selector: "#notification", init: function () { }, on: { viewload: function (node) { } } }); }, "0.0.1", {"requires": [ "module" ] }); module.alert(trans.greeting); module.broadcast("greeting", trans.greeting); module.listen("need-‐love", function (e) { /* do something */ }); new Y.ScrollPagination({node: node}); welcome/_notification.js 所有的功能都圍繞著模組化開發 多國語系 共⽤用的 popup 送廣播 聽廣播 加上其他相依模組 trans.greeting = module.getTrans("greeting", "Hello World"); ,"module-‐popup", "module-‐intl", "gallery/scroll-‐pagination" 限制團隊成員在沙箱(Sandbox) 中開發 功能擴充也能有一致介面 只專注開發該模組功能、無法污染外界
不只是 JavaScript Ninja! 認識軟體⼯工程與持續集成,事半功倍!
需從軟體工程的角度出發 • Lint 自動檢查程式碼 • Combine/Compress 自動合併及壓縮 JS/CSS • Optimize
image 圖檔最佳化 • Compass 用 High Level 的語言讓 CSS 簡化 • Skeleton 自動建立樣板檔案 導⼊入⾃自動化、減少「⼿手⼯工」、才能提昇品質
在 miiiCasa 實踐了這些理念 很幸運可以從零開始、擔任前端⼯工程部⾨門主管 這些想法與理念都⼀一⼀一地實踐了 難道就不會有問題了嗎? http://www.slideshare.net/josephj/ss-7705095 建立前端開發團隊
第 2 課 from miiiCasa 必須先設計、並導⼊入更好的 JavaScript Pattern
miiiCasa Space 家庭雲:用單一 URL 存取家中裝置上的資料 • 4 個不同的媒體: 照片、音樂、影片、文件 •
2 個不同的類型: 首頁列出 Storage、內頁只列目錄 • 都是檔案列表、但差異很大: • View 都各自有差異 • 照片要 Slideshow • 音樂要播放器 • 影片用 VLC / Flowplayer • 文件要用 Lightbox 顯示照片、同時支援 影片、音樂、Google Drive Preview...
有時程壓⼒力... 該怎麼快速產出?
『coding』= 複製貼上的工作 http://but.tw/2008/10/programmers_rule/ 團隊的每個⼈人都有責任
用「複製、貼上」達成需求與滿足時程 • 一模組約 1,500 行 JS • 4 個不同的媒體 •
2 個不同的類型 • 差異很大 = 修修改改 1,500*4*2 = 12,000 行 後續有新功能都幾乎是「複製貼上 x 8」
Winchester Mystery House http://www.flickr.com/photos/harshlight/3670192350/ 外表富麗堂皇、也確實地達成應有功能與時程
http://www.flickr.com/photos/dalvenjah/33560263/lightbox/ 內部的結構... http://www.flickr.com/photos/skinnylawyer/5570163978/ 疊床架屋是軟體開發最常見的問題 在煙囪上架屋頂? ⾛走向屋頂的樓梯?
壓縮開發時程之謎 Stoyan Stefanov The few man-hours spent writing the code
initially end up in man-weeks spent reading it. 數⼩小時寫出的程式碼、得花數週或更多的時間維護它 要在 8 個 JavaScript 上: • 增加新功能 • 修改 Bug • 改變邏輯 • 看不懂、乾脆重寫 ⽼老闆跟專案經理永遠無法理解的事...
面對問題 未來要怎麼預防同樣的問題、或避免讓問題繼續蔓延
EDD – 設計文件 圖表 Branch URLs 檔案結構 Controller 模組詳細說明 預先規劃的假資料
JS 的架構日益複雜 需要跟後端程式一樣先規劃 負責人先仔細思考、撰寫出此文件 所有開發人員一起討論可行性、問題點 把思考不周延之處找出來、了解配合模式 時程預估較為準確、有機會先預防
Refactoring - 重構
重構 = 打掉重寫? 應避免 NIH 綜合症(非我所創、Not Invented Here Syndrome) NO!
技術人員應該用更客觀的心態面對重構 重構 = 持續且小的改進。
開發 重構 開發 重構 把重構納入產品開發的 Iteration ... ... 無法⼀一開始寫出完美的程式碼 藉由實作、看到問題與需求,再著⼿手修正
逐步達成理想的程式碼品質
重構案例:Pop-up 視窗 util.showDialog(module, title, message,
okText, cancelText); module.broadcast("dialog-‐show-‐request", { title: title, msg: message, buttons: { ok : { label: okText, callback: okHandler }, cancel : { label: cancelText } } }); new Y.Panel({ headerContent: title, bodyContent: message, buttons: [] render: true, visible: true }) 過去⾄至少有三種不同的作法 統⼀一作法、將預設⾏行為確認 module.alert(message); module.confirm({ title : title content : message }, okHandler); module.inform(message); 對程式碼精簡、⾏行為的⼀一致性獲得⼤大幅改善
重構案例:Pop-up 視窗 util.showDialog(module, title, message,
okText, cancelText); module.broadcast("dialog-‐show-‐request", { title: title, msg: message, buttons: { ok : { label: okText, callback: okHandler }, cancel : { label: cancelText } } }); new Y.Panel({ headerContent: title, bodyContent: message, buttons: [] render: true, visible: true }) 過去⾄至少有三種不同的作法 統⼀一作法、將預設⾏行為確認 module.alert(message); module.confirm({ title : title content : message }, okHandler); module.inform(message); 對程式碼精簡、⾏行為的⼀一致性獲得⼤大幅改善 重構的價值 減少程式碼中光怪陸離的現象 未來開發更容易 減少 UI 的不一致
Decoupling - 抽離 避免把所有程式碼都放在一個 JS 中
為什麼會產出「一大包」JS? • 麻煩!JS 載入需考慮「前後順序」 <script/> 有先後順序,例如載入 jQuery UI 的 Tabview.
• JS 本身缺乏「模組」的觀念 直到最近 ECMAScript 才要內建 • 「頁面」眾多、分割不易 不像其他的語言,大多只要 require 就可以使用 • 對 JavaScript 缺乏「軟體工程」的態度 非本科:對程式抽離、正規化概念薄弱。本科:對 JS 不用想這麼多吧!
抽離範例:Space Photo • 主要功能:列出 Router USB 裡的照片。 • 其他功能: 提供下載檔案、幻燈秀、縮圖產生機制、
檔案描述、LightBox、分享、重新命名等機制。 這才是此程式中最重要的 每一個都可以另開 Module 處理
代碼抽象三原則 • DRY - 不要重複自己 出現重複時就抽象出一個解決方法 • YAGNI - 你不會需要他
快 + 簡單!不要把精力放在抽象化上 • Rule of 3 - 三次原則 當同樣的情況出現三次才進行抽象化 http://www.ruanyifeng.com/blog/2013/01/abstraction_principles.html
功能抽離範例 space-centralize.js (共 103 行) /** * @module space-‐centralize */
YUI.add("space-‐centralize", function (Y) { // Implementation here... Y.Space.bindCentralize = bindCentralize; }, "0.0.1", { "requires": [ "space", "node-‐base", "event-‐resize" ] }); 需要讓圖⽚片隨螢幕寬度置中對⿑齊,瀏覽較舒適 原本負擔很重、1500+ ⾏行的 JS 檔 /** * @module space/photos/_photos_main */ YUI.add("space/photos/_photos_main", function (Y) { // ... Y.Space.bindCentralize(); // ... },}, "0.0.1", { "requires": [ // ... "space-‐centralize", // ... ] }); 只增加兩行
採用模組化 Library 解決 HTML 中 JavaScript 缺乏模組機制的問題 define(“editor”, [‘a’,’b’,’c’], function
() { function Editor { /* Constructor */ } return Editor; }); require(["editor"], function (Editor) { new Editor(); }); editor.js – 定義 editor 模組 demo.js – 使⽤用 editor 模組 任何⼀一個網站都應該要⽤用!
應加入的規範 • 一個 JS 檔案不應超過 500 行 • 一行不應超過 100
個字元 維護一個大雜匯的 JavaScript 有何意義? 會超過 500 行應代表你該抽離功能了
未來還能做些什麼
給自己未來的一些題目 大多是更多工具的整合、讓自動化來提升品質 ⼯工具 ⼯工程師 • 無聊 • 重複性的 • 浪費時間的
藉由⼯工具持續回饋
自動偵測重複的原始碼 需要把「避免重複原始碼」變成⼀一個習慣
是很重要的一件事! 大家所熟悉的 JSLint, JSHint 卻沒有 Orz... 都只有「單一檔案內」的語法檢查
PMD - 原始碼分析器 其中 CPD 工具可以分析 JS 的重複 /bin/run.sh cpd
-‐-‐minimum-‐tokens 50 -‐-‐files ~/project/foo/js -‐-‐language ecmascript
跑出來的結果 重複的行數 重複的檔案列表 非常需要納入 Commit 流程或 Auto Build 檢查
Error Log 管理 JavaScript 錯誤應該被即時記錄並回報 瀏覽器錯誤 window.onerror try-catch 錯誤發生 ӱൔ㢯ק൞ڎေສഈ❟
ӱൔ㢯ק൞ڎေສഈ❟ 把錯誤丟到 Server 做記錄、回報 就不用辛苦地翻程式碼找問題 控管好這兩個時間點
// Log to server.
window.onerror = function (message, url, line) { var queryString, el; queryString = location.search.slice(1); el = document.createElement("img"); el.src = LOG_URL + "?" + [ "hostname=" + encodeURIComponent(location.host), "message=" + encodeURIComponent(message), "line=" + encodeURIComponent(line), "url=" + encodeURIComponent(url), "query=" + encodeURIComponent(queryString) ].join("&"); return true; // Avoid browser error. }; 把錯誤回報給 Server 常見作法:用假圖片 Request 達成、可跨網域 但是!錯誤需要被 Grouping 才有價值
推薦工具 - Sentry 接收各種程式語言錯誤、分組、寄通知信
Esprima http://esprima.org/ 最近只要聊到 JavaScript Code 品質,幾乎都會聽到這個工具
Esprima 運行原理 程式碼 抽象語法樹 Source Code Abstract Syntax Tree var
answer = 6 * 7; { "type": "Program", "body": [ { "type": "VariableDeclaration", "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "answer" }, "init": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Literal", "value": 6, "raw": "6" }, "right": { "type": "Literal", "value": 7, "raw": "7" } 將程式碼轉成結構⼀一致的 AST 格式,很容易做後續處理 經過 Esprima Parse
Esprima 範例 – CodePainter 問題:每個⼈人寫的空格、引號習慣都不⼀一樣,能否統⼀一? 跑⼀一次⽤用 Esprima 實作的 CodePainter ⼯工具,問題全搞定
https://github.com/fawek/codepainter
Esprima 的可能應用 • JSHint: 將會改用 Esprima • 語法高亮 • 塞
Log,協助偵錯: • 在每個 Method 都放: console.log("someMethod() is executed.") http://www.slideshare.net/ariyahidayat/javascript-parser-infrastructure-for-code-quality-analysis
Continuous Integration 持續集成 「所有」⾃自動化檢查,都應該與 CI 整合 中央 Git 個⼈人 Git
git push post-‐receive trigger git clone Build JSHint Code Duplication Unit Test Functional Test Code Coverage 通知 成功或失敗 Performance 讓檢查像喝⽔水⼀一樣簡單、確保品質 CI 伺服器
推薦服務 CodeShip 懶得⾃自⼰己架⼀一台 CI 伺服器? 市⾯面上有好幾家 SaaS 的服務可⽤用 若你的原始碼是放在 GitHub
CodeShip 與 Travis 都只要勾選就可以使⽤用
把團隊更緊密的綁在一起 把所有訊息 (Commit, Wiki, Issue) 都倒進聊天室 不用交談也知道彼此的做了什麼、點選可看詳細內容
文學編程 Literate Programming 寫程式的理想型態
Donald Knuth 現代電腦科學的鼻祖 A style of programming that maximize our
ability to perceive the structure of a complex piece of software. 文學編程的理念 w൞ℭީਔđⁿ֥ӱൔ۷ݺĆx ໓⇥ṇӱ൞၂⊕⇔ӱൔ֥མྙⅢ ⁿỚᧄℂⅴ֥ૄἠ♶≗ὔᾳି ԉٳֹࢳ
更有組織維護自己的文件 Leo Editor - 依自己的思路撰寫文件、組織代碼 可以是任何的內外部⽂文件、 節點可以任意地被複製搬移 ⾃自由地組織、編排節點順序 產出的程式碼可與其他⼈人 Merge、Leo
會幫你追蹤 ⽀支援 Textile、Web 投影⽚片的輸出
更有組織維護自己的文件 Leo Editor - 依自己的思路撰寫文件、組織代碼 可以是任何的內外部⽂文件、 節點可以任意地被複製搬移 ⾃自由地組織、編排節點順序 產出的程式碼可與其他⼈人 Merge、Leo
會幫你追蹤 ⽀支援 Textile、Web 投影⽚片的輸出
Leo Editor 很強大、也不針對特定語言,但是... 每個人都有自己愛用的編輯器(Vim 或 Sublime) Leo 在程式碼編輯功能上似乎不怎麼樣... 在一堆編輯器中切換也是件很愚蠢的事 以喜歡的編輯器、⽤用⽂文學編程寫
JavaScript Leo 的缺點
https://github.com/jostylr/literate-programming 以 JavaScript 實作的文學編程 編譯 Markdown 產出 JavaScript James Taylor
https://gist.github.com/josephj/5580918 Demo > File count.js saved literate-‐programming ⽂文學編程.md
寫程式就像寫部落格⼀一樣! 可重新組合章節 讓別⼈人⾮非常容易理解
Literate CoffeeScript CoffeeScript 的作者 = 文學編程的大力推廣者 Jeremy Ashkenas Journo 部落格系統
Docco API 文件產生器 以⽂文學咖啡寫成: 缺點:得依照原始碼的順序寫
Journo 的 README.md 就是部落格系統的完整原始碼 (journo.litcoffee) $ coffee -‐c journo.litcoffee #output
journo.js
文學編程過去不是主流、未來也不會 文學編程小結 但身為一個開發者,應秉持文學編程的精神: 「程式碼是給人閱讀的」 以上兩種作法,似乎也可以稱為「部落格編程」 是我們現今最容易理解技術的一種 Material
Code Review 設計⽂文件 產出 API ⽂文件 模組化 模組架構 代碼規範 Pair
Programming 檢查清單 ⾃自動合併與最⼩小化 Lint 單元測試 物件導向 重構 代碼重複檢查 JS 語法分析、重置 持續整合 品質的 TODO LIST 抽離原則 ⽂文學編程 團隊活動 觀念及架構 ⾃自動化 整合訊息 看團隊需求來做導入或整合 Prototyping
寫程式是個良心的事業 過去的評價會⼀一直跟著你,我們應該盡⼒力寫好
程式碼品質,大師們都會強調再強調
2b || !2b that is a question.
Thank you! • GitHub - josephj • Facebook - 蔣定宇
• Slideshare - josephj • Linkedin - josephj6802 聯繫我