你是“最佳實踐”的受害者嗎

lanzhiheng發表於2019-01-28

這篇文章是有感而發,也算是自己軟體開發生涯的一些所思所想的總結吧。IT科技在這幾十年來發展迅速,各個領域都萌生出所謂的“最佳實踐”。今天主要想來談談這些所謂的最佳實踐可能並不是那麼的“最佳”,甚至有的時候它們還會是“最糟”的存在。

表明立場

首先需要表明一個立場,我並沒有排斥最佳實踐的意思,我跟許多人一樣是Ruby On Rails,Django這些Web開發最佳實踐的全棧式框架的受益者。這些框架的開發者根據自己或者社群的經驗把一些能夠方便開發者的,比如,資料庫操作,目錄結構,路由定製等特性進行有效組織並整合到框架當中,雖說不同的社群側重點有所不同,但是總體而言並沒有脫離MVC這個基礎模型。或許我可以認為即便它們“長相”各異,寫法各異,分屬於不同的社群,但他們的核心靈魂以及概念是想通的。

然而如果要脫離基礎概念,區別對待,硬要從Rails,Django這些框架中選擇出一個所謂的“最佳實踐”就有點耍流氓了。前面也說過每個社群的側重點不同,我以前寫Django的時候還不知道有靜態資源編譯這回事,那時候的Rails早就有了AssetsPipline。另外,Django可能是為了讓i18n的效能更加出眾,相關的翻譯資源都需要經過預編譯的,而Rails則是執行時直接從yml檔案中讀取。那到底誰的做法更佳?似乎是個見仁見智的問題了。

為此請允許我簡單把最佳實踐歸納為

特定領域最佳思想之實踐。

跟今天許多人所尋求的“最佳框架”,“最佳語法”的實踐似乎不是同一個頻道。你會以執行速度不夠快來抨擊Ruby,他會以囉嗦來抨擊Java,還有人會以語法過於複雜來抨擊C++。在這種層面上誰才是“最佳”真的能夠爭出個結果來?合適的才是最佳的。

下面我從幾個方面來談最佳實踐,以及一些最佳實踐為團隊帶來的負面影響。

最短即“最佳”?語法糖的濫用

今日之開發,抽象程度越來越高了。人們之間似乎流行出一種“最短”即“最佳”的想法。

想想剛入前端圈那一年工作組為了“掩蓋”語言本身的“醜陋”,釋出了ES6,確實帶來了許多好處,比如總算有塊級作用域了,class關鍵字也能用了,生成器,裝飾器都有了。有了這些利器我們可以讓程式碼變得更簡短,優雅,這本身並沒有什麼問題,但是這似乎也為過度封裝大開方便之門。

拿裝飾器來說事,它實質上就是一層語法糖衣,它的作用大概如下

@decorator
class A {}

// 等同於

class A {}
A = decorator(A) || A;
複製程式碼

這是一個不錯的改善,能夠精簡語法。但是一旦被過用,程式碼將會變得有點奇怪了,我曾經見過這種程式碼

@a
@b
@c
class A {}
複製程式碼

好好的糖衣變成了糖精-或者說語法糖漿(英語:syntactic syrup),指的是未能讓程式設計更加方便的附加語法。這似乎應了那句話

金錢使淺薄的人更淺薄,使深刻的人更深刻。

最早接觸裝飾器是寫Python的時候,我記得當時有個人說過:“即便裝飾器很好,但是如果多了它會使程式碼變得晦澀難懂,所以請儘量限制層數”。作為程式設計師應該要在程式碼易讀的基礎上讓程式碼變得更簡潔,脫離易讀性而單單追求簡短的程式碼純粹是炫技,如果真的只是為了炫技而寫程式碼,何不直接寫二進位制?那就真的沒幾個人能看懂了,而且還會顯得自己很高階。

統一寫法等同於最佳實踐?

最近許多人都追求寫法統一

Write Once Run Everywhere

美其名曰提高開發效率,能夠使得程式設計師更高產。React Native這些技術的出現,讓JavaScript編寫移動端應用成為可能,這似乎是好事,我可以只學會React技術就去編寫移動端軟體了。更有甚者MPVUE以及Taro等框架的興起,似乎意味著只需要學React或者Vue就能夠編寫各種小程式或者APP了。假設你有一個React的團隊,或許採用Taro這些框架將會比寫原生的小程式原生語法更爽,許多人把這看成是最佳實踐。不過據我觀察,世界比你想象的要殘酷。

畢竟我沒能夠開發出這種型別的框架,沒資格對這些框架評頭論足,但我只想就事論事。關於統一寫法我有以下的考慮

1. 統一寫法重要嗎?

我記得有一些這類框架的擁戴者的說法是“微信的語法很多坑,所以我要上這個框架。”,“應該把注意力放在用React或者Vue來寫特定業務,而不是小程式的坑爹語法。”等等。

對這些說法我覺得用Erlang語言的發明者Joe大大的話來回答最好

Erlang並不適合處理所有場景,如果你發現有其他語言更適合某種場景,我將會是第一個支援你使用別的語言來解決這個問題的人。

