Springok's Blog

Ruby Conference Taiwan 2016 小小與會心得

| Comments

前言

這是我第二次參加 Ruby Conf Taiwan,成為 Rubyist 到現在是接近一年半的時間,這次很幸運地是由公司補助,然後跟同事一起來的~相較於去年,自己的技術已經有所提升啦,所以很多 Talk 聽起來,都可以了解個八九成沒問題啦~
這次一樣也有來自世界各地的外國講者,在台灣就可以現場聽到這些講者的分享,甚至交流,這個機會真的滿棒的~想要簡單整理幾個這次與會的心得,就從各個 talk 開始吧~

The Philosophy of Ruby

第一場的 keynote 是 Matz ,在 talk 裡,以過勞死的現象,來帶出我們如何用程式來更有效率的打造人們生活所需,而 Ruby 也在思考如何變得更有效率,相較於其他一些程式語言,的確 Ruby 執行效率可能有些不足的地方,而 Ruby 的核心開發團隊也一次一次的改進這些不足。

而 Matz 也在 talk 裡重新宣揚發明 Ruby 的初衷與 Ruby 的哲學,焦點放在人身上,我們寫程式的目的是為了讓電腦為我們工作,同時在寫程式的同時,讓工程師充滿幸福感(?) 也正是因為我們懶惰,所以我們努力變得更有效率,提高生產力,持續發展 Ruby ,由社群到其所凝聚出來的資源,因而逐漸打造出來的生態圈系統,正是而推動 Ruby 發展的最大動力來源。

“When you feel you are in community, you are in community”

Matz 提到有些沒寫過 Ruby 的人們也跑過來跟他說,他們也覺得自己是 Ruby 社群的一份子(笑),

另外現在是 12 月,Ruby 核心開發團隊也有個聖誕禮物要給大家也就是 Ruby 2.4,包含:

  1. Faster hash
  2. Integer unification means no more fixnums and bignums
  3. Better Unicode case mapping

Matz 提到 Ruby 的每次改版,都會考慮到如何為使用這個語言的人們帶來好處,提供更好的做法,與大家溝通,而願意去做這些改變或升級,雖然轉換過程可能會有些陣痛,但絕對是值得的,如同軟體開發應該傾聽使用者的心聲,持續為使用者帶來好處,用來撰寫軟體的程式語言,也應該傾聽開發者的心聲,讓開發者不論在開發品質或效率都可以不斷向前。

我個人很認同這些理念與想法,聽完這個 talk,心裡想說,能夠成為 Rubyist 真是太好了啊~寫起 Ruby 來又更有動力了~

技術新知

Value And Pain to Keep Rails Applications Alive

slide https://speakerdeck.com/nay3/value-and-pain-to-keep-rails-applications-alive
現場的大家其實還滿有共鳴的,所使用的表達方式也讓人會心一笑,尤其是描述升級 Rails 版本的那張圖,真的是相當經典啊~前半段是在講升級上遇到的困難。
後半段說明,當專案上線使用超過兩年,某種程度也代表這個專案算是成功,而且有一定價值的,然而另一方面讓專案可以持續運作是有代價的,有一些做法是講者推薦的,像是可能的話就儘早更新 dependency 跟 Ruby/Rails 版本,注重 codebase 裡一些 Dry, Difficult, Messy, Easy 的平衡,過與不及都不太好,但我覺得這是需要經驗的,什麼時候要做 refactor 或是 dry,最後是 document (comments in codes / wiki) ,其中我自己覺得最重要的一點,要一定記錄下為何做這個更動,不管是在 comment / commit message 裡,這個資訊比單純紀錄下做了什麼有用太多。
另外,講者的可愛女兒,這兩天裡的 conference 也是很搶戲啊,滿場跑~

It's More Fun to Compute

http://rubykaigi.org/2016/presentations/juliancheal.html
講者這個講題也很酷,用 Ruby / sonic pi 來寫曲子~前半段介紹了聲學的基礎是包含振動與振盪器(oscillator) 然後操作不同波形的聲音,還有雜訊,從單音到模擬樂器發出的聲音,最後用 Ruby 的程式碼,組合成一首歌,還有 Live demo,意外的小插曲就是講者當天 demo 的時候,設備有些狀況,所以隔天中午又在大家用餐的場地,重做一次 Talk 跟 Live demo ~很新鮮的 Ruby 題材。

利用Ruby撰寫勒索軟體並探討如何安全的使用密碼系統

講者是趨勢科技的研究員,而自己平常用的程式語言是 Ruby ,來研究 reasomware 的一些心得,這場對我而言,滿新鮮的,平常常會聽到勒索軟體,但卻對其背後實際的運作原理不太了解,原來勒索軟體的核心技術是加密演算法,然後再想辦法在對方付了贖金之後,解密資料,如何解密的實作也有好幾種,有各自的優缺點。
作者最後也提到,研究勒索軟體的目的,也是為了如何防範或應對這些攻擊,在 Q&A 也有人問到 Ruby 適不適合寫 reasomware ,講者提到適合也不適合,適合的是相對來講很好實作、但另一方面現在大部分還是使用 windows 系統,而Ruby 在這些平台一般而言無法執行。

Buidling HUGE web apps: Rails at 1,000,000 Lines of Code

講者的 blog http://fractalbanana.com/
這個講者,來分享他們公司的一些 practices 關於維護大型的 Rails 應用程式,講者首先談了自己先後兩家的工作經驗,雖然都是處理大型的應用程式,但現在公司實作成果比前一間公司好太多,每天都可以 release 兩到三次,其中的關鍵應該還是團隊的自主管理 ( autonomy ),聽起來是導入 agile 的理念,而且團隊成員都很認同這些做法,才能達到這個效果,講者的 blog 也有滿多不錯的文章,還有一些他之前在其他 conference 的演講影片,如果之後影片釋出,我應該也會再看一次吧~

成為更好的工程師

Solving your onboarding problems with Ruby

講者一開始提了滿多新人在進公司之後滿常會遇到的問題,在 debug 與環境設定上卡住許久,或因為對公司的 codebase 還不太熟悉,而多花費超過預期時間來實作等等,之後提出一些建議來改善新人 onboarding 的流程,其中我自己滿喜歡的一點是 pairing ,pairing 的過程常有知識的傳遞,然後也可以互相學習,每個人都一定擁有一些自己所欠缺的技能或概念,透過 pairing 可以互補不足、一起成長,自己在公司裡做過幾次,覺得效果還不錯,但也有些缺點,就是 pairing 所需要的時間滿長的,尤其溝通需求的過程,而且每個人的思考速度或路徑也都有所不同,但整體來說,我覺得是很不錯的方式,不過是對於帶新人或是在實作一般需求上。

To Code Is Human

slide http://www.slideshare.net/DonWerve1/to-code-is-human
這個講者 Don 在上次的 Ruby Conf 也有一場很棒的 talk,而這場的主題其實跟前一天 Matz 的 Talk 有所呼應,寫程式的,是我們人類,而人不是機器,需要休息,也有生理需求上的限制,而講者提出一些建議,對我而言,最重要的啟發是 “manage your energy, not your time” ,而充足的睡眠、維持良好的健康狀態是維持能量的基礎,然後瞭解到人們認知或心理的一些限制,進而用一些做法,讓效率提升。並且走在持續進步的道路上,很棒的一場 talk ,而 slide 中的每句話,都值得去思考或實踐。

