iOS App 程式開發

Function Naming 指南:適當為函式命名 讓程式碼更簡潔清晰

Function Naming 指南:適當為函式命名 讓程式碼更簡潔清晰
Function Naming 指南:適當為函式命名 讓程式碼更簡潔清晰
In: iOS App 程式開發, Swift 程式語言
本篇原文(標題: Function Naming in Swift)刊登於作者 Medium,由 Pablo Villar 所著,並授權翻譯及轉載。

在本篇教程中,我們將探討一個在編寫函式時經常遇到的問題:我該如何命名這個函式呢?

雖然這個問題看起來很簡單,但作為軟體開發人員,適當地命名函式對我們職涯非常重要。下文我們將會看到,適當地命名函式可以讓 code base 更清晰、更易於使用。

簡潔 API 的重要性

如果你要使用第三方套件中的函式,比如說要創建 FancyLabel,你會選擇以下哪個方法來命名函式?

// A
static func makeLabel(withTitle title: String) -> FancyLabel
// B
static func configure(_ text: String) -> FancyLabel

你覺得哪一個比較適合?A 還是 B 呢?

如果你還在猶豫,這邊給你一個線索:我會選擇 A。

那我為甚麼選擇 A 呢?

首先,讓我們分析一下為甚麼選項 B 不好,因為選項 B 沒有標示我們實際上在配置甚麼。這是一個已經存在的物件嗎?還是函式會創建一個新的物件?它會回傳一個新的物件嗎?這邊也沒有標示它所期望的 String 含義是甚麼。我們只能從中知道,它會收到一個 String,並回傳一個 FancyLabel,但我們無法並知道它的作用,從而導致意義模糊和資訊不足,而這是應該避免的。

另一方面,選項 A 則明確表達了下列三項資訊

  • 函式需要甚麼來運作  ── 一個 Title
  • 函式用來做甚麼   ──  生成一個 Label
  • 函式結果是甚麼   ──  一個被創建的 Label
注意:我們關心函式會做甚麼(或應該做甚麼),而不是如何做那件事。我們不關心函式的內部工作原理,這就是封裝的運作方法。

只要這三個資訊明確標示,這個函式的使用就會變得非常自然,因為我們可以知道函式的用處,而不會產生誤解,就是這麼簡單。

看看如何調用這些函式,就會更清楚哪個方法比較好:

let labelA = FancyLabel.makeLabel(withTitle: "Hello world") // clear
let labelB = FancyLabel.configure("Hello world") // not so clear

現在,如果我們將這個範例轉換成一個真實專案,由多個開發人員參與開發,你會選擇如何為函式命名?而你又會希望同事如何為函式命名?選項 A 還是 B?

你可以這樣想:每次你定義一個函式時,其中也是在定義其他人將來會使用的接口。即使函式是私有的、即使你認為其他人不會用到函式,讓它保持簡潔還是很重要的,因為開發人員隨時都有可能需要處理專案中各類別的內部程式碼(包含你自己),但你永遠無法預計。

總而言之,如果你花點時間去命名函式,清楚標示它們的輸入 (input)、輸出 (output)、和用途,那麼當其他人需要調用你的函式時,就可以節省很多時間,他們不需要運行就可以理解程式碼。透過這種方式,我們可以節省時間,並避免可能導致錯誤的誤解。在程式碼中清晰定義接口,可以讓 CodeBase 更易於處理、使用、構造、和維護。

你花於思考函式名稱起一分一秒,都是值得投資的。

Swift 的函式簽章 (Function Signature)

Swift 從 Swift 3.0 開始,與 Objective-C 相比,最根本的變化就是 Function Signatures 的運作方式。從那個版本開始,Swift 不僅更簡潔,而且更加清晰。

我們來看一個例子:

dateLabel.text = [formatter stringWithDate: [[Date alloc] init]]];
dateLabel.text = formatter.string(with: Date())

我們在這裡看到兩個主要差異。首先,在第一種情況之下創建 Date 實例更加冗長,儘管只是因為 Objective-C 語法比較冗長。另外,我們可以觀察到,除了許多額外的括號外,Objective-C 函式還包含一個 Swift 沒有的額外單詞 ── Date。

