almost 13 years ago

第 2 件事:application deployable from day 1

在進入開發階段後,我會做的第一件事: ** make application deployable**

也就是:專案開始第一天,就必須要有個 production 直接可運行(可以鎖密碼,當作測試 server)才行。(我在 Rails 101 這本書最後一章,加入 capistano 與裝機為必練技能,就是這個緣故。)

為什麼專案需要 deployable?

提前控制風險:開發環境與線上環境的不同

在一般的經驗中,往往在在專案進行到尾聲快上線之時,才會注意到一個可能使專案時程大爆炸的事情:** 開發端與線上端的環境通通不一樣 **。

在開發過程中,所有人只專注在自己的機器上能不能動,這是常態。專注在實現功能,東西有缺就先在 local 上塞假資料。在最短時間內將 feature 盡可能寫完絕對是第一要務。

但很可惜的,寫完並 不等於 放到正式環境上可以動。

網站上其實非常多功能需要實際被「真人」測試,才會知道到底有沒有問題。有一些設定,甚至開發環境與上線完完全全不一樣。(以 Rails 來說,其實就差很多。比如說程式 class 會不會被 cache,asset 有沒有 optimize,上傳路徑以及與第三方接軌的設定等等...)

如果拖到最後一個月才作 deploy 的這件事,因為「到底有多少東西不一樣」,變成了一個完全的未知數。原本夠用的一個月測試期,被這樣一壓縮可能完完全全就不夠用了。而且因為專案截止日已進,隨之而來的壓力更加大了犯錯的可能性。

一個透明的已知進度

Day1 就有一個可以直接實際測試的站台,還有一個很大的好處,能夠確保專案中所有人都知道現在進度,與規格書上的東西到底差多少。如果有重大瑕疵,或者是絕對不可行的功能,就可以早早會提出修改,下架等等。節省大家寶貴的開發精力。

如果專案截止日最後十五天,大家才知道很多東西原來根本是作不出來的,或者是跟原本想像差太多的,這時候鐵定陷入交相指責,一遍慌亂的狀況。

絕對注意:捍衛進度

不過這一招的使用,專案經理或者是 RD 主管要特別注意。因為 Day 1 就有一個直接可以看的站台,不少完全不懂「技術」的專案參與者(通常是企劃或老闆),會對網站的「裸站」狀態感到極度的恐慌,他們會挑剔 UI,會不滿 implement 細節,進而想要實際插手進度修改內容。請務必堅持住,堅持到進入最後一個階段:測試修飾期才可以讓他們修改(通常進入準完工階段,裸站狀態其實也消失了,當初挑剔的東西幾乎在這個階段不復存在,故也沒有修改的必要。)

P.S. 可以架設一個 issue tracking system,把他們提出的修改事項先通通記起來,但通通不實作。等到接近測試期,再來看看這些當初的「建議」到底還有哪些實際需要被執行。

只有「完全不合實際應用」的東西,或者是「變更會讓實作方式更合理」的東西可以在整個開發期,被丟入排程中。

否則,他們的驚慌,會害這個專案完全結不了案。

====

系列文章:

 
almost 13 years ago

很多人知道如何實作網站功能。但是卻不知道如何將網站成功的完工,並且如期上線。往往明明專案開始之初有不少的工期,有不錯結果的卻很少。上線前後總是一團慌亂。

其實「上線」這件事情完全是可以被掌控的。這當中有不少眉角,只是多半被疏於控制,導致風險橫生。

在回答別人幾次這樣的問題之後,我決定把我的經驗分享整理出來:

第 1 件事:界定時程

這是我認為在專案管理過程中,最重要的一件事。累積參與過幾十個專案下來的經驗之後,我發現上線前手忙腳亂的原因,幾乎都是時程的安排不當。時程混亂冒出的很多風險又沒有被妥善的管理,最後才大失火...

傳統瀑布式專案進行法:寶貴的時間被大量的浪費

一般的專案進行方式,雖然都會有確切的完工期,但專案進行的方式往往會形成相當的浪費而最後造成大量的風險。

比如說一個需要 6 個月工期的案子進度通常是這樣的:

  • 花了 3 - 4 個月無盡的訪談需求
  • 花了 1 個月請美術設計視覺與介面,以及反覆修改
  • 最後剩下不到 1 個月請 RD 寫程式

=> 完全來不及寫完程式 => 半成品上線

