良好程式碼的優點大同小異。
不好的程式碼的糙點卻各有巧妙之處。
這次來介紹一個有趣的物件,叫 God Object[1]。
任何問題找他就對了。這種全知全能的物件,就被稱為 God Object。
為了避免程式碼外洩,我們只看 minimap
這段程式碼,總共有 755 行。
minimap 大概只顯示 200 行。
可視區一次顯示 30 行。
而且這是三位一體,基督教的三一真神[2]呀!!!
(三個 GodObject 互相呼叫的架構。)
後端從 route 來之後,會依序經過這三層
以刪除成員為例!!
此程式碼已經修改成 js 的實作。(原本不是)
kernel
class serviceKernel {
//...
delMember(req, res) {
res.body = {
returncode: 0,
returnMessage: ""
};
let input = new serviceImplement.DelRestoreMemberData();
let output = new serviceImplement.BaseResultData();
input.Id = req.body["id"];
input.Version = req.body["version"];
serviceImplement.processDelMember(input, output);
res.body["returncode"] = output.returnCode;
res.body["returnmessage"] = output.returnMessage;
}
//...
}
implement
class serviceImplement {
//...
processDelMember( filter, resultData /*out*/ ) {
let execute_result_code = serviceTransactions.processDelMember(filter, resultData);
if ( execute_result_code != SUCCESS ) {
console.log(execute_result_code)
}
resultData.returnCode = execute_result_code;
resultData.returnMessage = getErrMessages(execute_result_code);
}
//...
}
Transactions
class serviceTransactions {
//...
processDelMember(delFilter, resultData) {
let result_code = SUCCESS;
let db_emp_list = database.employee.getDataset({
id: delFilter.id
});
if(!db_emp_list.length) {
result_code = ID_NOT_EXIST;
return result_code;
}
else if( db_emp_list.length > 1 ) {
console.log("DATABASE_DATA_FAIL");
console.log("Database have two the same record or more in database.employee");
console.log("id: " + delFilter.id);
result_code = DATABASE_DATA_FAIL;
return result_code;
}
let PARAM = database.employee.id;
let db_sys = database.systemParameters.getData({
sectionId: 'admin',
targetParmeter: 'id',
targetValue: delFilter.Id
});
if( !db_sys ) {
result_code = DISALLOW_DELETE_ADMINISTRATOR_ACCOUNT;
return result_code;
}
let db_emp = db_emp_list.shift();
db_emp.modifyDate = new Date();
database.save();
return result_code;
}
//...
}
在 serviceKernel
, serviceImplement
, serviceTransactions
三個 class 中,是把所有的 API 通通放進去當作 function 。
若是用 express 的架構來反思 God Object 其實是不需要的,因為它的 docs 裡介紹的 function 沒有屬於任何的 object 而在此介紹的範例有。
這是什麼樣的糙點呢?
請再回頭仔細看看,這所謂的三層之間的責任是什麼呢?各別做了什麼事?
再想想,什麼是 MVC 架構?
組合語言 演進成 C 語言 的時代,是不是就是把邏輯分類呢?
在這樣的 God Object 產出,原因多半是開發者沒有仔細了解這個程式架構中,有什麼概念是保有完整性的呢?換句話說,有什麼「主詞」可以先被抓出來。
在一個後端中,最重要的主詞是 API。每一個 API 都應該是一個抽象,它有它自己的邏輯。
另外,如果有接資料庫的話,每一個 Table 也有一個自己的邏輯和資料。(ORM 的概念)
所以,後端出了兩個主詞: 「API」、「Table」
class api {
//...
}
class table {
//...
}
這樣要怎麼寫呢?
換一個樣子來看看。
class controller {
//...
}
class model {
//...
}
這樣有沒有和 MVC 有呼應到了呢?
在這個時代,前端依然有在分類邏輯,而且,不這麼做就 GG 了。
「前端框架是以資料驅動的方式設計而成。」
這是什麼意思呢?
資料,有資料的邏輯,靠開發者撰寫。
畫面,有畫面邏輯,由資料決定,資料與畫面之間的邏輯,由開發者撰寫。
這樣要怎麼寫呢?
換一個樣子來看看。
vuex 存放資料,vuex 的邏輯放在 action 裡,透過 mutation, getter 存取 store 的資料。
components,有 components 的邏輯,由資料決定,開發者透過 v-if
, v-for
...語法完成資料與畫面的邏輯。
其實前端早就正在進行邏輯的分類了。
一直以來,我沒有寫過這樣的物件。但是一直聽說它的存在。
尤其是在 Java 的世界。原因在於有些類似 middleware 的工具需要存在,但不屬於誰,就放在 Helper Object 中。
但是,我個人覺得,這個一個也許不用存在的物件。但是幫他分類有時太花心思,不過,如果不分類新人接手怎麼會知道裡面的「巧妙之處」呢?
[1]: God object
[2]: 三位一體
[3]: MVC - 維基百科,自由的百科全書