有一句廣為流傳的話:代碼是寫給人看的,而不是為了給機(jī)器執(zhí)行。然而,編寫人類易于閱讀的代碼,這說起來容易做起來難。這件事需要花費(fèi)幾年時(shí)間去學(xué)習(xí),花費(fèi)幾十年才能掌握。我也許可以提供一個(gè)捷徑:像一名教育者一樣思考代碼質(zhì)量?!敖輳健边@個(gè)詞表達(dá)的能力很強(qiáng)大。這并不是一個(gè)捷徑。但我認(rèn)為,這種觀點(diǎn)很重要。Alan Kay 說過,觀點(diǎn)抵得上 80 點(diǎn)智商。
在工作中,我們使用 Rails、Node 和 Vue。主應(yīng)用程序是用 Rails 寫的,前端的一部分是用 Vue 寫的,然后我們還用 Node 編寫了一些 lambda 函數(shù)。在理想世界中,Rails 人員寫 Rails,Node 人員寫 Node,Vue 人員寫 Vue,但實(shí)際情況并非如此。實(shí)際上,我們會(huì)遇到這樣的情況:Node 和 Vue 人員不得不閱讀或編寫 Rails 代碼。委婉地說,Rails 是一個(gè)古怪的框架,會(huì)發(fā)生很多奇怪的事情,約定大于配置。例如,如果你看到如下代碼:
# app/controllers/api/foo/bar/baz_controller.rb
def showend
Rails 會(huì)自動(dòng)在app/views/api/foo/bar/baz內(nèi)部尋找show.html.erb或show.jbuilder來作為響應(yīng)。但如果你不是一個(gè) Rails 開發(fā)者... 你不會(huì)知道這些!你所看到的只是一個(gè)空方法,它似乎什么也沒做!更重要的是,你沒辦法搞明白。答案不是隱藏在一些父類或 mixin 中,而是藏在這種部落知識(shí)的書中。https://guides.rubyonrails.org/?fileGuid=rU8e3yc0h4Mztn6T我不確定這個(gè) controller actions 的示例是不是一個(gè)好例子。實(shí)際上,這是你很快就能學(xué)會(huì)的,或者你團(tuán)隊(duì)中的某人可以馬上發(fā)現(xiàn)并幫助你的。但是在其他一些情況下,你可以用 Rails 做一些古怪的事情,而只有那些正好掌握這些部落知識(shí)的人能夠理解。當(dāng)你在一個(gè)擁有經(jīng)驗(yàn)豐富的 Rails 專家的團(tuán)隊(duì)工作中時(shí),這不是個(gè)問題。事實(shí)上,這些古怪的東西能夠幫助 Rails 專家變得更高效。但是,如果你工作在一個(gè)對 Rails 都是新手的團(tuán)隊(duì)中時(shí),這些菜鳥絕對會(huì)陷入絕望和沮喪中。這就是需要像一名教育者一樣思考的地方。假設(shè)你是一名教授。如果你站在一小群博士面前,舉辦一個(gè)高度專業(yè)化、集中化的研討會(huì),你可以使用花哨的術(shù)語等而不用擔(dān)心這些術(shù)語超出觀眾的認(rèn)知。但是... 如果你發(fā)現(xiàn)自己站在一座演講廳中面對一群本科生,那么,使用這些術(shù)語就不是一個(gè)明智的選擇。對于 Rails 也是這樣。問題不在于某樣?xùn)|西是“最佳實(shí)踐”還是“Rails 編程方式”,而是在于它對你的受眾是否有意義。
https://adamzerner.bearblog.dev/using-obscure-features-of-a-programming-language/?fileGuid=rU8e3yc0h4Mztn6T
在以前的一家公司,我們使用 Rails、Angular 和 Python。我是那個(gè)“使用 Angular 的家伙”。團(tuán)隊(duì)的其他人大部分都是 Rails 人員。我對于自己對 directives 的使用感到少許得意。但我的上司叫我停止使用這些東西,堅(jiān)持使用正常的 controllers。他甚至提到,他的理由是因?yàn)檫@是大部分軟件開發(fā)人員如果進(jìn)入一個(gè)代碼庫期待看到的編程方式。當(dāng)時(shí),我認(rèn)為很明顯,他錯(cuò)了。我看到的 Anguar 專家撰寫的所有視頻和書籍,都告訴我這些是最佳實(shí)踐。他們都是專家,而且他們看起來比我的上司更了解 Angular,所以我認(rèn)為我應(yīng)該相信這些專家而不是我的上司。至少我是這么想的。
在《函數(shù)式編程為什么重要》一書中,Eric Normand 談到了一個(gè)有關(guān)游戲樹的程序。他說,在大學(xué)里,他用一堆for循環(huán)寫過一個(gè)類似的程序。然后,他談到了一篇論文作者采取的方法:他的解決方案,當(dāng)然更簡潔,是... 非常簡潔。非常簡潔。我也不知道我能不能讀懂它。
這說明了一些問題,因?yàn)?Eric Normand 是一名函數(shù)式編程方面的專家。如果你的代碼過于簡潔,以至于即使是領(lǐng)域?qū)<乙埠苜M(fèi)勁才能理解它,那么這可能不是你應(yīng)該追求的目標(biāo)。在同一期播客中,Normand 反思函數(shù)式編程語言 / 代碼是否過于簡潔。這讓我想起 EliezerYudkowsky 在《Explainers Shoot High. Aim Low!》中寫的有些東西:幾年前,一位著名的科學(xué)家曾告訴我,他是如何以比平時(shí)低得多的技術(shù)水平為自己的領(lǐng)域撰寫一篇解釋性文章的。他認(rèn)為這對該領(lǐng)域以外的學(xué)者,甚至報(bào)道者,都會(huì)有用。這篇論文最終成為他所在領(lǐng)域最受歡迎的論文之一,被引用次數(shù)超過了他所寫的其他任何文章。*
并不是他的同行科學(xué)家都很愚蠢,而是我們往往大大低估了正確理解事物所需的努力。*
我認(rèn)為在編寫代碼時(shí)記住這一點(diǎn)是一件好事。
“了解你的受眾”并不一定意味著你需要將所有東西都降低水平。想想大學(xué)教授教本科生。在學(xué)期開始的時(shí)候,可能需要慢慢來,在解釋事物時(shí)要非常慎重。但是,隨著特定術(shù)語和概念開始為全班所熟悉,自由地使用這些術(shù)語可能就更好。同樣,當(dāng)有一些術(shù)語和概念很難被人們理解時(shí),慢慢介紹這些概念而不是完全避免使用這些概念可能更有意義,這樣學(xué)生們就可以學(xué)習(xí)這些概念并在將來使用它們。我認(rèn)為問題的關(guān)鍵是,像往常一樣,這涉及到權(quán)衡問題,你需要意識(shí)到這些問題并在你的決策中加以考慮。
教育者使用什么工具來教學(xué)?幻燈片、教科書、講座視頻、演示、測驗(yàn)、辦公時(shí)間、家庭作業(yè)、圖表、模擬,等等。當(dāng)我們編寫代碼時(shí),這些工具對我們開發(fā)者還有使用意義嗎?其中一些是不適用的。例如,一個(gè)完整的教學(xué)視頻。其它則是有點(diǎn)兒傻。例如,測驗(yàn)。但是,我認(rèn)為至少有些工具是可以使用的。
讓我們重新考慮一下講座視頻。對于你寫的每個(gè) 10 行函數(shù)代碼,進(jìn)行一個(gè)深入的講解是不現(xiàn)實(shí)的。但是對于更大的代碼塊呢?對于一個(gè) lambda 函數(shù)或者一個(gè)重要的模塊進(jìn)行深入的講解,我認(rèn)為是有意義的。事實(shí)上,我認(rèn)為類似的事情已經(jīng)發(fā)生了。當(dāng)處理代碼庫中一些自己不太熟悉的部分時(shí),我最喜歡的一個(gè)小技巧是使用git blame來增進(jìn)自己對代碼的理解。我會(huì)看到大部分代碼是誰寫的,在 Slack 上交流,然后他們會(huì)花費(fèi)大約 20 分鐘時(shí)間給我進(jìn)行大致的講解。我覺得這非常有用。那么,為什么不像這樣記錄一份講解,并在文件頭部以代碼注釋的形式鏈接到這份講解呢?我認(rèn)為最大的原因是可維護(hù)性。隨著代碼庫的演變,視頻將變得陳舊過時(shí)。當(dāng)代碼注釋這樣的東西變得過時(shí)了,很容易編輯它們,但是對于一個(gè)視頻,你不能真正地編輯從 17:34 到 21:40 的片段。至少不太容易。我對這個(gè)觀點(diǎn)有一些反對意見。是的,它最終會(huì)變得陳舊,但那又怎樣?如果代碼更改很小,視頻就仍不會(huì)過時(shí),其收益大于成本。如果代碼變化很大,那么你可以再花 20 分鐘錄制一份講解。即使出于任何原因,團(tuán)隊(duì)沒有同步,最終導(dǎo)致在代碼變化很大時(shí)沒有更新視頻,我也不認(rèn)為這會(huì)造成任何重大傷害。如果有人點(diǎn)擊它并開始觀看,他們會(huì)很快意識(shí)到這個(gè)視頻過時(shí)了并停止觀看。另一個(gè)我反對的觀點(diǎn)是錄制視頻很費(fèi)時(shí)。那簡直是胡說八道。我們已經(jīng)花費(fèi)了大量時(shí)間來盡量產(chǎn)出高質(zhì)量的代碼:前期工作、重構(gòu)、代碼評審,等等?;?20 分鐘時(shí)間,以一種隨意的意識(shí)流的方式對著鏡頭進(jìn)行講解,與你花的其它時(shí)間相比是微不足道的。我認(rèn)為這種觀點(diǎn)真正要表達(dá)的是,錄制視頻給人的感覺像是要做一件大事。
我覺得圖表很棒!幸運(yùn)的是,它們已經(jīng)被一些人采用了。特別是在架構(gòu)層次,來說明不同的模塊是如何連接到另外一個(gè)模塊的。下面是一個(gè)例子,說明如何將它用于架構(gòu)級別較低的事務(wù)。對于“水容量最多的容器”問題,以下視覺參考會(huì)非常有用:在我看來,前端代碼領(lǐng)域是圖表尤其未被充分利用的一個(gè)領(lǐng)域。我認(rèn)為在代碼旁邊伴隨圖表很酷,這樣你就可以放一張圖片展示一個(gè) React 組件是什么樣子的。是的,你可能已經(jīng)通過打開一個(gè)網(wǎng)頁,并且使用檢查工具(或者僅僅通過常識(shí))來確定哪些代碼對應(yīng)哪些 UI,但這樣做會(huì)有點(diǎn)兒小別扭。也許減少這些小別扭是一個(gè)不錯(cuò)的主意。特別是我想到的以下幾點(diǎn)。你的文本編輯器中應(yīng)該有這個(gè)插件。當(dāng)你的文本編輯器看到一段代碼注釋后面跟著一個(gè)以.jpg結(jié)尾的 URL
// https://example.com/code-images/modal.jpg
它左邊會(huì)有一個(gè)小的折疊 / 展開箭頭,當(dāng)你點(diǎn)擊展示時(shí),它會(huì)內(nèi)聯(lián)展示圖片!我想這樣會(huì)方便很多。
我的朋友 Brendan Long 有一個(gè)好主意:使用某種插件根據(jù)這些組件的一些模擬數(shù)據(jù)自動(dòng)生成這些圖表或圖片。總之,這條思路不僅僅是我個(gè)人的強(qiáng)烈感覺,更是一種猜想,但確實(shí)很有趣!
讓我們拋開視頻之類的邊緣話題,回到一個(gè)我們更熟悉的世界。在這個(gè)世界里,我們嘗試以一種更容易被他人理解的方式編寫代碼。就像我在文章開頭所說的,如果你將自己當(dāng)作一個(gè)教導(dǎo)團(tuán)隊(duì)其他人如何使用這段代碼的人,很多公認(rèn)的關(guān)于 clean code 的想法都會(huì)自然而然地產(chǎn)生。描述性變量名、模塊化、恰當(dāng)?shù)目s進(jìn),等等。我還從 clean-code-javascript“借”了一些示例過來。
// What the heck is 86400000 for?setTimeout(blastOff, 86400000);
// Declare them as capitalized named constants.const MILLISECONDS_IN_A_DAY = 60 * 60 * 24 * 1000; //86400000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);
const address = "One Infinite Loop, Cupertino 95014";const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;saveCityZipCode( address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);
const address = "One Infinite Loop, Cupertino 95014";const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];saveCityZipCode(city, zipCode);
function emailClients(clients) { clients.forEach(client => { const clientRecord = database.lookup(client); if (clientRecord.isActive()) { email(client); } });}
function emailActiveClients(clients) { clients.filter(isActiveClient).forEach(email);}function isActiveClient(client) { const clientRecord = database.lookup(client); return clientRecord.isActive();}
function addToDate(date, month) { // ...}const date = new Date();// It's hard to tell from the function name what is addedaddToDate(date, 1);
function addMonthToDate(month, date) { // ...}const date = new Date();addMonthToDate(1, date);
/** * 2016-12-20: Removed monads, didn't understand them (RM) * 2016-10-01: Improved using special monads (JP) * 2016-02-03: Removed type-checking (LI) * 2015-03-14: Added combine with type-checking (JR) */function combine(a, b) { return a + b;}
////////////////////////////////////////////////////////////////////////////////// Scope Model Instantiation////////////////////////////////////////////////////////////////////////////////$scope.model = { menu: "foo", nav: "bar"};////////////////////////////////////////////////////////////////////////////////// Action setup////////////////////////////////////////////////////////////////////////////////const actions = function() { // ...};
function hashIt(data) { // The hash let hash = 0;
// Length of string const length = data.length;
// Loop through every character in data for (let i = 0; i < length; i++) { // Get character code. const char = data.charCodeAt(i); // Make the hash hash = (hash << 5) - hash + char; // Convert to 32-bit integer hash &= hash; }}
應(yīng)該避免這樣使用位置注釋和明顯的注釋。然而,我對于“好代碼通常是它自身的文檔”這一點(diǎn)有所保留。我通常默認(rèn)假定:我不想爭論這些注釋是沒有被充分利用的。那很難。相反,我只是想建議你據(jù)此重新評估自己的立場。下次編寫函數(shù)時(shí),問問你自己,是否會(huì)有其他人會(huì)很難理解你所寫的代碼。問問你自己,是否可以添加一些不會(huì)顯得多余和臃腫的注釋。問問你自己,一名教育者會(huì)怎么做。
后記:像個(gè)可用性設(shè)計(jì)師一樣思考?
這篇文章是關(guān)于你在寫代碼時(shí)像一名教育者一樣思考。我認(rèn)為這個(gè)想法很好,但這是唯一的好想法嗎?填空:“像個(gè) ____ 一樣思考代碼質(zhì)量”。還有哪些有意義的想法?我想到的最重要的是“可用性設(shè)計(jì)師”。為什么?因?yàn)槲乙恢闭J(rèn)為,用戶測試是人們應(yīng)該在代碼庫中做的事情!問問你自己,是否會(huì)有其他人會(huì)很難理解你所寫的代碼
可用性設(shè)計(jì)師一直在做這類事情!這是他們的工作!但不僅如此,他們還做其它哪些事情?用戶測試! 他們不會(huì)憑空猜想人們會(huì)理解如何使用他們的產(chǎn)品。他們會(huì)進(jìn)行測試。把它放到真正的用戶面前,看看有哪些別扭的點(diǎn)。為什么我們不能對代碼也這樣做呢?原文鏈接:
https://adamzerner.bearblog.dev/think-like-an-educator-about-code-quality/?fileGuid=rU8e3yc0h4Mztn6T
逆鋒起筆是一個(gè)專注于程序員圈子的技術(shù)平臺(tái),你可以收獲最新技術(shù)動(dòng)態(tài)、最新內(nèi)測資格、BAT等大廠大佬的經(jīng)驗(yàn)、增長自身、學(xué)習(xí)資料、職業(yè)路線、賺錢思維,微信搜索逆鋒起筆關(guān)注!
如何把 if-else 重構(gòu)成高質(zhì)量代碼?
編寫高性能 Java 代碼的最佳實(shí)踐!
常見代碼重構(gòu)技巧(非常實(shí)用)
怎樣寫出可讀性高的代碼?
編寫高質(zhì)量代碼 改善Python程序的91個(gè)建議
點(diǎn)個(gè)在看少個(gè) bug ??