上線後一個月:

  • 到處都是 Bug
  • 發包方抱怨
  • 使用者抱怨

上線後第二個月:

  • 終於寫完當初規劃的程式
  • 終於修完大部分的 Bug
  • 使用者早已認定這是個未完工的網站,不再來訪

上限後第三個月:

  • 因為網站規劃不良,使用者對這個網站不感興趣
  • 因為網站規劃不良,預計的成效沒有出來
  • 還有資源 => 繼續籌畫下六個月的改版
  • 已無資源 => 死城

「規劃」從來不是最重要的事

「規劃」其實絕對不是開發一個網站的最重頭項目。「施工」和「調整」才是。

傳統的專案進行方式往往會掉進一個陷阱:六個月看似非常長,於是就大膽的將大部分的時間都丟入「規劃」這個一階段,因為沒有時間壓力,於是會議也通常沒有結論,或者是 feature 發散。等到驚覺時間已大幅燃燒殆盡,再不進行開發絕對完蛋,才匆匆結束。

「規劃」畢竟是個空想產物,等到實際請美術設計頁面,又會發現很多畫面以及 UI 實際上不可能完成。

於是在這一個月,團隊又會大幅的來回修改刪除功能:直到一個勉強接受的範圍,等到視覺完工再轉交給程式設計師「套版」。

在上一個階段,粗估的一個月往往是不夠用的。因為還牽扯到往來的修改時間。而這時交出的產品 scope,也僅只限於「UI」部分有辦法被完成。

「UI」部分有辦法被完成 不等於 「功能」有辦法被完成。有時候畫面上一個小小的按鍵功能,背後的基礎開發工時可能要花上三個月。

最終的上線版本,因為不夠時間了,通常最後只有寫完當初規劃出的功能的 10 - 30% 。而且 Bug 還很多。(因為時間關係,只有辦法完成勉強達到 UI 操作的目的,細部細節根本來不及實作)

最後成效不彰,檢討會議上大家互相指責。但無論如何怎麼檢討來檢討去,完全沒有人會把最根本的問題朝向「規劃時間太長」,只會輕描淡寫的用「必要之惡」一筆代過。

我的方法:從後面倒回來推算時程

我的作法完全相反。如果一個工期是六個月。我會這樣分:

  1. 什麼時候要上線:上線前 1 個月前要 Feature Complete,留足夠的時間進行各樣測試和修復 bug。(剩下 5 個月可以用)
  2. 寫程式要花多久時間:寫程式要花多久時間是不一定的事,但是可以粗估不出包的時間大概是 2 - 3 個月,可以粗抓 2.5 個月。(剩下 2.5 個月)
  3. 視覺設計要花多久時間:畫面設計要花多久的時間也是不一定的事,,但是可以粗估不出包的時間大概是 1 - 2 個月,可以粗抓 1.5 個月。(剩下 1 個月)
  4. 是的。只剩下 1 個月時間可以開會、規劃、畫草圖。請不要浪費時間。

只有 1 個月,是否不夠時間詳細規劃功能?

完全不會。

我會在以後其他的專案管理文章解釋為什麼。

====

系列文章:

 
almost 13 years ago

Hi, 各位讀者好。

因為 Apple 一直在改變 XCode 的編譯套件位置,所以 Rails 101 內附的裝機實務已經過期了。

我最近正在籌劃下一次的改版,已經進行的差不多了。將會直接 support 到 Rails 3.2.2。

不過因為裝機實務這個步驟比較會卡到大家,所以我先放這個章節: Rails on Mac 安裝最佳實務 出來給大家使用。

若您在裝機上還碰到什麼問題,請至 Ruby Taiwan Group 上面回報。

 
almost 13 years ago

一兩個禮拜之前因為太累,我回家時忘記把 iPhone 4S 從牛仔褲掏出來。洗完澡之後就恍神直接把髒衣服拿去洗衣機直接洗了。

一兩個小時,等我回神過來之後,要幫手機充電,才發現手機已經躺在洗衣機裡面被洗得亮晶晶了。這還不夠,手機還是在開機狀態進去洗的,跟一般只是掉到馬桶進水的狀況不一樣。

Anyway,朋友建議我拿去 忠孝新生站 3 號出口的 麥克愛愛 碰運氣修看看。傳說中這是一間服務非常棒的水果商,他們也「兼修」iPhone 這樣....

