陳威齊

不知是否夠格自稱 Engineer,但是熱衷於分享所學與傳承經驗、技術。喜歡撰寫程式提升工作效率。持續進修、富責任感、依優先程度自己安排工作順序。愛料理最早下班,工作效率好的Backend Developer。


[email protected]

0917233996
1989/1/25

過往背景


經歷

Polydice ( iCook )

  • Backend developer ( 2017/7月 ~ 現在 )
  • Backend intern  ( 2017/3 ~ 6月 )


教育背景

  • 研究所:中原大學通訊工程碩士 
  • 大學:中原大學電子系


部落格

就業後:NickWarm – Medium

退役後:NickWarm's Blog


在 iCook 的歷練


接觸過的語言、框架、gems


在公司的影響力

  • 帶起 iCook 工程部同仁貢獻技術 Quip 的風氣
  • 編輯工程手冊,協助新進同仁快速入門專案:29 篇
  • 公司內部 Quip 分享自己開發經驗
    • Ruby / Rails:26篇
    • ActiveAdmin:3篇
    • API、測試:5篇
    • SQL & Query:6篇 ( 純ORM )
  • 隨時看到可以優化的 code,會主動去 refactor
  • 重複的工作內容會寫程式讓它自動化,i.e:
    • 更新活動頁的圖片
    • web team 開發環境設定 ( 進行中 )
  • 開發功能時
    • 獨立思考業務、PM、app team成員開出來的需求規格,是否有改進的空間,主動實作時規格上沒提到,但可能會需要的功能
    • 把自己遭遇到的問題、思考過程、採取的解決方案都會留言紀錄在 Github 或 Phabricator 上面,事後再整理成Quip 分享給同仁
    • 習慣閱讀使用的 gem 的 source code,會主動思考改進空間並且送 PR

貢獻過的 open source

在愛料理的貢獻

在此僅列幾個代表性讓我印象深刻的貢獻

iCook主站後台、子站後台各種功能

愛料理的後台用 ActiveAdmin。後台member action、batch action、custom csv、 custom filter、custom panel 都實做過。

後台權限管理

這是最近最有趣的工作。不同的身份會有不同的權限,i.e:編輯、審查、客服 ...etc。
  • 最初考慮用 enum 做的,但是一個 admin user 可以擁有複數個權限,於是改用 bitfields 來實作不同身份權限。
  • ActiveAdmin有跟 pundit 整合,所以用 pundit 做權限控管
  • 擁有不同的權限,在edit頁面會看到不同的內容。為了讓程式好維護,寫了一個可以接 proc 的 authorize_to method,讓後台的DSL如ActiveAdmin 原本設計的一樣簡潔。
這專案正在進行中,接著要串 Google 的 Gsuite 綁公司信箱登入,來做安全處理

品牌廚房、活動頁的各種業務邏輯設計、實作、套版

愛料理的盈利除了 vip會員、廣告外,也會跟廠商合作舉辦各種活動。我開發過站上各種 品牌廚房活動頁優惠頁 的
  • 業務邏輯設計
  • 實作  ( model 間的關聯、custom validator、custom callback、soft delete、Sidekiq、ActiveJob、ActionMailer、redis )
  • 套版 
    • 剛接手時前人重複的 code 到處寫,於是重新 refactor 成語意清楚的 partial view
    • 一個活動頁面,常有複數個相同的版,會用 zip 組 nested array 然後用 each 去套版

今年元旦後到過年前,這段時間是我在愛料理活動相關的票最多的一次。當時連續數週每週都有活動要上線,往往三~七天內要完成
  1. 業務邏輯設計 
  2. 構思如何實作
  3. 開發
  4. 送 code review 並修改。

這段時間內,每檔活動都跟廠商談好時間不能開天窗,養成依優先程度自己安排工作順序的習慣,讓所有任務都在期限內完成。

為 app 端的各種需求開API

品牌廚房、活動 tab 開 API 給 app

愛料理 app 上面,品牌廚房、活動的頁面原本是純 hybrid view。為了要通過 Google Android Excellence 的審核,需要讓 hybrid view 的 navbar 與 app 的一致,於是拆掉hybrid view header,改用 api 出。
  • 原本品牌廚房、活動頁 hybrid view 的 navbar 是用 semantic_navigation 這套件,一個 tab 一個判斷式,判斷要出哪些tab
  • 最初模仿這寫法,在 jbuilder 的 json template 裡寫了一堆判斷式,整個API超慢
  • 後來把它抽象化,在 controller/concern 加個 HybridTabHelper
  • 我定義了兩個hash,兩個hash都用一樣的keys
  • 先定義一個全部 tab 會有哪些tab、link 的 nested hash
  • 然後把該品牌廚房的tab要的就是 true,不要的就是 false,然後只取要的tab 存成一個hash
  • 然後兩個 hash 用 select 去挑出 key 存在的 key-value pair 回傳的hash 就是我們要的tab的資訊

這段還沒決定要不要講
  • 在此要先講一下品牌帳號的設計,一個品牌帳號其實就是一個 User 帳號
  • 但是business user 比普通 user 多出來的資訊,像是哪些 tab 要出,哪些 tab ( 一個true or false 的判斷 )
  • 前人過去的實作是再建一個 BrandSetting model 並給他一堆 boolean 欄位,BrandSetting belongs_to User
  • 然後 user model 去 delegate BrandSetting 的這些欄位
  • 於是 semantic_navigation 這套件, tab 判斷式的判斷條件就是剛剛那些在User model 裡 delegate 的 method。

recipe API 的 cover / cover_pictures 二選一

