2016年1月26日 星期二

[實作] Git 同步(刪除)遠端與本地端 Tag

#Delete local tags.
git tag -l | xargs git tag -d
#Fetch remote tags.
git fetch --tags origin
#Delete remote tags.
git tag -l | xargs git push --delete origin
#Delete local tasg.
git tag -l | xargs git tag -d
簡單說明語法,
刪除所有本地端的Tag
git tag -l | xargs git tag -d
重新抓取(Fetch)所有遠端的Tag  (這時本地端與遠端的Tag 已經是一致的了)
git fetch --tags origin
這裡用了點小手段,將本地的所Tag 列出,並推送(push)到遠端刪除 ,
因為在上一步驟執行後,本地與遠端的Tag 是一致的,所以遠端所有Tag 都將被刪除
git tag -l | xargs git push --delete origin
再次刪除所有本地端的Tag,這樣本地與遠端的Tag就都刪除完畢
git tag -l | xargs git tag -d


同場加映

在windows 10 底下,透過SourceTree的CustomAction,
同步刪除遠端與本地端的Tag。
  1. 首先準備一個SyncRemoveTags.sh檔
    #Delete local tags.
    echo 'Remove all local tags'
    git tag -l | xargs git tag -d
    #Fetch remote tags.
    echo 'Fetch tags from origin'
    git fetch --tags origin
    #Delete remote tags.
    echo 'Remove tags from origin and local'
    git tag -l | xargs git push --delete origin
    #Delete local tasg.
    git tag -l | xargs git tag -d
    說明:
    • 刪除本地所有Tag
    • 重新抓取(fetch)origin所有Tag
    • 將本地的所Tag 列出,並推送(push)到遠端刪除(因為在上一步驟執行後,本地與遠端的Tag 是一致的,所以遠端所有Tag 都將被刪除)
    • 刪除本地所有Tag
  2. 準備一份Call-Git-bash-SyncRemoveTags.bat,內容如下:

    cd %1
    C:\Users\admin\AppData\Local\Atlassian\SourceTree\git_local\git-bash.exe D:\Bat\SyncRemoveTag.sh
    注意:
    這是呼叫git-bash.exe去執行SyncRemoveTags.sh ,所以要注意git-bash的路徑(一般來說有安裝SourceTree就會有),與步驟1的SyncRemoveTags.sh所在位置的路徑。
    請依實際位置修改。 之所以這樣操作是為了讓
    SourceTree呼叫git-bash (Customer Action預設會執行command),再透過git-bash 呼叫去操作git tag
  3. 在Source Tree上選擇Tools => Options,切換至Custom Actions => Add
  4. 輸入名稱"Sync Remove Tags",選擇之前的檔案Call-Git-bash-SyncRemoveTags.bat,並加入參數"$REPO",Show Full Output可勾可不勾
  5. 之後就可以直接在選單上使用Custom Actions > Sync Remove Tags的功能了


2016年1月24日 星期日

[實作]Git gc 指令學習,回收消失在歷史之中的commit所佔用的空間。


Git本身的原理記錄檔案快照,也是就是完整的備份,而不是差異備份。


Git每一次的版本(git),都是完整快照


一般的版控是差異備份 EX: SVN





























所有的commit都可以獨立看待,這樣的優點是有相當高的自由度,
你可以任意組合你的commit,建立你的history線圖,而且大部份的操作都可以離線作業。
缺點是會佔用相當大的磁碟空間,比如說:你簽入了一個大的檔案(圖檔之類的),或是你常常reset 你的commit ,因而產生這unreachable commit 。

Git 本身提供了GC(Garbage collect)的機制,不定時的會執行git gc,將過期且不被使用的物件清除,但是我們如果想手動清除掉這些不用的物件,以釋放空間,可以手動執行以下命令。

git reflog expire --expire-unreachable=now --all
git gc --prune=now




