使用複合條件來判斷是否進入下一輪 Java 迴圈
在 Java 迴圈寫法中,假如我想要透過一個外部判斷來提前中斷這個迴圈,之前我習慣寫: public class Test { public static void main(String[] args) { int [] ints = {1,2,3,4,5}; boolean continueCond = true; for (int i=0; i<ints.length; i++) { continueCond = ints[i] < 4; if (!continueCond) break; System.out.println(ints[i]); } } } 但這樣寫其實有點冗,今天看到在 Functional Interfaces in Java 裡的一個範例寫法: public class Test { public static void main(String[] args) { int [] ints = {1,2,3,4,5}; boolean continueCond = true; for (int i=0; i<ints.length && continueCond; i++) { continueCond &= ints[i] < 4; System.
Windows 裡的類 homebrew 工具: scoop.sh
新工作的環境是 Windows 系統,所有的開發工具生態系都要重新摸索。剛開始發現可以用 Git for Windows 裝好後的 console 下平常習慣的 bash 指令後,努力想要自己寫一些 shell script 去自動化開發工具跟環境變數的初始化,簡單的情境下好似都還堪用。 可是如果要安裝的套件都要一個一個手刻 script 好像又有些白癡。 因緣際會下被提點去找其他平台上的類 Homebrew 方案,權衡系統權限低落等實際情況下,好像也只剩 scoop.sh 可以用了。 搞了一整天反覆試驗了一陣子,總算是把裝機清單給列了出來,放在這裡。雖然還是要手動輸入指令,但是可以統一管理這些套件,用指令反安裝等已經比之前的原始人狀態進步多了。 被 oh my zsh 慣壞眼睛的我,有幸發現可以用 concfg 稍微把 PowerShell 的顏色弄得順眼一點。所謂山不轉路轉,路不轉人轉,接下來還需要努力爬行。(握拳)
在 RSpec 裡測試 Rake Task
最近被 Rake Task 的測試設定搞得一頭霧水,簡單記錄一下測試 Rake Task 的測試設定,以及各種鬼打牆的血淚史: TL;DR 為了避免各種 task 載入、執行狀態等相互干擾導致 test case 會偶發性失敗,每一次執行 test case 時就去做「載入」、「卸載」會比較沒有鬼打牆狀況出現。 # spec_helper.rb config.before(:each, rake: true) do Rails.application.load_tasks end config.after(:each, rake: true) do Rake::Task.clear end 把 Rails.application.load_tasks 放在 before(:each) 確保每次載入 test case 前都有正確 load 到要測試的那隻 task ,並在 after(:each) 時用 Rake::Task.clear 去清空剛剛載入的 Rake Task。 透過 rake: true 這個 flag 可以避免其他不相關的單元測試也去載入 Rake Task。 透過每個 each 都做載入跟卸載 Rake Task 後,就可以在 test case 單純使用 Rake::Task['task_name'].invoke 來手動執行 Task 而不用另外去作載入或卸載。
書摘 | Soft Skills = The software developer's life manual
公司前輩分享了 Soft Skills: The software developer’s life manual 這本書,後來又在 Soft & Share 看到推廣介紹,抱著當休閒讀物的心情來閱讀是很不錯的。 作者 John Z. Sonmez 在這本書中想要涵括的內容實在包山包海,如果對於人生迷惘的捧油,的確只要看了這本書所簡單介紹的內容就大概可以對人生重拾一些希望,也能循著這些主題繼續往深探索。比較特別的是,每個章節的篇幅被設計成大概一篇 Blog 文長度,所以閱讀起來的節奏感很是不錯,即使有些主題令人打哈欠,有些主題不斷地出現各種課程推銷,但都還能在睡著與失去耐心之前看完一個段落,這點是很值得效尤的閱讀設計技巧。 討論的主題分成七大部分: Section 1 - Career / Section 2 - Marketing Yourself 這兩部份討論的事情差不多,主要觀點是:把自己當成事業經營。 每個人的人生想成就的事物不盡相同,但大致上不出「創業」、「職員」、「自由工作者」這三種工作型態,每種工作型態都有其優缺點,沒有最好的選擇,只有最適合、最自在的選擇。制定目標的技巧:由大至小,先抓大方向,然後再去規劃要怎樣分階段性地往大方向前進,在執行計畫目標的過程當中,也不斷地去重新思考「目前的走向」是不是在往「想要的目標」前進,不斷地修正、不斷地思考,減少瞎忙的狀態。 每個人的人生想成就的事物不盡相同,但大致上不出「創業」、「職員」、「自由工作者」這三種工作型態,每種工作型態都有其優缺點,沒有最好的選擇,只有最適合、最自在的選擇。制定目標的技巧:由大至小,先抓大方向,然後再去規劃要怎樣分階段性地往大方向前進,在執行計畫目標的過程當中,也不斷地去重新思考「目前的走向」是不是在往「想要的目標」前進,不斷地修正、不斷地思考,減少瞎忙的狀態。 把自己當成事業經營,適當時候要勇於承擔風險,即使是受僱,心態上也應該將工作表現視為擦亮自己「工程師專業」這塊招牌的方法之一。心境不同,面對困難的態度也會有所不同。 除了砥礪自己的正直人格之外,也要適當地行銷自己的工作能力,名聲資產的累積管道除了被動地讓共事的同事發掘之外,可以積極地利用自媒體增加自身技術能力的曝光度,對公司內部分享技術心得、寫 blog 文章、參與 open source 專案、錄製 youtube 教學影片、參加 conference 或 meetup 活動,用開放地態度分享自己的心得,和業界的其他工程師教學相長營造正循環,累積一些口碑的被動收入(? Section 3 - Learning 作者提出了一套學習的方法論,大致上是: 了解領域範疇的大輪廓 制定學習目標 定義目標達成標準 搜集學習的資源(書、演講、課程) 制定學習計畫 過濾資源 學習可以開始動手的最小幅度知識 透過實際使用學習到的知識做一些有用的事情 第 8 步驟撞牆的時候回過頭去繼續補充所需要的進階知識 透過教學他人來融會貫通學習到的知識內容 個人覺得學習陌生領域最困難的入門點在於「不知道自己目前不知道什麼」、「不知道自己應該要先知道什麼」,所以步驟 1~6 其實已經有點「雞生蛋、蛋生雞」,有時候會遇到選一本很多人推薦的書開始讀了以後,陷入書裡面額外提到的各種細節而無法前進(其實大多時候是那種書都很厚重本身就有一種難以征服的心理壓力),又或者是努力地做了一堆「入門」練習然後就卡住無法自己融會貫通地應用在想做的專案上。 我後來發現一個簡單的方法,可以不用在學習之前就花時間搜集資料跟理解當下看再多也看不懂的材料,那就是 Udemy 的課程(或是其他已經整理好的學習計畫),特別是一些透過實作來做教學的程式課,選一些「看來像自己專案需要之技術」、「對於某特定技術的簡介與案例操演」類課程,跟著課程的模組實際動手做,不錯的課程設計已經把步驟 1~6 給完成,直接進入 7~8 階段。最後透過在自己的自媒體上分享所學到的知識內容,重新在腦中組織一次剛塞進去不久的知識,順便累積曝光資產,有時候遇到新的問題要回去查找資料時,自己寫的 blog 文章也會意外成為不錯的參考資料。
工具 | Kindle "My Clippings.txt" 的轉檔 gem KCFU
Kindle 的剪貼簿功能雖然在 Kindle 上很好用,但真的要抽出來另外處理書摘的時候還真的麻煩,因為 My Clippings.txt 就是一個很簡單的純文字檔,每次在 Kindle 上面 hightlight / bookmark / notes 時就會依照書的 title 去新增一段特定格式的文字段落,所以如果同時看很多本的時候,打開 My Clippings.txt 會發現裡面就依照 clippings 時序夾雜著來自不同書裡的內容,得再經過一些處理才能分成不同的來源。 原先有找到 firewood 這個套件,不過沒辦法在我的電腦上使用 QQ,乾脆就自己刻個輪子吧。 GitHub 上面的 kindleclippings 是用 Ruby 寫的,簡單又方便使用,站在小巨人的肩膀上刻了一個 kcfu 來做基本的拆分檔案,另外加配了一個陽春的 Markdown 格式轉換器方便做書摘。 最簡單的用法是開一個資料夾,把你的 My Clippings.txt 放到裡面,再寫個小 Ruby 檔: # kcfu.rb require 'kcfu' parser = Kcfu::FileUtil.new parser.parse_file(File.expand_path("#{File.dirname(__FILE__)}/My Clippings.txt"), convert: :markdown) 然後安裝 KCFU(沒有安裝 Ruby 的同學若要服用請先安裝 rbenv 跟 ruby ) gem install kcfu # Under folder of your kcfu.rb and 'My Clippings.
在 Trailblazer 的 Policy 中透過客制 Exception 來處理複雜的「錯誤回應」
為了盡量貼近 Trailblazer 的設計概念,許多原先會透過 Controller before_action 去處理的權限管控,盡量都搬進 Trailblazer 的 Policy 裡。 Policy 採用類似 Pundit 的語法,典型的 Policy 如下: class Thing::Policy def initialize(user, thing) @user, @thing = user, thing end def create? (admin? || approved?) && @thing.persisted? end private def admin? @user.admin == true end def approved? @user.is_approved end end 在 Operation 中若要調用這隻 Policy 的話要宣告: class Thing::Create < Trailblazer::Operation builds -> (params) { dispatched_class_accroding_to(params) } def self.dispatched_class_accroding_to(params) Thing::Create end include Trailblazer::Operation::Policy policy Thing::Policy, :create?
初探 Trailblazer 框架
最近公司的 Rails 專案試用了 Trailblazer 這套整理 Rails 程式碼的框架。(目前使用的是 1.1 版) Trailblazer 是擺在 Rails 上的一套工具,雖然有本專書可以翻找,但實際上就是個自成一格的整理程式碼套路,除了要學新的 DSL 外,在 API 文件沒有寫得非常詳細,加上使用者也沒多到可以 stackoverflow 的情況下,假如開發需求和設計者 Nick Sutterer 設想的情況不一樣時,小小撞牆是難免的。 Trailblazer 是模組化設計,所以並非所有模組需要安裝才能開始享受 Trailblazer 帶來的方便感,除了主要的 Operation / Policy / Contract / Cell 等稍微有摸過外,其他的眉眉角角尚待開發。稍微整理一下截至目前為止使用這套框架的個人認知,這套 Trailblazer 的目的是將原先 Rails 單純 MVC 架構下可能會散亂在 Controller / Model 層的商業邏輯,集中起來包在 Operation 的概念裡,(在理想狀況下)分別簡化日益肥大的 Controller / Model / View 邏輯: Controller 讓 controller 單純負責傳送 current_user / resource 到正確的 operation 並視操作結果導向相對應的路由 權限控管交給 Policy 處理,用 controller 塞給 operation 的 current_user 配合 operation 的 model!
筆記 | Practical Object-Oriented Design in Ruby (POODR)
Practical Object-Oriented Design in Ruby (POODR) 不會很厚,循序漸進地介紹物件導向設計的各種重要概念,而且範例用的是 Ruby 來解說,挺親切的。 除了各種設計原則之外,也簡要解釋了 Inheritance / Module / Composition 的使用時機與差異。 最後一章介紹測試原則,除了說明一般的測試原則之外(例如主要應測試 public interface / incoming message / outgoing command ),也很清楚地說明要怎樣去分別把不同的測試責任分在 module / test double / test class 上,以及讓 test double 與實際的程式碼同步的技巧,可以反覆閱讀的參考書。 Chapter 1 - Object-Oriented Design P.4 Practical design does not anticipate what will happen to your application, it merely accepts that something will and that, in the present, you cannot know what. It doesn’t guess the future; it preserves your options for accommodating the future.
利用 find_in_batches 在 Rails 做跨資料庫的資料移轉操作
在處理跨資料庫搬動並且需要一筆一筆資料去做各種運算處理時,最直覺的方式,是把表格裡的所有資料通通透過 ORM 撈到 ActiveRecord::Association 陣列裡,再用 each 去做操作: User.all.each do |user| user.email = "assign@new.email" ... end 但由於 Rails 會需要先去建立這些 objects,如果資料筆數很多的話,一次通通撈出來會佔用過多不必要的記憶體,可以使用 find_in_batches 做批次處理,減少系統 RAM 的負擔。 User.find_in_batches do |group| group.each do |user| user.email = "assign@new.email" ... end end 但如果要做跨資料庫的處理時,需要特別安插 ActiveRecord::Base.establish_connection 讓 Rails 知道當前操作需要連到哪個資料庫,舉例而言,假如想把資料一批一批從 :origin 調出來,然後檢查、編輯以後塞到 :migrated 資料庫裡,那麼需要在 Query 前去告訴 Rails 目前要連到哪個資料去撈資料: # Tell rails to get data from :origin ActiveRecord::Base.establish_connection :origin User.find_in_batches do |group| group.each do |user| # user variable here are the user object that Rails queried from :origin DB and initialed # Tell rails to switch connection to :migrated for data manipulation ActiveRecord::Base.
使用 Google Sheets API 拉資料到 Rails APP 裡
Google Sheets 很好用,一些程式中需要跨部門討論的字串定義,又或者是需要讓不方便存取原始碼的同事也能清楚知道原始碼裡部分設定字串的時候,通常都可以利用 Google Sheet 來做討論平台,再以 Google Sheets 上面的文件為基礎,匯入主程式中做各種處理,確保主程式的內容與 Google Sheets 上的內容同步。 要匯入 Google Sheets 內容到程式裡最簡單的方式,是輸出 csv 後寫個小 script 去讀取 csv 資料,轉成 Array 後就能靈活使用。 但若是開發過程當中常常要不斷更新 Google Sheets 欄位後再手動匯出 csv 跑 script 去後處理,這種半自動的方式還是令人覺得太過麻煩。可以考慮進一步用 Google Sheets API 去拉特定 Google Sheets 工作表資料,把半自動的「到瀏覽器視窗匯出 csv > 儲存檔案到特定資料夾 > 執行 script 完成匯入」簡化為「執行 script 完成匯入」。 首先到 Google API Console 申請一個可用的 API 身份,因為這隻 API 只要存取特定 Google Sheets 的內容,與其他 Google User 沒有互動,所以選用 Service Account 的授權方式就可以。 如果你的 Google 帳號之前沒申請過 Google API 的話,要先「建立專案」。