程式碼與質量的思考與隨筆

李熠發表於2019-07-21

讓我們從正經的聊聊 API 設計開始

在上一篇文章裡,我建議 API 應該圍繞消費端需求展開設計。“以消費者為中心”只是我個人的經驗之談。但是如果你有心去發掘,你會找到更多 API 相關的設計指南

在 《Designing Web APIs》 一書的第四章裡,作者提出了他認為的 Design Best Practices. 包括以下幾點:

  • Designing for Real-Life Use Cases
  • Designing for a Great Developer Experience
    • Make it Fast and Easy to Get Started
    • Work Toward Consistency
    • Make Troubleshooting Easy
    • Make Your API Extensible

在實際的敘述過程中,他舉了幾個來自專業人士的建議:

When we asked Ido Green, developer advocate at Google, what makes an API good, his top answer was focus: “The API should enable developers to do one thing really well. It’s not as easy as it sounds, and you want to be clear on what the API is not going to do as well.”

No matter how carefully we design and build our core API, developers continue to create products we’d never expect. We give them the freedom to build what they like. Designing an API is much like designing a transportation net‐work. Rather than prescribing an end state or destination, a good API expands the very notion of what’s possible for developers. —Romain Huet, head of developer relations at Stripe

Don’t overcomplicate your API and don’t future-proof it too much. Often by future-proofing your API, you make it too generic and/or too complex. Developers building applications on (or using) your platform are building stuff for the “now.” They like to move quickly and are not always thinking 10 steps ahead. Your API should cater to this mindset. —Yochay Kiriaty, Azure principal program manager at Microsoft

他們更傾向於關注當下,關注開發者。而並非以提供者為中心

而在 《APIs: A Strategy Guide》 一書第五章 Key Design Principles for APIs 中作者也同樣花費了一章的篇幅來表述他認為的 API 設計原則。其中非技術性的原則有

  • Design APIs for Specific Audiences
    • Designing for Developers
    • Designing for Application Users
  • Best Practices for API Design
    • Differentiate Your API
    • Make Your API Easy to Try and Use
    • Make Your API Easy to Understand
    • Don't Do Anything Weird
    • Less is More
    • Target a Specific Developer Segment

在這兩本書中,作者們提倡一種“漸進式”和“基於反饋”的開發模式:

Successful APIs often start with the absolute minimum amount of functionality, and then add functions slowly over time, as feedback is collected.

When talking to companies in the midst of launching an API, we often ask “Who are your target audiences?” If they answer by saying “Everybody,” we get worried. Similarly, if we ask them “What kinds of apps do you expect to see built?”, we get worried if their answer is, “All kinds.” Why? It’s really hard to create an API to meet the demands of every possible constituent and every possible use case. And even if you had the perfect API, you can’t market effectively to all these segments.

如果把以上種種稱之為理想流派的話, 在真實的世界裡,我不止一次聽到的是另一種聲音是:介面應該是儘可能穩定且一成不變的基礎服務,包容來自不同客戶端的消費。這又回到了上一篇文章我反對的起點:即一種大而全的渴望一勞永逸的 API 設計。

但是我們不應該批評這種做法,你可以把這種做法當作稱之為現實流派,這其實是目前絕大部分網際網路公司的現狀。想象一下你隨便在公司找一位研發同學和他聊我們應該精細化迭代和運營 API ,雖然他嘴上不說但是他的表情已經仍不住想告訴你:你瘋了吧。這裡的“瘋”隱射的是不現實:一方面我們沒有足夠的時間和人力分配到這樣的工作中來;另一方面即使我們這麼做了,我們又能從中得到什麼呢?KPI 依然沒有完成,使用者增長依然停滯不前。所以折(底)中(線)的方案是,簡單粗暴,能用即是好用。更重要的是,你身臨其境的看到這樣的 API 開發也是奏效的。

關於 API 設計的討論此為止。在這裡我想引出另一個問題:既然我們理想和現實如此分裂,甚至無力反抗現實時,我們是否仍然關心設計?

“關心”這個詞很微妙,它同時表達了兩層含義:Why and How


在《The Mythical Man Month》一書第一章的開頭,作者 Brooks 對 Program 和 Programming Product 進行了區分,前者可以僅僅是程式設計師個人在車庫裡的產出,而後者則是

This is a program that can be run,tested, repaired, and extended by anybody. It is usable in many operating environments, for many sets of data. To become a generally usable programming product, a program must be written in a generalized fashion.