How we replaced salary negotiations with a Sinatra app

silde https://speakerdeck.com/rkh/how-we-replaced-salary-negotiations-with-a-sinatra-app
這場是整個 conference 的 keynote 啦,是 Travis CI CTO 來他們在 Travis CI 如果做薪資協商,或換個角度來看,怎麼評估一個工程師應該拿多少的薪水,也提到一些其他公司的做法,對我而言是一個滿有啟發性的講題,也讓我去從另一個角度去思考,公司付你的薪資裡面到底包含了哪些東西或公司的期待,先簡單條列一些想法,我想之後再用一篇文章,說說也整理自己的思考。

  1. 講者也很用心地,事先調查了一些台灣的現狀,然後跟我們分享,他們也有做一個 project 在做全世界所得稅的整理 rkh/income-tax
  2. What is in a salary ? Value and Needs
  3. Transparent salary
  4. Engineer Ladder

與會感想

簡單回顧一下去年訂下的目標,在演講中可以舉手提問,這點沒有辦到,但已經可以針對當下的講題,在心中醞釀一些想法,與去年單方面的接受資訊,相較起來,已經有所進步,找外國講者 Talk ,這點也沒有辦到啊~但是有找了國外講者的同事 Talk XDD,後來還在 twitter 上相互 follow 了一下,希望明年可以去 Ruby Kaigi 朝聖一下有機會碰面再聊聊啊~發名片! 有有有~這應該是最容易的成就了。

其實參加研討會,當然可以從 Talk 中獲得技術層面的啟發,但更難得的經驗是能跟講者或與會者互動,跟一些許久不見的工程師朋友聊聊近況,跟工作人員與社群大大表達一些感謝,這些事情其實是很舒壓的啊~而且也獲得了一些在這條路上繼續下去的動力啊,明年還是會來的,朝著未完成的目標繼續努力~

Agile Tour Hsinchu 2016

| Comments

前言

其實在今天之前,我對於 agile 敏捷開發,並沒有太多的認識,除了公司內部是用看板管理需求的,跟自己之前看過一些 srcum 的基本作法,然後就沒了,而在今天的 Agile Tour 過後,我發現自己從開始當軟體工程師以來,在接近一年的時間當中,其實已經在不知不覺中間接實踐跟 agile 理想相符的做法或建立起相關的心態,事後回想,當然這歸功於團隊,在從我的 Day 1 開始,就要我用這些思維去看待需求與開發~ 所以邊聽這些 Talk 的方法框架與案例,邊與我的日常工作相互對照,常有頓悟之感,也就是 aha moment 吧。

每場 talk 都讓我收穫良多,在聽講的過程中,我一直把自己投射講者的範例中,讓自己融入那個情境,每個講者都有自己的故事或營造那個情境,再從案例帶出想跟大家分享關於 agile 的原則或是實踐方法 ,這些分享都讓我回來反思在工作的一切,從接到需求,估算完成時間到實際產出程式碼、上線,這整個過程跟 agile 開發精神 的關係,所以想先分享整理目前自己在公司裡實際開發上跟 agile 有關的原則與作法:

角色

首先,在 talk 中聽到 “get rid of your project manager from day 1” ,原來我們公司沒有 PM 是符合 scrum 的原則的啊XDDD
公司裡其實只有 PO (problem/Product owner) (公司其他部門,營運、會計等), Developer Team (tech lead, developers) 工程,PO 負責提出需求與問題交給 Developer Team ,然後由工程師們自主管理時程、產出 feature,而我就是其中的 developer 的角色。

擁抱變化

以 scrum 團隊觀點來看,應該主要指的是時程上預估,因為有可能會有突發因素來影響時程(插件、團隊人員請假等等)遇到這些無法預計的變化是很平常的事,但等遇到了,再來問自己如何調整優先順序,而從實作開發 coding 的角度上,因為需求可能也會改變,所以在實作上也會作出對應的處理。

提高透明度

目前團隊裡是透過 kanban 讓團隊各成員可以看到各自的進度或是一些團隊優先度高的需求,也可讓 tech lead 適當地去協助成員。

適時調整優先度

當開始實作,可能就會發現預估時程可能並不如想像中樂觀,而我現在大部分都只是負責評估一張 card (通常對應一個實作項目) 所需要的時間,所以也只是自己針對該張卡片在 Time, Resource, Quality 做取捨,同時也會回頭跟 PO 去確認該工作所擁有的彈性,再來考慮優先度調整與否。

自主管理

其實就是接到工作,就去確定需求、切細項、訂時程,然後執行,需要協助就跟團隊請求支援,需要確認規格就跟 PO 討論囉。

Talks

開場 Why Agile ?

讓工程師可以不用加班,開心地上班、放心地回家。
敏捷宣言Agile Manifesto

part 1 瓶頸處理九大原則 (講師: William Yeh)

Slide

講者開頭提到 Scrum Kanban DevOps 都是框架,實作上依各個公司都會有些差異~
一開始,講者先從 sprint 的規劃說起,假設了一個情境,實作 21 story point 估出來是 150 個工時,團隊有四個人,而且每個都是全方位的人才,什麼樣的工作都可以做,所以這樣算起來應該是 5 工作日可以搞定,但問了現場的聽眾,如果你帶這個團隊,有沒有信心跑一個星期的 sprint 就能做完,卻只有一兩個充滿信心的人舉手 XD
但基本上,因為工作之間會有相依性、團隊的人力資源專才也不盡相同 (backend, frontend, UX, test),還有其他太多不可預期的情況會發生,也就帶出限制理論 Theory of Constraint,而專案執行期間應該保持聚焦在瓶頸 (constraint) 上 。
接著,講者很專業的整理了瓶頸處理九個原則 ( 可參考 slide ) 跟大家說明。
再來提到,POOGI 聚焦五步驟:

  1. Identify 確認瓶頸
  2. Exploit 決定如何充分利用瓶頸
  3. Subordinate 其他一切遷就以上決定
  4. Elevate 鬆綁制約因素 (時程/需求)
  5. Percent Inertia 避免惰性,回到步驟一

最後,講者,提供他自己的判斷供大家,一個 sprint 應該安排 80% 的工作,要做一些風險管理,考慮工作的依存關係,以及過去相關經驗的統計波動(人員休假、工作心情)而相對應的做法就是:了解限制,瓶頸,制約 => 聚焦 => 持續改善。

part 2 從敏捷思考讀書會,創業,與人生 (講師: MaoYangChien)

silde
這場的講者是 soft & share 的創辦人簡茂仰,來跟大家分享創業與經營讀書會的心得,一開始先分享他過去失敗的經驗,而今年開始經營 soft & share 賣電子書,開團購,接著有網友建議他可以辦一些團購書籍的讀書會,就這樣被推坑了,開始構思讀書會應該怎麼舉辦、理想中的讀書會成員之間的互動又是怎麼樣的,做到現在已經是第四個 iteration ,而每次都有新的嘗試,成效也越來越好了,這讓他體會整個創業過程其實也有敏捷的精神在裡頭。

