chapter 1.
four parts of a method
- collecting input
- performing work
- delivering output
- handling failures
chapter 2.
1. We must identify the messages we want to send in order to accomplish the task at hand.
2. We must identify the roles which correspond to those messages.
3. We must ensure the method's logic receives objects which can play those roles
第二張 performing work
在講說
method裡面要做的事情
要定義好說
要傳遞的訊息是什麼(Message) 以及 誰接收這個訊息(Receiver Role)
def import_legacy_purchase_data(data)
purchase_list = legacy_data_parser.parse_purchase_records(data)
purchase_list.each do |purchase_record|
customer = customer_list.get_customer(purchase_record.email_address)
product = product_inventory.get_product(purchase_record.product_id)
customer.add_purchased_product(product)
customer.notify_of_files_available(product)
log_successful_import(purchase_record)
end
end
chapter 3.
3.2 Use built-in conversion protocols
If we want to provide maximum leeway in input, we can use explicit conversion methods like #to_i. If we want to provide a little exibility while ensuring that client code isn't blatantly mis-using our method, we can use an implicit conversion such as #to_int
3.3 Conditionally call conversion methods
在講說 有時候輸入的參數 要確認型別時 就條件式的轉換
她有這種型別方法的時候 就轉換
可能可以有好幾種型別 都沒有的時候就報錯
3.4 Define your own conversion protocols
建立自己的轉換型別的方法
3.5 Define conversions to user-defined types
定義好轉型的方法
主要方法接收參數時 只接有此轉型方法的參數
其餘的要報錯誤
3.6 Use built-in conversion functions
用最大的力量來轉型
3.7 Use the Array() conversion function to array-ify inputs
當參數需要是array時 用Array(參數) 先來強制轉型
3.8 Define conversion functions
建立一個idempotent的方法 強制轉換, 中間可能包含多種的轉換 不過結果就是出來一種型態
當我們需要某一個型態的時候 都用這個方法來強制轉換
3.9 Replace "string typing" with classes
當傳入的參數是string 而且方法裡面有很多case when的時候
試著把傳入的參數 變成有意義的物件
3.12 Reject unworkable values with preconditions
在preconditions就把一些需要的檢查做掉 還有需要使用到的變數轉換
3.13 Use #fetch to assert the presence of Hash keys
用fetch來判斷hash有沒有哪些key值
3.14 Use #fetch for defaults
用fetch來判斷default值
用block來當做參數 丟入fetch
If we had used the block form, the expensive computation would only have been triggered when it was actually needed.
3.15 Document assumptions with assertions
接外部可能會變動的api時
要再接的時候 針對每個參數 做處理檢查 一有不同 就要報錯
ex: hash要用 fetch確保參數都有, 型別轉換也要不是這個型別的話 就要報錯 Kernel#Float
amount = transaction.fetch("amount")
amount_cents = (Float(amount) * 100).to_i
3.16 Handle special cases with a Guard Clause
特別case的處理時 可以放在方法的最上方 當發生時 就導去別處
而不用因為用到if else 導致程式的結構不好閱讀
方法裡面主要就放常常發生的case
3.17 Represent special cases as objects
特別的case處理時 如果這個case再很多地方用到
可以用一個特別的class來處理他
例如current_user, 可以有一個特別的class => GuessUser 來代表沒有current_user的情況
3.18 Represent do-nothing cases as null objects
有時候會有一些要判斷是不是nil的情況時
可以用一個null object來處理 就不用寫很多if來判斷是不是nil
但是在null object裡面 log要寫好 不然有一些錯誤永遠不會發現
class NullObject < BasicObject
def method_missing(*) end
def respond_to_missing?(name) true end
def nil? true end
def ! true end
end
3.19 Substitute a benign value for nil
當nil的情況 是要走另一種情形 不會導致錯誤, 給他一個有意義的值
3.20 Use symbols as placeholder objects
當nil的情況 會導致錯誤時
給他一個有意義的symbol來報錯 會比較好debug
3.21 Bundle arguments into parameter objects
當兩個參數一定是要一起出現時 用一個物件把他包起來
當有if的情況出現時, 看是不是可以在refactor
3.22 Yield a parameter builder object
後面看不太懂
3.23 Receive policies instead of data
可以用block的方式 來做錯誤處理
def delete_files(files, &error_policy)
error_policy ||= ->(file, error) { raise error }
files.each do |file|
begin
File.delete(file)
rescue => error
error_policy.call(file, error)
end
end
end
4.1 Write total functions
當回傳的形態是array時
不管任何情形都要回array
4.2 Call back instead of returning
有時候用callback來取代回傳直會更好
用callback有時能更明顯的表達出這個function在做什麼
command-query separation (CQS). CQS is a simplifying principle of OO design which advises us to write methods which either have side effects (commands), or return values (queries), but never both
4.3 Represent failure with a benign value
不要用nil回復失敗的情況
用個有意義一點的值
4.4 Represent failure with a special case object
錯誤case時用特別的物件來回
反正不要nil就是了
4.5 Return a status object
當回傳情況有多種時 可以用一個新的狀態物件來回傳
4.6 Yield a status object
一樣用callback 可以讓function更清楚的表達她是要做什麼
callback是一個狀態物件的各種處理情形
就可以知道回傳的各種情況 是怎麼處理
4.7 Signal early termination with throw
用throw和catch來提早結束某些情況
5.1 Prefer top-level rescue clause
用top-level的rescue
5.2 Use checked methods for risky operations
還是用block的方式 傳入錯誤的時候要怎麼處理
5.3 Use bouncer methods
在用另一個方法 來包裝錯誤處理完後 要回傳的東西