
1. 從一個詞出發(fā)為什么impeccable值得單獨拿出來聊第一次看到impeccable這個詞被單獨拎出來當(dāng)作一個項目標(biāo)題我的反應(yīng)是愣了一下。這個詞在英文里的意思是無可挑剔的、完美的、零瑕疵的詞根來自拉丁語impeccabilis其中im-是否定前綴peccare是犯錯的意思合起來就是不會犯錯的。它跟perfect還不太一樣——perfect 強調(diào)的是達到了最高標(biāo)準(zhǔn)而 impeccable 強調(diào)的是找不到任何可以挑刺的地方是一種從審查者視角出發(fā)的判斷。把這個詞當(dāng)作一個項目來對待其實非常有意思。它不是一個具體的技術(shù)棧不是一個框架也不是一個工具庫而是一種質(zhì)量標(biāo)準(zhǔn)。我做了這么多年項目越來越覺得真正拉開從業(yè)者差距的往往不是你會不會用某個工具而是你交付的東西能不能經(jīng)得起別人拿著放大鏡看。impeccable 這個詞恰好就是這種狀態(tài)的精準(zhǔn)概括。所以這篇內(nèi)容我想圍繞如何把一件事做到 impeccable這個核心命題展開。它適合所有對自己交付物有要求的人——不管你是寫代碼的、做設(shè)計的、寫文檔的、做手工的還是做任何需要被別人檢驗成果的工作。我會從什么叫真正的無可挑剔為什么大多數(shù)人做不到具體在哪些環(huán)節(jié)最容易出問題怎么建立一套可復(fù)用的自檢機制這幾個角度把這件事拆開講透。需要提前說明的是impeccable 不等于過度完美主義。這兩者的區(qū)別非常大完美主義是我覺得還不夠好所以一直改impeccable 是從使用者的角度出發(fā)該覆蓋的場景我都覆蓋了該處理的邊界我都處理了。前者是向內(nèi)耗后者是向外負責(zé)。搞清楚這個區(qū)別是理解整篇內(nèi)容的前提。2. 拆解無可挑剔它到底由哪幾個維度構(gòu)成2.1 功能完整性主路徑之外的場景才是分水嶺大多數(shù)人做東西只覆蓋主路徑——也就是最理想情況下的使用流程。比如做一個表單主路徑就是用戶正常填寫、正常提交、正常收到反饋。這條路徑跑通很多人就覺得完事了。但 impeccable 的要求是主路徑只是及格線。真正決定質(zhì)量的是那些非主路徑場景。我習(xí)慣把它們分成幾類來逐一檢查空狀態(tài)用戶第一次進來什么數(shù)據(jù)都沒有的時候界面/輸出是什么樣是空白一片讓人不知所措還是有清晰的引導(dǎo)異常輸入用戶輸入了超長文本、特殊字符、負數(shù)、空值、格式不對的內(nèi)容系統(tǒng)怎么反應(yīng)是直接崩潰還是給出可理解的提示邊界值數(shù)量剛好為0、剛好為最大值、剛好差一個單位的時候邏輯是否還正確并發(fā)與重復(fù)操作用戶快速點了兩次提交、同時開了兩個窗口操作同一份數(shù)據(jù)會發(fā)生什么中斷恢復(fù)操作到一半網(wǎng)絡(luò)斷了、頁面關(guān)了、程序崩了重新進來能不能接上這五類場景我把它叫做隱性需求清單。它們不會寫在需求文檔里但每一個真實用戶遲早都會撞上。你提前處理了用戶覺得這東西真穩(wěn)你沒處理用戶覺得這東西能用但不敢依賴。impeccable 和能用之間的差距基本就藏在這張清單里。2.2 一致性同一個東西在不同地方必須長得一樣、行為一樣一致性是最容易被忽視、又最容易被用戶察覺的維度。人對不一致的敏感度遠超自己想象——按鈕圓角在這個頁面是4px、在那個頁面是6px用戶說不出哪里怪但就是覺得不精致。一致性至少包含三個層面視覺一致性。顏色、間距、字號、圓角、陰影、圖標(biāo)風(fēng)格必須有一套統(tǒng)一的規(guī)則并且所有地方都遵守。我見過太多項目做著做著就就地發(fā)揮每個頁面都像不同人做的最后拼在一起就是一股廉價感。交互一致性。同樣的操作在不同地方應(yīng)該有同樣的反饋。比如刪除這個動作如果A頁面是彈窗確認、B頁面是直接刪、C頁面是撤銷式刪除用戶就會困惑。選一種模式然后貫徹到底。語義一致性。同一個概念全項目用同一個詞。不要這里叫用戶、那里叫賬戶、另一個地方叫會員。術(shù)語混亂會讓用戶懷疑這倆是不是不同的東西增加認知負擔(dān)。我自己的做法是在項目一開始就維護一份約束清單把所有視覺和交互規(guī)則寫下來。每次新增內(nèi)容先對照清單而不是憑感覺。這份清單不需要多復(fù)雜一頁紙就夠但它的存在能讓一致性從靠自覺變成有據(jù)可依。2.3 可維護性三個月后的你還能看懂現(xiàn)在的你impeccable 有一個時間維度不只是現(xiàn)在看起來沒問題而是過一段時間回來還能不能順利接手。這個維度最考驗人。因為寫的時候你腦子里有完整上下文覺得這很明顯啊但三個月后上下文全丟了再看自己寫的東西就像看天書。判斷可維護性有個很簡單的測試假設(shè)一個完全不了解這個項目的人來接手他能不能在不問你的情況下搞懂每個部分的意圖要做到這一點核心是把決策的理由留下來。代碼里為什么用這個方案而不是那個、某個參數(shù)為什么設(shè)成這個值、某段邏輯為什么繞了一下——這些為什么如果不寫下來后來的人包括未來的你就只能靠猜。而猜錯的代價往往是改壞東西。我習(xí)慣在關(guān)鍵位置留三類注釋一是這段在解決什么問題二是為什么不用更直觀的方案三是如果以后要改需要注意什么。這三類信息加起來能讓接手成本降低一大半。2.4 容錯與降級出問題時的表現(xiàn)才見真章一個系統(tǒng)在一切正常時的表現(xiàn)說明不了太多。真正體現(xiàn) impeccable 的是它在出問題時的表現(xiàn)。理想狀態(tài)下任何環(huán)節(jié)都可能失敗數(shù)據(jù)源掛了、依賴的服務(wù)超時了、磁盤滿了、內(nèi)存不夠了。impeccable 的做法不是假設(shè)這些不會發(fā)生而是假設(shè)它們一定會發(fā)生然后設(shè)計好失敗時的行為。具體來說要回答幾個問題失敗時是直接報錯崩潰還是優(yōu)雅降級到某個可用狀態(tài)錯誤信息是給開發(fā)者看的堆棧還是給用戶看的可理解提示失敗后能不能重試重試有沒有次數(shù)限制和退避策略部分失敗時是整體回滾還是保留已完成的部分這些問題在順利的時候想不起來在出事的時候又來不及想。所以必須在設(shè)計階段就過一遍。我的經(jīng)驗是把每個外部依賴都當(dāng)成隨時會掛來對待然后為每個依賴想好掛了之后怎么辦。這個習(xí)慣一旦養(yǎng)成交付物的穩(wěn)定性會有質(zhì)的提升。3. 為什么大多數(shù)人做不到 impeccable三個真實的阻力3.1 阻力一完成比完美更緊迫的現(xiàn)實壓力說實話絕大多數(shù)項目不是做不到 impeccable而是沒時間做到。排期壓著、需求催著、上線時間定死了能跑通主路徑就已經(jīng)謝天謝地哪還有精力去摳邊界場景。這個現(xiàn)實我完全理解也不主張為了完美而無止境地拖。但我想說的是impeccable 不等于無限投入它更多是一種優(yōu)先級意識。你不需要把所有場景都做到極致但你需要知道哪些場景是必須覆蓋的然后把有限的精力花在這些地方。我的做法是給場景分級P0 是不處理就會導(dǎo)致數(shù)據(jù)錯誤或崩潰的必須做P1 是不處理會讓用戶困惑的盡量做P2 是錦上添花的有余力再做。這樣即使時間緊也能保證最關(guān)鍵的部分不掉鏈子。真正的問題不是沒時間而是很多人根本沒意識到還有 P0 場景沒覆蓋。3.2 阻力二自己測自己天然存在盲區(qū)第二個阻力更隱蔽你很難發(fā)現(xiàn)自己寫的東西的問題。因為你的腦子里已經(jīng)預(yù)設(shè)了正確用法測試的時候會不自覺地按正確用法去操作自然測不出問題。這是認知層面的盲區(qū)靠更仔細一點是解決不了的。破解辦法只有一個換視角。具體有幾種可操作的方式換人測找一個完全沒參與的人來用什么都不告訴他看他在哪里卡住。他卡住的地方就是你的盲區(qū)。換心態(tài)測假裝自己是個惡意用戶專門輸入奇怪的東西、專門做反常操作看系統(tǒng)扛不扛得住。換時間測寫完先放一放隔一天再回來測。隔了時間你就沒那么熟悉了更容易發(fā)現(xiàn)問題。換環(huán)境測在不同的設(shè)備、不同的網(wǎng)絡(luò)條件、不同的數(shù)據(jù)量下測。很多問題只在特定環(huán)境下才暴露。我自己最常用的是換人測。每次找同事幫忙試用總能發(fā)現(xiàn)一堆我完全沒想到的問題。這不是因為我水平差而是因為作者視角和用戶視角本來就是兩回事。3.3 阻力三沒有一套固定的自檢流程全靠臨場發(fā)揮第三個阻力是流程層面的很多人做檢查是想起來就查一下沒有固定套路。結(jié)果就是狀態(tài)好的時候查得細狀態(tài)差的時候草草了事質(zhì)量忽高忽低。impeccable 的本質(zhì)是穩(wěn)定輸出高質(zhì)量而不是偶爾超常發(fā)揮。要做到穩(wěn)定就必須把檢查變成流程而不是靠心情。流程的好處是它不依賴你當(dāng)下的狀態(tài)只要照著走就能保證一個基本的下限。下一節(jié)我會詳細講這套流程怎么建。這里先點明一個原則流程要短、要具體、要能勾選。太長的清單沒人會認真執(zhí)行太抽象的條目沒法判斷到底做沒做。好的自檢清單應(yīng)該是每一條都能明確回答是/否的。4. 建立一套可復(fù)用的自檢機制我的實操流程4.1 交付前的三遍過法我在每個東西交付前都會強制自己過三遍每一遍的關(guān)注點完全不同。這個方法我用了很多年效果很穩(wěn)。第一遍功能過。只關(guān)注該有的功能是不是都有、該走的路是不是都通。這一遍不看細節(jié)就看整體是否完整。對照最初的需求清單一項一項打勾。有遺漏的記下來。第二遍邊界過。這一遍專門找茬。把前面提到的隱性需求清單拿出來逐條驗證空狀態(tài)什么樣異常輸入怎么處理邊界值對不對重復(fù)操作會怎樣中斷了能不能恢復(fù)這一遍往往能揪出最多問題。第三遍體驗過。這一遍把自己當(dāng)成第一次使用的用戶從頭到尾走一遍感受每一步是否順暢、提示是否清楚、反饋是否及時。這一遍關(guān)注的是感受不是功能。三遍分開過的原因是如果混在一起注意力會被分散很容易顧此失彼。分開之后每一遍都有明確的焦點效率反而更高。4.2 一份可以直接抄的自檢清單下面這份清單是我自己長期用的覆蓋了大部分場景。你可以根據(jù)自己的領(lǐng)域增刪但建議保留結(jié)構(gòu)。檢查維度具體檢查項判斷標(biāo)準(zhǔn)功能完整性主流程是否跑通無阻斷性錯誤功能完整性需求清單是否全部覆蓋逐項打勾無遺漏邊界處理空狀態(tài)是否有引導(dǎo)不是空白一片邊界處理異常輸入是否有提示提示可理解、不崩潰邊界處理邊界值是否正確0、最大值、臨界值驗證通過一致性視覺規(guī)則是否統(tǒng)一對照約束清單無偏差一致性交互反饋是否一致同類操作反饋相同一致性術(shù)語是否統(tǒng)一同一概念同一叫法容錯性依賴失敗是否有降級不直接崩潰容錯性錯誤信息是否友好用戶能看懂可維護性關(guān)鍵決策是否有注釋說明為什么可維護性接手者能否獨立理解無需口頭解釋這份清單不需要每次全過一遍但至少要在交付前掃一眼確認沒有明顯遺漏。用久了之后很多項會變成肌肉記憶但清單還是要留著——因為人總會累、會趕、會疏忽清單是最后一道防線。4.3 把復(fù)盤變成習(xí)慣而不是事故后的補救很多人只在出問題之后才復(fù)盤這叫救火式復(fù)盤。impeccable 的做法是主動復(fù)盤即使這次沒出問題也定期回顧哪些地方本來可能出問題。我習(xí)慣在每個階段結(jié)束時問自己三個問題這次有哪些地方是靠運氣才沒出事的如果重來一次哪個環(huán)節(jié)我會做得不一樣這次積累了什么經(jīng)驗下次可以直接用第一個問題最關(guān)鍵。因為靠運氣沒出事和靠設(shè)計沒出事是兩回事前者是隱患后者才是能力。把靠運氣的部分找出來補上設(shè)計下次就不用再賭運氣了。5. 幾個容易翻車的細節(jié)來自一線的踩坑記錄5.1 提示信息寫得太技術(shù)用戶根本看不懂我見過太多項目出錯時彈出一句Error: null pointer exception at line 42或者操作失敗錯誤碼 500。寫的人覺得信息很全啊但用戶看到只會一臉懵。impeccable 的提示信息必須回答三個問題發(fā)生了什么、為什么發(fā)生、用戶能做什么。比如同樣是失敗好的提示是保存失敗可能是網(wǎng)絡(luò)不穩(wěn)定請檢查網(wǎng)絡(luò)后重試。它沒有暴露任何技術(shù)細節(jié)但用戶知道該怎么辦。這里有個原則技術(shù)細節(jié)寫進日志用戶提示寫人話。日志給開發(fā)者看可以詳細提示給用戶看必須通俗。兩者分開各司其職。5.2 狀態(tài)管理混亂導(dǎo)致看起來對但實際錯狀態(tài)不一致是特別隱蔽的坑。比如界面上顯示已保存但實際數(shù)據(jù)沒落庫或者列表顯示有5條點進去只有3條。這種問題在測試時不容易發(fā)現(xiàn)因為看起來是對的但用戶一旦依賴這個狀態(tài)做決策就會出大問題。避免這個坑的核心是單一數(shù)據(jù)源。同一個狀態(tài)只在一個地方維護其他地方都從它派生。不要在兩個地方各存一份然后靠同步來保持一致——同步遲早會漏。5.3 過度設(shè)計為了完美引入了不必要的復(fù)雜度這一條是給完美主義者的提醒。impeccable 不是越復(fù)雜越好。我見過一些項目為了處理一個幾乎不可能發(fā)生的邊界情況引入了一大堆抽象和配置結(jié)果主流程反而變得難懂、難改。判斷標(biāo)準(zhǔn)很簡單這個處理帶來的收益是否大于它增加的復(fù)雜度如果一個邊界情況發(fā)生的概率極低且發(fā)生后影響可控那不處理或者簡單處理可能就是更 impeccable 的選擇。真正的無可挑剔是恰到好處不是堆砌。5.4 文檔和實際不符比沒有文檔更糟文檔寫的是A實際做的是B這種情況比完全沒文檔更危險。因為沒文檔時人會去讀代碼、去問反而能拿到真實情況有錯誤文檔時人會信文檔然后被帶偏。所以我的原則是文檔要么不寫要寫就必須和實際同步。如果沒精力維護寧可不寫把關(guān)鍵信息放在代碼注釋里至少離真相更近。6. 把 impeccable 變成一種工作方式而不是一次性的沖刺聊到這里我想強調(diào)一個觀點impeccable 不是某個項目的終極目標(biāo)而是一種持續(xù)的工作方式。它體現(xiàn)在每一次交付、每一個決策、每一個細節(jié)里而不是靠某一次突擊就能達成的。我自己的體會是做到 impeccable 最難的不是技術(shù)而是心態(tài)上的轉(zhuǎn)變——從做完就行變成做完還要經(jīng)得起看。這個轉(zhuǎn)變一旦發(fā)生你會發(fā)現(xiàn)自己對很多東西的要求都變了寫注釋會多想一步別人能不能看懂做界面會多想一步空狀態(tài)長什么樣設(shè)計流程會多想一步出錯了怎么辦。這種心態(tài)帶來的回報是長期的。你交付的東西越來越穩(wěn)別人越來越信任你你自己也越來越少被事后救火消耗。短期看你多花了時間長期看你省下的返工和溝通成本遠超當(dāng)初多花的那點精力。最后分享一個我一直在用的小技巧每次交付前問自己一句——如果這個東西明天被一個我很尊敬的人拿去用我會不會心虛如果答案是會那就說明還有沒做到位的地方繼續(xù)查。如果答案是不會那基本就到位了。這個自問自答比任何清單都管用因為它直接調(diào)動了你內(nèi)心對質(zhì)量的那桿秤。