另外也分享了他在經營這個事業所使用的 MVP (Minimum Viable Product) 工具,部落格、文案技巧,整場演講中穿插大量許多書籍的引用(如何閱讀一本書、工作、行為改變、文案技巧、心靈雞湯),強調讀書的重要與獲得的啟發,整場演講宛如創業人生相關書籍的導讀會,默默地自己的待讀書籍清單又多了好幾本。

個人而言,這場演講在心靈層面收穫滿多,可以試問自己,人生到底在追求什麼?面對恐懼,是否能找出真的恐懼,面對它,思考解決的方案?

part 3 Scrum Estimation Model (講師: Joey Chen)

講者也是一開始假設了一個情景,以日常生活的觀點出發,規劃好的事情總是會有不如預期的情況發生,導致計畫改變甚至執行上遇到瓶頸,如果再加上當下的處理不好,最後就是根本無法到達目的地,搞不好團隊也已經四分五裂了。

這個影片已經把整個 talk 的精華濃縮啦,強烈推薦值得一看啊,而且講師很會帶氣氛,舉例淺顯易懂,也用了滿多很棒的梗,如他開頭所說,不用帶腦,放鬆來聽,也會有很多的收穫的~

專案估算重點圍繞在範圍、速率、時間的取捨與調整。

範圍是團隊可以完成的需求,其中需求也有分大小,利用相對比較的方式來估算需求大小。
速率是團隊開發的速度 ( 1 sprint 可以消化的 需求story points)
時間就是時程啦

在第一次的 sprint 之後就有依據可以開始修正,隨時檢視優先度、調整做法,若時程很硬,允許有計劃的欠一些技術債,持續優化流程與做法,適時引進提升人員士氣的做法(提供好的硬體設備等等)。

最後提到的原則就是依據變化,時刻調整決策,讓開發團隊成員自主管理、持續改善。
這個 Talk 雖然是從團隊的角度去看待估算開發時程這件事,而因為我現在都還停留在自己估算自己工作的階段,但相對的我其實也可以利用估算需求大小的方式來拆解我所負責的需求,來更準確地預估出我實作所需的時間,之後也會試著將這個估算模型應用到工作裡~

part 4 我們來開公司吧~ (工作坊) (講師: 王泰瑞, Terry Wang)

這個工作坊是讓大家同樂玩遊戲的,同時又能學習到導入 agile 原則(提高團隊透明度、自主管理)之後所得到的效率提升與好處,遊戲過程中與結束後的討論也相當精彩,之後,講者也分享了自己公司的導入 Scrum 的案例給大家~關於遊戲的內容,就不在這裡分享啦,我覺得自己去體驗,會更投入然後會去對講師拋出的這些問題,思考自己的答案之後再跟講師提供的答案對照,那收獲感會更為強烈。

而講師也提到在 Scurm 團隊裡,每個人都會是專業的成年人,專業的成年人會有什麼特質呢? 對事不對人,永遠追求卓越,只有好跟更好,面對批評可以坦然接受,而且表達感謝~

希望之後有機會再跟這位講師學習其他的課題啦。

part 5 Retrospective Meeting

Appreciative Inquiry

  1. 真誠傾聽
  2. 做自己
  3. Yes…and…. (not but)
  4. 打開心扉
  5. 了解大家都是唯一的,都不一樣

這個部分,講者帶大家一起回顧,並鼓勵記錄下今日印象最深的人事物、以及未來對這個 Agile Tour 的一些想像與期許,發現我真的沒有畫圖的天分 XD

雜想

是因緣際會在 soft & share 的 slack channel 裡看到這次的報名資訊,很開心自己當下沒有太多猶豫,馬上報名,而也真的是大豐收的一天,毫無冷場,早上九點初到會場,下午五點左右離開,覺得好像進入精神時光屋,意猶未盡啊~

第一次看到圖像紀錄的玩法,好棒啊,令人驚艷,每張海報都惟妙惟肖,而且都帶入今天講題重點,充滿紀念意義而且別出心裁~隔天看到某位講者的 FB 大頭貼,馬上換上他與自己那張海報的合照 XDDD

感謝主辦單位在新竹辦了一個這麼好的活動,明年我也要報名啦,不過這次辦得這麼好,好的東西人人追求,感覺下次開放報名,勢必是一 場搶票大戰啊~

附錄:當天活動簡介(含講師群介紹)與 AgileTourHsinchu FaceBook Page

  1. AgileTourHsinchu 2016
  2. AgileTourHsinchu

Rails Pacific 2016, Taiwan

| Comments

About

這是我第二次參加關於Ruby/Rails的Conference,而很幸運小弟剛好現在有份工作,公司也願意補助報名費,就跟同事們一起去出遊與吃Buffet學習啦。

另一方面,也看看現階段的自己,對於Ruby/Rails技術上的Talk可以了解多少,不過老實說並沒有做太多的事前功課,而幸好這次也只有單軌,沒有取捨講者的困擾。

這次議題所圍繞的三個主軸:

  1. Computer Science Education 與自我成長的討論。
  2. Rails Developer的職涯討論,進入別人的公司或自己創業的心得分享。
  3. Rails 5相關的技術更新與討論。

而且還請到了Confreak的團隊全程紀錄下各個Talk,

Talk Highlights

這裡想分享幾個自己印象深刻,收穫不錯的Talks,其實Talk之後應該都可以在confreak上看得到

Keynote: Computer Science Education for the Next Generation

All abstractions leak, but some are useful.
這個對我而言是個很具啟發性的概念,也值得再去深究,簡單來說,我們所看到物件的行為表現,其背後運作原理可能相當複雜,但可以用簡化後的modeling來描述物件的行為,這個原理通常會有一些缺陷,儘管如此,他還是有一定代表性,幫助我們解決一些所遭遇到的問題,講者舉了個例子,高中物理在某些計算時,有時候會忽略摩擦力等等因素,雖然與現實情況不符合,但的確也讓我們瞭解其運作方式。反過來說,很多解決問題的方式,都有它的限制或前提,不瞭解或忽略這些限制或前提,都可能讓你付出一些代價。

It takes a village to raise a child, and we should be the village.
Just be the village, and Just do IT!!

When Making Money Becomes a Headache. Dealing with Payments

這個talk我很喜歡的原因,是講者整個背景故事的鋪陳到一些技術的細節到最後的結論歸納,都非常流暢,而且會反覆回來主題上,再次強調應該要解決的問題是什麼?最重要的是建立與顧客之間的信任,如果你最近對於處理payment感到不爽,可以聽聽看講者相關的經驗與解決方式。slide

Taming Chaotic Specs: RSpec Design Patterns

Secrets of Testing Rails 5 Apps

不知道為啥對於testing相關的主題有著濃厚的興趣,可能是最近剛好也在讀Test Prescription這本書吧,雖然公司用的是Minitest,但很多概念是相通的,之後或許可以試著將這些Design pattern或是Rails5對於處理contoller test的作法用在平常工作上。
Slide1, Slide2

Continuous Learning, Teaching and the Art of Improving Yourself

