Bruce 的玩具間

my works and notes on ruby, rails, git, ubuntu linux, mac os x, etc...

本部落格改用 Jekyll 搬到 S3 上囉 & 如何自動發佈到 S3 [附影片]

| Comments

最近把這個部落格搬到別的地方,除了捨棄 BSP 改用 Jekyll 並用 S3 host,也順便把 domain 正名了,這邊將不再更新,歡迎到我的新部落格看看:

 

改用 Jekyll 後得到一些新功能跟特點:

  1. Host 在 Amazon S3 上,並使用 CloudFront 加速 (跟省錢) 看了一下帳單似乎沒省錢效果
  2. 使用 Wercker 達成 Git 一有更新就會自動 deploy 到 S3、清除 CloudFront cache
  3. 單篇文章可指定 og:image,不指定的話就會套用預設的 og:image
  4. 首頁、Layout、RSS feed 都可雙語切換、部分文章可雙語切換
  5. 數量不限、可高度客製化的 pages

新部落格的第一篇會介紹我搬家的過程,如果你也有興趣把自己的部落格改到 Jekyll,歡迎參考我的新文章:

部落格搬家筆記: 改用 Jekyll 並透過 wercker 自動發佈到 S3 上

該篇文章雖然沒有 step by step 詳細教學,但有很多實際的 tips 與相關文件連結可參考。

特點 2 的影片:

《超效率!生活習慣》電子書開賣囉

| Comments

我大約從去年 10 月開始寫的電子書 《超效率!生活習慣》 開始販售囉!

超效率!生活習慣

本書的主要內容是各種效率技巧,包括生活撇步、推薦購買的生產力工具、懶人理財、Mac 設定、行事曆使用、個人 Issue tracking、工作 Issue tracking、檔案目錄配置原則、備份原則、程式設計師效率等;總之就是包山包海的效率建議的精華集。點進去的產品頁就有更詳細的介紹了,所以這篇我想講一些背後的故事。

為什麼會想寫這本書

主要是我偶爾會聽到別人在抱怨生活上有個問題很繁瑣,或者聊天過程中聽到對方的生活習慣很沒效率,情況允許的話我會提出建議,但有時候不是那麼適合,而且也會搞得好像我意見很多似的,於是乾脆來個意見大爆發。對!我意見就是很多。

另一方面則是我想嘗試看看 Lean 的精神 —— 快速出貨,快速改進商品,所以如果您有想知道的類別、覺得應該補充的項目、覺得我解法不夠好的地方都歡迎跟我說。在本篇文章底下留言或寄 Email 都可以:

書名是怎麼來的

這也是我想實驗的事情之一:投放 Google 廣告,依照點擊率決定產品名稱

最後是由 19% 的 "超效率 生活習慣" 勝出(Google 廣告標題禁止包含驚嘆號),其他的比率分別是 17%, 15%, 11% (中途有刪除掉兩個太冷門的候選標題)。

附帶一提,原本我意屬的是 15% 的那個,還好我有投廣告決定。

定價是怎麼決定的

10 月左右的時候,我問過幾個技術圈的朋友願意用多少錢買這樣的書,大部分回答都出乎我意料的高,也許是習慣技術書的價錢吧 |||

不過我最後並沒有直接採用問到的平均價錢,而是再低一點點的價格,大致上的考量有:

  • 台灣實體書通常會打 66折 ~ 79折
  • 台灣實體書標價大概 250 ~ 360
  • Leanpub 上某本停滯很久的未完成中文書的售價還掛在 6.5USD

希望實際售價能跟上 Leanpub 裡面的售價(一個字:貴),但又不要偏離台灣實體書的價錢太遠,於是:

N * 5折 = 6.5USD
=> N = 13USD
=> 標價 = 12.99USD,打 5折 ~ 79 折

嗯,真是隨性啊。

