About

Programmer
鼓手
人夫
孩子的爹

| Posted by Yang-Hsing Lin

Docker 初體驗

之前就有聽說過 Docker, 看了他的介紹和 documents 感覺超潮的阿!
最近試著把它加入日常生活的 workflow, 結論是只有找到 database 的 usecase 比較合用...

日常 workflow

我日常生活(?)的 workflow 是在 Ubuntu 的電腦上跑 Rails + database (MySQL/Postgresql) + RSpec。我預期 Docker 可以幫我做到的是讓我可以不用裝相關的 dependencies 在我 local 的機器上,這樣好像就可以無痛切換 dependencies (像是 ruby 升級之類的),或者是可以順利地讓 local 的環境複製到 server 上。
但是這樣的 settings 必須要讓我可以輕鬆地做:

  1. 跑 RSpec test case
  2. migration, bundle install 等等的東西

現在的解法

目前以 Rails(或其他 ruby 相關的 project)來說,bundler 好像解決了 project 之間 dependencies 的問題。然後用 Capistrano deploy 再搭配 bundler, 可以做到一鍵 deploy.

可能的施力點

這樣看起來好像沒有什麼太多的施力點可以讓 docker 來解決問題,但是我還是想了一些:

  1. project level dependencies (ex: 不同的 projects 需要同一個 gem 的不同版本)
  2. service level dependencies (ex: 不同的 projects 需要不同版本的 Postgresql / ngxin)
  3. 把環境加到 code 裡面一起 version control, 這樣就可以有系統地 upgrade 環境

結果

project level dependencies:

像上面提到的,這個問題 bundler 似乎就解決惹,用 Docker 的優勢好像沒有很明顯。

service level dependencies:

這個部份好像用 docker 就很不錯,目前有試著把 database 交給 docker 來管:
目前的作法是在 local 就不裝 db 了,而是直接 run 一個 Docker 的 container 當作 database, 然後再把相關的 data link 到 local 的檔案
這樣的話可以做到每個 project 有自己專屬的 database, 所以如果需要不同版本的話也可以做到。
Postgresql 來說,我的作法是:

  • $HOME/var/postgres/data 裡面放 Postgresql 相關的 data
  • run 一個 docker container:
    $ docker run --name postgres_svr -d -p 9527:5432 -v /home/mz026/var/postgres/data:/var/lib/postgresql/data postgres:9.3
    

這樣就可以在 0.0.0.0:9527 連到一個 Postgresql 的 server

把環境加到 code 裡面一起 version control, 這樣就可以有系統地 upgrade 環境:

這個野望後來沒有被實現 orz, 我想到的作法是在不要自己 maintain 一個 image host 又不要付錢的前提下:

  • 加入一個 Dockerfile 在 source code 裡面,用這個檔案來控制 project 所需要的環境,
  • deploy 的時候,在 server 的機器上 build 這個 docker image

這個作法遇到的問題就是,每次在 server 上 build 的時候,bundle install 這步要重來 orz, 所以每次根本都超慢 der。
這個問題的解法應該是只要自己 host 一個 image host (或者付錢給 docker hub),然後隨著每次的 code update, 把相關的 image update 也 check in 進去 image host。如此一來,在 deploy 的時候就只要在 server 上 pull image host 上面對應版本的 image 就好了。但是目前這個的 deployment 的作法 (Capistrano + bundler)好像也相安無事,所以等有遇到困難再來研究。

心得與感想:

感想就是這個 docker 真的是很潮阿,因為 run 起來相當的快,感覺等到有需要的時候應該會是很有力的解法。
又或者如果跳離 Rails 的環境需求的話,可能又會有更有趣的應用方式。

TODO:

要試一下用 Docker 在 continuous integration 的時候來 run test

然後我買了這本書 The Docker Book 但是還沒看 orz, 希望可以變成 docker 達人阿!如果有任何好用的 usecase 請告訴我!

| Posted by Yang-Hsing Lin

小工具系列: Angular Page Visibility

最近寫了一個把Page Visibility API和 AngularJS 接起來的小工具: angular-page-visibility

話說從頭

其實就是因為最近kono 的 web app需要在 user 切換 tab 的時候,去trigger一些特定的事件。一開始找到了jquery.blurjquery.focus, 結果發現有點糗。糗點在於,我本來預期的行為是,當 user 切換 tab 到別的地方的時候,立刻 trigger blur 的 event, 然後在 user 回來的時候,再 trigger focus 的事件(對,就像正常人想像的那樣)。結果事實上是,當 user 離開 tab 的時候, blur沒有被 trigger, 然後當 user 回到我們的 tab 之後,立刻 trigger focus 再 trigger blur, 基本上就是全錯的意思 @@。 後來找到了原來有 Page Visibility API (我現在才知道 orz)。 但是好像沒有合意的 AngularJS interface。於是動手自己搞一個。

How it works

其實真正做的事情就像MDN寫的那樣,和 Angular 的介面,我把它做成一個可以被 inject 的 factory, 接到的是一個 $scope object, 以便於用熟悉的 $broadcast, $on 來收發 events.