每門技術都有它擅長的事情,什麼都想幹,最終可能會導致啥都幹不好。即便工作組不斷在“優化”JavaScript語法,JavaScript也不可能一統天下。統一寫法並不是銀彈,能夠用Vue和React語法來寫小程式似乎是一件令人開心的事情,但回過頭來想,學習小程式難度大,還是學習React難度大?答案顯而易見。

難道上了一個框架寫法統一了之後我們不需要學小程式了?可能性不大。即便是移動端這個相對穩定的平臺也尚且不能做到,根據我一些移動開發同事的反饋,React Native確實能完成許多的業務場景,但有不少問題你還是需要通過編寫的Object-C或者Java程式碼才能夠解決(抱歉,我們公司還沒有上Swift以及Kotlin)。

這似乎得替移動開發群體喊冤了,以前做移動開發懂Object-C或者Java即可,然後便是深入相關領域,學習調優,工資還蠻高,工作也好找。如今所謂的統一寫法的“最佳實踐”流行之後,除了懂這些之外還得另外學JavaScript,React Native,以及一堆的預編譯工具。工資水平卻似乎卻不如從前了,工作還不好找。但本質上要解決的問題似乎跟以前沒什麼差別,這想想不也挺折騰的嗎?

2. 真的解決了問題?

我們都知道一個叫做80/20的定律

80%的事情其實花費了你20%的時間,另外20%的事情將會花費你80%的時間。

請允許我將這個理論用在小程式上,我個人比較幸運,沒什麼機會開發小程式,以至於我可以用旁觀者的身份來觀察身邊同事的工作。從他們的開發經歷來看,開發一個微信小程式,只要是客戶還算理智,正常的業務邏輯其實並不會耗費掉多少時間。小程式的價值不就是簡單輕量嗎?

然而小程式有個問題就是平臺不夠穩定,更新頻繁。這個過程可能會修復掉一些Bug,但也可能會引入一些新的Bug。往往一個業務不怎麼複雜的小程式為了“掩蓋”這些問題所花的時間都要趕上業務開發的時間了。試問上一個封裝程度更高的框架就能夠“修復”這種問題嗎?我感覺這像是沙堆上建房子。另外,大家遇到的業務場景不一樣,你遇到的問題他不一定會遇到,因此我不相信一個基於不穩定平臺的抽象能夠自動處理該平臺本身的問題。

這讓我想起美劇《矽谷》裡面蓋文.貝爾森的對白

請大家想想有這麼一個革命性的功能,一旦整合進“紐核力”平臺,可以修復平臺釋出過程中出現的任何問題。

GB

他真不愧是21世紀最不切實際,最會忽悠並壓榨員工的科技公司的管理者,而且這種型別的管理者似乎也不在少數。可悲的是,這也是很多人上一個框架的初衷,覺得框架會幫我們修復一些我們自己不願意修復的問題,別做夢了,世界還是很殘酷的。另一方面,使用一個基於不穩定的平臺開發出來的框架,出bug的機率還是比較大的,當bug出現的時候,你可能還要花時間去定位是微信自身的bug還是開發框架所帶來的bug,這都是比較耗時的工作。而這種時候,到底框架幫你解決了什麼問題呢?

關於寫法統一的問題,在2016年的RubyConf China裡面一個叫Terry的演講者(他現在是Nervos Network的CEO)在會上講過一句話對我影響很大,大意如下

我發現今天的Web開發跟十年前相比並沒有什麼不同,既然十年前我們就用Ruby來寫後端,用JavaScript來寫前端互動,為何十年後的今天我們一定要統一寫法呢?

回過頭來看,這些業界所強加給你的最佳實踐可能並沒有你想象的那麼的“最佳”。作為程式設計師我們是被僱傭來解決問題的,請儘量別讓自己把問題複雜化。

前後端分離是最佳實踐?

前後端分離到底是不是最佳實踐?不同人會有不同的看法。在我看來解決問題才是目的,分不分離都只是手段罷了。 隨著React,Vue這些框架的盛行,不分離者成了眾矢之的,因為業界都覺得分離才是“最佳實踐”,確實前後端分離可以讓前端專注於自己的開發流程,但有的時候前後端一旦分離,掙脫了後端約束的前端便猶如脫韁的野馬,一小心就成了Rei所說的前後端分裂了。

在充分利用Webpack大殺器之後,我們甚至可以用自己喜歡的任何語法來寫前端程式,漸漸地可能會發展成一種只有自己才能夠看懂的DSL,熟悉的人自然得心應手然而其他工程師要學習,理解,並且提出質疑都會花費彼此不少的時間,這都是成本。我始終覺得如果一個前端工程師寫的程式碼後端需要花費很大的力氣才能夠讀懂的話,那或許應該稍微反省一下了,是不是某些地方過度工程了?