這也是我滿喜歡的talk,講者把主題分成三個部分,Productivity, Learning, Teaching,讓自己在這條路不斷成長,其實很多概念之前都有聽過,但是實際去做又是另外一回事了,我在聽講的同時也在反省自己是不是也已經有建立一些自我成長的工作或生活習慣,承認自己在Balance Learning vs doing上做的不是太好,雖然有在看書,但還是要透過累積大量實作與解決問題,才能靈活的運用這門語言啊。

What if Shakespeare Wrote Ruby?

原來Adam是念過戲劇(Acting)相關的科系啊,難怪這麼有戲誒,這個talk就推薦上confreak去看啦。
DHH也在2014 RailsConf中提過相似的概念,Writing Software
身為一個software developer同時也要努力成為一名softeware writer~

Lightening Talks

印象最深刻的還是JuanitoFatas的Contious Update/Update early啦,平常就會在社群活動跟他聊天,主題明確也很輕快,另外其他幾個開發者Lightening Talks的分享也很棒,都是自己正在開發或好玩在做的東西,滿有啟發性的~

Panel Discussion

Education & Self Education:
這個session,各個講者分享了自己學習Rails的心路歷程,如何到現在這個階段,透過哪些方式讓自己在Rails技術或工作上成長,包含參與open source的專案,以及對於現在CS education的看法,以及有沒有什麼是我們可以做的,進而讓更多的人投入軟體開發,選擇到這個領域工作。

Hiring Developer:
這個session,是分享講者自己的一些面試經驗,以及如何找尋適合自己團隊工作的理想人選,並且給正在找工作的人一些建議。

我自己對於來自葡萄牙的講者LUÍS FERREIRA的分享十分有共鳴,他們是小公司,而通常對來應徵工作的人都會有兩次面試,第一次的面試並不會問太艱深的技術問題,主要是了解面試者的個性與解決問題的態度,穿插一些簡單基本的開發背景知識,也會說明目前工作團隊的情況,第二次可能就會有較多專業上的討論,對於職缺刊登的敘述,也不會用什麼ninja/monkey的字眼,老老實實地把工作的內容敘述完整,也不要求具備CS背景,最重要的還是選擇跟目前團隊相容與工作理念相近的developer。

Q&A時,有人問到關於男女就業平等的問題,但事實上,講者分享自身收到履歷的件數,男女比例其實已經相當懸殊,我自己也覺得這個本身是個結構性問題,雖然有很多活動像是Ruby girl/Rails girl在提倡這些議題,也希望幫助讓女生可以有更多機會認識接觸這個語言,甚至能發展成自己的工作,但其實聽到實際參與其中的社群朋友們的分享,效果也有限,這個真的很難改變啊,而這好像是全世界共同的難題,也是個值得深思的議題。

Make Some Friends

這次Talk穿插不少Tea break,所以有滿多機會跟與會者互動的,看起來,我們公司說不定是現場最大團的,7個Rails developer都到了,大部分時間都跟公司其他人一起行動,不過也有機會跟許久不見的朋友聊聊彼此的近況,也認識了一些新朋友,大家因為Rails有了交集,社群參與真的是督促自己成長不可或缺的養分,也是分享經驗、交換所學的平台土壤。

After party的時候,也有機會跟幾個朋友,還有來自上海、日本的開發者聊了滿多工作、生活上的事情,大家都在各自的領域都有滿多精彩的故事,聽得滿過癮的~

這次主辦團隊真的很用心在辦這個活動,Rexy跟其他團隊成員,每個人都很好相處,也很謙虛,為這個活動與在某些Talks上加分非常非常多,再加上其他常在Ruby社群付出心力的大大們的共同參與,也希望這個活動能夠越來越好,之後能夠延續下去。

LearnRubyTheHardWay, Exercise 39: Hashes, Oh Lovely Hashes

| Comments

寫在前面

這篇是翻譯LearnRubyTheHardWay, Exercise 39: Hashes, Oh Lovely Hashes的後半段,因為對我來說實在有點難搞懂,就花了點時間翻譯與反覆推敲,來檢視我是否了解這個概念,Array跟Hash也是Ruby中滿核心的組成,完全搞懂是必要的,其實這段滿有意思的,程式碼部分就沒有貼過來了。

建立屬於你自己的Hash Module

本練習的最後一段程式碼,讓你知道如何僅僅利用array來達到與Hash相同的資料結構組成,這段程式碼或許不好理解,但請耐下性子花點時間把它搞懂,這段程式碼裡也並沒有引入任何新的概念,但是具有一定的複雜度,也有些部分需要你額外在做些參考資料的尋找。

這個Hash module將命名為Dict,是與Hash有相同資料結構的別名,指的也就是一對一的映對關係,檔案請命名為dict.rb,後面會在範例檔ex39_test.rb中使用。

程式碼說明

Dict其實只不過是由一堆bucket所組成的array,bucket中有一個個slot,而這些slot中存放著key/value對 “,讓我花個幾分鐘來拆解上面這段論述。
“一堆bucket所組成的array“
Dict function裡,先生成一個array叫aDict,接著在這個array中再塞進更多的array!
[[] [] [] [] [] [] ....]
“bucket由一個個slot組成”
而這些更多的array(bucket),一開始都是空的,但當我們在bucket中這些slot塞進key/value對的時候....
[[slot, slot] [] [] [] [] [] ....]
”這些slot當中存放著key/value對“
指的是每個slot中都存在著一個(key, value)元組(tuple)或pair。

如果對於上述的這種資料結構,仍沒有任何感覺,沒關係慢慢來,試著動手在紙上畫看看,直到你搞懂它!事實上,動手在紙上描繪出來或寫出來,是個理解演算法的好方式。

現在你已經知道資料的結構組成,再來你只需要知道演算法中的每個操作。而演算法是由步驟操作與資料結構所組成,也是讓這個資料結構可以正常運作的程式碼。我們將透過編寫程式碼來實現每個操作,而Dict的說明如下:

  1. 將key轉換成一個integer,轉換的方式是利用function: hash_key
  2. 將這個hash轉換成一個bucket number,轉換的方式是利用% (modulus)運算子
  3. aDict這個array所包含的眾多bucket中取得該bucket,再取得裡面的slot,再找到我們所需要的key!

在'set'這個function中,我們所做的是取代原本或以append的方式加入新的key。