Usage

用法是把它 inject 進任何你想 inject 的地方,然後聽 pageFocusedpageBlurred 這兩個事件:

// my_controller.js

angular.module('app')
       .controller('MyController', function($scope, $pageVisibility) {
         $pageVisibility.$on('pageFocused', function(){
           // page is focused

         });

         $pageVisibility.$on('pageBlurred', function(){
           // page is blurred

         });
       });

然後在 page blur / focus 的時候,就會 trigger 該 trigger 的 listener 惹。

Testing note

這個小 project 的 unit test 還是用 jasmine + sinon.js
最近開始嘗試 coffee script, 發現原來 karma 可以讓 test code 不用先轉成 javascript 就直接跑,這樣跑起來快蠻多的。(也是現在才知道!!)

結論

code 在這邊, 如果有 bug 或任何意見,請不吝指教阿阿阿。

| Posted by Yang-Hsing Lin

vim 與我,我與 vim

我超愛 vim der。

vim 是什麼?

vim 是一個文字編輯器。 主要的功能就是拿來打字。 對的,就像附屬應用程式裡面的記事本一樣。 但是是終極的強化版。基本上記事本之於 vim, 就像是紙飛機之於飛機一樣。

好在哪?

效率王

我覺得 vim 最大的好處 (可能也是壞處) 就是 所有的動作都只能靠鍵盤來完成

沒錯,包括移動游標、打字、刪除、複製、貼上等等。 全部由鍵盤來完成的結果就是, 如果很熟練的話,那動作會非常快。 對於某些特定的人需要長時間專注的編輯文字,像是 developer, 這整件事情最大的價值在於你的思考不會被編輯器的動作中斷
例如說你突然想到這個地方應該要怎麼做,要寫哪些東西,這個時候如果你花30秒找到你要改的地方、複製、貼上、排版等等, 可能等你搞好這些之後你就忘了你本來要幹麻。於是你又花了另外的15秒重新想一次,這是常見又惱人的狀況之一。 所以如果說我們可以找到「想法」和「執行結果」中間的最短路徑,那工作效率會大大的提升。 (就好像電競選手會狂用快捷鍵是一樣的道理)

在 server 上面可以用

有些時候我們會要在 server/工作站 上面寫 code,
這時候陪伴我們的,只有冷冰冰的 terminal 和熱情的 vim。
如果平常你就跟 vim 很熟的話,那在這種時候你就會覺得像是在自己家一樣啦!

對於一個有經驗的 vim 使用者來說,他的眼睛到哪,游標就跟著到哪

障礙:

學習曲線:

大多數人對於 vim 望之卻步的主要原因之一是它的學習曲線確實蠻高的。光是要用鍵盤移動游標這件事情,聽起來就夠嚇人。
我覺得如果要把 vim 搞會,進而發揮它的威力,第一件事情就是先學會如何打字

學會如何打字的意思是,要可以不看鍵盤打出所有的英文字母、數字、符號、ctrl、tab、shift、alt。這件事情基本上就是沒有捷徑了,就是要練習。 速度不用到超快,只要可以打字的時候不要想,這樣應該就 ok 了。

學會如何打字之後,第二步就是強迫自己用 vim 寫 code
這步聽起來有點無聊,但我自己就是用這個方法。
一開始確實有點痛苦,想說我只是要找一個關鍵字或複製一段文字,為什麼搞得像是上上下下左左右右ABAB一樣,
但漸漸地,當你發現你別人用滾輪滑了老半天,或者是在選單列找某個功能遍尋不著,而你只花了0.5秒就搞定的時候,你就會發現果然痛苦會過去,美會留下。

設定:

vim 的預設設定很難用,幾乎到了 我幹麻不用記事本 這麼難用。
但是經過好好設定過後的 vim, 就可以飛天遁地了。
vim 的設定是透過一個文字的設定檔 vimrc 來完成的。
vimrc 本身要用 vim 提供的某種 script 來完成,這件事情對我來說蠻痛苦的。
因為這種 script 本身沒有特別好懂,而且它就只是 config 檔嘛,插麻搞得這麼複雜。
所幸在現代,就有人做了一些 vim 的套件管理工具, 像是 vundlepathogen 等等, 再配合 github,可以讓設定 vim 這件事情變得容易很多。 而這樣的套件管理工具,讓原本就存在的大量 vim 使用者可以貢獻、交流自己的設定/工具,進而達到世界大同(?)的狀態。

雖然說我不會寫 vim 的 script,但我時常花很多時間看各式各樣的 plugins, 然後看看有沒有平麼好用的。
就像你有一個工具包,即使你不會自己生產工具,但你會時不時去逛工具店看看有沒有什麼稱手的新玩意兒,可以讓你的效率更高,或者在 code review 的時候更帥。

