Company Ghost Story 公司鬼故事 3

contents

  1. 1. Java
    1. 1.1. Setter/Getter
    2. 1.2. Inner/Anonymous Class
    3. 1.3. Long Name Method
    4. 1.4. Create Context
    5. 1.5. Create Context II
    6. 1.6. Create Context III
    7. 1.7. Create Context IV
  2. 2. Regression Test
    1. 2.1. Create Test Folder
    2. 2.2. Create Test Folder II

Java

Setter/Getter

1
2
3
4
5
6
7
class Parser {
X getX() {}
boolean x() {}
boolean readX() {}
void parseX() {}
void X() {}
}

Java 特性預設都是透過 setter/getter 的概念來完成成員變數的存取。為了擴充使用不建議直接存取變數。

這毫無設計的函數是發生甚麼事情?名字這麼像是想害死誰啊,而且還都是不同邏輯。

1
2
3
4
5
6
class Parser {
X eX() {}
boolean aX() {}
boolean sX() {}
void pX() {}
}

不是這樣子說完,就用奇怪的前綴解決。把整個動詞完整描述出來會讓你打字很痛苦嗎?

Inner/Anonymous Class

現在我們用一個指令去搜尋建立的 class files。

1
2
3
4
5
$ find ./bin -name "*\$[0-9]*.class"
xxxx$1$1.class
xxxx$64$1.class
...
xxxx$64$64.class

居然發現了非常非常多的匿名類別,而且還是爆炸性的嵌套。這意味者當改變一個 class 檔案時,編譯會一次可能產生上百個檔案。

1
2
3
4
5
6
boolean getToken() {
return new Token {
@Override
public String toString() { return "here we are"; }
}
}

這也是常常在調適函數時,不知道為什麼會有 IDE 崩潰的情況發生。其實都是上述的寫法氾濫,連帶的內存洩漏問題也很嚴重。事實上,大部分的匿名類別都可以額外地用功能去描述類別,請重新宣告並且命名好。

Long Name Method

1
2
3
void addXXXsToAdjacentYYYsSetSoItWillNotAAABBBWhereMMM();
void setXInDatabaseAAABBBField();

這種命名函數比惡名昭彰的匈牙利還兇殘,直接把文件描述寫在函數上,這時候又願意打字了。

請找個稍微中立一點描述方法,等到哪天換了連帶功能,所有相關函數都要重新做過。

Create Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boolean read() {
try {
readPartA();
externalCall();
} finally {
setCacheEnabled(true);
}
}
boolean readPartA() {
setCacheEnabled(false); // why not place it in read()?
...
}
// in external.xxx
java::setCacheEnabled(false); // what are you doing?
...
return true;

建立 context 的習慣是要寫在同一個檔案中,而且盡可能寫在同一個函數內。

跳來跳去,有時候只有下文,有時候只有上文,不覺得很可怕嗎?萬一中間執行失敗,直接萬劫不復。

Create Context II

1
2
3
4
5
boolean read() {
db.setDbCheckEnabled(false);
...
// where's your setDbCheckEnabled(true);, can I trust you more?
}

直接把所有重要檢查通通關閉,卻忘了開起來,直接出逃啦。

Create Context III

1
2
3
4
5
6
7
8
9
10
boolean read() {
try {
db.setDbCheckAEnabled(false);
db.setDbCheckBEnabled(false);
...
} finally {
db.setDbCheckAEnabled(true); // setDbCheckBEnabled() first, please
db.setDbCheckBEnabled(true); // setDbCheckAEnabled() last, please
}
}

大部分都不會錯,但建議採用堆疊的順序撰寫。因為有些保護機制會造成重複工作。

Create Context IV

1
2
3
4
5
6
7
8
9
10
11
12
boolean read() {
try {
db.setDbCheckAEnabled(false);
db.setDbCheckBEnabled(false);
...
db.setDbCheckBEnabled(true); // I don't know.jpg
...
} finally {
db.setDbCheckBEnabled(true);
db.setDbCheckAEnabled(true);
}
}

我不知道.jpg。

Regression Test

Create Test Folder

1
2
3
4
5
6
$ tree Regression/FunctionA
├─testBBBB
│ └─testCCCC
│ └─testDDDD
│ └─test.sh
...

為什麼需要前綴 test?請給我一個理由。

Create Test Folder II

1
2
3
4
$ tree Regression/FunctionA
├─DoNotThrowNoSuchElementException
│ └─test.sh
...

如果是預期丟出錯誤的測試就算了,但錯誤的實例也是會變動的,這樣的資料夾名字不具有太深遠的意義。