接下來透過說明Dict中的各個function讓你瞭解到底發生了什麼事,確認你搞懂每行程式碼,並在旁寫下註解確認你完全瞭解了,我建議你可以花點時間在Ruby shell試試看這些程式碼的作用或試著在紙上練習看看。

  • new
    首先建立一個function來為你新增一個Dict,也稱為initializer。我所做的就是新增一個名為aDict的array,然後再放入數量num_buckets的array!這些bucket將用來存放Dict的內容,之後在其他function我會使用aDict.length來確認aDict有幾個bucket存在。

  • hash_key
    這個function是一個hash如何運作的核心概念,其實他做的事是利用一個Ruby內建的function來將一個字串(string)轉換成一組數字。Ruby利用這個function來實作Hash的資料結構,這邊只是重新引用這個方式,建議你應該開一個Ruby console來試著操作看看,瞭解一下他如何運作的,一旦我取得這組數字作為key,我再借用一個%的運算子與aDict.length運算,將原本很龐大的一組數字轉換成相當較小的一組數字,最後得到我可使用的key,如果不太清楚上述的轉換過程,建議可利用Ruby console實作做看看這個過程。

  • get_bucket
    之後由這個function利用hash_key找到包含我們需要的key的對應bucket,而由於我們在hash_key中利用%aDict.length做了一些轉換,我知道不管我得到什麼bucket_id都可以讓我對應到aDict array中的位置,利用這個bucket_id就可以找到需要的key所對應的該bucket。

  • get_slot
    這個function先用get_bucket找到所需bucket,然後搜尋bucket中的每個元素直到找到符合的key,一旦找到,就會回傳(i,k,v),也就是index,key本身,與其映對的value。現在你應該可以知道這個資料結構是如何運作的。這個過程透過key與hash的轉換找到bucket,再搜尋該bucket找到目標。透過這些function執行有效率分工達到資料結構上必要的搜尋,最後找到目標資料。

  • get
    這事實上是大部分使用者希望透過Dict能實現的function。利用了get_slot找到(i,k,v),然後僅回傳v也就是value,確認你已了解default變數的運作原理,與get_slot中的(i,k,v)是如何放到geti, k, v中。

  • set
    要設定或存放一組key/value對,首先找到bucket然後在將新的(key, value)以append的方式丟進去,這樣之後就可以取用。但我們這裡希望Dict一次只允許存在一個key,為了滿足這個條件,就必須先找到bucket確認這個key是否已經存在,如果是就直接以我們設定的(key, value)取代,如果不是那就以append的方式丟進去。這種方式的執行速度會比以單純appending的方式慢一些,但可能會更貼近使用者對於Dict運作方式的期待。而如果你希望一個key可以映對取得不只一個的value,只要讓get搜尋該bucket的每一個slot後,回傳一結果array即可,這裡是個設計module上的參考示範。目前是get的執行速度上比較快,而set相對慢一些。

  • delete
    要刪除一個key,我只需要找到bucket,找尋到bucket對應的那個key,將他從array中刪除即可,但這是因為在這裡我選擇讓set只允許每個key僅存在一key/value對,所以我只要找到對應的key刪除就結束了,但是如果我決定讓每個key可以有多個不同的value的話(也就是在set終以單純appending的方式,而先不確認key是否唯一),delete的設計就必須搜尋bucket中的每個slot完後,找到對應的key把他砍掉,而這會讓delete的執行變慢。

  • list
    最後一個function只是個小小的debug功能,可以列出Dict中的物件,找到每個bucket,然後走遍bucket的每個solt。

最後ex39_test.rb是一段測試碼來驗證這些function正常運作。

三層Array!(Three Levels of Arrays)

[[slot, [] ] [] [] [] [] [] ...]
如同在先前討論中所提到的,set會以新的value覆寫或取代原本key所對應的value,在這個例子中,我已經設計讓set的執行速度慢一些,但這代表其他的function會跑快一些,但如果我很想讓Dict這個類別的每個key都可以具有多個value呢?

我需要做的就是在每個bucket中的slot改成可存放多個value的array。這表示我要加入第三層的bucket,接著slot中改放一個可存放多個value的array。這也符合先前我對於這種Dict的描述,"每個key可以具有多個values",或者說是"每個key都有映應一個存放多個value的array",一個slot放key,而另一個slot改成可存放多個value的array,就完成啦!

如果你想做更進一步的研究,可以試著改寫程式碼,使每個key都可以有多個values吧。

什麼時候該用Hash?什麼時候該用Array?

如同在練習38所提到的,array具備一些特性可幫助你以array的資料架構形式保存或組織資料,Hash也是,但他所具備的特性與array有些不同,因為他是由key映對到values,也就說在下列情況你會使用到hash:

  • 你需要基於一些非整數的identifier幫助你取得映對的資料,像是姓名、地址、或任何可以當作key的東西。
  • 你不需要資料有順序(order)的排列時,Hash中沒有順序的概念,而array有。
  • 你需要新增或移除資料中的各個value與其映對的key。

也就是說當你需要用非整數的key時,使用hash,而如果你希望存放的資料是依順序排列,使用array。

Web開發101-Session與Cookie

| Comments

Cookie是什麼?

當使用者開啟某個網站時,瀏覽器就會傳送保存在用戶端的cookie到伺服器端,cookie中包含使用者上次瀏覽該網站的一些活動紀錄與資訊,而檔案大小上限為4kb。

當你瀏覽網站時,瀏覽器會自動下載cookie,用來追蹤你在網站上的一些活動紀錄,而在Rails中,保存cookie的cookie container本身看起來像一個hash,於controller中,就可透過相關的method來讀取其中的資料,許多Rails開發者使用cookie來記錄一些使用者偏好設定與資安方面較不敏感的資料,但千萬不要將重要資訊保存在cookie中,cookies 屬於沒有加密的公開檔案,且是可由使用者任意讀取的。

預設情況下,Rails提供相關的helper可操作cookie container。

舉例來說,Rails中你可以直接操作cookies這個特別保留的hash,而當中每個key-value pair分別儲存不同的資訊,如果加入cookies[:hair-color]=“blonde"在某個Controller#Action中,當執行時,打開瀏覽器的developer tools就可以看到在cookie中看到key(name)為hair-color,而value為blonde,被儲存在用戶端,而透過cookies.delete(:hair-color)就可以刪除該cookie。

Cookies參考說明:
http://skillcrush.com/2012/05/16/cookies/
http://www.theodinproject.com/ruby-on-rails/sessions-cookies-and-authentication

Session是什麼?

Session id原理

一般而言,相對於cookie儲存在使用者(Client)端,session則是儲存在伺服器(Server)端,session也需要cookie的輔助才能產生運作,當使用者造訪我們的網站時,我們由伺服器產生 session id (32 byte long MD5 hash value),並傳送存有這個 session id 的 cookie 給瀏覽器儲存,之後使用者每次造訪我們網站時,只需要比對 cookies 上的 session id 和 session 裡的 session id 就可以知道使用者身份,大部份的網站也是運用此原理實作儲存 User 登入狀態的機制。

換句話說,如果使用者(client)端的cookie清掉,那你當下的登入狀態,也會跟著消失,重整網頁之後會產生一個新的cookie,但就不是你先前的登入狀態了。

在Rails中使用Session

因為HTTP是一種無狀態的通訊協定,為了能夠讓瀏覽器能夠在跨request之間記住資訊,Rails內建了session功能,像是記住登入的狀態、記住使用者購物車的內容等等,都是用session實作出來的。

在Rails中要操作Session,直接操作session這個Hash變數即可,舉例來說:
session[:cart_id] = @cart.id

Session Storage

然而目前Rails預設是採取CookieStore,是上述的Session id原理不太一樣的做法,CookieStore其實就是直接將session資料透過config/secrets.yml的secret_key_base編碼後儲存在使用者端的cookie,好處是對伺服器的效能負擔很低,但檔案大小上限只有4kb,而因為網站每次傳送request都會包含cookie,較大的cookie檔案也意味著較慢的網站效能,如果不小心外洩secret_key_base或被反編碼成功,Session資料就會被解出來,因此安全性較低,不適合存放機密資料。