vimrc 這個檔案就會為跟著你一輩子(?)的設定檔,以後當你兒子要寫 code 的時候你就可以跟他說,「來,這是老爸的累積了二十年的 vimrc,現在交給你了」這樣。
再配合現在很方便的 github / bitbucket, 你可以把同樣的設定檔同步到每一個工作的地方 (像是公司的電腦、家裡的電腦、 server 上面等等), so sweet!

我常用的 plugins

這是 我的 vimrc

和大家分享若干我的最愛 plugins:

command-t

command-t 是一個讓你可以快速找到檔案的 plugin,
例如說我有一個檔案的路徑是 app/controllers/users_controller.rb, 利用 command-t, 我只需要打部份的路徑,好比說 "acur" 之類的, 這時候 command-t 就會很聰明的幫你找到該檔案。
這件事情對於我這種常常只記得部份的檔案名稱的人相當好用。 和 command-t 類似的還有另一個叫 ctrl-p, 但我個人覺得 ctrl-p 常常找錯檔案。

easy-motion

easy-motion 是可以讓你把游標跳到螢幕上任何地方的 plugin, 是 眼睛到哪,游標就到哪的重要關鍵之一! 用法大致上就是你按下某個快捷鍵,然後螢幕上每一個單字前面就會像中毒一樣都出現一個不同的小英文字,然後你再按該單字前面的小英文字,就可以跳到那邊。 可以參考他的 github 網站,有 gif demo

snipmate

這個應該是從 textmate 偷過來的 feature,
它的主要功能就是可以讓你少寫好多 code,
好比說時常我們要寫一個 for loop:

for (var i = 0; i < theArray.length; i ++) {
  // do something here

}

在這個例子裡面,十之八九我們要改的東西其實只有 theArray// do something here 而已。
所以透過 snipmate 就可以讓我們只打 for 然後按下某個快捷鍵, 就寫出 for loop 的 template, 並且把游標停在 theArray 的地方, 在我們改好 theArray 之後, 再按下某個快捷鍵, snipmate 又再度幫我們把游標停在 do something here 的地方。

類似的例在還有 function, 或 html 等等。

我覺得這個 plugin 的威力在於, 要增加/修改 各式的 template 相當容易,所以你可以自己定出各式各樣屬於自己的懶人組合。

結論

提升效率是一件很棒的事情,而對於工程師來說,這件事情所帶來的效益通常會比其他行業的人來得更顯著。而找到一個稱手的文字編輯器,並且熟悉它,是提升效率裡面很重要的一步。 vim 毫無疑問的是最好的文字編輯器之一,也有很穩定且強大的社群,是一個報酬率很高的投資。

happy hacking!

| Posted by Yang-Hsing Lin

檢查 hash format 小幫手: Hash Police

在寫 Rails test 的時候,時不時就會要檢查 hash 的格式對不對,
好比說有一個 API 是會要 return

{
  "id": 123,
  "nickname": "Michael Jackson",
  "age": 50,
  "alive": false,
  "genres": [ "pop", "funk" ]
}

這個格式如果不小心被改壞了,那接這個 API 的 client 就有可能會壞掉。
於是在 controller test 裡面就會出現: (using RSpec)

response_body_hash = JSON.parse(response.body)
response_body_hash.should have_key('id')
response_body_hash['id'].should be_kind_of(Fixnum)
response_body_hash.should have_key('nickname')
response_body_hash['nickname'].should be_kind_of(String)
# balah balah balah...

如果我們的 API 有好多個 keys, 那簡直是檢查不完,而且 code 的可讀性也大大降低。
時間久了就會產生一種想吐的感覺。

Hash Police is at your service

於是我寫了一個叫作 hash_police 的 ruby gem,
功能就是你給他一個符合格式的 hash,
他就幫你 recursively 檢查格式有沒有錯。

所以上面的 code 就會變成:

response_body_hash = JSON.parse(response.body)
rule = {
  :name => '',
  :age => 1,
  :alive => true,
  :genres => ['']
}
police = HashPolice::Police.new(rule)
result = police.check(response_body_hash)

puts result.error_messages unless result.passed?
result.passed?.should be_true

還是太醜

沒錯,上面的作法雖然可以不用一個一個 key 去檢查,
但是如果錯了的話,沒辦法好好的用 RSpec 的格式 log 出來,
所以搭配RSpec custom matcher服用的話:

RSpec::Matchers.define :have_the_same_format_as do |expected|
  result = nil
 
  match do |actual|
    police = HashPolice::Police.new(expected)
    result = police.check(actual)
    result.passed?
  end
 
  failure_message_for_should do |actual|
    result.error_messages
  end
end
 
 
actual.should have_the_same_format_as(expected)

本來的 test case 就可以寫成:

response_body_hash = JSON.parse(response.body)
rule = {
  :name => '',
  :age => 1,
  :alive => true,
  :genres => ['']
}
respose_body_hash.should have_the_same_format_as(rule)

這樣就爽快多惹。

Notes:

  • 如果有什麼 bug 或者任何問題,請不吝指教 :D
| Posted by Yang-Hsing Lin

Hola World!

Hola World

耶黑! 要開始寫 blog 惹,希望可以認真一直寫。