實作記錄如下:
  1. 建立一個資料夾「GitGC」
  2. 開啟CMD切換到「GitGC」
    admin@pc MINGW32 /$ cd /d/Repo/SandBox/GitGC/
  3. 建立Git Repo
    dmin@pc MINGW32 /d/Repo/SandBox/GitGC (master)
    $ git init
  4. 檢查一下目前git repo的大小
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 0
    size: 0
    in-pack: 0
    packs: 0
    size-pack: 0
    prune-packable: 0
    garbage: 0
    size-garbage: 0
  5. 放入一個大的圖檔,加入track
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git status

    On branch master
    Initial commit
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
           80-20121007_stitch.jpg
    nothing added to commit but untracked files present (use "git add" to track)

    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git add .

    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git status

    On branch master
    Initial commit
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)

            new file:   80-20121007_stitch.jpg
  6. 簽入local 的Repo
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git commit

    [master (root-commit) ed987f4] add image:
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 80-20121007_stitch.jpg


    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git status

    On branch master
    nothing to commit, working directory clean
  7. 檢查 Repo 目前的大小
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 3
    size: 37467
    in-pack: 0
    packs: 0
    size-pack: 0
    prune-packable: 0
    garbage: 0
    size-garbage: 0
  8. 隨便改一改圖,再簽入(重複這個動作2~3次),讓我們有多個commit,這時候節點應該會類似於下圖
  9. 檢查一下 Git Repo的大小,可以看到Git Repo Size的膨漲
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 10
    size: 73770
    in-pack: 0
    packs: 0
    size-pack: 0
    prune-packable: 0
    garbage: 0
    size-garbage: 0
  10. 接下來我們Reset 回第一個commit
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git reflog

    3260eda HEAD@{0}: commit: modify image2
    d29b377 HEAD@{1}: commit: modify image
    91af9eb HEAD@{2}: commit: modify image
    ed987f4 HEAD@{3}: commit (initial): add image:

    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git reset ed987f4

    Unstaged changes after reset:

    M       80-20121007_stitch.jpg
  11. 再檢查一下Size 並沒有因此縮小
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 10
    size: 73770
    in-pack: 0
    packs: 0
    size-pack: 0
    prune-packable: 0
    garbage: 0
    size-garbage: 0
  12. 強制執行git gc ,但是git repo並不會縮小,這是因為git gc只會回收過期的commit (預設是90天)
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git gc

    Counting objects: 10, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (10/10), done.
    Writing objects: 100% (10/10), done.
    Total 10 (delta 1), reused 0 (delta 0)


    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 0
    size: 0
    in-pack: 10
    packs: 1
    size-pack: 73802
    prune-packable: 0
    garbage: 0
    size-garbage: 0
  13. 所以,我們必須讓這些不屬於任何branch的commit,強制過期,執行以下語法
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git reflog expire --expire-unreachable=now --all

  14. 再執行一次GC
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git gc --prune=now
    Counting objects: 3, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), done.
    Total 3 (delta 0), reused 3 (delta 0)
  15. 檢查大小,可以看到Git Repo已經縮小
    admin@pc MINGW32 /d/Repo/SandBox/GitGC (master)

    $ git count-objects -v

    count: 0
    size: 0
    in-pack: 3
    packs: 1
    size-pack: 37471
    prune-packable: 0
    garbage: 0
    size-garbage: 0
參考聯結

[[[本誌僅為個人分享與記錄,不保証內容永久正確性,如有謬誤、疏漏或侵權還請留言告知]]]

2016年1月16日 星期六

[心得]2016總統大選

選舉終於結束了,
不知道大家心中的理想人選是不是選上了呢?
但是我們的民主,仍然非常落伍。
選舉並不是選了一群人,
就把所有的事情丟給他們,
要持續監督這個政府,
「政治乃眾人之事」,
眾人管理眾人之事,是民主的基本精神。

台灣開放民選以來,
從省籍、藍綠、世代到貧富,
都是一種對立,以民主國家來說
這應當是再正常不過的事了。
民主本應兼容多種聲音,
但是在這過程中,仍然看到許多的貼標籤與仇視的行為,
一切的根源仍是每個人看東西的角度與起點不同的關係。
比如說「689」

689本來是指2012年總統大選後,馬英九得票數達689萬票,
隨著2012年後馬英九的民調下滑,689成為了泛綠攻擊泛藍的一個名詞。
也許是命運的巧合,這次總統大選,蔡英文也是689萬票。
「689」或許將有不同的意義。
兩次都是689的我特別有感覺,
期待人民彼此不再互貼標籤。

未來四年期待能有新氣象,
一個是希望國會持續改革,
降低霸免門檻,讓人民可以實際監督代議的立委。
二是經濟的區域整合,不再過度依賴中國,也不要切割。
三是產業的轉形與居住的正義,讓青年有機會翻身。
最後是醫療與教育的改革。

期待「公平簡單」、「公開透明」與「濟弱扶傾」
可以真的落實在我們的社會之中。


[[[本誌僅為個人分享與記錄,不保証內容永久正確性,如有謬誤、疏漏或侵權還請留言告知]]]

2016年1月10日 星期日

[心得]從小就該學寫程式?

晚安,2016年又過了一周,今天是1月9號,

有時真的會感嘆時光的飛逝。

越來越多人投入軟體工程領域,

這實在是一件好事,同時也代表著軟體產業確實有著這樣的需求,

恰巧讓我有些共鳴,其實我認為未來二十年軟體領域將會進入一個黃金期

以一個年紀30歲的青年來說,這二十年將會是他人生的精華所在。

也就是說如果你現在處在軟體相關產業的人,

真的是恭逢其時,至少二十年內,你不會缺少機會與舞台,

再來若你不在軟體產業,準備好迎接衝擊吧,

是挑戰也是機會,電子商務、智慧/自動車、智慧宅、綠能、…

這股浪潮將會像是工業革命般改變全世界、全部的產業。

不要覺得不干自已的事,改變已經開始了。

這二十年的到來,的確讓人振奮的想要跳起來,

