about 1 year ago

有同學最近在問 RSpec 的問題,因為會回答很多次,乾脆寫「一個經典例子」,來介紹 RSpec 的常見 syntax,來介紹一串重要的手法。

例子:Course#publish?

publish? 的判斷方式是 published_at 這個欄位存在與否。

class Course < ActiveRecord::Base
    
  def published?
    published_at.present?
  end
end

觀念 1: 測試要寫 正 / 負場景

在這個例子裡面,因為是測 boolean 值,比較好的方式,是要寫正反例子。

RSpec.describe Course, type: :model do
   describe "#publish?" do 
    it "return true when published_at present?" do 
      course = FactoryGirl.create(:course, published_at: Time.now)
      expect(course.published?).to be_truthy
    end

    it "return false when published_at blank?" do 
      course = FactoryGirl.create(:course)
      expect(course.published?).to be_falsey
    end
  end
  
end

觀念 2 :當 when 與重複語句出現,應抽出變成 context

  • when published_at present?
  • when published_at blank?

這兩句是場景,所以接下來可以改寫成

RSpec.describe Course, type: :model do
  describe "#publish?" do 

    context "when published_at present?" do 
      it "return true" do 
        course = FactoryGirl.create(:course, published_at: Time.now)
        expect(course.published?).to be_truthy
      end
    end

    context "when published_at blank?" do 
      it "return false" do 
        course = FactoryGirl.create(:course)
        expect(course.published?).to be_falsey
      end
    end

  end
end

觀念 3 : 用 let 抽出 course,it 內只測 expect

將物件抽到 let。

RSpec.describe Course, type: :model do
describe "#publish?" do 

    context "when published_at present?" do 
      let(:course) { FactoryGirl.create(:course, published_at: Time.now) }
      it "return true" do 
        expect(course.published?).to be_truthy
      end
    end

    context "when published_at blank?" do 
      let(:course) { FactoryGirl.create(:course) }
      it "return false" do 
        expect(course.published?).to be_falsey
      end
    end

  end
end

觀念 4 : Minimal Valid Object 與「測試真正的變因」

但是在步驟 3 中,這樣的測試手法,是生成了「兩個不同的物件」去測。但我們寫這個測試的目的是要「測試一個物件,在published_at值不同」的情況下的回傳狀況。

真正的「宿主」是 Coruse 本身。所以我們改用 subject。傳 nil 與 現在的時間,去測試真正要測的行為。

RSpec.describe Course, type: :model do
  describe "#publish?" do 

    subject(:course) { described_class.new :published_at => published_at } 
    context "when published_at present?" do 
      let(:published_at) { Time.now }
      it "return true" do 
        expect(course.published?).to be_truthy
      end
    end
    context "when published_at blank?" do 
      let(:published_at) { nil }
      it "return false" do 
        expect(course.published?).to be_falsey
      end
    end

  end
  
end

觀念 5 : xxxx? 可以使用 be_xxxxx 去測試

  describe "#publish?" do 

    subject(:course) { described_class.new :published_at => published_at } 
    context "when published_at present?" do 
      let(:published_at) { Time.now }
      it "return true" do 
        expect(course).to be_published
      end
    end
    context "when published_at blank?" do 
      let(:published_at) { nil }
      it "return false" do 
        expect(course).not_to be_published
      end
    end

  end

觀念 6 :is_expected

測 return true/ false 看起來像是超多餘的。而且我們是對 subject 測,所以又可以改成 is_expected

RSpec.describe Course, type: :model do
  describe "#publish?" do 

    subject(:course) { described_class.new :published_at => published_at } 

    context "when published_at present?" do 
      let(:published_at) { Time.now }
      it { is_expected.to be_published }
    end
    context "when published_at blank?" do 
      let(:published_at) { nil }
      it { is_expected.not_to be_published }
    end
  end
  
end

最後看起來是不是變得很好維護呢?

 
about 1 year ago

之前不少讀者都問過我一個共有的問題:就是如果它的產品很新,或者它的 TA 很小眾,要怎麼開始做 Growth / Marketing。我的建議都是請他們先「實作 Content Marketing」。

What is Content Marketing ?

現在網路上的用戶,每天都面臨著「廣告轟炸」。基本上如果你的產品很新或 TA 很小眾,下廣告基本上也沒什麼用。使用者通常也會跳過。

減肥粉絲團

更多人的購買決策是,觀看部落格心得、看別人推薦而購買。或者長期訂閱某粉絲團的內容,對該粉絲團產生信賴,進而購買這個粉絲團上面推薦的內容。

電子書下載

又或者我講一件更令你熟悉的場景。有天你逛到某一個電子書免費下載的頁面,輸入 email 就能下載該本電子書,然後你的電子信箱裡面就開始收到對方寄得一些厲害的 Tips,因為也很有趣,所以你沒退掉的意思。某天該公司推薦一個軟體,你覺得還不錯,就買了....

這就是「Content Markerting」做的事。

Content Marketing 的形式

Content Marketing 的技巧與策略有很多種。比較常見的格式是

  • 養粉絲團分享文章
  • 寫部落格(關鍵字)
  • 製作免費電子書
  • 線上研討會

See / Think / Do framework

本篇只是一篇 Content Marketing 的 Intro。我也沒辦法 Cover 太多的詳盡步驟。在這邊我想直接以製作部落格內容為例子,講解「好的」Content Marketing 要怎麼做。

這裏我想介紹的是一個簡易的 Framewrok 叫做 See / Think / Do。這個框架是一個在 Google 上班的行銷人 Avinash Kashykk 研發的。

See / Think / Do 框架,將所有觀眾分為三種人。也是一個漏斗架構

  • See 群眾,但他們可能沒有購買意願
  • Think 他們可能表達了一點購買意願
  • Do 已經傳達了非常清楚的購買意願

