良好程式碼的優點大同小異。
不好的程式碼的糙點卻各有巧妙之處。
一開始學習寫程式,有個還不會寫 function
的過程,常常出現一個 main 到底的程式碼。
//有一些變數宣告
var words = 'hello world';
//有一些程式碼執行
console.log(words);
後來,學了 function
就學會這樣的寫法
//有一些變數宣告
var words = 'hello world';
//有一些程式碼執行
function printHello() {
console.log(words);
}
printHello();
然後,覺得這很棒!!
相信很多人看到這個小小的例子,都可以看出一些糙點。
但是當它變成了大型程式,就看不出糙點了
它原本不是 js 的程式,為了避免侵權的問題,在此改寫成 js 的 code。
不影響它的糙點!
var gIniPath = `./config/app.ini`);
var gLogFile;
var gIniInfo;
var gIndicatorSettingDic = Map();
class myClass {
class IniInfo {/* ... */}
constructor () {
if (gIniInfo.CheckRepeatModule) {
// 避免重複執行
}
gLogFile = new LogFile();
gLogFile.readFile(gIniPath, "MsgLog");
gIniInfo = new IniInfo();
this.Exit = function () {
gAppEventBus = null;
gLogFile = null;
gIniInfo = null;
}
}
print () {
for (let [ key, val ] of gIndicatorSettingDic.entries()) {
console.log(key + " = " + val)
}
}
}
在 myClass
裡,其實並沒有真正做到模組化。這些 「g開頭」的全域變數,其實並沒有需要成為全域與別人「共用」(或「不小心會誤用」)
大多這麼寫的工程師,心裡面會想著「用起來方便呀」、「隨叫隨到的變數」、「不用思考怎麼把它傳進來」....等。
其實,很不好!
製造痛點!!
對寫 code 的人很開心,對用 code 的人不開心呀!!
var myObject1 = new myClass()
// 你知道它載入的是什麼設定檔嗎?
var myObject2 = new myClass()
myObject1.print();
myObject2.print();
// 你知道印出來會不會是同樣的內容嗎?
gIndicatorSettingDic = null;
myObject1.print();
myObject2.print();
// 你知道被清空了嗎?
以語法來說,是封裝不良的問題。
myClass
這個要載著什麼樣的概念,它會有什麼行為?以此例,myClass
需要載入 .ini
檔。
var myObject1 = new myClass(`./config/app.ini`);
var myObject2 = new myClass(`./config/app.ini`);
這樣就會知道,此物件要吃某個 config 檔。
又或者建構式提供一組預設值,再另外吃 config 也行
var myObject1 = new myClass();
myObject1.setConfig(`./config/app.ini`);
var myObject2 = new myClass();
myObject2.setConfig(`./config/app.ini`);
這樣一來,使用這一個 class
的開發者,就不會因為不良耦合的關係,心中浮現一句這樣的話
「誰知道!? 誰!? 誰呀!?」
「誰!?」
static
要小心使用有些程式語言可以將 static
用在變數上,讓它的生命週期跨越生死,永續保存。
這個要小心,不要濫用!!
以上述的 js 程式碼為例。
如果將所有的全域變數,搬到 myClass
裡,然後宣告成 static
而且,在 destructor
或 Exit
時,將這些變數變成 null
,就是原本「糙味加倍」的樣子。
原因在於,物件本身的生命週期可以利用,將變數變成區域變數,就不用擔心跨 myClass
物件之間存取相同的參考資料, myClass
不用時,也只需要靠垃圾收集即可。
[1]: 工程師心中最軟的一塊:談前端開發者體驗(Developer Experience)