良好程式碼的優點大同小異。
不好的程式碼的糙點卻各有巧妙之處。
Photo by Alec Foege on Unsplash 使用巨石陣圖是對《人月神話》, Ch15 致敬
你是否知道,眼前的這一切是什麼作用?
你再用心、再用力一點,花點心思,是否可以看出一點端倪
沒有任何說明,也沒有任何文件的高科技精品,也就就像現在人觀看古文明一樣,充滿待人解開的謎團。(以後問人家「你在寫什麼糙 code 」可以用「你怎麼做了一個巨石陣(或金字塔)」取代(誤))
很多糙點本身,其實是來自同事的才能,他有用心而不是不用心。但是用心的地方,總是充滿創意,只是難懂!難懂就會讓人覺得糙,這種心思不被懂,雙方都無奈呀
這是一個來自 1988年 第五屆 國際混碼大賽的 westley 寫的[1]
#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
_-_-_-_
_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_
_-_-_-_
}
它的它的美好,但是請止於研究與自我滿足。
不要在協作時,展現這份美好
甚至於有日本人出書在介紹[2]
用文學來譬諭短碼,就像是華麗詞藻
別這樣,好嗎?
幫狗和貓...(假設有 n 種)類別加上跑步的需求
class Dog {
public:
int location;
Dog (const string& name): location(0) {}
// void run (int distance); <- 想要具備的功能
};
class Cat {
public:
int location;
Cat (const string& name): location(0) {}
// void run (int distance); <- 想要具備的功能
};
繼承,只有兩種使用方式,小心使用,以及禁止使用
繼承會增加程式複雜性
如果繼承符合 Liskov 替代原則 (LSP) 就可以降低因繼承而衍生的複雜性
--《Code Complete 2/e》, Ch6 Working Classes, 6.3 Design and Implementation Issues, Inheritance (“is a” relationships)
之前《Code Complete 2/e》的讀書會的討論中有個小小的精要心得:
is a
→ 繼承has a
→ 包含 (用 property)在這個例子,適因為想要的是 run()
所以適合使用繼承
用泛型 function
讓你們通通可以用泛型的「跑步魔法」來移動距離
template<typename Animal>
void run(Animal* animal, int distance) {
animal->location += distance;
}
main()
Dog *lucky = new Dog("lucky");
run(lucky, 20);
cout << lucky->location; //20
但是,這時應該使用父類別來繼承,利用物件導向的語意來實作會更適合。
這種情況,常見於資料表的操作,有些資料表具備某個共同的功能,就寫一個抽象到不行的來套用,完全不管語意的問題,這樣協作的伙伴,怎麼透過語言本身來了解這樣巧妙之處呢?
這就是就是華麗詞藻!!
就...C# 的用法。
和短碼一樣,這些都是屬於炫技的用法。而不是為了夥伴而寫的 code 。未來會讓你召來負面情緒,也是自己造的.....(XD)
這些要有適合的取捨,就要看開發者是否了解語法中,內含的語意與語言表達極限。
物件導向,不適合用來描述非同步問題,也許這樣的情況之下,才適合使用泛型或 delegate,而 JavaScript 將這兩個用法視為一般用法,反而不強調物件導向,原因也許是 JavaScript 天生就是為了非同步問題而生。
這指的是 C++ 的時候,常見的問題
有時,在 class 裡的 member variable,也沒有繼承關係,但是硬生生的就是用了 pointer 。其實,不用 pointer 也可以做到一樣的事情時,盡量別用 pointer ,在 C++ 中沒有垃圾搜集器,所以忘記 delete 就真的一直存在湯瑪森[4]了。
class A
{
int* m_ptr_i;
public:
A():m_ptr_i(new int()){
}
~A(){
delete m_ptr_i;
}
};
C++ 的初衷之一也是想要開發者隱藏 pointer 這個複雜度。
一般的宣告方式,變數會隨著類別啟動解構式時,自動消滅,這個特性可以用來隱藏一些「容易忘記」的相對做法。
例如:
寫硬體描述語言時,就有聽過
- 控制與運算要分開
- 控制和資料要分開
寫軟體時,就聽說更多的原則
- 資料和運算要分開
- 介面和運算分開
這麼說吧!
能用最簡單的語法表達,就用簡單的語法。
能拆分權責就拆分權責。
能寫成程式碼就不要用註解。
能少給權限,就少給權限。
再不行就常常 code review 吧!
高手同事說 ok 就是 ok 滴!!!! (好糙的標準!!)
[1]: 5th International Obfuscated C Code Contest, 1988 - westley.c
[2]: Short Coding 寫出簡潔好程式-短碼達人的心得技法
[3]: 教育讓作文變得矯情:真正的「語言癌」,在國中會考的答案卷上
[4]: 台北路上觀察學會, 【主題2】印象最深的觀察, 小知識 * 何謂湯馬森?
[5]: API Design for C++