最後呢,由於這本書很多方面都是我第一次嘗試,寫這篇文章的時候都還沒有發生任何一筆賣書收入,其實有點擔心能不能回本(封面的圖片版權、投放 Google 廣告、時間成本等),因此,方便的話請幫我一個忙:任選做一件以下的事情(複選也歡迎)

  • 按本篇文章 FB 讚
  • 轉貼本篇文章或 Leanpub 上的介紹頁 到您的 Facebook timeline / Twitter / Plurk / Google+
  • 私訊您所知、對這種書會有興趣的朋友
  • 購買本書(趁現在還是 5 折的時候)

謝謝您的支持,也希望這本書有幫助到您。

Sublime Text ERB end[tab] 自動完成的關鍵字衝突問題

| Comments

本來想寫一篇部落格文講這個問題的,但寫到一半跑去開 PR 給 ERB-Sublime-Snippets 增加說明,就這樣被接受了。

因此請看 ERB-Sublime-Snippets > README > Resolve conflicting tab trigger 小節。

主要的問題點是,我同時裝了 ERB-Sublime-SnippetsRails Developer Snippets 這兩個 packages,再加上內建的 Rails package,他們有幾個 tab 自動完成關鍵字是相同的,其中最常遇到的就是 <% end %> 了。

解決方法就如連結裡所寫。