但是我看到很多的人提出的觀點,保持著懷疑的態度,

就是「讓孩子從小當工程師」

我完全贊成小孩需要學點程式,因為這有助於邏輯思考,

但重點在邏輯思考,而不在程式啊!
但重點在邏輯思考,而不程式啊!
但重點在邏輯思考,而不程式啊!

這是柯P在台大演講,裡面對邏輯思維的養成,

相當值得一看(建議用1.5倍速),


另外,我認為未來二十年後奇點將至,

軟體或許將會變得M型化,

簡易的需求將會有更快速的工具去滿足,

Blog、購物網站、App或是遊戲,

都能用套裝的工具去達成,而且可以有高度客制化的能力,

自我搭建、研發的成本將高於服務,一般的公司多會使用PaaS、SaaS的服務,

M型的一端,將會是以一檔百的工程師,而且業界將會求才若渴,

M型的另一端,則是只會應用其服務的工程師,

當其應用越變越簡單跨過了工程師的門檻時,

工程師就與User沒有兩樣了。

當然這沒有不好,這可以讓一般User更專注在自已想實踐的部份上,

而且還有自我還有高度客制化的能力,

這是進行式,當然要完全取代工程人員,

短期內不太可能會發生

努力讓自已走向M型的另一端,不要停留在安逸的地方,

學無止盡,一起加油吧。

二十年說長不長,說短不短,我們等著看。

本周其它文章推薦



[[[本誌僅為個人分享與記錄,不保証內容永久正確性,如有謬誤、疏漏或侵權還請留言告知]]]


2016年1月7日 星期四

[開發]CommonJS & AMD & ES6

簡介:
只是一種標準,
這個標準的基本原則如下:
  1. 一個檔案就是一個模組 (module)
  2. module 包含以下三個變數
    1. module : 物件 module 本身
    2. require :  函數 用以載入相依的模組
    3. export :  物件 用以揭示模組對外的API
  3. 不被export的資訊將被包在模組的scope底下,以保持全域的清淨。
因為Javascript 原始設計是base-on browser ,
隨著Javascript發展,
Server Side 的js Engine 引擎如雨後春筍冒出 ( rhino、v8、 Spidermonkey and JavaScriptCore),
大型的專案所需要的模組載入功能
Javascript(ECMA-262) 卻未提供,苦無統一的標準,
CommonJSAMD 因而誕生,用於載入模組,
ES6 的標準將會補足這一塊。


CommonJS 與 AMD 最大的差異點在於,
同步載入與異步載入,造成此點最大的差異在於使用的環境,
CommonJS的使用情境為Server (ex: nodejs),
模組都位在同一系統下,不會有非同步載入的情境發生,
AMD針對Browser的使用情境,需要透過http取得模組,
所以會有非同步的情境,
Requirejs 是實作AMD的一個Lib。



參考資料:

[[[本誌僅為個人分享與記錄,不保証內容永久正確性,如有謬誤、疏漏或侵權還請留言告知]]]

2016年1月2日 星期六

2015前端生態發展回顧(二)

原文:https://github.com/kuitos/kuitos.github.io/issues/32
上篇

架構的變化

2015年出現的新的技術及思路,影響最大的就是技術選型及架構了。我們可以從下面幾點來看看它對前端架構上都有哪些影響。

組件化

React的風靡使得組件化的開發模式越來越被廣大開發者關注。首先要肯定的是,組件化是一個非常值得去做的事情,它在工程上會大大提升項目的可維護性及拓展性,同時會帶來一些代碼可複用的附加效果。但這裡要強調的一點是,組件化的指導策略一定是分治(分而治之)而不是複用,分治的目的是為了使得組件之間解耦跟正交,從而提高可維護性及多人協同開發效率。如果以復用為指導原則那麼組件最後一定會發展到一個配置繁雜代碼臃腫的狀態。如果以組件的形態劃分,可以分為兩個類型:基礎控件和業務組件。基礎控件不應包含業務邏輯不然達不到拿來即用的效果,因此它也會表現出可複用的價值,但是根本還是為了提高業務組件的可維護性。至於業務組件,可複用的價值就很低了。
  1. 組件化指的是什麼
    組件化這個詞,在UI這一層通常指“標籤化”,也就是把大塊的業務界面,拆分成若干小塊,然後進行組裝。
    狹義的組件化一般是指標籤化,也就是以自定義標籤(自定義屬性)為核心的機制。這也是我們通常認識的組件。
    廣義的組件化包括對數據邏輯層業務梳理,形成不同層級的能力封裝。它不一定是一個自定義語義標籤:它可以是一個包含邏輯(js)、樣式(css)、模版(html)的功能完備的結構單元,也就是我們常“口口相傳”的模塊(從術語準確性的角度來看模塊這個描述並不合適,應該稱之為組件);它也可以是一個單純的js,比如http組件這種純邏輯單元。嚴格從概念上來講,css跟html是不具備單獨/組合成一個組件的,它們不具備描述邏輯的能力(非圖靈完備)。從這個層面來看,全組件化是沒有任何問題及疑義的。
  2. 是否需要全組件化
    我們通常說的組件指的是狹義上的組件,而且往往我們理解的全組件化也是建立在狹義的組件基礎上的,
    代表框架是React。 React+Flux體系下,它提倡盡可能將頁面作細粒度的組件拆分,組件的數據全部由父級組件通過props傳遞而來。這本身是一件非常有價值的事情,能有效的確保應用狀態的穩定及可預測性,但是應用一旦複雜龐大起來,組件樹變得“枝繁葉茂”導致葉子節點層級過深,當出現數據問題時,我們必須一層層的回溯來定位bug。而且組件樹過於龐大也會增加組件之間的通訊負擔。從狹義的組件來看,我對全組件化是存懷疑態度的,工程上的成本太高是最大的問題,而且大部分開發者很難拿捏合適的組件粒度,容易出現過細/過粗的拆分。很多場景其實並不適合實現成狹義上的組件,它以零散的模板的方式存在更合適。
    但是如果從廣義的組件來看,全組件的意義是很大的,我們需要通過拆分頁面邏輯區塊的方式實現程序的解耦,從而提升應用的可維護性。