在這裡我舉兩個我喜歡的兩套 SaaS 軟體,來讓各位更了解這是怎麼一回事。

例子 1 : Codeclimate

Codeclimate 是一家用來檢測「軟體品質」的軟體公司,基本上 Ruby on Rails 界的人,人人都知道這間公司。它的功用就是你將程式碼上傳,Codeclimate 會自動檢測你的程式碼裡面的「壞味道」「安全漏洞」,將你的程式碼評級。

它的 See / Think / Do 群眾就是

  • See : 有在寫程式的人
  • Think : 認為把程式寫乾淨有點重要的人
  • Do : 認為團隊的程式「絕對要乾淨」的資深程式設計師,正在找工具讓團隊的程式碼品質更佳的人。

例子 2 : GrooveHQ

Groove 是一家線上客服軟體公司。基本上可以把客戶寄來的 Support 信,自動轉成 ticket,讓公司內客服協作,也提供 FAQ site 功能。我們公司就是用 Groovq 做客服管理。

它的 See / Think / Do 群眾就是

  • See : 有在做生意的人
  • Think : 認為做好客服有點重要的人
  • Do : 認為「客服好」等於「賺大錢」的老闆。正在找工具,讓公司客服回覆速度更快的人。

Why See / Think / Do 框架重要?

很多人做「內容行銷」,花了很多力氣在「Do」這個層面的客群。

甚至認為 Do 才是最正確的客群。

  • Do : 認為團隊的程式「絕對要乾淨」的資深程式設計師,正在找工具讓團隊的程式碼品質更佳的人。
  • Do : 認為「客服好」等於「賺大錢」的老闆。正在找工具,讓公司客服回覆速度更快的人。

所以方向也會建立在:介紹自己產品多好用啦。講自己產品多屌啦。etc.etc.etc...

但事實上,多數成功的 Content Marketing 實作者是怎麼做的?

以 CodeClimate 來說。他們真正成名是這篇 *7 Patterns to Refactor Fat ActiveRecord Models

這篇幾乎所有程式 Refactor 書籍都會提到的經典文章。讓很多不知道怎樣將 code 寫得更好的人,有了大概的基本觀念。也對把 Code 寫得更乾淨這件事有了更高的認知。當他們在尋找「能協助將 Code 寫得更好的工具」時,就會想到 CodeClimate。

而 Groove。我是偶然在 HackerNews 上看到這篇轟動的部落格「把 SaaS 創業公司做到月營業額 10 萬美金」* A SaaS Startup’s Journey to $100,000 a Month 的文章後。開始訂閱他們的部落格。

而他們的部落格也常常會分享「週五創業家心得」、「客服做得更好」的例子。比如說我就很喜歡上個月的這篇文章 10 Tips for Sending Better Customer Service Emails

他們關於使用客服改善服務品質、促進銷售的文章總讓我獲益良多。因此,當我在尋找將客服做得更好的工具時,我第一個想到的就是 Groove。而且就算幾個服務攤開來比較。別家就算做得比較好,我也還是比較傾向使用 Groove。

See / Think 型觀眾才是內容行銷的 TA

所以其實內容行銷的寫作重點與 TA,不在於找「Do」層面的人。而是要找「See / Think」層面的人。

因為這兩個層面的人,不知道「投入這個領域的好處」「如何把這件事做到更好」。

如果你寫作的內容可以把它們的興致「燒起來」,將來他們要做購買決策的時候,第一個想的就是你。

Summary

所以你的內容行銷方向該怎麼做?

  • 不藏私,整理你知道的訣竅告訴大家
  • 把重點落在協助「想進入這個領域」的人,變得更強。

雖然這是很老套的觀點。但是你正在看的這篇文章,其實就是這個策略的示範。

 
over 1 year ago

RedPotion 是我最近在玩的一套 iOS App 開發框架。

大家應該了解 用 Ruby 開發的 Rails,在網站開發這一塊,有多強大。那麼白話的形容「redpotion」,你可以想像成它就是 RubyMotion 上的 Rails。

What is RubyMotion?

RubyMotion 是一套在 2012 年誕生的新語言,希望解決的事是「用 Ruby 寫出跨平台的 App」。跨平台的 App 當然包括 iOS App。

這在當時引起了一陣騷動,因為 Ruby 的語法比起 Objective-C 以及 JAVA 起來實在是好寫太多了。如果真的可以寫 Ruby,快速開發出 iOS 與 Android App,那會是一套很棒的事。

Why not RubyMotion?

當然,好日子沒有過的太長。Ruby Motion 更新非常快,母公司技術實力也雄厚。但在推展上卻有一點小阻力。

最大的問題有兩個:

  • Apple 在 2014 年中推出 Swift,把 iOS 的開發門檻大量的往下拉。
  • RubyMotion 的語法還是很囉唆,要寫一個 RubyMotion iOS App,純靠 Ruby 功力鐵定是不行的,你還是要在 Ruby 裡面寫出很多像 Objective-C 的 Code。

所以有人開玩笑說,如果要用 RubyMotion 加速開發,開發者的 Ruby 與 Objective-C 功力都要有一定才可以。否則還不如去學 Swift。

What is RedPotion?

RedPotion 是一家技術狂熱的公司 infinitered 在 2014 年底開始的專案。初衷有點像是 RubyMotion 懶人包,幫開發者準備好上手的 boilerplate (模板),內建許多厲害的 gem。逐漸把 RubyMotion 開發變成是更簡單的事。舉例來說,以下是兩個 app 的 app_delegate.rb ( app 起始檔案)

用 RedPotion 寫出來的程式碼,就比較像人可以維護的程式碼。也像是正常人「希望 RedMotion」可以長成的樣子。

RubyMotion 的 app_delegate.rb