當然Rails也提供存放Session的其他選項來供開發者做選擇,透過修改config/initializers/session_store.rb來達成包含:

  • :active_record_store 資料庫
  • :mem_cache_store 使用Memcached快取系統來儲存,適合高流量的網站
  • :cache_store 使用Rails快取

一般來說使用預設的CookieStore即可,如果對安全性較高要求,可以使用資料庫。如果希望兼顧效能,可以考慮使用Memcached。

更多Session參考說明:

關於Strong parameter

| Comments

Strong parameter是Rail4 之後內建的一種安全機制,避免有心人士在填資料時,偷塞參數,惡搞資料庫,輕則資料被刪除竄改,重則資料外洩,造成安全問題。

Rails的參數(Parameter)

由使用者瀏覽器端送出的請求(Request)包含著參數(parameter)再提供給伺服器端,伺服器端再依據請求中的這些參數做處理,產生頁面回傳,最常見的請求種類是HTTP GET,而參數就夾雜在URL中,舉例來說,如果使用者瀏覽器端發出請求的URL如下:
http://www.example.com/?foo=1&boo=octopus
在Rails中的params[:foo]會是1,而params[:boo]就是”octopus”

在HTTP/HTML中,參數就是一連串的key-value對,key與value都是字串(String),而Rails中的特殊語法會將這些參數包成Hash在包到另一個Hash當中,舉例來說,如果使用者瀏覽器端發出請求的URL如下:
http://www.example.com/?voteitem_id]=1&voteuser_id]=2[
params[:vote]就是一個hash物件,而params[:vote][:item_id]就會是1params[:vote][:user_id]就會是2

Rails中的實作方式舉例by ihower實戰聖經

def create
  @event = Event.new(event_params)
  @event.save

  redirect_to :action => :index
end

private

def event_params
  params.require(:event).permit(:name, :description)
end

像上述的例子,在private底下作一個event_params method來作Strong parameter,如此一來,當使用者提出請求呼叫controller#create,只能修改:name :description兩個參數,其他參數就算傳送到伺服器端也都會被擋下,無法取代原先在資料庫中的對應欄位資料。

如何讓 strong_parameter 接受 nested_attributes

有時候因為專案需求會做nested form,而實作Strong parameter的方式步驟,一般而言如下:
1. 在對應的model裡宣告accepts_nested_attributes_for :nested_model
2. 修改新增controller裡的private底下的model_params 的 permit ( :model_attr1, :model_attr2, nested_model_attributes: [:nested_model_attr1, :nested_model_attr2])
參考資料:
官方API文件說明:http://api.rubyonrails.org/classes/ActionController/Parameters.html
GitHub上的Rails原始碼
https://rocodev.gitbooks.io/rails-102/content/chapter1-mvc/c/strong_parameters.html
http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters

User Story入門

| Comments

User story 是什麼?

“ User Story(使用者敘述)是一段簡單的功能敘述,以客戶或使用者的觀點撰寫下有價值的功能(functionality/feature)。與其說它是規格文件(documentation),不如說它代表(represent)客戶的一個需求而已,因為實做細節將延後至開發時才會確定。 ”

藉由討論產生的User Story就可以進一步規劃產品各項功能、ERD、使用者行為,工程師依據這些資料來做產品開發。
而通常在Run Scrum 會用,Scrum七分鐘簡介影片

為什麼我們要用 user story?

1. 去蕪存菁,幫助聚焦

“User stories 是一種非常好用且容易上手的需求文件,它是一種極簡主義,只要求寫下最有價值不要忘記的東西,而且夠讓我們足以估計時程以及與客戶溝通。”

“User Story 強調透過一份簡單的情境規格,具體的描述出軟體在「使用者」的手上,是怎麼樣被「操作」的。能夠讓 RD 在開發時,能夠盡可能地貼近真實被需要的 Application。而不需要的功能,或者無法被實作的功能,將在一個一個循環之中,被捨棄。“

2. 幫助溝通,並鼓勵使用者/客戶參與

“ 以User stories導向的軟體開發,客戶最好要實際參與User stories的撰寫,而不只是簽名而已。作為開發者我們可以協助撰寫和提供建議,但是這應該是客戶的責任。由客戶主導的好處有 1. 由自然語言撰寫,不會充滿技術詞彙,這樣客戶也才可以根據商業價值排定優先順序。而不是由開發人員根據技術相依性來決定順序。(不過這其實也有新的問題:技術風險。開發人員會希望先進行技術風險高的 stories,這時候就需要與客戶協商討論) 2. 承上,也因為是自然語言,非技術人員也可以輕易了解內容,進行跨部門的合作 3. 由實際的使用者來描述軟體行為,再適當也不過了。”

“對客戶來說,撰寫 User story 可以幫助他們思考什麼才是真正他們想要做到的東西(商業價值 business value)”

有使用者/客戶共同參與這個過程,也能降低因溝通不良、或雞同鴨講,造成專案開發結果不符合當初期待的風險,間接節省因走錯路而需花費的成本。

3. 有助於專案開發流程規劃進行、工作拆解與節點檢討

“對開發者來說,User stories 可以給開發者很快的了解開發”目標”、要做到什麼功能,而不會見樹不見林。”

“透過把冰冷的規格轉成具體的小情境,RD 可以更知道要怎麼將架構切分成較小且可以單次就開發完畢的小元件。利用一個一個小的故事,開發出一個一個的小功能,再堆疊成一個完成的網站。同時透過 User Story 的內容對比,RD 能夠開始有辦法排出輕重緩急,甚至估算出正確時程。”

User story 的撰寫形式

User Story撰寫

一般最常見的User Story範本是:
作為一個 (某個角色) 使用者,我可以做 (某個功能) 事情,如此可以有 (某個商業價值) 的好處。
As a (role of user), I want (some feature) so that (some business value).

幾個 User Stories 的範例如下:

  • 使用者可以在網站上張貼履歷
  • 使用者可以搜尋有哪些工作
    • 使用者可以依工作地區、經歷、相關性分類工作
  • 公司可以張貼新工作
  • 使用者可以限制誰可以看到他的履歷

像依據上述的User Stories,就可以初步展開網站功能,像是張貼工作時,需要有哪些欄位,另外也需要一個使用者後台來管理履歷狀態等等,之後再更有清楚條理的拆解成可實作的步驟,進行開發。

小結

雖然自身目前的開發經驗還相當不足,User Stories的實作經驗也不多,但還是簡單整理相關解釋與做法,我個人覺得這種方式來做開發產品的依歸似乎還不錯,相較於開規格,讓人更聚焦在專案本身想要達成的目標或是解決使用者的需求,比較像是任務導向,說不定在討論User Stories的過程,反而琢磨出更簡單就能解決需求的方法也不一定,以上個人淺見囉~如果有錯,還請野生路過不世出的高手,提點小弟。

參考資料:

GitHub上Submodule(Subproject)問題排除

| Comments

問題描述與解決過程:

[11/20Update補充說明]
如果是用Submodule的方式來做,會如下圖所示,看不到底下的相關檔案,因此後來是先把資料夾中的.git資料夾整個砍掉,再依下面步驟,回到母層的資料夾的git repo作commit重新push上GitHub。