綜合來看,我覺得工程上更具可行的全組件化方案應該是:細粒度的基礎組件庫+ 粗粒度的模板/組件。

工程化

工程化是近年前端提到最多的問題之一,而且個人認為是當前前端發展階段最有價值的問題,也是前端開發通往工業化時代的必經之路。這裡不贅述,有興趣的同學看我前陣子整理的一篇文章前端工程化知識點回顧
應用架構層 MVVM & Flux
MVVM想必大部分前端都耳熟能詳了,代錶框架是angular、vue、avalon。 angular在1.2版本之後加入了controllerAs語法,使得controller可以變成一個真正意義上的VM,angular整個架構也才真正能稱之為嚴格的MVVM(之前只能說是帶有雙向綁定的MVC/MVP )。
Flux是facebook隨React一併推出的新的(準確來說其實是改進的,並非原創)架構模型,核心概念是單向數據流。 Flux實質上就是一個演進版的中介者模式,不同的是它同時包裝了action、store、dispatcher、view等概念。關於Flux對應用分層、數據在不同層之間只能單向流轉的方式我是很贊成的。應用的分層在業務稍複雜的應用中都是很有必要的,它更利於應用的伸縮及拓展,副作用是會帶來一定的複雜度(在我看來這點複雜度根本就可以忽略不計)。
今年被黑的最多的前端主流框架莫過於angular了。老實講前端圈真的挺善變的,去年各種大會都在分享angular黑jquery,今年就變成了都在分享react黑angular了。黑的點大致有三:
  1. angular的部分實現太low
  2. 太多Java身上帶來的臭毛病(並沒有在黑Java)
  3. mvvm自身的缺陷
第一點第二點我並無異議。 angular的髒值檢測機制相對於其他mvvm框架的雙向綁定實現方式確實不太優雅,同樣有硬傷的還有失敗的模塊語法及過多過於複雜的概念。但是對於第三點,我有不同的看法。
大多數人黑mvvm會以Facebook那張經典的flux vs mvc的圖為論據,對於雙向綁定造成的數據流紊亂及應用狀態的不確定導致問題定位困難的觀點我是認同的,這一點我也有切身體會,但是單純的這一點就足以否定mvvm麼?就說flux比mvvm高明?
MVVM在富表格型(自造的詞😄)應用開發效率上是高於Flux的,典型的就是一些後台管控平台。而且最重要的是,MVVM跟Flux並不互斥,我們在MVVM中照樣可以引入Flux中的一些機制從而確保應用狀態的穩定。很多時候我們對於框架/架構的孰優孰劣的爭論是沒意義的,拋開業務場景談解決方案都是耍流氓。
業務數據層 Relay & falcor
這一層對大部分前端來說可能是比較新的概念,其實我們可以這樣理解:在一個完整的應用中,業務數據層指的就是數據來源,在angular體系中可以等同於ngResource模塊(準確來說應該是$http)。
Relay是f家推出的在react上應用GraphQL的框架,它的大致思路是:前端通過在應用中定義一系列的schema來聲明需要的接口數據結構,後端配合GraphQL引擎返回相應的數據。整個事情對於前端來說意義簡直是跨時代的,工業化典範!不僅能極大提升前後端協同的開發效率,還能增加前端對於應用完整的掌控力。但是目前來看問題就是實施過於復雜,而且還得後端服務支持,工程成本太高,這一點上Meteor顯然做的更好。
falcor則是Netflix出品的一個數據拉取庫,核心理念是單一數據源,跟Redux的單store概念一致。用法跟Realy類似,也需要前端定義數據schema。 另外還有一個新的W3C標準api:fetch,它的級別等同於XMLHttpRequest,旨在提供比ajax更優雅的資源獲取方式,目前幾個主流瀏覽器支持的都還不錯,也有官方維護的polyfill,幾乎可以確定是未來的主流數據請求api。
業務數據層是前端應用中比較新的概念,它的多元化主要會影響到應用的架構設計,這裡不細講後面再來說。