作者之所以對這兩類程式做出不同的劃分,是想說明它們的生產代價不同, Programming Product 的成本至少是 Program 的三倍以上 。而在我看來,它們存在著性質上的不同。

每天你都能在掘金社群或者 Medium 網站上看到諸如 Vue + Webpack + Express + GraphQL 全家桶組合教程。Wow,全棧、 最新最夯的技術、融合官方推薦的最佳實踐,無懈可擊簡直無敵了。新生、完美、純淨,但它只是一個 DEMO。我把它劃分為 Program

而實際上這麼多年我每天工作中需要維護的前端系統像是變異的怪物:可能 RequireJS 和 ES6 共存,可能 Grunt 和 Webpack 共存,還有許多團隊老大寫的半死不活的框架也被揉入其中,導致每次增改程式碼都如履薄冰。醜陋、臃腫、禁錮、可它是實實在在的線上產品。我把它歸類為 Programming Product

而它們的根本不同點之一,就是程式碼的可維護性不同。毫不客氣的說 DEMO 通常是一次性的,我嘗試過了,證明它們的組合是可行的,再證明我能力就足夠了。但線上產品中,你找不到任何一個不需要二次維護的程式。

軟體行業有幾條公認的真理:

  • 唯一不變的就是變化本身
  • 程式碼不可避免的會走向腐爛。

所以你們看到的所有“好”的東西,比如重構、TDD、DDD都是在儘可能的減緩和改善程式碼的腐爛,設計也是

腐爛並不意味著不可用,而是意味著維護成本極高。但是在網際網路公司弔詭的事情是,維護性高並不算是一個問題,或者說它是個問題但不在解決的範圍之內,一方面相比這樣無法量化並且只有基層關心的與上線產品沒有半毛錢關係的問題,跑馬圈地的速度更顯重要;另一方面如果因為員工離職率高真的到了無人能維護的地步,重寫通常是最佳的選擇。我很難想象一個系統在網際網路公司內部能夠維護 5 年乃至 10 年以上。即使有通常的結果也是名存實亡,它確實堅挺了很多年,但是已經不知道經歷了多少次重寫多少代團隊的手了。However, 這樣的做法無可厚非。


我不相信程式碼質量存在文化相對主義,程式碼質量是有絕對的好壞之分的。好比你無論如何都無法說服自己這段五百行的函式是一段好程式碼,無論是在任何程式語言中。

承認吧雖然我們每個人都不希望接手維護的是爛程式碼,但事與願違總是在發生。以至於每次我都忍不住開啟 git blame 看一眼究竟是誰的“好事”,然後默默把這個人記在自己的小本本上,也難免有幾次發現是自己

但是你有沒有想過,我們為什麼要把程式碼寫好?

我可以簡單粗暴的回答沒有為什麼,這是職業道德。無論從事任何職業如果凡事只想敷衍了事就是不對的。但是站在軟體工程的角度上看寫好程式碼能夠讓程式維護性更好,僅此而已。

僅此而已,卻難以上青天。

你可能會反駁我上面剛剛不是說了絕大部分公司不在乎程式的可維護性嗎?站在公司的視角的確如此,但現在你我都不是公司的經營者。作為程式設計師此時此刻你是在乎的,我也是在乎的,我們都認可這件事,這就夠了。

對個人而言這還關乎看來這關乎程式設計師的 respect —— 什麼是 respect ?

如果你讀過類似於 《Peopleware》之類 IT 企業管理的圖書的話,你會發現 IT 團隊管理和傳統的企業管理有非常大的不同。有一篇很有意思的文章 《Opinion: The unspoken truth about managing geeks》 戳破了程式設計師不同與傳統公司員工的另一類心態:

Few people notice this, but for IT groups respect is the currency of the realm. IT pros do not squander this currency.

Gaining respect is not a matter of being the boss and has nothing to do with being likeable or sociable; whether you talk, eat or smell right; or any measure that isn't directly related to the work. The amount of respect an IT pro pays someone is a measure of how tolerable that person is when it comes to getting things done, including the elegance and practicality of his solutions and suggestions.

IT pros always and without fail, quietly self-organize around those who make the work easier, while shunning those who make the work harder, independent of the organizational chart.

While everyone would like to work for a nice person who is always right, IT pros will prefer a jerk who is always right over a nice person who is always wrong. Wrong creates unnecessary work, impossible situations and major failures. Wrong is evil, and it must be defeated. Capacity for technical reasoning trumps all other professional factors, period.