另外,我仍然 fork 了自己的 ERB-Sublime-Snippets 版本 (https://github.com/ascendbruce/ERB-Sublime-Snippets),原因是作者不接受 erperc 這兩個關鍵字 (預設的是 er, pepc)。我個人是覺得 erppe 較直覺啦,所以... 歡迎使用,不過我還沒更新 README 的安裝教學,可以先參考 這個

T客邦目前使用的 code 品質輔助工具

| Comments

這篇介紹一下T客邦跟我個人有在使用的品質(尤其是 coding style)輔助工具,有些是我幫T客邦引入的,有些是我從T客邦現有的制度學來的。

RSpec

比起這篇要介紹的其他項目,測試算是不太一樣的類別,但它很重要。例如改 Apple modle 意外的搞爆 Banana controller 而不知,如果你沒寫測試,可能就會到上線後才知道。

小作業:去查 regression testing 跟 non-regression testing 是什麼

寫這篇的時候,T客邦的測試大部分還是很陽春的狀態,覆蓋率不高、寫法也沒有特別遵循一些已知的 guidelines,但即使是最基本的測試也可以享受到一些好處。T客邦的測試寫法還有很大個改善空間,就等優秀的你來應徵。(☉▽☉)

加入 Gemfile

Gemfile
group :development, :test do
  gem 'rspec-rails', '~> 3.0'
end

bundle install

跑 generator

rails generate rspec:install

先寫一個很陽春的 spec,改到 rspec 可以順利跑完為止

spec/controllers/posts_controller_spec.rb
require "rails_helper"

describe PostsController, type: :controller do
  describe "GET 'index'" do
    it "renders index template" do
      get :index
      expect(response).to be_success
    end
  end
end

之後再視需求追加測試、追加 gems (例如 capybara, faker, fabricator 等)。如果你的目標是確保執行路徑上不要有嚴重錯誤就好,可考慮寫 feature tests 為主。

如果你使用 capistrano 做 deploy,但沒有架 CI server 的話,可以參考 Use codeclimate-test-reporter without a CI server 把 run_tests 的 capistrano task 設定好,如此一來若有忘記跟著功能程式碼一起修改的 test 敗壞的話,就會阻止你 deploy。(這部分是學自 Reliably Deploying Rails Applications 一書)

Coding style, code smell 與 best pratices 工具

這幾個項目其實都不用寫在 Gemfile 內,但我習慣直接加進去,因為只要 bundle install 就都裝好了,且以後新人即使一開始不知道有這些 gems 可用、只要肯搜尋各個 gems 的用法就也會發現。

修改這些警告項目時,如果有不錯的測試覆蓋率將會增加修改的信心,反之就會很擔心會不會搞爆功能了、最後還是不敢動它。如果你維護的專案既沒有測試也沒有遵循 coding style,我會建議:

  1. 先修嚴重的問題,例如 brakeman 警告中,特別嚴重的安全問題
  2. 補一些陽春測試,確保執行路徑上不要有嚴重錯誤,並且跑不過就不准 deploy
  3. 之後再開始修次要 coding style

Brakeman

是用來偵測 Rails 寫法造成的安全性問題的工具。

Gemfile
group :development do
  gem 'brakeman', :require => false
end

bundle install

在 project 根目錄執行

brakeman

就會看到它提出的建議,似乎大部分建議也都可以在官方的 Ruby on Rails Security Guide 看到。

rails best pratices

是依照社群維護的 Rails Best Practices 提供寫法建議,常見的建議有:在 partial 內不要用 @instance_variable使用 render 的簡化寫法應該從 view 移到 model / controller / helper 的 code移除行尾空白 等。

Gemfile
group :development do
  gem 'rails_best_practices', :require => false
end

bundle install

在 project 根目錄執行

rails_best_practices

參考官方 README > Customize Configuration 把你確定不處理的警告關掉。

EditorConfig

是指定空行、換行 style 的編輯器外掛+設定檔。雖然各編輯器通常可以自己設定,但使用 EditorConfig 的好處是只要要求新人裝對應的外掛即可,不怕新人設定錯,而且設定可以跟著 project 走。

在 project 根目錄加設定檔

.editorconfig
# Please install EditorConfig plugin for your editor or IDE

# Usage and plugin list can be found here: http://EditorConfig.org


# top-most EditorConfig file

root = true

[*]
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
indent_size = 4

並到 EditorConfig 官方網站尋找你使用的編輯器,安裝相應的編輯器外掛。

幾個月前我第一次嘗試使用 EditorConfig 時發現 Sublime 的 global settings 會覆蓋掉 EditorConfig 的設定,但第二次嘗試時就正常了,不確定是誰 update 過。

rubocop

依照社群維護的 bbatsov/rails-style-guidebbatsov/ruby-style-guide 提供建議。常見的建議有各種縮排層級、空白、空行的位置/數量、統一使用單引號或雙引號(依照你的設定) 等非常詳細的 coding style 問題。

Gemfile
group :development do
  gem 'rubocop', :require => false
end

bundle install

在 project 根目錄執行

rubocop

就會看到修改的建議

參考 官方 README > Configuration 把不修正的警告關閉、與團隊現有 coding style 不符的地方改參數。另外也可以在誤判的程式碼前後加上特殊的註解即可小範圍排除特定的警告。

另外,Rubocop 具有自動修正的功能,我使用以下的流程(實際指令要去翻 README):

  1. 寫一個把所有 cop 都關閉的設定檔
  2. 寫一個繼承上述設定檔,並且 override 掉想修正的項目(但不是所有 Cop 都支援自動修正)
  3. 執行 Rubocop 的自動修正指令
  4. 回到第二步,改成下一種要修正的項目

可用的外部服務

這部分是一些可以幫你跑檢測工具,並透過較友善的介面回報給你的服務。

Hound

是 Rubocup + CoffeeLint + JSHint 的服務
且偵測到問題會自動在 Pull Request 上直接留言

計費方式

  • 12USD per project per month
  • 有 Open Source 可以自己架

Code Climate

是 Brakeman + 複雜度與重複性 的網路服務
其介面設計的很漂亮,且若有誤判可以從網頁介面隱藏掉(如果你自己跑 brakeman 的話,可能就要自己記住那個其實是誤判等等)

計費方式

  • 5 users x 5 private repos = 99USD per month
  • 16 users x 10 private repos = 199USD per month
  • 32 users x 20 private repos = 399USD per month

PullReview

還沒有認真的用,但初步看起來,使用方式跟 Code Climate 類似、功能較多,但計費方式不同。
功能似乎相當於有 Rubocop + Brakeman + 複雜度與重複性檢測,但底層是用誰目前不確定,支援 GitHub 跟 BitBucket。

  • 1 user x unlimited private repos = 20EUR per month

其實還有一些其他的服務,但因為我自己沒用過所以就不特別介紹了。

T客邦技術部的 20% 自由研究時間

| Comments

上禮拜趁機會向主管提出我考慮好一段時間的政策:20% 自由研究時間,意外的沒有遭到什麼反對,我們的主管很支持,也幫我們跟老闆溝通,於是今天就是第一次實行 20% 研究時間的日子。

為什麼要有 20% 的自由研究時間

Google 的 20% 自由研究時間,或者 Atlassian 的 FedEx day,是很有名的一項福利,在這段時間你可以做跟工作無關的事情、寫跟工作無關的 code,但其中偶爾會有成為公司主力產品的例子。

工作上勢必有些雜事、大家都不想做的苦差事、無聊差事等,為了讓公司順利營運,這些東西少不了,但一直讓員工做這些事的話,員工會不爽、會萌生離職念頭。

這就是為什麼我認為要有 20% 自由研究時間

  • 工程師會很興奮(工程師快樂是很重要的)
  • 可以幫公司內部做好用的工具(但這種東西一般是不會排進專案時程的)
  • 可能可以撿到公司下一隻金雞母業務

兩年前我有寫過一篇讀書心得,其中也有提到相關的話題:動機,單純的力量 重點與讀書心得

雖然聽說 Google 的 20% 自由時間已名存實亡,被員工酸是 120% 的工作時間,但我認為還是可以嘗試的,名存實亡的問題等公司跟 Google 一樣大再來擔心。

附帶一提,T客邦目前是上班打卡制、下班還是打卡制,時間到就好走了,最好不要賴在辦公室。

我們採用的規則

  • 每週五一整天(一週的 1/5 工作天 = 20%)
  • 放在禮拜五的原因是如果做開了,禮拜六日回家可以自己繼續做
  • 如果沒有想要做的主題,該週可以改成每天 20% 時間做小實驗,直到有明確的 idea 為止
  • 工程師不是機器,平常多少有狀況不好的時候,所以撥出 20% 時間其實不是很嚴重的事
  • 智慧財產權屬於公司

尋找題目

實行這樣的政策,有沒有題目作可能是維持下去的關鍵之一,如果大家都想不到要做啥,可能就會「啊算了、隨便啦」,就不了了之了。

我們找題目會從這幾個方向找

  • 公司非技術同仁提出他們面對的問題,例如 Facebook 留言抽獎的名單整理程式
  • 工程師自己在公司面對的問題,例如開發團隊 Dashboard
  • 與工作完全無關,解決自己私下面對的問題(但磨練技術最終還是會跟對公司貢獻有關)

一般來說,實做的成果能被使用(解決別人或自己的問題)、能獲得回饋(這邊如果改成…的話會更好)、受人肯定(這真好用耶!)就是不錯的題目。

示範成果

其實之前雖然沒有明文規定的 20% 自由研究時間,但工程師們本來就常常會找零碎時間做一些自動化的工具,以下兩個是我們之前做的小玩具。

Facebook 留言抽獎名單

是 Facebook 即將禁止的抽獎方式,不過當時常常有這樣的活動。

T客邦工程部 Dashboard

因為T客邦同時維護多個 Rails 網站,且都有一定的規模,加上有一些限制在,所以常常要多人對多個站平行做事、容易互搶主機,有 Dashboard 後就可以加速判斷是否搶到別人主機使用等。

另外也有待處理票的提示、開票自動化、各站的 coverage report shortcut 等方便開發者的功能。

在T客邦工作

T客邦目前還有 Rails 職缺,歡迎對 20% 自由研究時間會感到興奮的人來應徵:(工程師魂!)

Rails Developer 數名 - T客邦 (城邦文化事業股份有限公司) - Inside Job Board

另外也可參考 新進工程師如何學習 Rails 了解在T客邦可能的學習之路。

Use codeclimate-test-reporter without a CI server

| Comments

For some reason, we didn't setup a CI server. But we still want Code Climate to know test coverage after each deployment.

After some searching and experiment. We came up with this solution.

1. Add Capistrano run_tests task

Because we don't have a CI server. We use Ben Dixon's run_tests technique covered in his book Reliably Deploying Rails Applications, which is:

lib/capistrano/tasks/run_tests.cap
namespace :deploy do
  desc "Runs test before deploying, can't deploy unless they pass"
  task :run_tests do
    test_log = "log/capistrano.test.log"
    tests = fetch(:tests)
    tests.each do |test|
      puts "--> Running tests: '#{test}', please wait ..."
      unless system "bundle exec rspec #{test} > #{test_log} 2>&1"
        puts "--> Tests: '#{test}' failed. Results in: #{test_log} and below:"
        system "cat #{test_log}"
        exit;
      end
      puts "--> '#{test}' passed"
    end
    puts "--> All tests passed"
    system "rm #{test_log}"
  end
end
config/deploy.rb
set :tests, ["spec"]
before :deploy, "deploy:run_tests"

It will run test before every deploy. And stop deploy process if there are any failed test.

2. Install and setup codeclimate-test-reporter

Install codeclimate-test-reporter by adding it into Gemfile

Gemfile
gem "codeclimate-test-reporter", group: :test

and run bundle install

Start the test reporter. Make sure that you put these lines at top of your spec_helper.rb.

spec_helper.rb
require "codeclimate-test-reporter"
CodeClimate::TestReporter.start

Manually tirgger fist test report (your project token can be found at Settings > Test Coverage)

(in terminal)
$ cd your_project_root
$ CODECLIMATE_REPO_TOKEN=your_token_here bundle exec rspec spec

It should show following message:

Coverage = xx.xx%. Sending report to https://codeclimate.com for branch master... done.

Now you should be able to see the report showing in Code Climate. Sometimes it can take a few minutes.

3. Modify run_tests and make it report after each deployment

When you run rspec without CODECLIMATE_REPO_TOKEN, even you have test reporter started, it won't send test report to Code Climate. In other words, you can control when to send report by giving token or not.

Modify the rspec command in lib/capistrano/tasks/run_tests.cap

I assume you always run complete test suit with this technique.

lib/capistrano/tasks/run_tests.cap
namespace :deploy do
  desc "Runs test before deploying, can't deploy unless they pass"
  task :run_tests do
    test_log = "log/capistrano.test.log"
    tests = fetch(:tests)
    tests.each do |test|
      puts "--> Running tests: '#{test}', please wait ..."
+      rspec_command = "bundle exec rspec #{test} > #{test_log} 2>&1"
+      rspec_command = "CODECLIMATE_REPO_TOKEN=#{fetch(:codeclimate_token)} #{rspec_command}" if fetch(:codeclimate_token)
+      puts "--> Running tests: '#{rspec_command}', please wait ..."
+      unless system(rspec_command)
-      unless system "bundle exec rspec #{test} > #{test_log} 2>&1"
        puts "--> Tests: '#{test}' failed. Results in: #{test_log} and below:"
        system "cat #{test_log}"
        exit;
      end
      puts "--> '#{test}' passed"
    end
    puts "--> All tests passed"
    system "rm #{test_log}"
  end
end
config/deploy.rb
set :codeclimate_token, your_token_here

Now, test will be run before every deployment and test report will be sent after that.

Note: you can put your token in run_tests.cap for simplicity. But I rarely commit any key or token into repostory. Instead, I put it in a git-ignored, separated config file. Than read and assign the value in config/deploy.rb.