motion_app/app_deligate.rb
class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    rootViewController = UIViewController.alloc.init
    rootViewController.title = 'my_new_app_2'
    rootViewController.view.backgroundColor = UIColor.whiteColor

    navigationController = UINavigationController.alloc.initWithRootViewController(rootViewController)

    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    @window.rootViewController = navigationController
    @window.makeKeyAndVisible

    true
  end
end

RedPotion 的 app_delegate.rb 與 home_screen.rb

potion_app/app_deligate.rb
class AppDelegate < PM::Delegate
  include CDQ # Remove this if you aren't using CDQ


  status_bar true, animation: :fade

  ApplicationStylesheet.new(nil).application_setup

  def on_load(app, options)
    cdq.setup # Remove this if you aren't using CDQ

    open HomeScreen.new(nav_bar: true)
  end

  # Remove this if you are only supporting portrait

  def application(application, willChangeStatusBarOrientation: new_orientation, duration: duration)
    device.orientation = new_orientation
  end
end
app/screens/home_screen.rb
class HomeScreen < PM::Screen
  title "Your title here"
  stylesheet HomeScreenStylesheet

  def on_load
    set_nav_bar_button :left, system_item: :camera, action: :nav_left_button
    set_nav_bar_button :right, title: "Right", action: :nav_right_button

    @hello_world = append!(UILabel, :hello_world)
  end

  def nav_left_button
    mp 'Left button'
  end

  def nav_right_button
    mp 'Right button'
  end

def will_animate_rotate(orientation, duration)
    find.all.reapply_styles
  end
end

RedPotion 內建了什麼 gem 可以讓 RubyMotion 變得這麼好寫?

RedPotion 內建了幾個好用的 gem,讓 RubyMotion 寫起來更加容易,更像 Rails。

RMQ

一套 UI Library。支援

  • events and gestures
  • view factory
  • stylesheets
  • actions
  • position
  • selecting (querying views)
  • templates
  • traversal through view hierarchy (moving around the tree)
  • animations
  • validations
  • tagging
  • colors
  • fonts
  • image utilities
  • app
  • device

白話的說,就是用了 RMQ。可以用 jQuery 的方式 select UI 元件,做出你想要的視覺效果。然後也讓你的 View 可以用類似使用 stylesheets 的方式排版。

ProMotion

把 Screen 變得更好寫。提供了很多排版樣式,常見的內建排版形式都有提供:

  • Screens
  • Navigation Bars
  • Tab Bars
  • Table Screens
  • Grouped Tables
  • Searchable
  • Refreshable
  • SplitScreens
  • Map Screens
  • Web Screens

ProMotion 本身自己也是一套小型框架,所以有一卡車的 addons。比如說 roMotion-XLForm 就還蠻有名的。可以讓開發者很快地就作出一個表單。

比如說,這是我最近在開發登入畫面的程式碼:

sing_in_screen.rb
class SignInScreen < PM::XLFormScreen
  title "Sign In"
  stylesheet SignInScreenStylesheet

  form_options on_cancel: :cancel_form

  def cancel_form
    app.delegate.open_authenticated_root
  end

  def form_data
    [
      {
        cells: [
          {
            title:       'Email',
            name:        :email,
            type:        :email,
            placeholder: 'Enter your email',
            required:    true
          },
          {
            title:       'Password',
            name:        :password,
            type:        :password,
            placeholder: 'Enter your password',
            required:    true
          },
          {
            title: 'Sign In',
            name: :save,
            type: :button,
            on_click: -> (cell) {
              authenticate
            }
          }
        ]
      }
    ]
  end

  def authenticate
    Auth.sign_in(email: values["email"], password: values["password"]) do |response|
      if response.success?
        ApiClient.update_authorization_header(Auth.authorization_header)
        app.delegate.open_authenticated_root
      elsif response.object
        puts response.object
        app.alert "#{response.object['error']['message']} (#{response.object['error']['code']})"
      else
        app.alert "Sorry, there was an error. #{response.error.localizedDescription}"
      end
    end
  end
end

出來成果就會長這樣。

額外搭配使用: MotionKit

如果我要做的版面,超過 ProMotion 可以提供的部份(比如說我要做 Customized Cell),我還會用 MotionKit,直接拉版面。拉的方式很像是寫 HTML ..