今天把自己練習的專案推上GitHub發生如下的問題:


資料夾無法點選,因此也看不到底下的相關檔案,點擊旁邊的Complete 2 practices進去,拉到最底下,看到:

我對這個Subproject所代表的意義沒有概念,於是Google了一下,發現就是Git Submodule,也在stack overflow上看到有人遇到類似的問題,試了在專案底下,輸入下面指令,想說這樣應該就可以看到這個submodule repo底下的各個檔案:
$ git submodule update —-init
結果得到下面訊息:
No submodule mapping found in .gitmodules for path ‘Udemycourse'

看來我根本就沒有建立過這個路徑,然後又用這個訊息google看到另一篇Stack overflow,於是再輸入下面指令:
$ git rm --cached Udemycourse
出現結果訊息 rm 'Udemycourse'

再輸入$ git status指令確認,出現:

看來問題解決了,重新commit一次再push上GitHub,想說OK了,結果:


看起來被reject了,但因為這個專案都是一些練習而已,我知道應該不會發生什麼大問題,因此,我用force-pushed bypass掉了這個問題,順利的把專案push上去GitHub。

再上去GitHub看,果然顯示了:


但已經可以看到底下的檔案了,Case Closed!
我想以後重要的專案還是避免這樣搞,了解Reject的原因,排除之後,再push會比較好。

結論:

其實發生問題的原因我其實不是很確定,猜想可能是之前已經在該資料夾生成一個local repo,過了幾天,我又直接在其母層資料夾init repo,然後commit一些新做的練習,push上GitHub才發現這個問題,不過趁這個機會也知道了git submodules這個東西的存在,目前還沒實際操作過,但也收集了一些相關資訊在底下供未來參考囉。

Submodule參考資料:

Git 工具 - 子模組 (Submodules)
https://git-scm.com/book/zh-tw/v1/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E7%B5%84-Submodules
Git Submodule 介紹與使用
http://blog.wu-boy.com/2011/09/introduction-to-git-submodule/
Git Submodule 用法筆記
http://blog.chh.tw/posts/git-submodule/

一些Yahoo Frontend Best Performance 最佳實務整理

| Comments

之前上課的時候,Xdite介紹很多實務上提升網站效能的方式,其中也包含廣為人知的Yahoo Frontend Best Performance,總共有35條,並分類為Content, Server, Cookie, CSS, Javascript, Images, Mobile,而Rails中的Asset pipeline就已經包含其中的一些實作。
以下簡單翻譯整理最常見的其中五條:

  • Minimize HTTP Requests
  • Use a Content Delivery Network
  • Put Stylesheets at the Top
  • Put Scripts at the Bottom
  • Gzip Components

1. Minimize HTTP Requests (Content)

藉由減少HTTP請求數量來調校網站的執行效能是個不錯的開始,根據Tenni Theurer's blog post Browser Cache Usage - Exposed!的文章中提到,每日40~60%網站造訪者是empty cache,這也意味著增加網頁讀取速度是帶給使用者良好體驗的關鍵所在。

Combined files方法是透過將所有Script整合成一份Script,達到減少HTTP請求數量的目的,如網站中所有需要的CSS都彙整成一份CSS檔案,HTTP就可以減少為一次,減少Response時間,但當每個網頁所需要的CSS或Script不同時,就會增加實作上的難度。

  • CSS Sprites是常見用來減少image requests的實作方式,結合各背景圖片(background image)成單一張圖片,並以CSS background-image 與background-position properties來呈現所需的網頁效果。

  • Image maps則是整合多張圖片成單一圖片,檔案總大小不變,但減少了HTTP請求數量,加速了網頁讀取,但此實作方式僅適用contigous形式的網頁如Navigation bar。定義Image map的對應座標,實作上相當繁瑣乏味且容易出錯。實務上並不推薦使用。

Inline images使用data: URL scheme將圖片資料嵌入實際頁面中,此舉將增加HTML文件的檔案大小,可減少HTTP請求數量,但並非所有瀏覽器都支援inline images。

2.Use a Content Delivery Network(Server)

約80~90%的用戶端的response time是花費在下載網頁所需的各種物件上包含images, stylesheets, scripts, Flash等等,與其花費時間重新設計網站架構增加效能,倒不如將一些static content分散式儲存,透過CDN來實現,可大幅降低response time。

content delivery network (CDN) 是透過分散各地儲存相同內容的web server更有效率傳送相關內容到用戶端,通常都依據用戶端所在計算選用對應的web server來發送內容,例如選用透過較少的network hops或是具最快response time的web server。

大公司通常都會擁有自己的CDN,一般新創公司或小型私人網站,實行CDN通常是一筆可觀投資,但當用戶數成長與來自全球各區域的客戶增加,CDN就是必要採取的效能提升方式,以yahoo為例,其透過CDN改善了用戶端的response time達20%以上,選用CDN是相較於其他程式優化之下較簡單的實作方式,而且可以有效改善網站效能。

3.Put Stylesheets at the Top(CSS)

當在Yahoo!中研究網站效能時,團隊發現到將stylesheet移到HTML文件HEAD位置時,網頁具有較快的讀取速度,這是因為此舉可使呈現頁面上更按部就班。
前端工程師希望HTML頁面的呈現順序是header,the navigation bar, the logo at the top等等向下進行,如此一來使用者等待網頁讀取的同時也能接收到一些回饋,可改善使用者體驗。
此外將stylesheet移到HTML文件移至底下時,會限制頁面上對應效果的呈現,可能就會造成頁面出現空白區塊。

4.Put Scripts at the Bottom(Javascript)

Script文件所造成的效能問題在於,下載Script時會阻斷其他並行的檔案下載,而直到Script文件下載完畢前,都不會下載網頁中的其他物件。

但在某些情況下,這實作方式會遇到困難,例如,可能在網頁中需呈現一些Script中的效果(像是document.write),若此時找不到Script文件就會造成Scoping issue。此時有個選擇是使用deferred scripts,此類含DEFER attribute的scripts不包含document.write,這樣網頁會略過此動作而繼續呈現頁面,但Firefox不支援DEFER attribute。若使用deferred scripts就可以將Script文件下載動作移至網頁文件最後執行,可增加縮短網頁讀取速度。

Ref:
Explaining JavaScript Scope And Closures(http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/)

5.Gzip Components( server)

一般而言,傳送HTTP請求到取得回應所花費的時間可由前端上做大幅度的改善,當然其他因素如:使用者的網路頻寬速度、網際網路服務商等等也會造成影響,但這些都不在開發團隊的管轄,但還有其他變數,像是壓縮(Compression)可縮小HTTP請求的檔案大小進一步減少Response time。

從HTTP/1.1開始,在HTTP請求中加入Accept-Encoding header可使Client端可支援壓縮,指令如下:
Accept-Encoding: gzip, deflate

當Server端接收到含有此header的請求,就會使用Client端指定的方式中選定一個執行壓縮,而Server端則在回應加入一行Content-Encoding header 指令:
Content-Encoding: gzip

Gzip是目前最常見與最具效率的壓縮方式,一般而言可減少約70%左右的response檔案大小,現今聲稱90%網路中透過瀏覽器傳送的請求與回應都支援Gzip