API 裡面會同時出 cover & cover_pictures,佔用了很大的傳輸空間。從user agent 去判斷 user 的 app 版本,不同版本出不同 API
  • 在 application helper 裡寫版本判斷的helper
  • 若要在 api controller 裡用 ApplicationHelper,需要用 helper ApplicationHelper
  • 我們家有自己寫 UserAgentParser 用 regexp 去取得 app 版本
  • Gem::Version 做版本判斷

統一 API 找不到物件的錯誤處理

以前的做法真的很醜,在 api 的 action 裡到處寫判斷式。後來 refactor 把它拆出來用 rescue_from 去解
  • 在 api contorller 裡 rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
  • 以前的做法真的很醜,在 api 的 action 裡到處寫判斷式,沒有就 render status: 404, json: { error: '...略' }
  • 改用 regexp 去撈 exception.message,依照不同的 record_type 來出不同的 error message


重寫 FCM API

FCM API 要增加圖片,並且用 pushing gem 重寫
  • 原本的 FCM API 是用前同事自己手刻的 gem 寫的。舊的 FCM 寫法 json format、logic 都寫在一起,維護不易
  • 改用 pushing 的好處是,像MVC架構一樣 view、controller 分離,這樣比較乾淨。 
  • 此外 pushing 對 ActiveJob、Sidekiq也有著較好的支援,
  • 用 pushing 的 deliver_later! 並且去 Sidekiq Configuration File 配置,就能把 notifer 丟到 sidekiq Queue 去處理了 

cache everywhere


每新增一筆活動報名,自動 update BrandCampaign 的 cache key

  • user 在報名活動後,品牌廚房的module 會顯示報名人數,但要在後台update 後才會更新報名人數。
  • 後來發現是 cache 的緣故,於是在活動model 用 after_touch 去執行 custom callback 來 touch 品牌廚房。

用 Cells 來對 ActiveResource 做 cache

為了要讓愛料理市集取得主站的食譜資訊,用 ActiveResource 開 API 出來讓市集去打。為了讓撈回來的資料做 cahce,所以用 Cells

修復 wpdb_activerecord 的 cache_key timestamp

  • wpdb_activerecord 的設計概念,是讓Rubyist可以用習慣的 ActiveRecord ORM 來操作 wordpress db。
  • 改用 wpdb_activerecord 時發現,該成功cache的地方卻失敗了。追了老半天rails 的 source code 才發現 rails 5.0 與 5.1 在 timestamp_attributes_for_update 的實作上整個大改,採了這雷後送 PR 去 修復 cache key 的問題

隨手 refactor 、把重複的工作內容自動化

更新活動頁的圖片自動化

活動、品牌廚房頁面的圖片是放在專案裡的。由合作廠商時常要求更換圖片。每次更換圖片都會走下面這流程
  1. 從公司 Google Drive 下載圖片 
  2. ImageOptim 優化圖片 
  3. 圖片改檔名,改成活動、品牌廚房固定的命名慣例 
  4. 刪除專案裡的舊圖檔,並放入新圖片
這些修改都是重複、簡單,但是浪費時間的工作,所以就寫個 rake task 把這流程自動化,並詳細紀錄操作方式在公司 Quip

後台一樣但是到處寫的 code 用 meta programming 生成 dynamic method

愛料理的架構,事前後端分離的。主站一個專案,後台一個專案。業務邏輯 ( model 、 validation ) 拆出來成一個獨立的gem,給主站後台使用。

後台欄位常需要輸入複數個id,像是推薦食譜 id。
類似的功能在愛料理後台非常多。這功能只有後台會需要所以我們是在後台的

  • 過去是用 rails decorator, 一個model寫一個到處都是這種code。
  • 後來我把它抽出來在 ApplicationRecord 實作 class method,依照固定的命名慣例用 define_method 重寫。

給網址帶參數

在愛料理我們給 user 填的問卷會帶 user 資料,也會帶 utm 參數來理解,user 是從app 還是從 web 來造訪愛料理。

Market 訂單 sms 調整:下單時寄一封簡訊,訂單截止日當天再寄一封簡訊提醒

3/27 開始簡訊增加送兩次之後,ATM逾期率 顯著降低6.9% 
  • 3:45.9% 
  • 4月:39.0% 
  • 每個月簡訊花費增加:800元
  • 保守估計提升營收:112,000元

修改市集訂單的通知,簡訊縮網址、帶入utm參數。並讓未登入的 user 可以看到部分訂單內容
  • Addressable::URI 給網址帶 utm 參數 
  • 先研究完 google_url_shortener 這個 gem ,學習到可以用 rest-client 來打第三方 API
  • 在 google shorten API 被停掉後,改用 branch.io 的縮網址 api 
  • 用 perfom_later 來跑 SmsJob 假如寄信失敗就 raise error,Sidekiq 會自動retry

貢獻 open source

  • 第一次貢獻 open source 是 intern 時期,用 administrate 替換掉子站後台框架時,用 administrate-field-date_picker 時發現某些情境會讓網站壞掉,於是送 PR 修復之。
  • 愛料理生活誌 的 ORM 從 sequel 換成 wpdb_activerecord 時,因為 wpdb_activerecord 沒有實作 wordpress 裡的 get_option 於是送 PR 實作之。
  • editor 從 atom 換成 VScode 時,VScode 的Ruby註解用得不順手,就去讀它的 source code 送 PR
  • 像最近在開發的後台權限管理時,ActiveAdmin與Pundit 整合後並沒有 Policy generator,但是進 console 明明就能撈到 register 哪些 resource ,所以應該可以把建立Policy這件事給自動化,這也是之後會去研究如何實作並送PR。