這種細微卻有效的改變,其實可以歸功於 Swift 中類型的靜態特性。在 Swift 函式中,你無法傳入另一個不是 “Date” 的物件,因為編譯器不允許開發者這樣做。

這個改變很簡單,但它為 Function Signatures 的新世界打開了大門。一般來說,程式碼閱讀起來會更加輕鬆,因為它更簡潔,更像口語。

如上所述,下一步就是修剪 Functions Signatures,藉此讓函式變得簡潔而清晰,避免含糊不清。

修剪法 (Pruning)

最後,讓我們分析不同 Functions Signatures 的範例,並看看我們如何通過修剪 ── 也就是刪除一些贅字,使函式看起來更好。

// Signature
func moveView(view: UIView, toPoint point: CGPoint) { ... }
// Usage
moveView(view: headerView, toPoint: .zero) // ⚠️ long and redundant

我們可以把它改成:

// Signature
func move(_ view: UIView, to point: CGPoint) { ... }
// Usage
move(headerView, to: CGPoint.zero) // 👏 clear and concise

多虧了靜態類型,我們無須指明我們正在 Function Signature 中移動一個視圖物件。由於函式要求一個 UIView 物件,你可以唯一可以傳入的就是這種物件, 就像 point 一樣。

但這也有例外,你仍然需要指定參數的內容,因為它的類型可能不足以描述它。

// Signature
func makeButton(withTitle title: String) -> UIButton { ... }
// Usage
let button = makeButton(withTitle: "Function Naming") // 👍 good

讓我們看看在這裡進行修剪時會發生甚麼事:

// Signature
func makeButton(with title: String) -> UIButton { ... }
// Usage
let button = makeButton(with: "Function Naming") // 👎 not clear

發生這種情況,是因為類型 (String) 與內容的語義 (title) 不完全匹配。因為除了 title 之外,String 還可以表示許多其他內容。

在這種情況下,我們可以有兩種方法可以解決。如上例中的第一部分所示,我們可以把參數名稱改得更明確,藉此指定內容的語義。或者,我們可以創建一個更具體地描述語義的新類型,並用那個新類型為參數;在該範例中,我們就可以一個創建 Title Type 來管理 title。最理想的情況是後者,因為你從靜態類型系統中能夠獲得更多優勢,程式碼亦會變得更加安全。針對這個目的,我建議你學習更多關於 phantom typestagged types 的技巧。

總結

  • 雖然為函式命名是很難,但是投入的時間是值得的,這樣可以減少了誤解,讓其他開發人員或你自己,無須看完所有程式碼的運作,都可以理解一個函式的作用。所以,花點時間來命名函式吧
  • 利用靜態類型的優勢,使 API 更清晰簡潔。
  • 與你的同事分享這知識,並積極實踐。
  • 練習!練習!練習!

請記住,一個函式應該能清楚表達這三件事:

  • 它需要甚麼  ── 輸入
  • 它在做甚麼  ── 描述過程而不暴露內部工作
  • 它將回傳甚麼  ──  輸出

謝謝你的閱讀。希望本教學指南對你有用,歡迎你在評論中分享你的經驗和意見。如果你覺得本文實用,請和你的朋友分享。

本篇原文(標題: Function Naming in Swift)刊登於作者 Medium,由 Pablo Villar 所著,並授權翻譯及轉載。
關於作者:Pablo Villar,一位不斷學習、追求 Clean Code 的 iOS 和 SwiftLang 開發者。
譯者簡介:陳奕先-過去為平面財經記者,專跑產業新聞,2015 年起跨進軟體開發世界,希望在不同領域中培養新的視野,於新創學校 ALPHA Camp 畢業後,積極投入 iOS 程式開發,目前任職於國內電商公司。聯絡方式:電郵 [email protected]

FB : https://www.facebook.com/yishen.chen.54
Twitter : https://twitter.com/YeEeEsS

作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。