賭賭運拿去麥克愛愛修幾天後,幾天店員回電說檢修後發現主機版、螢幕和無線網路模組都炸光光了。維修費用應該會是 ㊙(遠低於我的預算,反正在一萬以內),不過他想他還是可以幫我修看看。

今天被通知修好了,所以就過去拿了。除了香噴噴(咦?)亮晶晶以外(開玩笑,我都用熊寶貝幫他洗澡了...),手機也跟新的一樣活跳跳的回到我手上了。

感謝 麥克愛愛 幫我修好手機,所以特此寫這一篇文章推薦他們。如果你有蘋果電腦或者是 iPhone 手機的問題,歡迎找他們。服務真的相當專業到位。

電話與聯絡方式在 麥克愛愛的臉書專頁 有,出發之前請先電話預約洽詢。

 
almost 13 years ago

關於 Github 被入侵這件事,目前在國外開發圈傳的沸沸揚揚。看來中文圈還沒有消息,我來報導一下到底發生了什麼事好了。順便宣導一下開發 Rails 程式碼需要注意的其中一個觀念..

到底發生了什麼事

Rails 的 master 被某個 hacker 塞上這一段 commit。以證明 Github 是可以被入侵的。

為什麼會發生這件事(糾紛起源)

有個俄羅斯 Hacker : homakov 到 Rails 的 Github issue 頁,report 了一個 issue

聲稱他發現很多「中等程度以下的」Rails 開發者開發任何網站,都沒有在 model 內作上任何 attr_accessible 的防護,這樣會引起很多安全性的問題。

Rails 官方應該設計一個機制強迫大家一定得「使用」attr_accessible

因為寫 code 要塞 attr_accessible 被多數開發者認為是根本是一個「常識」。所以這個 issue 很快就被 Rails core team 關掉了。他的意見是這不是 Rails 的問題,而是開發者的問題。(正常人都會做出這樣的反應)

這個 Hacker 覺得他好心來報告,但是卻被忽視,感到很生氣。

於是!他 Hack 了 Github 證明這件事情是真的。

他不僅利用這個漏洞在 rails/rails 中塞了 commit ,連當初被關掉的 issue ,也用同樣方法打開了。

所以這下就鬧到舉世震驚了!…XDDDDD

為什麼會發生這件事(剖析 Rails )

從 Rails 表單機制談起

Rails 秉持著 Don't Repeat Yourself 的精神,將 Form 表單 Helper 直接與 Model 欄位直接結合,節省不少開發者撰寫表單的時間,是一個很聰明的作法。

<%= form_for @post do |f| %>
  <%= f.text_field :title %>
  <%= f.text_area :content %>
  <%= f.sumbit "Submit" %>
<% end %>

當表單送出後,會被壓縮成一個 params[:post] 這樣的 Hash。controller 裡面透過 massive-assignment 的技巧直接 mapping 進 Model 裡。

class PostController < ApplicationController
  def create
     @post = current_user.posts.build(params[:post])
     if @post.save
       # do something
     else
       # do another thing
     end
  end
end

這是一個自 Rails 誕生以來就有的機制了,十分便手。

有些不了解的 Rails 的其他 Developer 批評這是一個不安全設計,並因此拒絕使用 Rails。欄位暴露在外被人知道,讓他們感到非常不自在。

萬一被人猜到 user 權限是用 user.is_admin 作為 boolean 值,這樣豈不是很危險嗎?在修改個人資訊頁時,假造 DOM 就不是可以把自己提升為 admin 了嗎?

Rails 內建的安全防禦措施

Rails 也不是沒有針對這件事設計出防禦措施,有兩組 model API :attr_accessibleattr_protected。其實也就是 白名單、黑名單設計。

attr_accessible 加在 model 裡,可以擋掉所有 massive assignement 傳進來的值,只開放你想讓使用填寫的欄位。

class Post < ActiveRecord::Base
  attr_accessible :title, :content
end

attr_protected 是完全相反地機制。

知名認證 Plugin 皆內建 attr_accessible

也因為 user.is_admin 幾乎是所有懶惰開發者會寫出來的 code。因此長久的歷史演變下來,許多知名認證 plugin,如 devise ,restful-authentication 等等…,在 User model 裡都會加上 attr_accessible(你可能沒有察覺到,因為可能是透過 include Module 塞進來的功能)。

因為是隱藏的內建防禦,很多不夠經驗的開發者,反而會被這道自動防禦整到,在設計修改使用者資訊這個功能時,常常表單明明沒問題,但就是修改不了除了密碼和 email 以外的欄位 XDDD