新的編程範式

函數式編程(FP)

函數式編程(functional programming)是近年比較火爆的一個編程範式,FP基於lambda演算,與以圖靈機為基礎的指令式編程(Java、C++)有著明顯的差異。 lambda演算更關注輸入輸出,更符合自然行為場景,所以看上去更適合事件驅動的web體系,這點我也認同。但問題是,太多開發者看到redux那麼火爆就急著學redux用js去玩函數式,我覺得這個有待商榷。 js作為一個以基於函數(scheme,父親)跟基於對象(Self,母親)的編程語言為藍本設計然後語法又靠近Java(隔壁老王)的“混血”語言,你非得用它去寫函數式,是不是過於一廂情願?尤其是在現在瀏覽器還不支持尾調用優化的情況下,你讓那激增的調用棧可如何是好😂如果你確實鍾情於函數式,可以去玩玩那些更functional的語言(Haskell、Clojure等),而不是從js入手。最近看到一個老外關於js的函數式編程的看法,最後一句總結很精闢:Never forget that javascript hate you.😂

函數式響應型編程(FRP)

函數式響應型編程(functional reactive programming)不是一個新概念,但也不過是近兩年才引入到前端領域的,代表類庫就是ng2在用的rxjs。 FRP關注的是事件及對應的數據流,你可以把它看作是一個基於事件總線(event bus)的觀察者模式,它主要適用於以GUI為核心的交互軟件中。但FRP最大的困難之處在於,如果你想使用這樣的編程範式,那麼你的整個系統必須以reactive為中心來規劃。目前微軟維護的ReactiveX項目已經有各種語言的實現版本,有興趣的同學可以去了解下。

工具鏈的變化

去年最主流的前端構建工具還是grunt&gulp,2015年隨著react的崛起和web標準的快速推進,一切又有了新的變化。
webpack & browserify & jspm
webpack跟browserify本質上都是module bundler,差異點在於webpack提供更強大的loader機制讓其更變得更加靈活。當然,webpack的流行自然還是離不開背後的react跟facebook(可見有個強大的干爹多麼重要)。但是從現在HTTP/2標準的應用及實施進展來看,webpack/browserify這種基於bundle的打包工具也面臨著被歷史車輪碾過的危機,相對的基於module loader的jspm反而更具前景(雖然現在使用前兩者的開發者都多於jspm)。

PostCSS & cssnext

PostCSS作為新一代的css處理器大有取Sass/Less而代之的趨勢,Bootstrap v5也有著基於PostCSS去開發的計劃。但從本質來講它又不算一個處理器,它更像是一個插件平台,能通過配置各種插件從而實現預處理器跟後處理器的效果。 cssnext官方口號是“使用來自未來的語法開發css,就在今天!”,但是cssnext又不是css4,它是一個能讓開發者現在就享受最新的css語法(包括自定義屬性、css變量等)的轉換工具。這一塊筆者還沒有過具體實踐,暫不多言。

寫在最後

從前端的發展現狀來看,未來理想的前端技術架構應該是每一層都是可組裝的,框架這種重型組合的適用場景會越來越局限。原因在於各部件不可拆卸會增加架構的升級代價同時會限制應用的靈活性。舉個例子,我有一套面向pc端的後台管控平台的架構,view層採用angular開發,哪天我要遷移到移動端來,angular性能不行啊,我換成vue就好了。哪天覺得ajax的寫法太挫,把http層替換成fetch就好了。又有一天后端的GranphQL平台搭好了,我把ngResource換成relay就OK了。
這種理想的方式當然是完全正確的方向,但是目前來看它對開發者/架構師的要求還是太高,工業級別上一套帶有約束性的框架還是有相當的需求的(特別是當團隊開發者的水平良莠不齊時。當然我覺得更正確的方式是流程上有一套完整的自動化方案用於確保團隊提交的代碼質量,只是目前基於動態分析的代碼質量檢測工具還沒有出現,而且估計很長一段時間內都不會有)。雖然美好但是組合的方式也不是沒有問題,各種五花八門的搭配容易造成社區的分化跟內耗,一定程度上不利於整個生態圈的發展。
近年前端生態的野蠻發展影響最大的應該就是新產品的技術選型了,亂花迷人眼,我們很難設計出一套適應大部分場景、而且短時間內不會被淘汰的架構。前端的變化太快通常會導致一些技術決策的反复,今天的最佳實踐很可能明天就被視為反模式。難道最合適的態度是各種保留各種觀望,以不變應萬變?在這一點上即使如我這般在技術上一向激進的人都有點畏手畏腳了。那句話怎麼說的來著?從來沒有哪個圈子像今天的前端一樣混亂又欣欣向榮了。有人說2015年或許是大前端時代的元年,目前看來,如果不是2015,那麼它也一定會是2016年。
最後引用計子winter的一句話作為結語吧:
前端一直是一個變化很快的職能,它太年輕,年輕意味著可能性和機會,也意味著不成熟和痛苦。我經常擔心的事情就是,很可能走到最後,我們會發現,我們做了很多,卻還是一無所獲。所幸至今回顧,每年還是總有點不同,也算給行業貢獻了些經驗值吧。


