發(fā)布于:2020-12-30 15:27:57
0
128
0
我同意這樣的說(shuō)法:“如果您不對(duì)舊代碼感到尷尬,那么您就不會(huì)成為一名程序員?!?我40年前開(kāi)始休閑地編程,而30年前開(kāi)始專(zhuān)業(yè)地編程,所以我犯了很多錯(cuò)誤。作為計(jì)算機(jī)科學(xué)教授,我鼓勵(lì)學(xué)生從錯(cuò)誤中學(xué)習(xí),無(wú)論是自己的,我的還是著名的例子。我覺(jué)得是時(shí)候照亮自己的錯(cuò)誤,使自己保持謙虛,并希望有人可以向他們學(xué)習(xí)。
第三名:Microsoft C編譯器
我有一個(gè)高中英語(yǔ)老師,他認(rèn)為羅密歐與朱麗葉不是悲劇,因?yàn)橹鹘莻儧](méi)有悲劇性的缺陷:他們愚蠢的舉動(dòng)是因?yàn)樗麄兪乔嗌倌?。那時(shí)我不喜歡該參數(shù),但是現(xiàn)在看到了它的真實(shí)性,尤其是與編程有關(guān)的事實(shí)。
在麻省理工學(xué)院大二畢業(yè)后,當(dāng)我在Microsoft的C編譯器團(tuán)隊(duì)開(kāi)始暑期實(shí)習(xí)時(shí),我既是少年又是編程少年。在完成一些艱苦的工作(例如添加對(duì)性能分析的支持)之后,我開(kāi)始進(jìn)行我認(rèn)為是編譯器最有趣的部分:后端優(yōu)化。具體來(lái)說(shuō),我必須改進(jìn)為switch語(yǔ)句生成的x86代碼。
我瘋了,下定決心要在我能想到的每種情況下生成最佳的機(jī)器代碼。如果大小寫(xiě)值很密集,我將它們用作跳轉(zhuǎn)表的索引。如果他們有一個(gè)共同的除數(shù),我將使用它來(lái)使表更密集(但前提是可以通過(guò)位移來(lái)完成除法)。當(dāng)所有值均為2的冪時(shí),我進(jìn)行了另一個(gè)優(yōu)化。
如果整個(gè)值集都不滿(mǎn)足我的條件之一,那么我將案例分開(kāi),然后遞歸調(diào)用代碼。
經(jīng)驗(yàn)教訓(xùn)
正如大衛(wèi)·帕特森(David Patterson)和約翰·軒尼詩(shī)(John Hennessy)在《計(jì)算機(jī)組織與設(shè)計(jì)》中所寫(xiě)的那樣,計(jì)算機(jī)體系結(jié)構(gòu)(也包括軟件工程)的一項(xiàng)重要原則是“使普通案例變得快速”:
快速實(shí)現(xiàn)普通案例比優(yōu)化罕見(jiàn)案例傾向于更好地提高性能。具有諷刺意味的是,通常情況下通常比罕見(jiàn)情況下簡(jiǎn)單。這種常識(shí)性建議意味著您知道什么是普通情況,只有通過(guò)仔細(xì)的實(shí)驗(yàn)和測(cè)量才能實(shí)現(xiàn)。
在我的辯護(hù)中,我確實(shí)嘗試找出實(shí)踐中的switch語(yǔ)句是什么樣的(即,有多少個(gè)案例以及常量的分布程度),但是數(shù)據(jù)早在1988年就不可用了。但是,只要我能提出一個(gè)人為設(shè)計(jì)的示例(現(xiàn)有編譯器無(wú)法生成最佳代碼),就給我許可證以繼續(xù)添加特殊情況。
我應(yīng)該和一個(gè)經(jīng)驗(yàn)豐富的編譯器作者或開(kāi)發(fā)人員坐下來(lái),對(duì)常見(jiàn)情況做出最好的猜測(cè),然后僅對(duì)那些情況進(jìn)行徹底處理。我將編寫(xiě)更少的代碼行,但這是一件好事。正如Stack Overflow聯(lián)合創(chuàng)始人Jeff Atwood所寫(xiě)的那樣,軟件開(kāi)發(fā)人員是他們自己的最大敵人:
我知道你有最好的意圖。大家都這樣做。我們是軟件開(kāi)發(fā)人員;我們喜歡編寫(xiě)代碼。這就是我們所做的。我們從未遇到過(guò)用膠帶,陪審團(tuán)制的衣架和少量代碼無(wú)法解決的問(wèn)題。
對(duì)于大多數(shù)軟件開(kāi)發(fā)人員來(lái)說(shuō),承認(rèn)這一點(diǎn)很痛苦,因?yàn)樗麄兎浅O矚g代碼,但是最好的代碼根本就不是代碼。您愿意帶給世界的每一行新代碼都是必須調(diào)試的代碼,必須閱讀和理解的代碼,必須得到支持的代碼。每次編寫(xiě)新代碼時(shí),都應(yīng)該勉強(qiáng)這樣做,因?yàn)槟耆帽M了所有其他選擇。代碼只是我們的敵人,因?yàn)槲覀冎杏刑嗟某绦騿T在編寫(xiě)大量的代碼。
如果我編寫(xiě)了處理普通情況的簡(jiǎn)單代碼,那么如果需要的話(huà),可以很容易地對(duì)其進(jìn)行修改,而不是留下沒(méi)人希望(或不敢)碰到的爛攤子。
第二名:社交網(wǎng)絡(luò)廣告
在Google上處理社交網(wǎng)絡(luò)廣告時(shí)(還記得Myspace嗎?),我寫(xiě)了一些C ++代碼,看起來(lái)像這樣:
for (int i = 0; i < user->interests->length(); i++) {
for (int j = 0; j < user->interests(i)->keywords.length(); j++) {
keywords->add(user->interests(i)->keywords(i)) {
}
}
程序員的讀者可能會(huì)看到錯(cuò)誤:最后一個(gè)參數(shù)應(yīng)該是j而不是i。我的單元測(cè)試沒(méi)有發(fā)現(xiàn)錯(cuò)誤,我的審閱者也沒(méi)有發(fā)現(xiàn)錯(cuò)誤。
在完成啟動(dòng)過(guò)程后,我的代碼被推到深夜,并立即使數(shù)據(jù)中心的所有計(jì)算機(jī)崩潰。
但是,這沒(méi)什么大不了的。沒(méi)有中斷,因?yàn)樵谌滞扑痛a之前,已在單個(gè)數(shù)據(jù)中心內(nèi)對(duì)代碼進(jìn)行了測(cè)試。這只是意味著SRE必須停止播放池并回滾一些代碼。第二天早上我收到一封電子郵件,告訴我這包括崩潰的堆棧轉(zhuǎn)儲(chǔ)。我修復(fù)了代碼,并添加了可能捕獲該錯(cuò)誤的單元測(cè)試。自從我按照正確的程序進(jìn)行操作(如果沒(méi)有的話(huà),我的代碼將無(wú)法上線),就是這樣。
經(jīng)驗(yàn)教訓(xùn)
有人認(rèn)為犯了這么大的錯(cuò)誤可能會(huì)導(dǎo)致某人失業(yè),但是(a)程序員犯了錯(cuò)誤,并且(b)程序員不太可能再次犯該錯(cuò)誤。
實(shí)際上,我確實(shí)認(rèn)識(shí)一個(gè)程序員,盡管他是一名優(yōu)秀的工程師,但由于一個(gè)誠(chéng)實(shí)的錯(cuò)誤而被解雇。然后,他被Google聘用(后來(lái)被提拔),他并不關(guān)心這個(gè)錯(cuò)誤,我的朋友在面試過(guò)程中公開(kāi)承認(rèn)了這個(gè)錯(cuò)誤。
關(guān)于IBM傳奇董事長(zhǎng)兼首席執(zhí)行官Thomas Watson的故事:
“政府提出了非常高的出價(jià),接近一百萬(wàn)美元。IBM Corporation(不行,Thomas J. Watson Sr.)需要每筆交易。不幸的是,推銷(xiāo)員失敗了。IBM失敗了。那天,銷(xiāo)售代表出現(xiàn)在沃森先生的辦公室。他坐下來(lái),把辭職信紙放在首席執(zhí)行官的桌子上。沃森先生不看就知道那是什么。他期待著。
他問(wèn):“怎么了?”
銷(xiāo)售代表概述了交易的每個(gè)步驟。他著重指出了哪里犯了錯(cuò)誤,以及他本可以做些什么。最后,他說(shuō):“謝謝沃森先生,給我一個(gè)解釋的機(jī)會(huì)。我知道我們需要這筆交易。我知道這對(duì)我們意味著什么。” 他起身離開(kāi)。
湯姆·沃森(Tom Watson)在門(mén)口遇見(jiàn)他,看著他的眼睛,將信封遞給他,說(shuō):“為什么我剛剛投資一百萬(wàn)美元給您的教育,我為什么會(huì)接受呢?” “
我有一件T恤,上面寫(xiě)著“如果人們從錯(cuò)誤中吸取教訓(xùn),那么現(xiàn)在我必須擁有碩士學(xué)位?!?我有博士學(xué)位。
第一名:App Inventor API
要真正弄糟,一個(gè)錯(cuò)誤應(yīng)該影響大量的用戶(hù),要公開(kāi),并存在很長(zhǎng)一段時(shí)間,并且應(yīng)該是本來(lái)應(yīng)該知道的人。我最大的錯(cuò)誤來(lái)自所有方面。
越差越好
我在90年代讀研究生時(shí)讀了理查德·加布里埃爾(Richard Gabriel)的《壞蛋的崛起會(huì)更好》,我非常喜歡它,因此將其分配給我的學(xué)生。如果您最近沒(méi)有閱讀,請(qǐng)立即閱讀。很短
這篇文章將“正確的事情”與“更糟的是更好的哲學(xué)”在許多方面進(jìn)行了對(duì)比,包括簡(jiǎn)單性:
正確的事情:設(shè)計(jì)必須在實(shí)現(xiàn)和接口上都簡(jiǎn)單。接口要比實(shí)現(xiàn)簡(jiǎn)單,這一點(diǎn)更為重要。
越差越好:無(wú)論是在實(shí)現(xiàn)上還是在接口上,設(shè)計(jì)都必須簡(jiǎn)單。簡(jiǎn)單的實(shí)現(xiàn)比接口更重要。
擱置一會(huì)兒。不幸的是,我將其擱置了多年。
App Inventor
我是Google團(tuán)隊(duì)的一員,創(chuàng)建了App Inventor,這是一個(gè)在線拖放編程環(huán)境,使初學(xué)者可以創(chuàng)建Android應(yīng)用程序。
早在2009年,我們就趕緊發(fā)布Alpha版本,以供夏季的教師研討會(huì)和秋季的課堂使用。我自愿實(shí)現(xiàn)了精靈,并回想起我年輕時(shí)在TI-99 / 4上與他們一起寫(xiě)游戲的情況。對(duì)于不熟悉該術(shù)語(yǔ)的人來(lái)說(shuō),子畫(huà)面是具有2D表示并能夠移動(dòng)其他程序元素并與之交互的功能的對(duì)象。精靈的一些例子是太空飛船,小行星,球和槳。
我們用Java實(shí)現(xiàn)了App Inventor,它本身就是面向?qū)ο蟮?,因此它一直是?duì)象。由于球和圖像精靈的行為非常相似,因此我創(chuàng)建了一個(gè)抽象的Spriteclass,它具有X,Y,Speed和Heading等屬性(字段)。它們具有碰撞檢測(cè),從屏幕邊緣彈起等常見(jiàn)方法。
球和圖像精靈之間的主要區(qū)別在于繪制的是:實(shí)心圓還是位圖。由于我首先實(shí)現(xiàn)了圖像精靈,因此自然要使x坐標(biāo)和y坐標(biāo)指定將圖像放置在封閉的畫(huà)布上的左上角。
當(dāng)精靈工作后,我意識(shí)到用很少的代碼來(lái)實(shí)現(xiàn)一個(gè)球形對(duì)象將很簡(jiǎn)單。問(wèn)題是我這樣做是最簡(jiǎn)單的方式(從實(shí)現(xiàn)者的角度來(lái)看):讓x坐標(biāo)和y坐標(biāo)指定包含球的邊界框的左上角。
我應(yīng)該做的是讓x坐標(biāo)和y坐標(biāo)指定圓的中心,就像在每本數(shù)學(xué)書(shū)以及其他所有圓中指定的那樣。
與主要影響我的同事的其他錯(cuò)誤不同,這影響了數(shù)百萬(wàn)的App Inventor用戶(hù),其中許多是孩子,或者不是編程新手。他們必須在所創(chuàng)建的每個(gè)使用ball組件的應(yīng)用程序中進(jìn)行額外的工作。雖然我可以嘲笑其他錯(cuò)誤,但我確實(shí)為這個(gè)錯(cuò)誤感到mort愧。
十年后,我終于在最近才修復(fù)了該錯(cuò)誤。我說(shuō)的是“修補(bǔ)”而不是“固定的”,因?yàn)檎鐐ゴ蟮募s書(shū)亞·布洛赫(Joshua Bloch)所說(shuō),“ API永遠(yuǎn)存在”。我們無(wú)法進(jìn)行任何會(huì)影響現(xiàn)有程序的更改,因此我們添加了一個(gè)屬性O(shè)riginAtCenter,該屬性在舊程序中默認(rèn)為false,以后為true。用戶(hù)可能會(huì)想知道為什么地球起源于中心以外的任何地方。答:十年前,一位程序員很懶,沒(méi)有創(chuàng)建明顯的API。
經(jīng)驗(yàn)教訓(xùn)
如果您曾經(jīng)開(kāi)發(fā)過(guò)API(幾乎所有程序員都在這樣做),則應(yīng)該遵循最佳實(shí)踐,您可以從Joshua Bloch的視頻“ How to Design a Good API And What Matter ”中學(xué)習(xí)或從保險(xiǎn)杠摘要中學(xué)習(xí),其中包括:
API可能是您最大的資產(chǎn)或負(fù)債之一。好的API可以創(chuàng)造長(zhǎng)期客戶(hù);不好的人會(huì)造成長(zhǎng)期的支持夢(mèng)night。
像鉆石一樣的公共API永遠(yuǎn)存在。您有機(jī)會(huì)把它做好,所以請(qǐng)盡力而為。
API的早期草稿應(yīng)該簡(jiǎn)短,通常是一頁(yè),其中包含類(lèi)和方法簽名以及一行描述。當(dāng)您第一次使用不正確時(shí),這使重新構(gòu)造API變得容易。
在實(shí)現(xiàn)API之前,甚至在正確指定API之前,都要對(duì)用例進(jìn)行編碼。這將使您不必實(shí)施甚至指定根本損壞的API。
如果我只寫(xiě)了一個(gè)包含示例用例的一頁(yè)建議,那么我可能會(huì)意識(shí)到我的設(shè)計(jì)錯(cuò)誤并予以解決。如果沒(méi)有,我的一個(gè)隊(duì)友就會(huì)擁有。人們必須忍受多年的任何決定至少都應(yīng)該經(jīng)過(guò)一天的考慮(無(wú)論我們是否在談?wù)摼幊蹋?/span>
理查德·加布里埃爾(Richard Gabriel)的文章“更糟的是更糟”的標(biāo)題是指即使有缺陷的產(chǎn)品,也要首先投入市場(chǎng),而不是永遠(yuǎn)花時(shí)間去創(chuàng)造完美的東西。但是,當(dāng)我回顧Sprite代碼時(shí),我發(fā)現(xiàn)以正確的方式做事甚至不會(huì)是更多的代碼。無(wú)論如何,我做出了一個(gè)錯(cuò)誤的決定。
結(jié)論
程序員每天都會(huì)犯錯(cuò)誤,無(wú)論是編寫(xiě)錯(cuò)誤的代碼還是不嘗試嘗試會(huì)提高他們的技能和生產(chǎn)力的新事物。雖然可以成為一個(gè)程序員而不會(huì)犯我所犯的那樣大的錯(cuò)誤,但如果不承認(rèn)并從錯(cuò)誤中汲取教訓(xùn),就不可能成為一個(gè)好的程序員。
作為一名老師,我經(jīng)常遇到一些學(xué)生,他們擔(dān)心他們會(huì)犯錯(cuò)誤,因此擔(dān)心他們不適合計(jì)算機(jī)科學(xué),而且我知道冒名頂替綜合癥在技術(shù)領(lǐng)域非常猖ramp。我希望讀者能記住本文中的所有教訓(xùn),但我最希望您會(huì)記住的是,無(wú)論我們笑,哭,臉紅還是聳聳肩,我們所有人都會(huì)犯錯(cuò)。的確,如果我不能為本文撰寫(xiě)未來(lái)的續(xù)集,我會(huì)感到驚訝和失望。
作者介紹
熱門(mén)博客推薦