---
# System prepended metadata

title: 乾淨的函式(Clean Functions)
tags: [Note, Clean Code]

---

# 乾淨的函式(Clean Functions)
:::info
函式是編寫大部分代碼的地方
:::

內容：
- 參數
- 長度
- 抽象層級
- 切分函式

## 函式
- 函示聲明
    - 簡單
    - 易讀
    - 需要設計參數編排順序
- 函式呼叫
    - 呼叫需要易讀

## 如何編寫乾淨的函式
- 最小化參數的數量(盡量不要超過3個)
    - 越少參數越好
    - 過多參數
        - 更難呼叫
        - 更難記
        - 更難理解
    - 減少參數的方法
        - 把幾個參數打包成一個參數(用容器(hashMap/dict))
        - 把參數打包成類,初始化後,使用類方法來調用(參數部分使用 self)
        - 拆分函式
- 避免輸出參數(特別是他們不可預期的時候)
    - 解法：
        - 使用 OOP (類) 來使之變得可預測
- 函式應該要精簡
    - 更易讀/理解
    - 如果函式過胖
        - 拆分
- 盡量不要混用不同抽象層級的代碼


:::info
拆分代碼有很多好處：
- 不臃腫
- 易讀/理解
- 讀者可以不必讀完所有代碼(透過命名得知內容)
- DRY (重複使用性)
:::


## 如何拆分函式
- 使用功能面來拆(抽象層級)
    - 每個函式都只會做一件事
- 使用經驗法則(rule 0f thumb)
    - 萃取做相同功能的代碼
        - ex. `user.setAge()` + `user.setName()` => `user.update({name:...,age:...})`
    - 萃取比周圍其他代碼需要更多解釋的代碼(有關抽象層次)
        - ex.


### 如何定義**一件事**
不同操作+不同抽象層級
![](https://i.imgur.com/qZxdKFm.png)

函式做他命名的抽象層級下一級的事(用低層級的任務完成高層級的要求)

:::success
高階函式名稱,也是用來解釋他內部所發生的所有低階操作
:::

![](https://i.imgur.com/S78Tsrh.jpg)

### 抽象層級 (需要經驗去判斷)
有相對的低階和高階
![](https://i.imgur.com/PTTQglS.png)

- 低階
    - 技術上較清楚表達如何實現
    - 可能需要解釋
    - ex. 語言內建 API
- 高階
    - 易讀
    - 不需要去解釋
    - ex. 自己寫的函式

## 盡量不要混用不同抽象層級的代碼
- 混用需要去讀/理解不同的步驟
- 不混用只需要去理解步驟
![](https://i.imgur.com/HQFvb9X.jpg)


## DRY (Don't Repeat Yourself) -> 不要重複自己的代碼
好處：
- 重構只需要修改一個地方

沒有達成 DRY 的跡象：
- 當你在複製貼上自己的代碼
- 你需要更改你代碼的多個地方

如何達成：
- 萃取相同邏輯/相同任務的代碼

## 過度拆分可能造成的風險
- 代碼過度顆粒化(顆粒化並不會增加可讀性,反而有可能讓代碼複雜化)

做出合理決定,在以下情況不要拆分：
- 如果你的動作只是把操作重命名
- 拆分後會需要花更多時間去閱讀
- 不能幫萃取的函式想出好名字

## 保持函式單純
函式單純性
- 相同輸入會獲得相同輸出
- 沒有副作用

不符合單純性：
- random

:::info
1. 有必要永遠保持函式的單純性嗎?
函式不單純並不是壞事
但會讓結果變得難以預測
因此應該只在必要的時候,破壞函式的單純性

2. 副作用
操作不只使用函式輸入值,並改變函式輸出值,還會改變整個系統/程式的狀態
ex. 
- startSession(user) -> 可能會改變外部狀態

副作用使用場景：
- starting session
- sending http request
- logging thing to console
- store thing in database

副作用並不全是壞的,但不可控的副作用應該避免
可以盡量用命名來完整表示：函式+副作用
並且函式的命名應該表達所有副作用,否則副作用可能變成不可控的副作用

:::

![](https://i.imgur.com/BZaJ9MM.png)
##
###### tags: `Clean Code` `Note`