2015前端生態發展回顧(一)

原文:https://github.com/kuitos/kuitos.github.io/issues/32


引用蘇寧前端架構師的一個總結作為開篇
編程技術及生態發展的三個階段
  • 最初的時候人們忙著補全各種API,代表著他們擁有的東西還很匱乏,需要在語言跟基礎設施上繼續完善
  • 然後就開始各種模式,標誌他們做的東西逐漸變大變複雜,需要更好的組織了
  • 然後就是各類分層MVC,MVP,MVVM之類,可視化開發,自動化測試,團隊協同系統等等,說明重視生產效率了,也就是所謂工程化
處在2015年這個時間段來看,前端生態已經進入了第三階段。看上去好像已經走的挺遠了,實則不然。如果再用人類歷史上的三次工業革命來類比,前端發展其實不過剛剛邁入了蒸汽機時代,開始逐步用工具來替代過往相當一部分的人工作業,但是離電氣時代的自動化流水線作業還有很長一段路要走。回顧一下2015年前端的生態發展,我大致整理了幾個我覺得比較有歷史意義的事件。
按時間順序:
  1. 年初React Native的發布,引領React正式走上歷史舞台。
  2. 3月angular2.0第一個預覽版發布
  3. 5月http/2.0標準正式發布,同月iojs 與nodejs合併。
  4. 6月 ES6 和 WebAssembly 落地
  5. 迄今為止React生態圈影響最大的Flux實現redux發布1.0版本
  6. 8月Facebook公開了在React上應用GraphQL的relay框架的技術預覽版
  7. 9月 React Native for Andriod 發布
  8. 11月伊始,es標準委員會宣布將歷時3年研究的Object.observe從草案中移除,儘管它原本已經是stage2,幾乎已經是ES7的事實標準。雙十一剛一結束,阿里手淘團隊發布了名為無線電商動態化解決方案的Weex,也有人給了它一個更具象的名字,vue native。
  9. 12月,趕在2015的尾巴,aurelia和angular2先後發布beta版。 css方面,postcss & cssnext先後高調走到台前。

觀念的變化

由於近幾年前端的野蠻生長以及前端應用的多元化和複雜化,整個技術形態已經跟幾年前純做頁面的時代完全迥異了。主要觀念的變化總結來看在於一點,現在的前端開發麵向的是web app而不是web page。今天的前端開發模式跟傳統的GUI軟體(如C++、.NET開發的windows客戶端)已經很接近了,而且由於現在前端領域為了解決日益複雜的web業務需求及體量,越來越多的借鑒了傳統客戶端的開發經驗,導致兩者變得越來越趨同。再加上前端一些獨特的特性(免安裝、增量安裝等),工程上的複雜度有過之而無不及。前端如今已經脫離了茹毛飲血、刀耕火種的原始社會,開始步入了工業時代。

框架 & 類庫的變化

今年最火的框架/類庫毫無疑問當屬React了。 React從2014年年中開始廣泛受到開發者關注,但是真正開始在社區獨領風騷還得歸功於2015年初React Native的發布。 React Native的發布使得js統一三端(前端、後端、移動端)開發成為可能(現在這個時間點看可能還是過於理想,但是整體方向還是對的),這一針強心劑吸引了大量開發者的眼球。筆者對此最大的感受就是,我在社區發表一篇react的入門教程級別的軟文便可獲得廣泛關注及轉發,相應的寫angular源碼剖析的準乾貨大部分情況則是門可羅雀😂。
我們挑幾個主流的框架來講講這一層的變化。

React & Redux

React基本簡介可以參考這篇文章React簡介,這裡不再贅述。我們挑幾個核心特徵簡單來講:
  1. virtual dom
    這個可以說是F家工程師超強工程能力的最佳體現了(Relay也算一個),從本質來看它是通過用js object來模擬了一個dom tree,然後將這層virtual dom插在react組件跟真實dom之間,配合強勁的dom diff算法實現它一直標榜的高性能。
  2. jsx
    同樣為了配合react中的組件化開發模式,F家發明了一套新的語法jsx。乍看之下它像是html in js,這也是初接觸的開發者最難以接受的,典型的違背前端推崇多年的表現與業務分離的原則啊。其實這裡要換個角度來看jsx,它並不是html in js,準確來說它是一個用來構建react組件樹的AST。這樣來想你就能理解react中這一看似怪異的設計了。
  3. immutable object
    不可變對像是函數式編程中的重要概念,react的介入使得這一理念在前端社區中流行起來。從目前各種類庫的實現來看,不可變對像在大型應用中擁有傳統可變對像不具備的優勢。尤其在這個內存不值錢的年代。從目前immutable object的良好走勢來看,將來有可能被es納入規範之中。目前可以通過facebook的immutable.js來實現。