User model 自動防禦,那其他 model 呢?

好問題!這就是這次 Github 發生的問題。嚴格來說,根本不是 rails/rails 的錯,而是 Github 內某個被罵 mid/junior level 的 developer 的錯。他根本沒有對其他 model 作上保護,才被 hacker 有機可趁。

Hacker 也是想要證明連 Github 都會犯這種錯,才會鬧出這種事件

看到 Github 的事件,我該做什麼?

請回家讀這兩組 model API :attr_accessibleattr_protected 的作用。

並檢查你的 project 內是否有類似問題:一般來說,容易被攻擊的點都跟 relation 比較有關係。也就是 xxxxx_id 的部分都要清查。

Scoped Mass Assignment

這是 Rails 3.1 加入的新 feature : scoped mass assignment,
http://enlightsolutions.com/articles/whats-new-in-edge-scoped-mass-assignment-in-rails-3-1

我也建議你閱讀。

Rails core team 目前的解法

大師 Yahuda Katz (wycats) 目前起草了一份新的 proposal,並且丟在 Hacker News 讓鄉民討論。應該可能近期就會近 Rails core 或以 plugin 的方式釋出。

我個人的感想

其實昨晚睡前看到一堆人說 Github 被 Hacked 掉,然後追了幾篇討論串之後,覺得真的是沒什麼,因為就我來說,的確應該就是這個 hacker 覺得有必要提醒大家,但這對多數的 Rails Developer 來說,根本是超小的小事,不值得這麼大驚小怪。

結果憤怒的 Hacker 攻擊了 Github,Github 真的還因為某個 developer 犯了低級錯誤中招。但我還是覺得沒什麼…

XSS V.S. Massive Assignment

後來睡醒以後才發現不對,其實這東西應該要被拿來跟 auto escape 相比:XSS 是一般設計 Web Application 最容易中招的攻擊。

XSS 的原因肇因是讓開發者開放讓使用者自行輸入內容,然後無保護的讀出來,Hacker 會利用這種漏洞,寫進有害的 JavaScript 讓使用者中招。正確的方式應該是:內容讀出來之後,都要利用 html_escape 濾掉。

問題是,html_escape 濾不勝濾,沒有開發者能夠那麼神,寫任何一段 code 都會自律的加上 h(content)。最後 Rails core 痛定思痛,在 Rails 3.0 後效法 Django 的設計,在讀出 content 時,一律先 escape。除非有必要,才另行設定不需 escape。

我想這次的 massive assignment 問題應該也要比照辦理才對…

延伸閱讀:

國外鄉民懶人包:GitHub and Rails: You have let us all down.

DHH 給出的 37Signals 的作法:https://gist.github.com/1975644

 
almost 13 years ago

我創業了。從 2012/03/01 開始,我跟我的好友:國內頂尖的視覺設計師 @evenwu 合組了一間新公司 RocoDev

我們專營:

  • Ruby on Rails Web Application 設計
  • HTML5 / Responsive Design 視覺與網頁設計
  • 網站體質優化 ( SEO / HTML5 semantic / Alexa ranking)

有興趣的朋友可以歡迎找我們洽談服務。

至於我創業的原因,寫在這裡:「我為什麼想創業」。

這也是我另外的一個小部落格,我對於人生的感觸和一些沒有那麼硬的短文會放在這裡。

 
almost 13 years ago

有些人問我平常日常怎麼補充知識,所以稍微整理一下我平常看的一些東西分享出來。我平常蠻常到處亂看東西,比例大概是這樣:70% 以上是 Ruby,30 % 是 JavaScript 和其他東西…

不過看完之後當然還要練習,東西才會變自己的就是了...

PODCAST

Screencast

Weekly issue

 
almost 13 years ago