程式設計師打心底有一種特殊 “尊重(respect)” 觀念,這種對人的尊重和人的地位、職位、愛好、談吐一點關係都沒有,只和這個人搞不搞得定事情有關。 他們會自發天然的圍繞在這種人身邊和他一起共事,哪怕他是一個混蛋,只要他擁有把問題處理的有好又漂亮的能力。

很顯然寫出爛程式碼不是一種能夠贏得尊重的行為,相反可能你反而會被邊緣化。(當然也不排除在某些公司會劣幣驅逐良幣)

而設計是另一種形式的編碼,從架構的角度影響著整個程式的可維護性。如果說架構需要設計,資料庫需要設計,程式需要設計,為什麼 API 不需要設計?


另一個 DEMO 的侷限性在於,它無法體現無論是程式設計者還是技術本身解決現實問題的能力。例如任何一個新進框架總喜歡用 TODO APP 來證明自己的可行性和新特性。但是一個離線的有限個元件的應用和實際上它要解決的使用者場景相差太遠了。量變產生質變是一個說爛了的梗,但現實的情況就是如此。維護 1 個元件和維護 1000 個元件的方法是不同的;要解決一個使用者和解決一萬個使用者的問題是不同的。以及當引入這個技術棧時,需要關心對團隊會有什麼樣的影響,產能爬坡的階段需要持續多久。

我個人的感受是,隨著需要解決問題的複雜度加深和 case 定製化,個人經驗乃至大眾經驗能夠帶來的幫助是越來越少。而你每天又不得不面對不同的技術方案決策,那麼你如何驅動你的決策?至少需要一條原則,哪怕這條原則只是底線而已。說的輕鬆點,原則決定你走哪條路;說的嚴肅點,原則決定了你什麼能做什麼不能做。公司是這樣,產品是這樣,程式碼也是這樣

我們認可了萬物皆可設計,但是設計的原則應該是什麼?

我最近看了兩本非常好的書《Code Simplicity》和《Understanding Software》,它們不是在談某一門程式語言或者程式設計技術,而是聊程式設計這件事。我非常認可書中作者提出的軟體設計的終極目標:幫助他人。即使作為程式設計師你編寫的程式類庫,它們也是為程式設計師服務的,程式設計師也是人。

更有意思的事情是,作者認為一個人寫出優秀軟體的潛力,完全取決於他在多大程度上理解了 “幫助其他人” 的思想。所以當你下次想放鬆下來寫一段爛程式碼時,多想想這件事,自然就被勸退了

這篇文章我只是想丟擲把程式碼寫好這件事很重要,而至於如何能寫好的程式碼,這兩本書裡給出很好的答案。以及你能參考的各種最佳實踐和方法論都是絕佳的材料


我最近參加了公司組織的幾場培訓,關於不同方面的能力建設。但之後的某一天我突然明白哪怕我參與了整整一週甚至一個月的培訓,也不代表我立刻擁有了對應的能力。我保證各位的每一位領導公司都為他們提供了類似於提升領導力的培訓,但是我們見過的混蛋領導還少嗎。

程式設計師也是一樣,會敲程式碼和合格的程式設計師根本就是兩碼事,會使用框架和合格的程式設計師也是兩碼事。那種已經有幾年工作經驗但是程式碼依然不堪入目的人我們也還見得少嗎?在工作這麼多年之後總是會不禁在想,我和坐在我斜對角那個維護著相同程式碼庫的大三實習生相比競爭力在哪? 如果我的團隊需要招聘新的成員,除了框架的熟練程度以外我還應該考察哪些方面?讓程式跑起來一點都不難,這是底線。難的是如何讓程式跑的更快,跑的更久,甚至通過一個程式讓整個系統變得更好。

最後我想對我開頭提出的問題自己做一個回答:我們應該承認和尊重理想流派的正當性。但是再實施層面,如果環境壓迫著你必須走現實流派我也理解你。如果有機會的話,請儘可能的向理想流派靠攏,讓程式碼變得更好

關於這一點在 《Understanding Software》一書當中有一段比喻特別好:

You have something like a house on fire, except that the house is the size of several mountains and it's all on fire all the time. You need to figure out which part of the "mountain" or "house " that you actually need right now, and get that into good shape so that it can be "used", on a series of small steps

Your first goal is to get the system into a place where it's getting better overtime, instead of getting worse.


本文同時也釋出在我的前端專欄,歡迎大家關注

相關文章