Redux則是目前react配套的Flux模式的各種實現(其實現在兩者的關係越來越模糊了)中最火的一個,在此基礎上它引入了函數式編程、單一數據源、不可變數據、中間件等概念。一定程度來講,redux是今年react生態甚至整個前端生態中影響最大的一個框架,它給整個前端技術棧引入了很多新成員,儘管這些概念可能在其他領域已經有了廣泛的應用。雖然它們是否會在大規模的應用實踐中被廣大開發者認可還需要再檢驗,但至少給我們帶來了一些新的思路。其中的單一數據源、不可變數據、中間件等思路目前來看還是非常有價值的,尤其是單一數據源跟不可變數據,很有可能在將來成為大型應用架構中的標配(目前來看至少在應用中構建Store層在當前的前端架構中是勢在必行的)。單一數據源就好比在前端構建了一個集中式數據庫,所有的數據存取操作對像都是它,不單如此它裡面還實現了觸發器,當有insert/update操作時它會對相應組件作rerender動作,這個在各組件之間有數據同步需求的場景下就非常有用了。
至於我對函數式編程的看法,後面單獨闡述。
在我看來,react的優勢並不在組件化,組件化的實現方案多種多樣。 react的優勢在於virtual dom及一個幾乎構成閉環的強大生態,這歸功於Facebook工程師強大的工程能力跟架構能力。 virtual dom將應用表現層從瀏覽器這個基於dom的上下文中抽離出來,通過原生js對像模型的方式使得react具備在任何環境支撐上層表現的能力。上層的渲染引擎可以是canvas、native、服務端甚至是桌面端,只要相應的端提供基於react組件的渲染能力,即可達到一套代碼、或者只要很少的改動就能移植到任一終端環境的效果,這個就非常誇張了。 react從0.14版本之後便將react-dom抽出來變成一個獨立的庫,可見react的野心並不局限於瀏覽器,相反從這點來看,react反而是受到了dom的掣肘。

Angular2 & Vue.js

ng2跟ng1相比是一個完全革命性版本而不是升級版,它是一個為了迎合未來的標準及理念來設計的全新框架,而這些新的理念又無法通過改進ng1.x的方式來實施,所以angular團隊做了這麼一個看似激進的決策,可以理解成重構已經無法滿足需求只能重寫了。 ng2也採用純組件化的開發思路,任何單元對於它來說都是組件。同時,ng2裡面也引入了一些全新的概念(對於前端而言)來提升框架的性能及設計,例如基於worker的數據檢測機制能大幅度提升渲染性能(對應實現是zone.js),基於響應式編程的新的編程模型能更大的改善編碼體驗(對應實現RxJS)。趕在2015年的尾巴,ng2正式發布beta版,對於angular的這次自我革命是否能成功,還有待後續檢驗。另外原angular團隊中出來的一個成員開發了一個類ng2的框架aurelia,有相當的開發者認為它更配稱為ng2,值得關注。
由於阿里在背後的技術實踐及支持,Vue.js今年也開始得到越來越多的關注。 vue相對於angular1.x的優勢在於輕量、易用、更優異的性能及面向組件化的設計,目前發展態勢也非常好,是移動端開發的一個重要技術選型之一。

標準 & 語言的變化

現在回顧起來,2015年是很有意義的一年:這一年是Web誕生25歲週年,也是js誕生的20週年。同時又是ES6標準落地的一年。 ES6是迄今為止ECMAScript標準最大的變革(如果不算上胎死腹中的ES4的話),帶來了一系列令開發者興奮的新特性。從目前es的進化速度來看,es後面應該會變成一個個的feature發布而不是像以前那樣大版本號的方式,所以現在官方也在推薦ES+年份這種叫法而不是ES +版本。

ES2015(ES6) & ES2016(ES7) & TypeScript

