這不是一篇寫命名要有什麼規則比較好的文章,而是整理了我所認同的命名“用詞”“邏輯”

不是要討論 fooBarfoo_bar 哪個比較好,而是告訴你為什麼不要寫一個函數叫做 disappear() 來隱藏一個物件。

我並沒有看過非常多關於程式碼風格的文章或是書籍,

這些都是以我的開發經驗去寫出來的,想從我個人原始的觀點去整理命名邏輯這回事。

因為我最近期的專案是遊戲開發,所以這篇的舉例都會以遊戲開發來舉例,但是放在其他領域也是行得通的。


動詞;名詞;形容詞

我在我參與過的專案,發現易讀的程式碼,通常都有這些特性:

函數的名字通常是動詞開頭的

寫一個 statement 就像是寫一個句子,敘述(state)一件事情發生。

而句子裡會有什麼?主詞動詞

在物件導向程式語言裡面,呼叫一個函式就像是寫一個完整的句子,也有主詞跟動詞:

1
2
// 玩家移動
player.move();

物件就是主詞;函數就是動詞。

如果動作有 受詞 ,那就是在 參數 裡:

1
2
// 玩家拿道具
player.pick(item);

一個易讀的敘述,讀起來就像個句子一樣。

變數通常是個名詞

一般來說,變數會出現在哪裡呢?

函數的前面、參數,或是單純的表示式(expression)

以一個句子的結構來說,就是 主詞 或是 受詞 的概念。

主詞或受詞,就是 名詞 了!

但是也是有例外的:

布林的變數、Getter、Setter 通常是個形容詞

或是isSomething

看到一個非形容詞的布林值,通常會讓我很頭痛:

1
player.die // 看起來像是個函數,結果是個布林變數

如果用

1
2
3
player.alive
// 或是
player.isAlive

就清楚多了!

畢竟 alive 只有 is alive 或 is not alive 嘛。

disappear() 怎麼了嗎?

我在參與的專案中看到了這個函數的命名:disappear(),用來隱藏一個物件。

怎麼了嗎?好像可以看出他是幹嘛的,但又覺得怪怪的

問題出在哪裡?

第一次看到這個函數時,可以有幾種解讀:

  1. 當呼叫函數時,物件就會消失。
  2. 當物件消失時,就會呼叫這個函數,做接下來要做的事。
  3. 或也許是個看他是否已經消失的getter?

沒有錯,disappear 的確是個動詞,但是他有一個問題:

disappear 是個 “我們看到了事情的發生,再把事情重新敘述出來時會用到的動詞”,也就是以 第三人稱 的角度來使用的動詞。

如果換成第一人稱會是什麼?我想是 Hide

看到 player.hide() 就會很清楚這個函數的用途了。

用文字來解讀的話看起來就像是:

1
player.hide(); // 隱藏玩家

而不是:

1
2
3
player.disappear(); // 玩家消失“了“

// 到底是要讓他消失,還是描述消失之後要做的事呢?

搞清楚主詞到底是誰

有時候在想寫一個處理角色被攻擊時,會不小心寫出 hit() 這種函數。

敵人的程式碼長這個樣子:

1
2
3
4
5
class Monster {
function attack(player) {
player.hit();
}
}

乍看之下沒什麼問題,

但單獨看Player的程式碼時,會覺得這個函數是不是要拿來 攻擊別人 用的。

我認為函數不只要是動詞,還要是”主動式“,不能是”被動式“

有種很常見的事件命名是加上 on 前綴,在這裡就是 onHit

感覺很清楚他是一個事件了,但我在前一個專案看到一個更清楚的寫法:

handle 前綴,handleHit

寫了個 處理 在動作前面,也就隱含了他是一個外來的動作了,而且也符合動詞的原則。

畢竟自己做的動作,就做了嘛,何必處理呢⋯

命名時就表示好“它”到底是什麼東西

你有沒有曾經發生過,想要更改UI元件上的文字:

1
postTitle = '安安您好';

就發生了錯誤:
Error: Cannot convert type String to Label

原來,postTitle 是一個 Label ,所以要寫成:

1
postTitle.text = '安安您好';

浪費時間!

一開始就把這個東西命名成 postTitleLabel 或是 labelPostTitle 就不會有這種誤會了。

我認為 一個項目的命名應該“清楚表示”它是什麼東西,而不是只是讓你在撰寫時能“分辨”它而已

不要縮寫!

這應該就不用多說了,使用縮寫雖然寫起來爽快大部份時候又看得懂,

但還是要顧及其他開發者與一個月後的自己的感受啊!

不必要的前綴,累贅!

當朋友問你你在哪裡的時候,你會怎麼回答?

當你們在不同縣市:

我現在在台北!

當你們在同個縣市:

我在信義區附近。

然後再接著說下去⋯

在寫地址時你也不會寫:

台灣台北市大同區…

郵差看了只會滿頭問號而已。

有時候我會看到在 Player 的 class 底下還用 player 前綴的狀況:

1
2
3
4
5
class Player {
playerName = 'Martin Garrix';
playerHealth = 100;
// ...
}

不必要的前綴,就去掉吧。

寫一篇會描述自己的程式碼

有些人主張程式碼就是要把註解寫好寫滿,這樣才不會日後不知道自己在寫什麼。

但我的看法完全相反,我認為除非你在寫測試、底層的程式或是在寫一些黑魔法,

不然寫越多註解越代表你的程式碼無法描述自己在幹什麼

如果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Player {
camera;
position;

constructor() {
this.setupCamera();
this.resetPosition();
...
}

function setupCamera() {
this.camera = new Camera();
this.camera.parent = this;
}

function resetPosition() {
this.position = new Vector3(0, 0, 0);
}
}

變成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Player {
// 玩家的 Camera
cam;
// 玩家的位置
playerPos;

constructor() {
this.firstRun();
}

// 第一次執行時才會呼叫這個函數,這個函數會創造camera放到player的子層然後把player移到原點....
function firstRun() {
// 創造一個攝影機
this.cam = new Cam();
this.cam.parent = this;
// 把Player移到原點
this.playerPos = new V3(0, 0, 0);
// ...
}
}

// 攝影機
class Cam {
// ...
}

// 三維向量
class V3 {
// ...
}

那看了會有多痛苦啊!

想像一篇文章裡充滿了

(這下面這段在寫一些關於x跟y到底在案發後發生了什麼事。t是湯姆,而l就是莉莉。)
某件事情之後
t驚慌失措地跑向了l,並向l說明了某件事情。l嚇。

這種鬼東西,那讀者有多可憐呀!

寫一篇會描述自己的程式碼吧。


這是我第一次寫關於程式風格的文章,也許還有許多盲點,請多多指教了。