昨天在 Happy Designer 5 上,有聊起了做 Responsive Web Design (特別是 mobile 版)的一些狀況。在這裡我提供一些自己的經驗和技巧:

  1. Mobile First:如果你要做 Desktop / Mobile 雙版本的網站。先設計 Mobile 版的,而且要從最小的尺寸開始做。

  2. 盡量讓 Mobile 的版本:大部分功能保持唯讀狀態。因為在 Mobile 上要將「輸入」這件事做得好,是很困難的,而且不少的寫入會牽涉到動線及頁面的跳轉,會大幅降低 user experience。雖然某些功能和元素幹掉很可惜,但要懂得「取捨」。

  3. 不要過於迷信 Media Query: media query 只能解決 CSS 的問題。但是 mobile client 上需要解決的問題不只是這些:

  • 內圖的尺寸與傳輸速度:圖可能是用 Desktop version 的圖硬縮的。
  • 3rd party social plugin:3rd party social plugin 多半沒有考慮 mobile 版本的問題。所以在 mobile 版面上,幾乎都會有尺寸問題。而這些 social plugin 的 js 因為都是由放置在外國的原站提供,在 mobile 版上 loading 更加的緩慢。

所以我會採取「偵測 agent 」與 media query 混合使用的招數進行開發。如果這個 agent 確定是手機,則直接移除掉 social 功能(直接從 server side 幹掉 DOM,而不是用 CSS 隱藏),並且吐尺寸較小的圖片。

  1. 我個人還是認為 Responsive 的用途比較適合用在 Tablet 的 Portrait / Landscape 的用途上。畢竟 Responsive Web Design 的想法,是讓 Desktop / Mobile 擠在同一個版面上,用同一份 code。再 conditional override 或者 remove。在需要「持續維護」的產品上,容易搞死 Developer…

P.S. 如果你對 Responsive Web Design 好奇,可以用手機打開 T 客邦 以及 Digiphoto ,這個站都是用此技巧設計的…

===

廣告:二月份 xdite 家桌遊團 又開放了,限八人,請儘速報名。

 
almost 13 years ago

I had a ruby project named "bootstrap_helper", which has 43 watchers on Github.

螢幕快照 2012-02-09 下午4.09.51

I thought having 43 watchers is sort of popular. But there is a weired thing: when I search keyword : "bootstrap helper", my gem is not in first page result.

螢幕快照 2012-02-09 下午3.59.56

Then I found I made a hugh mistake: Ruby naming convention told Ruby developer to name everything with underscore. So every developer names their projects with underscore.

But it's a giant SEO mistake: Search Engine treats snake_keywords as CamelKeywords. If your project's name contains meaningful keywords, it won't be matched. Because "snake_keywords" means "SnakeKeyword" not "snake keywords".

It's really bad for SEO.

 
almost 13 years ago

Twitter 的 Bootstrap 是一套很好用的 CSS Framework。可以讓開發者加上工具類 CSS 如 .btn,就設計出一個按鈕。

但有時候這東西也像 inline style 一樣討厭,比如說我要設計一排「按鈕] link,就非得每行都加個 class = "btn"

<div class="job-options">
  <span class="option-title"> 工作類別: </span>
  <%= link_to("網站設計師", jobs_path+"?m_type=1", :class=>"btn ") %>
  <%= link_to("美術設計師", jobs_path+"?m_type=2", :class=>"btn ") %>
  <%= link_to("手機APP開發", jobs_path+"?m_type=3", :class=>"btn ") %>
  <%= link_to("市場行銷", jobs_path+"?m_type=4", :class=>"btn ") %>
  <%= link_to("社群管理", jobs_path+"?m_type=5", :class=>"btn ") %>
  <%= link_to("其他", jobs_path+"?m_type=0", :class=>"btn ") %>
</div>

我在開發時並不是使用 Twitter 自己提供的 LESS 版本,而是採用人家拆好的 SCSS 版本 anjlab/bootstrap-rails

如何翻修這樣的 code 呢?我使用了 SCSS 的 @extend。

.job-options{
   padding-bottom: 10px;
   a{
      @extend .btn;
   }
}
<div class="job-options">
  <span class="option-title"> 工作類別: </span>
  <%= link_to("網站設計師", jobs_path+"?m_type=1") %>
  <%= link_to("美術設計師", jobs_path+"?m_type=2") %>
  <%= link_to("手機APP開發", jobs_path+"?m_type=3") %>
  <%= link_to("市場行銷", jobs_path+"?m_type=4") %>
  <%= link_to("社群管理", jobs_path+"?m_type=5") %>
  <%= link_to("其他", jobs_path+"?m_type=0") %>
</div>

這樣就可以把 .btn 從 HTML 裡面拿掉了。

其他

其實表格也可以比較辦理...

#feeds-list{
   @extend .zebra-striped;
}

====

不過不能 span2 這種定位的 class 不能 @extend。@extend bootstrap 這招只能用在與「位置」無關的 style 上。