6月中ES2015規范正式發布,從ES2015帶來的這些革命性的新語法來看,JS從此具備了用於開發大型應用的語言的基本要素:原生的mudule支持、原生的class關鍵字、更簡潔的api及語法糖,更穩定的數據類型。而這些new features中,有幾個我認為是會影響整個前端發展進程的:
  1. Module & Module Loader
    ES2015中加入的原生模塊機制支持可謂是意義最重大的feature了,且不說目前市面上五花八門的module/loader庫,各種不同實現機制互不兼容也就罷了(其實這也是非常大的問題) ,關鍵是那些模塊定義/裝載語法都醜到爆炸,但是這也是無奈之舉,在沒有語言級別的支持下,js只能做到這一步,正所謂巧婦難為無米之炊。 ES2016中的Module機制借鑒自CommonJS,同時又提供了更優雅的關鍵字及語法(雖然也存在一些問題)。遺憾的是同樣有重大價值的Module Loader在2014年底從ES2015草案中移除了,我猜測可能是對於瀏覽器而言Module Loader的支持遭遇了一些技術上的難點,從而暫時性的捨棄了這一feature。但是一個原生支持的模塊加載器是非常有意義的,相信它不久後還是會回歸到ES規範中(目前由WHATWG組織在單獨維護)。
  2. class
    準確來說class關鍵字只是一個js裡構造函數的語法糖而已,跟直接function寫法無本質區別。只不過有了Class的原生支持後,js的面向對像機制有了更多的可能性,比如衍生的extends關鍵字(雖然也只是語法糖)。
  3. Promise & Reflect API
    Promise的誕生其實已經有幾十年了,它被納入ES規範最大意義在於,它將市面上各種異步實現庫的最佳實踐都標準化了。至於Reflect API,它讓js歷史上第一次具備了元編程能力,這一特性足以讓開發者們腦洞大開。
關於ES2016的最重磅的消息莫過於11月初es標準委員會宣布將Object.observe從ES2016草案中移除了,儘管它已經是stage2幾乎已經是事實標準。官方給出的解釋是,這3年的時間前端世界變化實在太大,社區已經有了一些更優秀簡潔的實現了(polymer的observe-js),而且React帶來的immutable object在社區的流行使得基於可變數據的Object.observe的處境變的尷尬,O.o再繼續下去的意義不大了。
除此之外,ES2016的相關草案也已經確定了一大部分其他new features。這裡提兩個我比較感興趣的new feature:
  1. async/awai
    寫過C#的同學應該對這兩個關鍵字很熟悉了,async/await是為了更優雅的異步編程做的一個關鍵字級別的封裝,術語叫協程。 ES2016中async/await 實際是對Generator&Promise的上層封裝,幾乎同步的寫法寫異步比Promise更優雅更簡單,非常值得期待。
  2. decorator
    字面意思是裝飾器,其實等同於Java裡面的註解。註解機制對於大型應用的開發的作用想必不用我過多贅述了。用過的同學都說好。
目前ES2015/ES2016都有了比較優秀的轉譯器支持(沒錯我說的是babel),但是也不是all features supported,嚐新的過程中需要注意。
至於Typescript,你可以將它理解成加入了靜態類型的js的超集。不過我對於這種轉譯型語言一直不感冒(包括CoffeeScript),有興趣同學自己去了解下吧。

WebAssembly

WebAssembly選擇了跟ES2015在同一天發布,其項目領頭人是大名鼎鼎的js之父Brendan Eich。 WebAssembly旨在解決js作為解釋性語言的先天性能缺陷,試圖通過在瀏覽器底層加入編譯機制從而提高js性能。這個事情跟當時V8做的類似(有興趣的同學可以去了解下JIT),V8也因此一躍成為世界上跑的最快的js引擎。但是由於js是弱類型的動態語言,V8很快就觸碰到了性能優化的天花板,因為很多場景下還是免不了recompile的過程。因此WebAssembly索性將編譯過程前移(AOT)。 WebAssembly提供工具將各種語言轉換成特定的字節碼,瀏覽器直接面向字節碼編譯程序。其實在此之前,firefox已經搞過asm.js做類似的事情,只不過WebAssembly的方案更激進。有人認為WebAssembly可能是2016年最大的黑馬,如果wa能發展起來,若干年後我們看js編寫的應用會像現在看彙編語言寫出的大型程序的感覺。 WebAssembly項目目前由Apple、Google、Microsoft、Mozila四大瀏覽器廠商共同推進,還是非常值得期待的(寫不下去了我決定回去翻開我那本落灰的編譯原理。)。

Web Components

webcomponents規範起草於2013年,w3c標準委員會意圖提供一種瀏覽器級別的組件化解決方案,通過瀏覽器的原生支持定義一種標準化的組件開發方式。 webcomponents提出之際引發了整個前端圈的躁動,大家似乎在跨框架的組件化方案上看到了曙光。但是前端這圈子發展實在太特麼快了,在當前這個時間點,webcomponents也遭遇到了跟Object.observe相似的尷尬處境。我們先來看看webcomponents的幾個核心特性:
  1. Shadow DOM
  2. Custom Element
  3. Template Element
  4. HTML Imports
其中1、4現在都能很容易的通過自動化的工程手段解決了(shadow dom對應的是scoped css),而自定義標籤這種事情不論是React還是Angular這類組件框架都能輕鬆解決,那麼我用你webcomponents的理由呢?
另外webcomponents將目標對準的是HTML體系下的組件化,這一點跟React比就相對狹隘了(但是這並不表明React把戰線拉的那麼長就不會有問題)。
不過原生支持的跨框架的組件還是有存在的意義的,比如基礎組件庫,只是在當前來看web components發展還是有點營養不良。期待2016年能有實質上的突破吧。