# 程式設計規範 ![](https://forthebadge.com/images/badges/made-with-kotlin.svg) ![](https://forthebadge.com/images/badges/powered-by-black-magic.svg) ## 目錄 :::success [TOC] ::: ## 檔案編碼 #### 所有來源檔案都必須以 UTF-8 格式編碼。 ## 命名方式 ### 檔案命名 如果來源檔案只包含一個 Class,則檔案名稱必須**區分大小寫**,並加上 `.kt` 副檔名。 其他情況下,請選擇**能說明檔案內容的名稱**、套用**首字母大寫**拼法,並加上 `.kt` 副檔名。 <br> ### 變數與函式命名 變數、函式的字元一般使用英文或數字,特殊符號$_,不可數字開頭,可以包含拉丁字母或是中文 (合法的 unicode 字元,只是不會這樣用),但不可是保留字 ( reserved word)。 <br> > 在撰寫函式時,請使用 Snake Case 命名法。 ``` kotlin fun calculate_area_of_rectangle(length: Int, width: Int): Int { return length * width } ``` <br> > 在撰寫變數時,請使用 Camel Case 命名法。 ``` kotlin val numberOfApples = 10 val userName = "JohnDoe" var totalAmount = 100.50 ``` <br> ***以下為錯誤示範*** ``` kotlin // 合法,但不會使用的 val ಠ_ಠ = 1 val 測試 = 1 val _ts12et$ = 1 // 不合法的 val 1test = 1 // 不能以數字開頭 val @test = 1 // 不能包含特殊字符如@ val break = 1 // 不能使用保留字 ``` <br> #### 變數命名參考手冊 1. 不要使用長度超過50字元的變數,太長的變數會使程式碼可讀性降低,在清楚表達的前提下,名稱越短越好。 2. 變數的組成應為多個形容詞、名詞組成,避免使用單一動詞當作變數,如create = 1。 3. 區分單複數,例如: user是單數,users、userArray、userList、userCollection是複數。 4. 不要加入無意義的前綴,如: m_name,這寫法通常代表一個 class 下的成員變數(member variable) name,一個class底下的 name 只可能是成員變數,使用 name 即可。 5. 盡量不要使用無意義的單字,data、temp、value、等干擾詞,若是遍及整份程式碼,會掩蓋了具有意義的單字。 6. 使用可以發音的單字,在溝通時若選用難以發音的單字,就會增加溝通的難度。 7. 若要使用無意義的單字或是單個字母如: i, j, data 等,要確保變數的作用域在短行數的程式碼內,如 for loop 或一個 if block,當變數的作用域越廣則須越長的名稱清楚地描述該變數的意義,名稱的長度應與作用域範圍大小成正比。 8. 使用英文單字而不是類似中文拼音的方式或是自創的單字,如 biaoGe(中文拼音的表格) 。 9. 使用有意義或公認的縮寫而不是只有少部分人才懂得縮寫,如果不是就應該使用全寫。公認的縮寫像是 id (identity)、int (integer)這類,不好的縮好像是 order system 裡面的 user 簡寫成 os_user 或 soUser,比較好的是system_order_user或 systemOrderUser。 10. 選擇好一個單字就使用到底,如: 使用了 user 中間就不要換成 member,當定義一個動作為 get,就不要換成 fetch 或 retrieve等同義字。 11. 使用正確的資訊專業術語,如某種演算法或是 Factory、Interface,看程式碼的人都具有專業背景,使用專業術語更能清楚表達,若使用錯誤將產生極大的混淆。 12. 在命名時,應注重可搜索性,開發上很難避免搜尋變數,若是將大量的變數命名成 data,即使不衝突也會造成搜尋上的困擾。 13. 標示變數的相關訊息可幫助了解變數的狀態,例如: boolean 的變數取名為 isLogin,是 object 的變數取名為 userObj,是 array 的變數取名為 userList或是 userArray,比起 users 要清楚一點,相關訊息並不是指型態,所以不會出現 userString 或是 strUser 等。 14. boolean的變數可使用 is/has/can + 名詞或形容詞或 enable/disable + 動詞,以表達行為,如:isUser、hasName、canSignup、hidden、available、enableOrder、disableUpate,若是 function 返回 boolean值可在前面加check,如: checkHasName()、checkIsUser()。 <br> ## 排版 ### 大括號 大括號遵循以下的規則 * 左大括號前面不換行。 * 左大括號後面換行。 * 右大括號前面換行。 * 「僅在」右大括號終止陳述式,或終止函式、建構函式或「已命名」類別的主體時,才在右大括號後面換行。例如,如果右大括號後面有 else 或半形逗號,則「不」換行。 ``` kotlin if (string.isEmpty()) { return } else { doLotsOfProcessingOn(string, otherParametersHere) } ``` <br> > 不超過一個 else 和僅占一行的 if 運算式,不需要大括號。 ``` kotlin if (string.isEmpty()) return val result = if (string.isEmpty()) DEFAULT_VALUE else string ``` <br> > 所有 if、for、when、do、while 陳述式和運算式需要大括號,即使主體為空白或只包含單一陳述式也一樣。 ``` kotlin if (string.isEmpty()) return // 錯誤 if (string.isEmpty()) { return // 正確 } ``` ``` kotlin if (string.isEmpty()) return // 錯誤 else doLotsOfProcessingOn(string, otherParametersHere) if (string.isEmpty()) { return // 正確 } else { doLotsOfProcessingOn(string, otherParametersHere) } ``` <br> ### 縮排 程式碼的欄限制為 100 個字元,超過皆需換行。 > 每當新區塊或區塊式結構開啟時,縮排才會增加四個空格。區塊結束後,縮排會回到先前的縮排層級。縮排層級會套用至整個區塊內的程式碼和註解。 ``` kotlin fun main() { val x = 10 if (x > 5) { println("x is greater than 5") } else { println("x is not greater than 5") } } ``` <br> > 每個陳述式後面都要換行。請勿使用分號。 ``` kotlin println("Hello, world!") val x = 10 val y = 20 val sum = x + y println("The sum of $x and $y is $sum") ``` <br> > 在大括號的前後,for、while、if 等判斷式的左小括號前、右小括號後,以及運算子前後需要空格 ``` kotlin // 錯誤 for(i in 0..1){ } // 正確 for (i in 0..1) { } ``` ``` kotlin // 錯誤 }else { } // 正確 } else { } ``` ``` kotlin // 錯誤 val two=1+1 // 正確 val two = 1 + 1 ``` <br> > 以下例外符號不需要空格 ``` kotlin // 錯誤 val toString = Any :: toString // 正確 val toString = Any::toString ``` ``` kotlin // 錯誤 it . toString() // 正確 it.toString() ``` <br> ## 函式設計方法 ### 行數 function 的大小應盡量短小且做一件事 (或是說承擔一個職責),超過200、300行的 function ,不僅影響可讀性也影響可維護性,長度盡量不要超過50行。 只有一行的 function 也很常見,只是不要一味的拆分 function 成零碎的程式碼,把每一行都拆一個 function 顯然是錯誤的做法,因為 function 必須做完一件事。 <br> ### 參數 太長的參數被稱為 Long Parameter List,建議 function 傳入的參數不要超過3個。 ``` kotlin fun saveUserInfo(name: String, address: String, phone: String, email: String, identity: String) { // 函數內容 } ``` <br> 可以選擇新增一個 class 後,再把 class 傳入 function ``` kotlin class User( private val name: String, private val address: String, private val phone: String, private val email: String, private val identity: String ) fun saveUserInfo(user: User) { // 函數內容 } ``` <br> ### 抽象化 何設計好的 function ,必須要讓 function 只做一件事 #### 容易做多件事的 function * 行數太多 * 將動作用 and 分離,例如: getAndSave()、divideAndConquer() * 傳入 boolean ,例如: 傳入 canSave 參數,去分離兩個可以save跟不能save的操作。 <br> ### 保持純函數 > 意指相同的輸入,永遠會得到相同的輸出,而且沒有任何顯著的副作用。 副作用指當你調用一個 funciton 的時候,會改變整個系統的狀態,如全域變數、資料庫、檔案系統、輸入參數。 pure function 利於測試,也可以關注在 return 值上面。實際開發不可能完全保持純函數,有副作用的 function 只能盡可能的少。 <br> ## 參考資料 https://developer.android.com/kotlin/style-guide?hl=zh-tw https://medium.com/%E7%A8%8B%E5%BC%8F%E6%84%9B%E5%A5%BD%E8%80%85/%E8%AE%8A%E6%95%B8%E5%91%BD%E5%90%8D-f53cd1115076 https://medium.com/%E7%A8%8B%E5%BC%8F%E6%84%9B%E5%A5%BD%E8%80%85/%E5%9F%BA%E7%A4%8E%E4%BD%86%E4%B8%8D%E7%B0%A1%E5%96%AE-%E4%BD%BF%E7%94%A8function-a3f6561cc9bd