前後端分離是把雙刃劍,需要前後端人員相互協調專案才不至於失控。需要考慮分離帶來的好處是什麼,是為了表單提交更方便?還是為了頁面互動更加流暢?並不是說Facebook出了一個React,而它用這個框架重寫了Facebook還有instagram這些網站我們就一定要跟從。有時候還得考慮Facebook這些公司什麼量級自己什麼量級。如果只是需要提升部分頁面的互動效果,或許Gitlab這種只把關鍵部分的資源進行分離的做法會更適合我們。不考慮實際情況,只是為了脫離後端把控而實行的分離在我看來都是搞事情。

最佳實踐有時候會讓你遠離問題的根源

這是最近公司進行容器方面嘗試時遇到的問題。最近升級官網服務,想要基於這個專案做一些容器化的探索。初步的預想就是脫離原始的capistrano部署方案(這不是一個好主意)然後

  • 對官網專案容器化。
  • 基於容器實現自動化部署。

OK,理論上我只需要學習如何用Docker相關的技術來容器化整個專案,然後再使用輔助工具來實現自動化部署即可。而這個時候運維小夥伴為我引進了Kubernetes(K8S),這個業界容器化的“最佳實踐”。這是個好東西,但同時也給我帶來了其他的問題

  • 根據K8S提供的最佳實踐,我們需要把配置檔案存在Etcd(一個配置管理服務)裡面。
  • SSL證照要如何管理,是否應該採用更流行的Caddy服務?
  • 服務多了要怎麼做反向代理?K8S有現成的東西可以用,以後做擴容也方便。
  • 有那些服務需要掛載資料卷?

好吧,在對K8S沒有什麼瞭解,並且沒什麼運維經驗的人來說要消化這些問題難免需要點時間,我就花了一兩週的空閒時間去看K8S的文件,其實要熟悉K8S的命令不是很困難的事情,但是要理清不同服務之間的關係,並實現對應的“最佳實踐”卻是比較頭疼且耗時的工作。這期間還有一些其他專案的干擾,導致了新版官網遲遲沒有得到部署,因為精力都花在別處了。

後來才醒悟過來,好像我們都沉浸於業界的最佳實踐當中,被一堆所謂的最佳實踐的概念所淹沒,而忘記了一開始我們需要做的事情以及要解決的問題。其實我們想要做的本質工作只是把專案部署出去,最好是能夠自動化。K8S以及相關的最佳實踐只是可選項,我們沉浸於最佳實踐當中,卻沒能嚐到它帶來的甜頭,離問題的根源越來越遠。

大家都傾向於實現一個100分的解決方案,卻沒有考慮到要做到100分所要付出的時間還有精力,或許很多時候一個60分的不甚完美的解決方案更適合自己。因此最終我們還是決定只完成容器最基礎的部分,然後儘快把專案部署出去。K8S的事情延後,在以後的日子裡再慢慢去優化這個只有60分的解決方案。

最佳實踐讓你束手束腳

這是一個“先有雞,還是先有蛋”的問題。以前的人做開發普遍都是擼起袖子就幹,等到經驗有所積累之後慢慢重構已有的東西就得到了我們手上的框架。也就是說前人是先解決問題,然後把通用的解決方案抽象成框架,現在的人似乎不太一樣。而如今許多開發者是遇到問題,先找最佳實踐,如果沒有最佳實踐甚至不敢著手去解決問題。或許這也是Linux核心的開發者林納斯曾經怒斥最佳實踐的原因吧。他說

最佳實踐很多時候就是狗屎。

當“最佳實踐”成了一種思維的束縛,成為解決問題的巨大門檻的時候,它還算是最佳實踐嗎?當一個開發者被一個框架的思想所束縛,離開了指定的框架就無法完成任何工作的時候,那這個框架存在的意義又何在呢?還記得《倚天屠龍記》裡面張三丰教張無忌太極拳還有太極劍的時候讓他幹嘛了嗎?忘掉所有招式。如果這些所謂的招式對一個人來說只是束縛,那麼還要它何用?

實際上很多時候你能夠想出的解決方案已經足夠好了。不可能有人一開始就能夠把事情做得完美,Ruby On Rails經過了十幾年的洗禮,至今還有許多可以優化的空間,市面上那些琳琅滿目的框架有幾個經歷過這種時間的沉澱?

Erlang語言的創始人Joe老爺子曾針對一門語言不夠快而發表過這樣的言論

先把程式寫正確,然後慢慢優化,許多年後它就會變快了。

比起一開始就追求高效能,最佳實踐,或許有些時候我們可以先考慮如何把“程式寫對”,哪怕這個解決方案不是最佳,起碼你為這個問題思考過,而不是想著拿來就用。如果以後遇到更好的解決方案,我相信到時候再優化也為時不晚。

總結

以上是我對軟體開發過程中“最佳實踐”這個觀念的一些碎碎念,我個人並不是完全排斥最佳實踐,但是我認為所謂的最佳實踐是有場景限制的,考慮到時間成本,實現難度,人員調配等各方面因素,在某些場景下的“最佳實踐”在另一些場景下或許會成為“最糟實踐”。什麼都不想就隨大流,強上“最佳實踐”的做法無論對自己還是對團隊都是極度不負責任的。

相關文章