CDQ (https://github.com/infinitered/cdq)

CDQ 可以讓開發者操作 Coredata 就像在 Rails 裡面操作 ActiveRecord 一樣。

author = Author.create(name: "Le Guin", publish_count: 150, first_published: 1970)
author.name # => "Le Guin"

author.publish_count # => 150

author.attributes # => { "name" => "Le Guin", "publish_count" => 150, "first_published" => 1970 }

author = Author.first
author.update(name: "Mark Twain", publish_count: 30, first_published: 1865)
cdq.save
author = Author.first
author.destroy
cdq.save

AFMotion(https://github.com/clayallsopp/afmotion)

AFNetoworking 的 Ruby 版。在接 API 時非常 friendly。介面非常像平常寫習慣的 Ruby http-client library。

其他

Gemfile 裡面還有一些選項是 Optional 沒有打開,諸如:

gem "ProMotion-XLForm"
gem "ProMotion-push", "~> 0.2" # Push Notifications
gem "ProMotion-map", "~> 0.3"  # PM::MapScreen
gem "ProMotion-iap" # PM In-app purchases
gem "ProMotion-menu" # PM Side menu
gem "motion-mastr" # Attributed strings: https://github.com/skellock/motion-mastr
gem 'motion-blitz' # Easy HUD with SVProgressHUD
gem "motion-juxtapose", "~> 0.1" # Screenshot acceptance comparison tool
gem "bubble-wrap"

Summary

總之,RedPotion 內建的這幾個核心的元件。就是圍繞著幾個 iOS 內建最常需要被解決的問題

  • Screen 如何拉
  • Layout 如何快速排版
  • 容易的「上色 Styling」
  • 容易的存取 Core Data
  • 很好處理 API 來的資料流

如果你想要享受在 Ruby 上如寫 Rails 般暢快的開發 App 感。歡迎再給 RedPotion 一個機會。

相關資源

 
over 1 year ago

有朋友希望分享一下我過去怎麼管 Team。所以這邊分享一下過去我寫的 General Policy。(有中文版與英文版)

其實我認為這一份已經是正常的 Work Ethics(職業道德與工作完成標準了)

中文版

計畫階段

  • 如果你認為在哪個項目比較在行,但是票卻被指給其他同事。或者是你認為現在手邊哪一些工作,在這週對整體工作進度來說是比較重要的。請先提出來。
  • 團隊重視結果(是否能「幫助公司」或是「幫助同事效率」)高於實作品質或開發速度。
  • 交出成果前,請先找一個比較資深的人幫你看過給意見。

在實際投入工作之前

  • 在打開編輯器實際寫出第一行程式碼前,先問清楚:「為什麼我們要開發這個功能」?
  • 先確定手上這件工作的「死線」以及「重要性」
  • 與你的 stakeholder 時常溝通,取得 feedback 以及修正方向。
  • 如果現有的系統裡面已經有相似的功能時,請先問週遭的同事,是否我們應該針對類似的例子設計一套 pattern 。

在工作的時候

  • 先設計一套能動的東西,讓大家能夠測試。(在進入 Review 以及上線階段前,確定你沒有完全搞錯方向)
  • 在開發的時候,把所有相關的文件以及筆記,記在 Redmine 上,方便同事幫助你時可以找到相關資料。(包括 bug 的 log、資料連結、測試成果)
  • 盡量把 Task 拆細去實作。而不是一次 commit 一大包

完成工作後

  • 如果你感到你完成工作的方式太 Hack。請多開一張 Ticket for Refactoring。然後放在下個 Sprint。
  • 如果你在系統內引入了一套「新的外來技術」(比如說 gem , framework, js plugin 等等)。請在 Redmine 的 wiki 上記載以下相關資訊
    • 這是什麼東西?
    • 基本使用指南
    • 如何讓他跑起來
    • 你認為這套技術 API / 架構中,重要的部分
  • 如果你在系統內開發了一套「新的架構」(如 Service Object, Pusher..等等。請在 Redmine 上記載以下資訊:
    • 為什麼我們需要這套架構,去改良現有的系統
    • 基本的架構運作原理
  • 如果你正在「Refactor」,請記得在票上附上過程。(如 SQL tunning 或演算法變更)、並貼上 bechmark 成果或是截圖。
  • 在將 code merge 之前,請先找一個資深工程師看過,且簽名。

你該記得的基本原則

你蓋的任何東西,應該同時滿足以下幾個條件:

  • 能夠幫助公司
  • 能夠幫助同事把事情做得更好更有效率
  • 幫助自己成長
  • 常問問題並不可恥(別擔心,你不是在浪費同事時間)。沒有什麼比不問問題更糟糕的了。
  • 你蓋的東西,是會被「真的人」使用,而會會影響到「真的使用者」。
  • 為自己的作品自豪

=========

英文版

Genernal Policy

Sprint Planning

  • If you feel you are good at something but it's wrongly assigned to another colleague or you think something is important that you want to finish in this sprint, please let us know
  • We think highly of results (helping the company or helping colleagues ) much more than ticket quantity or development speed
  • Have your architecture reviewed by a senior engineer

Before starting to code

  • Ask "why are we doing this?" before opening your editor
  • Ask about the deadline & priority
  • Communicate with your stakeholder often
  • If there's something similar already in the system, please ask around whether we should we build a pattern/work on the architecture

During Coding

  • Build a prototype first to test drive (Before entering the review phase, ensure you are not building something completely wrong)
  • Document everything related in Redmine (including bugs, links, test results)
  • Break your task into smaller ones

After Coding

  • If you feel your way is too hacky, please create a separate ticket for "Refactoring" then put in next sprint
  • If you introduce a "new" technology in a ticket (gem, framework, js, etc.), write a Redmine wiki about it and inform the team
  • What is this?
  • How to use?
  • Basic Setup
  • The API and architecture you think it's important.
  • If you introduce a "new" design pattern in a ticket (Service Object, Pusher, ..etc), write a Redmine wiki about it and inform the team Why we need this approach?

Basic Structure

  • If you are doing refactor work, like "sql tuning" or "algorithm tuning", please attach benchmark results or screenshot
  • Before committing your code, have it reviewed by a senior engineer

Things to remember

What you must meet

  • Help company
  • Help colleagues do things more efficiently
  • Help yourself grow
  • There's no shame in asking colleagues for advice or seeking help (don't worry, you are not wasting their time). There's more shame in not asking.

The things you are building will affect and be used by "actual human beings". Be proud of your craft.

 
over 1 year ago

API Engineer 這個職缺,隨著 Mobile Application 爆炸性的成長,與架構 Micro Service 化,逐漸炙手可熱。但是,卻沒有工程師把握自信的說,自己很會「設計」 API。

API 變得越來越重要。但是工程師們卻都視「設計」API 為燙手山芋。大家有心想設計出好的 API,容易讓下游使用。想寫好的文件,讓後人容易維護。但是這個「想」,卻從來是有心無力的議題。

今天在這篇文章,我想同時介紹兩個東西

  • RAML - RESTful Modeling Language
  • Spec Driven Development

解放大家的痛苦。

API 是大家心中永遠的痛

為什麼很多人畏懼碰觸這個議題。這是因為:

  • 因為「建」(build)API 很簡單。
  • 「設計 API」很困難。
  • 「維護API」很困難。
  • 「寫文件」很困難。

傳統來說,一般 RD 的開發 cycle 是這樣的:

  • 第一種狀況:寫 API (射後不理)=> 改 API (崩潰)
  • 第二種狀況:寫 API => 補 TEST => 寫文件 => 擴增 API => 補 TEST => 改文件(精神崩潰)
  • 第三種狀況:TEST DRIVERN (寫 TEST ) => 寫 API => 補文件 => 修改 TEST CASE => 擴增 API => 改文件 (精神崩潰)

API 開發讓 RD 感到壓力主要的問題,是因為不管採取 BUILD FIRST 或者是 TEST FIRST 的策略。「維護成本都很高」,而一旦開發完畢,後面接著應更動文件,甚至變成了「壓死駱駝的最後一根稻草」。

而這當中最大的原因。主要是因為寫 API,後面一定至少有一個以上的 RD 等著接 API。如果對方等不及,你會採取 build first,直接 API 直接給他接。如果對方可以接受晚一點接,你會先 test driven,先 build test case,確定 API 不會爆炸,晚一點補文件給他。

文件很重要,但是大家都不喜歡寫文件

我們都知道文件很重要。但是幾乎工程師都不喜歡寫文件。系統的 code 瞬息萬變,誰有精力去寫文件呢?code 改完,還要補文件修改,老闆又不會多發一點薪水給我?

但最主要的問題是

  • 不想要維護兩套文件(程式碼註釋、API 本身文件)
  • 文件沒有立即性的用處。

這年頭有人甚至提倡 Spec Driven Development。但往往大家聽到這個名詞,通常卻覺得只是開玩笑而已。因為

  • 只有大公司節奏慢,經得起這樣耗,可以先寫文件再補 Test,反正公司有的是美國時間。小公司立刻就要有產出,誰跟你 Spec Driven 或 Test Driven。
  • 先寫文件,不先寫 API,下游 RD 絕對砍死你。
  • 先寫文件,產出的成果不會加速開發。不如先寫程式,由程式自動產生文件。所以即便 Swagger 有 API designer,但是大家還是偏好由 Swagger 掃描程式產出文件,而不是先用 Swagger 設計 API。

這就帶出了下面我想要介紹的這一套的解決方案:RAML。

RAML - RESTful API Modeling Language

RAML 全名為 RESTful API Modeling Language。是一套基於 YAML 格式的新 API 標準規範。這套規範同時符合兩個特性:

  • 機器可讀
  • 人類可讀

你可以直接用 RAML 設計 API 文件,詳細定義裡面的 meta,response,error, test case。
然後用工具產生 API 文件。這是 RAML 的一個範例:

%RAML 0.8
title: This is My API
baseUri: http://api.domain.com
version: 1

/resource1:
  get:
    responses:
      200:
        body:
          application/json:
            schema: |
              {
                  "type": "object",
                  "$schema": "http://json-schema.org/draft-03/schema",
                  "id": "http://jsonschema.net",
                  "required": true,
                  "properties": {
                    "firstName": {
                      "type": "string",
                      "required": true
                    },
                    "lastName": {
                      "type": "string",
                      "required": true,
                      "minLength": 3,
                      "maxLength": 36
                    }
                  }
              }

  /sub-resource:
    get:
      queryParameters:
        firstName:
          description: "the user’s first name"
          example: John
          required: true
          type: string

RAML API designer:mock backend

當然,產生 API 文件很多家工具都做得到。這沒什麼了不起的。但是 RAML 生態圈的這群人並不僅止於滿足產生文件。他們想的甚至是用 API 產生 mock backend service。

也就是當你用 RAML 設計完文件,連「假後台都寫好了」。也就是當文件寫好,你不必真的寫程式,你可以用工具將 RAML 轉成實際的 backend,讓你的下游 RD 直接對接,讓他實際使用,看看 API 設計得合不合理。

如果不合理,「修改文件」就可以了。你不必改 code。甚至到這時候你連一行 code 都不用寫。

為什麼 RD 對 API 的開發、修改視為畏途。是因為

  • 要實際開發程式碼
  • 要寫測試
  • 要寫文件

這造成了只要下游要求修改一個小小的結構,或擴充一組小小的功能,就會耗上一整天的時間。所以有時候即便 API 設計有瑕庛,原設計者也不是很願意修改。而且 API 開發的週期釋出太長,所以版本號甚至難以管理,或根本「不管理」(一直以來都保持在 0.1)

使用這個 RAML 以及 Spec Driven Development,你可以先用 RAML 改到下游高興為止,都還不必寫一行真正的 code。

就算要寫測試,也只要先對這組假 API backend 寫就好了。

RAML API proxy

甚至是這些工具,都還可以內建 API proxy 的功能。(這一點也蠻重要的)

因為 API 上線之後。可能也要面臨的一些挑戰是:

  • authentication / authorization
  • throttle
  • scalability / stability

特別是 Mobile 方面的 API ,用量都蠻大的。自幹 API 大概有點緩不濟急。前面擋個 API proxy,真的事情會變比較容易。

Summary :終結惡性循環

多數 API 的低維護性,多半出自於開發循環中的「技術負擔」(開發 + 測試 + 文件)徹底壓垮 RD 想要「整理」「根據回饋修改端口」的意願。

RAML 的出現算是把這個惡性循環終結了一大部分。如果你想對 RAML / Spec Driven Development / Design Perfect API。這裏我也分享幾個資源:

希望各位能夠少爆一點肝。

 
over 1 year ago

很高興的跟大家宣布,我個人撰寫寫的第一本實體書「Growth Hack 這樣做:打破銷售天花板,企業最搶手的成長駭客實戰特訓班」,今天 ( 5/7 ) 上市啦!

→ 博客來網址在這裡:http://www.books.com.tw/products/0010714065
→ Taaze 網址在這裡:http://www.taaze.tw/sing.html?pid=11100781639
→ PChome 網址在這裡:http://24h.pchome.com.tw/books/prod/DJAD3J-A90077NWU

一年前的今天

說實話,我真是沒有想到這一天。因為去年這個時候,我才剛在部落格的寫下以及分享第一篇關於 GH 的文章而已:「What is Growth Hack?」http://blog.xdite.net/posts/2015/05/06/what-is-growth-hack

國內媒體寫過幾篇 GrowthHacker 的文章,但是對 Growth Hack 技巧的文章幾乎沒有。這一陣子都在玩這個題目,有一些心得,所以決定寫一個初級一點的懶人包,以後跟人解釋時好有個基礎概念。」`

沒想到一年後可以走到今天這裡。

一年前的一個念頭

一個想幫助世界更好的小小念頭。一年來改變了超多人與事。

一直有朋友問我為什麼最近幾個月不開 GH 初級心法 / 實作班了(他們希望聽現場的,畢竟線上的感覺不同)。
之前會開這麼多場,只是因為很多朋友需要這些資訊而已。但是老實說,開這麼多場,我真的體力有限。而且,一個主題重複講這麼多遍,真的講到會厭煩了。。。。。。。。。

出書:推廣 Growth Hack 的最後一哩路

所以我跟出版社編輯商量了一下,我決定也把這門知識寫成書直接推廣出去。二三月在忙的其實也是這件事。一直以來,我的目的就是希望把 Growth 複雜的知識,化為簡單好上手的框架,推廣給大家而已。出書,就是最後一哩路。

希望這本書能夠幫助到大家。

  • 如果看完這本書,覺得很不錯,也歡迎分享推薦給你身邊需要這門學問的朋友!
  • 如果你覺得你的朋友太懶的去書店,那麼請暴力買一本塞給他!

我會努力再分享更棒的東西給大家!

 
over 1 year ago

在這裏很高興的要跟各位宣佈。RailsPacific 2016 又回來了。

其實在去年,我就一直想把這個年會辦回來,而且社群幾乎大家每個人見到我,都一直詢問這個年會重新回來的進度。但是辦一個年會其實後面耗用的資源非常大。不只我自己要有時間,同時社群其他主力也要騰出時間。

後來有一天,社群在 Mashable 上班的 Rexy 突然密我說,他想接手舉辦 RailsPacific,是不是可以教他怎麼籌備。甚至他還可以聯絡他幾個在美國的 Rails Committer 朋友來當講者。

我一聽實在太好了。於是就趕快把主辦權交出去。於是今年的 RailsPacific 就誕生了。時間在今年的 5/20 - 5/21。

為什麼你該來參加?因為這是一個會讓你功力大增的年會

世界上年會這麼多。為什麼該來參加這這個年會。

Ruby 世界的人都知道一件不爭的事實,雖然 Ruby 界裡面以 Rails 的職缺最多,但是世界社群裡面卻是 90% 都以 Ruby 年會為主。美國 RailsConf 可以聽到最多的超級講題、認識大神,以及參加到最頂尖實用的 Workshop。

雖說如此,要飛去美國參加一趟自費成本就超過 10 萬台幣。我們一直想讓在亞洲以及台灣的朋友,不用離開國門,就有機會就能吸收到這些經驗,學到這些技巧。所以才排除萬難,繼續舉辦這個年會。

今年會議的三個核心為:

  • Rails 5 ( ActionCable & Rails5 + Test )
  • 營運 ( Large Deployment / Payment / Scaling / Growth)
  • 成長( 教育 / 生涯成長 / Podcast )
  • 額外彩蛋:我們邀請到 2014 RailsConf 的最佳 Workshop 主講者 Adam Cuppy 來教 Rspec Pattern。社群對他的 workshop 的稱讚,洗了 twitter 頻道一整天。

你很難光去參加一個普通的年會,就聽到這些世界等級的架構或技術分享經驗。何況在台灣,也不用機票錢。

大神手把手教你技術、從神人前輩身上吸經驗。

講者:

今年我們邀請到主要的三個 Rails Committers:

  • Godfrey Chan (美國,Rails Core Team,Rails Comitter #28) : 今年大會的 Keynote。同時兼任 Ruby on Rails 以及 Ember.js 的 Core Teams。現任為 Tilde Inc. 的 Staff Engineer。Rails Weekly 的管理者。
  • Vipul A M (印度,Rails Isuues Team,Rails Comitter #39) : BigBinary 的 Director。 RubyIndia Community Newsletter 以及 RubyIndia Podcast 創辦人。 Deccan Ruby Conference 的主辦人之一。
  • Prathamesh Sonpatki (印度,Rails Comitter #41) : BigBinary 的 Director。Deccan Ruby Conference 的主辦人之一。

以及 9 位重量級講者:

  • Adam Cuppy (美國) :CodingZeal 的 COO,Infobrij 的 CXO,號稱是地表 Rspec 最強的男人。
  • Luís Ferreira (葡萄牙):Subvisual 的創始人之一。生涯至今教過超過 500 位 RoR 學生。RubyConf Portugal 的主辦人之一。
  • Sebastian Korfmann (德國):從 2000年初至今累積有豐富經驗的創業家以及開發者。
  • Richard Lee (台灣):知名 Rails 開發者。iCook Polydice, Inc. 的 CTO 以及創始人之一。
  • Ryan MacInnes (美國):洛杉磯 juicer.io 的 CTO 以及創始人之一。曾經歷 YCombinator。
  • Hiroshi Shibata (日本,Ruby Core Team):知名 Ruby Committer。現任 GMO Pepabo, Inc. 的 Chief Engineer。
  • Sebastian Sogamoso (哥倫比亞):現任 ride.com 的工程師。RubyConf Colombia、Bogotá Ruby、Bogotá Lambda 主辦人之一。
  • Miles Woodroffe (日本):日本上市公司 COOKPAD Inc. 的 CTO。RailsConf 2012 的 Keynote Speaker。
  • Xdite (台灣):台灣 GrowthSchool 和 Logdown 的創始人。

每一個無不是社群中名聲響亮、身經百戰的開發者。

Conference 內容

除了講題之外,同時本場也會保留 2014 最令人稱道的 Workshop 以及 Panel Discussion

而且 Workshop 還是請到地表 Rspec 最強的男人 Adam Cuppy 來教,光這一點就值回票價了。

彩蛋:與總統就職 5/20 同一天,辦在總統府正對面 10 樓的年會。

時間呢?在什麼時候?今年 Rexy 跟我講時間地點時,我一度覺得不可能。因為他想要辦在 5/20 總統府正對面,除了參加年會還可以看總統就職典禮。我還跟他說不可能,張榮發基金會不可能會租我們,那天一定會被管制。

沒想到,我們真的租到了。時間就在 5/20 - 5/21 總統府正對面的張榮發基金會。

門票多少錢:早鳥票 6000 元。

聽到這個價錢,你一定會倒縮一口氣。6000 也太貴了吧,還是早鳥票。

不過在這裡,讓我分享一篇當年的籌備心得文。當年的早鳥票是 5000 元,但我們把他辦得遠超過大家想像的值回票價與震撼人心

  • 90% 外籍大神講者
  • 3 個 workshop
  • 2 個欲罷不能的 panel discussion
  • buffet 吃到飽的中餐,燒烤吃到飽。

你就會知道這樣等級的 conf 一點都不貴。來這個 conf 你不是虧到,而是賺到(去年我們早鳥票一人 5000,籌辦成本一人是 6000)。而且還不用出國。

  • 早鳥票ㄧ:NTD 6,000 (到 4/20)
  • 早鳥票二:NTD 7,000 (到 5/13)
  • 一般票:NTD 9,000
  • 學生票:NTD 3,000

心動嗎?早鳥票只到 4/20 。

 
over 1 year ago

這三篇裡面我嘗試回答了幾個許多團隊都會遇到的問題,也是我過去七年的技術經驗累積:

  • User Story 的粒度怎麼切到夠上 issue tracking
  • 如何根據 User Story 精確的驗收 milestone 與控制開發速度與優先權
  • 如何讓專案管理與程式碼開發進度緊密結合
  • 如何讓客戶對你的專案管理,隨時能夠保持安心狀態
  • 如何 release 大的功能與大的 refactor
  • 如何設計出一個可以每天 15-20 支 pull-request 的 release 流程
  • 如何保持整個團隊的技術產品 release 訊息同步

過去我分享的敏捷專案管理,多半是屬於「規劃方面」的分享。這一個系列,我專注寫的方向是「如何具體執行」。

很多技術圈的朋友嚮往敏捷,但事實上敏捷非常吃隊友程度。而且實務上,總有很多理想是「這樣」、實際協作上卻是「那樣」的人際衝突。

總結:

關於工程執行以及協作,我可以歸納幾個「無關隊友程度」的原則給各位參考:

1. 清楚溝通,別通靈

User Story 講清楚,風險問題不要扭捏閃避。用 standup 時間釐清風險與優先權。

2. 克制貪心

Must have 與 Should Have 才是最重要的部分。不要讓太多 Could have 的貪心把未來緩衝時間用掉。

去掉 PM 本身的規劃疏失,專案 delay 很多時候都是 RD 的悶頭不溝通與 could have (炫耀)的貪心心態在作祟。

3. 有公德心

想想自己是負責 merge 與 deploy 的人時,你想要收到的 pull-request 是什麼粒度與格式。然後依據這種心態,好好的撰寫 pull-request 的說明。

一個壞的 pull-request,壞的不是 reviewer 的時間,而是技術團隊所有人的時間。

4. 進度公開透明,提早整合測試

很多專案的紛爭,都是因為「技術團隊寫了,還沒上線」,「技術團隊上線了,整個功能還沒有測試」。對於不懂技術的人,沒有上線進度就是 0,不是 50 分。盡量保持每一個進度「有可驗收成果」,信任程度才會高。

隨時讓技術團隊外的人,知道今天發生了什麼事。技術團隊的效率進度流速往往是其他團隊的 10 倍。
但是若技術團隊沒有可以展示的進度,外界對技術團隊的觀感就是 1/10 倍。

5. 保持自動化

容易人為造成的高風險部分,應該盡量利用工具自動化。

===

很多時候,信任、透明、進度展示、公德心,我認為才是「敏捷」的重點,而不是那些框架與方法。

 
over 1 year ago

Q: 如何一天做 15-20 支的 pull request 的 Release

過去我參與的的團隊一夕之間從 3 人膨脹到 20 人團隊。堆積如山的 pull request 成了我們的 devops 最頭大的問題。因為在當時 codebase 沒有測試( startup 怎可能會有測試)的情況,一天只能 deploy 一支 pull-request,還可能大爆炸。

而這也是在業界最多人常問我的問題:如何設計一個很多人 (a.k.a 10+ 人) 可以瘋狂拉 pull request,卻不會大爆炸的流程?

以下是我的答案

step 1. 切分 deployable 與 development branch

把 branch 切成

  • production
  • master

  • production 是正式 deploy 的 branch,只有 devops 可以對他進行變更,其他人不得任意進行操作。正式上 production 是去 deploy production branch。

  • master 是大家開發基準線的 branch,所以大家要開發什麼功能,以這個 branch 去 git checkout

  • 開發完畢之後的 branch 對 master 拉 pull request

pull-request 的原則

  • 須以 ticket branch 為名
  • 有自動測試,需綠燈。
  • 附上手動測試說明,手動測試需要在 15 分鐘內。
  • 手動測試部分,junior 須送 senior 做第一次的 code review,senior 可直送 devops

step 2. 只 deploy production branch

devops 收到這些 pull request 後,手動測試後沒問題,merge 到 production branch。

在明日的上班第一個小時 deploy production branch。

如果是 deploy heroku 的操作可以更細膩。

先 deploy 到 staging 的 server,再 promote 到 production branch

step 3. 寫 release log

這樣的開發速度,是沒有辦法對版號做 release note 的。所以之後的 release note 會以 day 為計算。

一開始的 workround 我們是寫 hackpad 紀綠:今天有哪些 pull request 在排隊,哪些 pull request 被 release 了出去。哪些 pull request 在 production 需要額外的操作(例如 data migration)。

然後這份 hackpad 要 cc 給全技術 team,包括技術 team 外的人知道,我們釋出了哪些功能,這樣 customer support 才會知道要憤怒的 customer 衝進來,大概會是為了什麼事。

後來這個手段 loading 實在還是太重了。我們找到 zendesk 開發的 samson,自動化的解決這一切。

samson 是一套網頁介面的部署軟體。samson 可以做什麼呢?

  • 對軟體打版號
  • 可以一鍵前進 deploy,可以一鍵後退 deploy
  • 網頁介面可以顯示這個 deploy 的版號上面,包含了哪些 pull request

然後我們再對 samson 做了一些 hack

  • 把 samson 接上了 slack
  • 讓 samson 支援 heroku ( 原本只支援 cap deploy )
  • 自動寄信給全 team,這次的 deploy release 了哪些 pull request
  • 規範了 pull-request 的 description 要怎麼寫
    • 寄給全 team 的信裡面就會有功能說明
    • devops 知道按下 deploy 鍵後,還要額外手動執行哪些 rake task

系列文章

 
over 1 year ago

Q: 如何讓專案管理系統上的 User Story 可跟程式碼進度同步 (a.k.a 可驗收)?

這當中手續有點複雜,我從幾個原則開始說明。

Ticket branch 使用專案管理系統的票號命名

很多人是使用 gitflow 這個流程去管理程式碼,坦白來說我覺得「不夠用」(a.k.a 很難用)。因為實際上:

  • 你面對的隊友程度不同,所以 feature 切的 ticket 粒度也不同
  • 實務上遇到的狀況是隊友程度不同,狀況緊急也不同,很多時候你無法強求寫 test,一大包的 pull request 混在一起的 branch,沒有辦法做驗收測試 (也就是風險很大,因為就算綠燈,你也還要測使用者介面,然後一個豬 pull request 就會污染大家)
  • 喪失決策歷史。不是每個人寫 code 習慣都很好,且懂得寫好的 commit log,或者交代他為什麼要做這個 pull request。

所以我們的作法就是,拉 pull-request 的程度必須到 ticket level 等級,然後用 ticket 號碼為 branch 命名。這麼做的好處有幾個:

  • 大家知道這個 branch 為何而開
  • 討論決策在 issue tracking 上可以追朔得到
  • 該 branch 至少解決了「 1 個明確需要處理的問題」

單支 Ticket branch 要 deliverable

所謂單支 ticket branch 要 deliverable,是指很多時候,我們理想要在一個 branch 裡面解決一個 User Story,但這是不可能做到的。這在設計一整個 workflow,或者是要 Refactor 一整組功能時,最容易發生。

狀況一:Refactor

工程師 refactor 的很開心,測試也綠燈。送上去 deploy,爆得亂七八糟,然後其他人因為這組 pull reqest,被搞得此次 release delay 連連。

而 release manager 要是擋了這組 pull request,又會回退到大家不開心。

我設計的 policy 是這樣,即便是 refactor 一整組功能。也必須要遵守這樣一系列的原則:

  • 單支必須要過可以自動測試
  • 單支必須要過同事手動使用者測試,而手動測試不能佔到同事 15 分鐘以上的時間,否則就是粒度太大

也就是這隻 pull request 必須要小到直接 hotfix 上去也不能死人。

狀況二:開發複雜的功能

如果是開發複雜的功能,那麼原則,大 ticket 專注在驗收「流程」,小 Ticket 專注在「功能」。假設今天我們要實作一個 Markdown 編輯器,除了要支援 Markdown 語法之外,還要可以拖拉上傳圖片。那麼 Ticket 可以切成這樣

  • (1) 產生文章編輯器後台。(純 Text Field 與純 Text Area )
  • (2) 把 Ticket Area 掛上 CodeMirror
  • (3) 實作後台上傳功能,用 File Field 實作
  • (4) 把 File Field 重構成拖拉上傳
  • (5) 把拖拉上傳的 Event Listenr 跟 CodeMirror 掛勾

也就是先解決「可完成 workflow」的功能,然後再把每一個小功能當作是 bug,「修復」上去。

如此一來,所有的功能都可以獨立驗收。

工程部分的原則

這當中最重要的原則精神就是,就是一天至少 15 支 pull request,也可以放心的 deploy,不用擔心晚上需要加班救火。

客戶方面的結案建議

在前面一篇我們提到了第一階段要能夠實作 continuous deployment。是因為很多外包的客戶,對於自己外包出去的進度不安心。

用這樣的過程,你可以將驗收階段切成比較無風險的三階段:

  • 工程期間,只驗收 workflow 與基本功能
  • 驗收階段,驗收細節與 bug 修復
  • 美術階段,驗收 UI 細節

這三件事分開驗收,感覺雖然比較麻煩,但是對於雙方信任程度與金錢、法律責任會有相當大的加分。

系列文章