Server根據檔案類型決定是否做Gzip,大多數網站對HTML文件做Gzip,包含scripts, stylesheet或是其他text response像是XML, JSON,而對image與PDF則不做Gzip,因為這些檔案本身已經做過壓縮。

盡可能對可執行Gzip的文件實作Gzip是一種簡單降低page weight與提升使用者體驗的方式。

在Heroku部署Rails專案結合AWS S3存放上傳圖片

| Comments

關於Heroku

Heroku是一種PaaS(Platform as a Service)服務,特點是部署簡單,藉由Git push即可實作。

一般而言,對於用量不大的App,使用Heroku提供的免費方案就已足夠,而對於用量較大的用戶,Heroku提供的擴充方案,是透過購買額外Dynos,可以想像Dyno就是一台用來跑你專案的機器,多個dynos就讓專案同時可以處理更多的流量與需求。

另外當你的專案一段時間都沒人去用的時候,Heroku會自動關閉跑你專案的dyno,進入睡覺模式,而當你再次使用時,就會有一段前置的等待時間,大約一分鐘,如果不希望你的專案睡覺,可以額外購買不會關閉的dyno或使用一些第三方服務(像是NewRelic),定時去ping你的專案網站。

將專案部署至Heroku

這部分在RailsBrigdeRails Girls Guides都有圖文並茂的解說,強力推薦參考。

Step0. 完成前置作業:

  • 安裝與設定Git
  • 建立SSH key
  • 申請Heroku帳號、安裝Heroku toolbelt並將SSH key加入

Step1. 確認Rails專案的Gemfile設定

推薦設定前先完成git commit,之後配合部署的更動再使用另一個commit,方便除錯。

Gemfile
group :development, :test do
  gem 'sqlite3'
end

group :production do
  gem 'pg'
  gem 'rails_12factor'
end

Rails預設下,可依development、test、production環境不同使用不同的資料庫,Heroku用的資料庫是PostgreSQL,因此配合在production環境底下安裝上述兩個Gem,並將development環境下使用的SQLite區隔,而同時在同一個環境下使用sqlite3pg會發生錯誤。

Step2. 確認Rails專案完成Git commit

Step3. $ heroku create
指令跑完git設定的remote repo會多一個heroku,才可進行下一步push

Step4. $ git push heroku master
把你的專案push到Heroku,同時Heroku會確認專案中的Ruby版本與跑`bundle install`

Step5. $ heroku run rake db:migrate
在Heroku端建立起資料庫

Step6. $ heroku open
一切OK之後,輸入上述指令,Heroku就會啟動dyno來跑專案,並自動在瀏覽器打開你的專案

常用的Heroku設定與指令

你可以(1)透過CLI或是(2)直接上Heroku網站的管理後台做一些跟專案有關的Heroku環境或參數設定,像是更改專案名稱、加入環境變數、管理SSH keys、設定第三方服務等等。

個人兩種方式都用過,舉例來說,更改專案名稱,Heroku在heroku create時會自動為專案命名,部署完成後,我們就可以更改專案名稱,如果用CLI做設定,只要key入$ heroku apps:rename newname,如此一來就完成更動,連Git remote heroku的設定也會做更新。

而根據個人經驗,如果你是在管理後台更改專案名稱為newname,回過頭來,就還要在本地端手動更正git remote heroku的位置,不然之後push新的專案版本的時候就會發生錯誤。
$ git remote remove heroku
$ git remote add heroku git@heroku.com:newname.git

而我現階段做法都是用CLI指令設定後,再上管理後台做double check,確保更動無虞。

另外,通常在Heroku上跑rails的相關指令,都需要在前面加上heroku run

  • $ heroku run rake db:migrate
  • $ heroku run console #使用上要非常小心,因為你處理的是實際在運作的資料庫
  • $ heroku logs
  • $ heroku restart

更多的指令可以參考官方指南

部署上常見錯誤(errors)與除錯

Heroku上的HTTP router如果遇到unstyled HTML就會丟503(Service Unavailable),這種情況發生在專案執行時遇到系統性錯誤(system-level error)或是maintenance模式被啟動中,而如果是遇到404或500,則是呈現部署專案中的錯誤頁面。

錯誤發生,通常都會去看歷史紀錄($ heroku log),確認發生了什麼事,而常見的問題如下:

在部署時發生問題,Heroku底下,Rails運行的是production模式,所以專案中production環境設定的相關設定檔,如config/environments/production.rb 或是Gemfile中Gem的設定就要特別小心。

專案運行時,遇到status 500系列的錯誤,如果是在使用第三方服務出現問題,檢查看看是不是串連的第三方服務API的環境變數漏了加在Heroku,或是應該API端配合的設定沒有做或忘了變更成production的設定。

結合AWS S3存放上傳圖片

如果專案需要使用到圖片上傳或類似相簿的功能,由於Heroku目前無法支援,而且空間容量也不夠大,因此通常會搭配其他服務如AWS S3來實作這些檔案上傳的功能,而Heroku也提供了操作指南供參考。

而這邊紀錄一下個人的實作經驗,我自己的專案是想實作圖片上傳的功能,在開發時,是把檔案存在本地端,也就是public/uploads底下,而部署之後希望能放到S3上,實作步驟大概如下:

Step1. 申請amazon帳號與啟用S3服務並新增一個Bucket
申請完 AWS 帳號後到帳號名稱的下拉選單裡面點「Security Credentials」,就可以看到有個「+Access Keys」這邊可以申請Access key ID,專案中的設定需要用到。

Step2. Gemfile加入gem 'fog'與執行bundle install

Step3. 如果使用carrier wave實作上傳功能,相關設定可直接參考這篇

而個人練習專案中的設定如下

image_uploader.rb
 ()
  if Rails.env.production?
  storage :fog
  else
  storage :file
  end
 ()
carrier_wave.rb
CarrierWave.configure do |config|
  if Rails.env.production?
    config.fog_credentials = {
      provider:              'AWS',
      aws_access_key_id:     ENV['S3_KEY'],
      aws_secret_access_key: ENV['S3_SECRET'],
      region:                'ap-northeast-1'
    }
    config.fog_directory  = ENV['S3_BUCKET']
  else
    config.storage :file
  end
end

值得一提的是region的設定方式,並不是直接看Amazon S3上bucket的region,像選tokyo,但程式裡的region設定應該是ap-northeast-1,可參考這份文件

Step4. 如果是使用env的方式設定amazon帳密,記得上Heroku管理後台去新增更新env,或在CLI直接下指令也行。
$ heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy

Step5. 這樣應該就OK了,到專案網址試著上傳圖片後,再到AWS確認看看吧~

參考資料:
關於Heroku:
https://devcenter.heroku.com/articles/how-heroku-works
http://www.openfoundry.org/tw/tech-column/8573-heroku-the-best-cloud-platform-on-ruby-language

Heroku官方使用指南:
https://devcenter.heroku.com/articles/getting-started-with-ruby#introduction

實作AWS上傳文章參考:
http://yulin-learn-web-dev.logdown.com/posts/259970-rails-app-how-to-access-aws-s3-service