戰(zhàn):從登錄框到開源項(xiàng)目的技術(shù)還原方法論)
1. 先把“reverse-skill”這個(gè)概念講清楚1.1 它到底是什么不是什么先說結(jié)論reverse-skill不是“逆向工程”的狹義說法也不是教你怎么破解別人軟件而是一種“從結(jié)果倒推原因”的底層能力。網(wǎng)上很多人把reverse-skill翻譯成“反向技能”聽著玄乎其實(shí)你在工作和生活里早就用過。舉個(gè)例子你看到同事做的報(bào)表特別清晰第一反應(yīng)不是問他“你怎么做的”而是自己打開文件看每一列怎么設(shè)的、條件格式怎么配的、數(shù)據(jù)透視表怎么拉的看完了合上文件自己重做一遍。這就是reverse-skill。放到技術(shù)和產(chǎn)品領(lǐng)域這種能力會(huì)被放大得更明顯。拿到一個(gè)沒文檔的老系統(tǒng)別人抓瞎時(shí)你能通過頁(yè)面請(qǐng)求和報(bào)錯(cuò)信息反推它的表結(jié)構(gòu)看到一個(gè)交互效果很炫的網(wǎng)頁(yè)你不是只會(huì)“哇”而是打開開發(fā)者工具看這個(gè)效果到底是用CSS動(dòng)畫、JS定時(shí)器還是Canvas畫的接手一個(gè)陌生的開源項(xiàng)目你不需要等別人給你講架構(gòu)自己順著入口文件、依賴關(guān)系和數(shù)據(jù)流向就能把骨架摸出來。需要特別說明的是reverse-skill絕不只是“看人家怎么做然后照著抄”。真正的reverse-skill包含三個(gè)層次第一層是“看出怎么做”第二層是“看透為什么這么做”第三層是“從中提煉出可遷移的方法”。只停留在第一層那叫模仿不叫技能。1.2 為什么現(xiàn)在比任何時(shí)候都需要它這兩年大家都有個(gè)明顯感受技術(shù)資料不是太少而是太多、太雜、太舊。你搜一個(gè)問題能搜到十年前的古早博客也能搜到剛發(fā)布的熱乎帖子哪個(gè)是對(duì)的AI生成的內(nèi)容也在大量涌入看似什么都懂實(shí)際很多是“正確的廢話”一旦你照著做發(fā)現(xiàn)跑不通反而更難判斷哪里出了問題。在這種環(huán)境下reverse-skill的價(jià)值變得非常具體它讓你從“找答案的人”變成“驗(yàn)證答案的人”。比如AI幫你寫了一段代碼你不能直接信任它而是要通過反向拆解理解每一行的作用知道它依賴了什么庫(kù)、用了什么API、邊界條件在哪里。拆過了你才敢上線不拆就上出了事故你連問題定位都無(wú)從下手。再往大了說很多優(yōu)秀產(chǎn)品是沒有文檔的。你不一定看得到它的源碼但你能看到它的界面、請(qǐng)求、交互和反饋。這些“產(chǎn)物的產(chǎn)物”就是你最好的老師。reverse-skill最核心的訓(xùn)練方式就是不停地拿遇到的成熟產(chǎn)物做拆解把表面現(xiàn)象還原成實(shí)現(xiàn)方案和設(shè)計(jì)決策。練得多了你再看任何東西都會(huì)有“透視感”這種透視感才是高手和普通人的分水嶺。我經(jīng)常跟團(tuán)隊(duì)里的小朋友說一句話不要等別人給你講業(yè)務(wù)你自己去看代碼、看接口、看數(shù)據(jù)看完能畫出一張圖來找我確認(rèn)這才叫主動(dòng)。這本質(zhì)上就是reverse-skill在職場(chǎng)協(xié)作里的體現(xiàn)。2. 四種最常見的reverse-skill拆解場(chǎng)景2.1 場(chǎng)景一前端頁(yè)面交互反推前端是最適合入門reverse-skill的領(lǐng)域因?yàn)槟憧吹降囊磺行Ч歼\(yùn)行在你的瀏覽器里所有資源都要下載到本地才能跑等于人家把答案送到你面前了。拿到一個(gè)你感興趣的頁(yè)面我習(xí)慣按下面這個(gè)順序看先開DevTools的Network面板刷新頁(yè)面看加載了哪些資源。這一步能快速判斷這是個(gè)靜態(tài)站還是動(dòng)態(tài)站用了什么前端框架。再切到Sources面板瀏覽JS和CSS文件。現(xiàn)在的構(gòu)建工具會(huì)把代碼打包壓縮成一兩行別慌點(diǎn)左下角的格式化按鈕Pretty print就能恢復(fù)縮進(jìn)。然后用CtrlShiftF全局搜索關(guān)鍵字比如你想知道登錄邏輯就搜login、password、token想知道錯(cuò)誤提示怎么彈的就搜error、toast、message。最后在關(guān)鍵位置打斷點(diǎn)重新觸發(fā)交互跟著執(zhí)行路徑走一遍。舉個(gè)我練手時(shí)印象很深的例子??吹揭粋€(gè)按鈕點(diǎn)擊后有個(gè)從右往左滑出的面板動(dòng)畫非常流暢。我第一反應(yīng)是“這應(yīng)該是CSS的transform加transition”因?yàn)樵谝苿?dòng)端這種動(dòng)畫性能最好。打開一看果然類名里掛著translateX和transition屬性。但光確認(rèn)到這步還不夠我又追問了一句那它是怎么知道點(diǎn)擊了哪一行數(shù)據(jù)才決定面板內(nèi)容的順著這個(gè)疑問我找到了點(diǎn)擊事件里的數(shù)據(jù)傳遞邏輯。這就是從“看到效果”推到“看到實(shí)現(xiàn)”。這種拆解練的是你的“技術(shù)嗅覺”看到一個(gè)現(xiàn)象先在心里建立三個(gè)候選答案然后逐一驗(yàn)證。很多初學(xué)者反推速度慢不是不會(huì)看DevTools而是腦子里候選答案太少看到什么都覺得陌生自然無(wú)從下手。2.2 場(chǎng)景二開源項(xiàng)目架構(gòu)反推接手一個(gè)不熟悉的中大型開源項(xiàng)目很多人第一反應(yīng)是“先跑起來再說”。這個(gè)思路不能說錯(cuò)但效率非常低你跑起來之后面對(duì)一堆代碼還是不知道從哪看起。我的做法是先不進(jìn)代碼細(xì)節(jié)而是站在項(xiàng)目門口看三樣?xùn)|西第一樣是README和官方文檔的目錄結(jié)構(gòu)不是讓你通讀而是看它重點(diǎn)介紹了哪些模塊模塊之間大概什么關(guān)系。第二樣是依賴清單就是package.json、requirements.txt、go.mod這類文件。依賴清單是最誠(chéng)實(shí)的架構(gòu)說明它告訴你這個(gè)項(xiàng)目用了什么生態(tài)、偏重哪方面的能力比如依賴了一堆狀態(tài)管理庫(kù)說明這個(gè)項(xiàng)目對(duì)復(fù)雜數(shù)據(jù)流很在意。第三樣是目錄結(jié)構(gòu)配合入口文件一起看。入口文件通常是main.js、app.py、main.go之類它是程序的起點(diǎn)也是你理解“先做了什么再做”的鑰匙。看完這三樣我建議你畫一張粗糙的模塊關(guān)系圖。不需要畫得多標(biāo)準(zhǔn)哪怕只是“入口 → 路由 → 業(yè)務(wù)模塊 → 數(shù)據(jù)層”這種大方向都行。然后帶著這張圖去挑一個(gè)你最關(guān)心的功能點(diǎn)比如“用戶登錄”從入口開始順著調(diào)用鏈往下走走到數(shù)據(jù)層再走回來一個(gè)閉環(huán)走通你對(duì)整個(gè)項(xiàng)目的理解立刻上一個(gè)臺(tái)階。這個(gè)場(chǎng)景里reverse-skill的本質(zhì)是你不是在“讀代碼”你是在通過代碼反推作者的架構(gòu)決策??吹揭粋€(gè)目錄叫services你就要想“作者為什么單獨(dú)抽一層service而不是把邏輯直接寫在接口層”答案往往是“因?yàn)槎鄠€(gè)接口需要復(fù)用同一套業(yè)務(wù)邏輯”。這種“每次看到一個(gè)結(jié)構(gòu)都要問作者在想什么”的習(xí)慣就是架構(gòu)反推的訓(xùn)練核心。2.3 場(chǎng)景三接口與數(shù)據(jù)結(jié)構(gòu)逆向反推這個(gè)場(chǎng)景在接老系統(tǒng)、接第三方平臺(tái)時(shí)特別實(shí)用。很多老系統(tǒng)文檔早就丟了你只拿到一個(gè)調(diào)用地址和幾個(gè)參數(shù)示例正常的接口聯(lián)調(diào)根本無(wú)法進(jìn)行這時(shí)候就得靠reverse-skill了。思路其實(shí)很樸素通過觀察請(qǐng)求和響應(yīng)反推對(duì)方的數(shù)據(jù)結(jié)構(gòu)。具體手法是多構(gòu)造幾種參數(shù)組合觀察返回結(jié)果的差異來判斷哪些參數(shù)是必填的、哪些帶默認(rèn)值、哪些只影響數(shù)據(jù)范圍??村e(cuò)誤信息。一個(gè)老道的后端工程師會(huì)通過錯(cuò)誤信息“釣”出更多接口信息。比如你傳一個(gè)不存在的字段名如果返回“field xxx not found”那說明接口會(huì)校驗(yàn)字段名你就拿這個(gè)錯(cuò)誤當(dāng)探針多試幾個(gè)單詞往往能猜出真實(shí)的字段命名風(fēng)格??错憫?yīng)耗時(shí)。某些接口對(duì)參數(shù)很敏感傳了某個(gè)參數(shù)后響應(yīng)時(shí)間明顯變慢大概率是觸發(fā)了不同的查詢路徑這就是性能側(cè)寫的逆向。碰到分頁(yè)參數(shù)我習(xí)慣把pageSize從10改成1、2、3這樣的小數(shù)字觀察返回結(jié)構(gòu)變化很快就能摸清分頁(yè)的實(shí)現(xiàn)方式。再用幾個(gè)特殊字符試試排序參數(shù)能看出它是前端排序還是后端排序——如果排序?qū)Ψ祷仨樞驔]影響那基本可以判斷這個(gè)參數(shù)被后端忽略了。這一套玩法對(duì)開發(fā)者的價(jià)值是你不光能“用”接口你還能“懂”接口。真正的資深開發(fā)者從來不只看接口文檔他們會(huì)通過接口的表現(xiàn)反推背后系統(tǒng)的設(shè)計(jì)約束。比如某個(gè)列表接口最大只能返回100條你再翻翻請(qǐng)求頭發(fā)現(xiàn)它帶了export這個(gè)參數(shù)那你就能判斷這個(gè)系統(tǒng)大概率有一份老舊的報(bào)表導(dǎo)出模塊——這些信息文檔上根本不會(huì)寫。2.4 場(chǎng)景四文案、方案與設(shè)計(jì)的逆向拆解千萬(wàn)不要以為reverse-skill只是技術(shù)人員的事。我看過很多非技術(shù)崗位的同事寫方案、做匯報(bào)、寫公眾號(hào)素材來源也是靠“拆”。拿到一份你覺得寫得特別好的方案不要只停留在“寫得好”的感嘆上而是拆它的骨架它的標(biāo)題是怎么擬的第一段是怎么建立信任的中間用了幾個(gè)分論點(diǎn)每個(gè)分論點(diǎn)的證據(jù)是什么結(jié)論是怎么呼應(yīng)開頭的拆完三份你就大概能總結(jié)出一套“好方案模板”。這個(gè)方法在競(jìng)品分析里尤其好用。我自己做產(chǎn)品調(diào)研時(shí)會(huì)把競(jìng)品的核心操作流程錄屏一幀一幀看它設(shè)置了哪些引導(dǎo)在哪個(gè)環(huán)節(jié)彈出提示什么時(shí)候要求用戶注冊(cè)這些節(jié)奏的選擇都是產(chǎn)品經(jīng)理反復(fù)調(diào)優(yōu)的結(jié)果。你通過操作路徑反推它的產(chǎn)品設(shè)計(jì)優(yōu)先級(jí)比看十篇分析報(bào)告都有用。說白了reverse-skill是一套通用的認(rèn)知方法換到任何領(lǐng)域都成立??吹饺魏我粋€(gè)被驗(yàn)證過“有效”的產(chǎn)物都值得你多問一句“它到底做了什么才有效”。這一問就把你和只會(huì)感嘆“真?!钡娜巳簠^(qū)分開了。3. 一輪完整的reverse-skill實(shí)操拆解一個(gè)登錄框3.1 實(shí)操前置準(zhǔn)備說了這么多方法論還是得來一輪完整的實(shí)戰(zhàn)不然都是空談。我們挑一個(gè)最常見也最適合練手的目標(biāo)一個(gè)普通網(wǎng)站的登錄框。登錄功能是幾乎每個(gè)系統(tǒng)都有的最小完整業(yè)務(wù)閉環(huán)它涉及前端交互、接口通信、狀態(tài)存儲(chǔ)、后端驗(yàn)證麻雀雖小五臟俱全。拆完它你對(duì)Web應(yīng)用的整體運(yùn)行邏輯會(huì)有一個(gè)非常直觀的理解。準(zhǔn)備工作很簡(jiǎn)單不需要搭任何復(fù)雜的環(huán)境。就用瀏覽器自帶的DevTools也就是按F12能打開的那套工具?,F(xiàn)代瀏覽器里Chrome或Edge的DevTools功能最全夠用了。我建議你在開始前先給自己定個(gè)目標(biāo)。不要籠統(tǒng)地說“我想搞懂登錄”而是具體一點(diǎn)比如“我想搞清楚登錄成功后前端是怎么知道用戶身份的”或者“我想知道密碼在傳輸?shù)臅r(shí)候到底有沒有加密”。目標(biāo)越具體拆解過程中你就越知道該看什么、該跳過什么。3.2 分四步還原完整登錄流程第一步看網(wǎng)絡(luò)請(qǐng)求的時(shí)序。打開DevTools的Network面板勾選Preserve log保留日志然后去正常操作一次登錄。注意千萬(wàn)要先勾選這個(gè)選項(xiàng)不然頁(yè)面一跳轉(zhuǎn)之前的請(qǐng)求日志就會(huì)被清空關(guān)鍵證據(jù)全丟了。登錄成功后回頭看請(qǐng)求列表你會(huì)看到一串請(qǐng)求但真正關(guān)鍵的通常只有幾個(gè)提交賬號(hào)密碼的登錄接口、加載用戶信息的接口、可能存在的刷新令牌接口。怎么分辨哪個(gè)是登錄接口呢最簡(jiǎn)單的方法是看請(qǐng)求方法。登錄接口一般是POST因?yàn)樗峤粩?shù)據(jù)路徑里通常也有l(wèi)ogin、auth、signin之類的關(guān)鍵詞。把鼠標(biāo)移到請(qǐng)求上右鍵選擇“Copy as cURL”就能看到這個(gè)請(qǐng)求的完整信息包括請(qǐng)求頭、請(qǐng)求體和目標(biāo)地址。第二步定位關(guān)鍵JS文件。還是在這個(gè)頁(yè)面切到Sources面板找到頁(yè)面引入的JS主文件?,F(xiàn)在的前端項(xiàng)目構(gòu)建出的JS都是壓縮過的可能就一長(zhǎng)串點(diǎn)左下角的“{}”格式化按鈕把它變成人可以讀的格式然后按CtrlShiftF全局搜索搜password或者login這類關(guān)鍵詞。你會(huì)看到這個(gè)關(guān)鍵詞出現(xiàn)在很多地方但沒關(guān)系我們要找的是一個(gè)函數(shù)當(dāng)你點(diǎn)擊登錄按鈕時(shí)它負(fù)責(zé)收集表單數(shù)據(jù)、組裝請(qǐng)求、然后發(fā)給服務(wù)器。這里有個(gè)實(shí)用技巧直接搜“querySelector”或“getElementById”看表單元素是怎么被獲取的順著DOM操作往上找往往能找到點(diǎn)擊事件的綁定處。然后再在事件處理函數(shù)里打斷點(diǎn)重新觸發(fā)一次登錄這次它會(huì)停在斷點(diǎn)上你就可以一行一行地看代碼執(zhí)行了。第三步觀察參數(shù)組裝與狀態(tài)流轉(zhuǎn)。斷點(diǎn)停下來后你會(huì)看到代碼里有一個(gè)對(duì)象里面裝著用戶名、密碼可能還有時(shí)間戳或者隨機(jī)數(shù)。重點(diǎn)來了如果密碼字段的值是明文那說明前端沒加密傳輸時(shí)可能依賴HTTPS來保護(hù)安全如果密碼被處理成一段很長(zhǎng)的字符串那說明走了加密邏輯你要往上找找加密函數(shù)看看用的是AES、RSA還是單純的哈希。跟到這一步再切回Network面板看登錄成功后前端把什么存到了本地。常見的存儲(chǔ)位置是localStorage、sessionStorage或者cookie你可以手動(dòng)在Console里執(zhí)行l(wèi)ocalStorage.getItemtoken這類命令看看有沒有拿到令牌。這個(gè)步驟非常關(guān)鍵因?yàn)椤暗卿洺晒笄岸俗隽耸裁础辈攀悄氵@次拆解的核心答案。第四步梳理狀態(tài)流轉(zhuǎn)并形成文檔。把上面看到的內(nèi)容整理成文字版的流程描述比如用戶輸入賬號(hào)密碼后點(diǎn)擊登錄按鈕觸發(fā)submit事件事件處理函數(shù)先做前端格式校驗(yàn)組裝請(qǐng)求體請(qǐng)求發(fā)送到某個(gè)接口等待響應(yīng)成功后拿到token存進(jìn)localStorage并跳轉(zhuǎn)到首頁(yè)。不用畫花哨的圖一段清晰的文字就夠用。寫完之后你再用同樣流程走一遍注冊(cè)和退出登錄對(duì)比差異你會(huì)發(fā)現(xiàn)登錄系統(tǒng)的設(shè)計(jì)套路就那么幾種一通百通。3.3 拆完之后把結(jié)果變成你自己的東西很多人拆到這里就停手了覺得“我看懂了完事了”。但真正的reverse-skill高手會(huì)再多做一步把拆出來的結(jié)果復(fù)刻出來。我的習(xí)慣是拆完一個(gè)登錄流程后不看原站代碼自己搭一個(gè)最小頁(yè)面。不用復(fù)雜的框架一個(gè)HTML文件加一個(gè)簡(jiǎn)單的后端接口就行把拆解中看到的邏輯用自己的代碼重寫一遍。這個(gè)過程才是技能內(nèi)化的關(guān)鍵你看的時(shí)候覺得什么都簡(jiǎn)單輪到自己寫就會(huì)暴露出很多被忽略的細(xì)節(jié)比如token存哪兒、請(qǐng)求失敗怎么提示、按鈕loading狀態(tài)怎么切換、同一賬號(hào)多端登錄怎么處理。復(fù)刻完我再把整個(gè)流程寫成一篇筆記包含請(qǐng)求路徑、參數(shù)結(jié)構(gòu)、關(guān)鍵函數(shù)、踩坑點(diǎn)和自己復(fù)刻時(shí)的改動(dòng)原因。這個(gè)筆記就是你的私有知識(shí)庫(kù)以后遇到類似的登錄需求直接拿出來參考省掉大量從零開始的時(shí)間。這里要特別提醒我講的這套流程適用于學(xué)習(xí)公共網(wǎng)站的正常瀏覽行為和分析自己開發(fā)的系統(tǒng)。如果要分析別人的站點(diǎn)請(qǐng)確保這個(gè)行為在其服務(wù)條款允許的范圍內(nèi)并且不要利用拆解結(jié)果做攻擊性操作。合理解析技術(shù)但別越界這是每一個(gè)開發(fā)者的底線。4. 逆向拆解時(shí)最常見的6個(gè)坑與排查實(shí)錄4.1 坑一把“看過程”當(dāng)成“懂原理”這個(gè)是新手最容易踩的坑沒有之一。跟著斷點(diǎn)走了一遍看到請(qǐng)求發(fā)出去了、響應(yīng)回來了、頁(yè)面刷新了就覺得自己學(xué)會(huì)了。但第二天讓你自己說一遍流程你會(huì)發(fā)現(xiàn)什么都說不出來。為什么會(huì)出現(xiàn)這種情況因?yàn)槟阒皇潜粍?dòng)地“看了一遍執(zhí)行”沒有主動(dòng)對(duì)著代碼提問。整個(gè)過程你的大腦是跟著代碼走的或者說被代碼帶著走完全沒有建立起自己的主線。我的破解方法是在拆解前先寫好問題清單比如登錄成功后token具體放在哪個(gè)位置、密碼有沒有二次處理、失敗時(shí)前端怎么判斷。每找到答案就手動(dòng)更新這份清單。拆完后再不看代碼憑記憶把整個(gè)過程講一遍講不出來的地方就是你沒真正懂的地方回去再看。這個(gè)“先問再看看完復(fù)述”的機(jī)制能有效防止你陷入“眼睛會(huì)了手不會(huì)”的假學(xué)習(xí)狀態(tài)。4.2 坑二一上來就追最新版本看到目標(biāo)站點(diǎn)或項(xiàng)目最近剛更新了代碼就總想讀最新版覺得學(xué)老的沒用。這個(gè)心態(tài)在reverse-skill里非常致命最新版本往往意味著功能最多、代碼最繞、歷史包袱最雜你一股腦扎進(jìn)去很容易在邊角邏輯里迷失方向。我一般會(huì)反過來先找一個(gè)穩(wěn)定、被大量使用的歷史版本或者線上穩(wěn)定版本拆解。原因很簡(jiǎn)單穩(wěn)定版本經(jīng)過大量驗(yàn)證代碼路徑更清晰、主干更明顯最適合用來建立整體認(rèn)識(shí)。等主干打通了再去看最新版的改動(dòng)日志重點(diǎn)看新版本多了什么能力這時(shí)候再看diff差異對(duì)比會(huì)非常有目標(biāo)感而不會(huì)淹沒在細(xì)節(jié)里。這個(gè)原則同樣適用于文檔和教程收藏了很多“最新教程”不如先老老實(shí)實(shí)把一個(gè)老版本吃透老版本的技術(shù)底層和核心思路往往和新版本一致變的是API和工具鏈。4.3 坑三不記錄假設(shè)驗(yàn)證時(shí)全憑感覺拆解過程需要大量猜測(cè)看到一個(gè)結(jié)構(gòu)你心里冒出“這可能是做權(quán)限校驗(yàn)的”這個(gè)念頭就是一條假設(shè)。很多人的習(xí)慣是這個(gè)念頭閃過就完了繼續(xù)往下看結(jié)果看了半天發(fā)現(xiàn)之前的假設(shè)錯(cuò)了但因?yàn)闆]記錄連錯(cuò)在哪一步都不知道整個(gè)過程亂成一鍋粥。高手會(huì)隨身帶著一張“假設(shè)清單”或者直接寫在筆記里格式非常簡(jiǎn)單編號(hào)、假設(shè)內(nèi)容、驗(yàn)證證據(jù)、結(jié)論。比如“假設(shè)登錄后token存在localStorage驗(yàn)證證據(jù)是在Console執(zhí)行l(wèi)ocalStorage.getItem后返回了以eyJ開頭的字符串結(jié)論成立”。一條條記下來你會(huì)發(fā)現(xiàn)拆解過程變得特別清爽每一步都有因果最后整理成文檔也異常順手。更重要的是假設(shè)清單能訓(xùn)練你的思考習(xí)慣你不會(huì)再看到什么都信而是習(xí)慣性地把信息轉(zhuǎn)化成“待驗(yàn)證的假設(shè)”。這種批判性思維在工作里非常值錢。4.4 坑四輕視構(gòu)建與配置拿產(chǎn)物當(dāng)源碼分析這是很多有經(jīng)驗(yàn)的人都會(huì)翻車的場(chǎng)景看到一份線上代碼或發(fā)布包直接拿它來分析結(jié)果發(fā)現(xiàn)邏輯和源碼對(duì)不上。原因很簡(jiǎn)單你看到的可能是構(gòu)建產(chǎn)物源文件經(jīng)過了轉(zhuǎn)譯、壓縮、混淆變量名都換成了a、b、c函數(shù)結(jié)構(gòu)被打散文件也被合并這時(shí)候硬啃效率極低。遇到這種情況先別急著摳代碼?;仡^看看打包配置比如webpack的配置文件里有沒有開啟sourcemap。有sourcemap的話在Sources面板里你能直接看到未壓縮的原始源代碼分析難度瞬間降回正常水平。沒有sourcemap的時(shí)候就用構(gòu)建工具的知識(shí)反推看到一堆chunk文件名帶hash就知道這是代碼分割的結(jié)果看到樣式是內(nèi)聯(lián)在JS里的就知道這是CSS-in-JS或者style-loader的手筆。這個(gè)坑的根源是混淆了“前置設(shè)計(jì)”和“后置構(gòu)建”。拿到任何代碼前先判斷它是源碼還是構(gòu)建物是構(gòu)建物就先想辦法找到映射關(guān)系。判斷不準(zhǔn)分析整個(gè)就變形了。4.5 坑五資料越查越亂陷入“收藏夾焦慮”拆解過程中你一定會(huì)搜到相關(guān)的博客、文檔、問答帖東存一個(gè)西存一個(gè)最后收藏夾滿滿當(dāng)當(dāng)腦子空空蕩蕩。這個(gè)現(xiàn)象我稱之為“資料囤積癥”有些人是覺得存了就等于學(xué)了有些人則是真的不知道哪些有用哪些沒用。我的處理原則是每個(gè)拆解項(xiàng)目只允許留一個(gè)收口出口。要么是一個(gè)文檔要么是一個(gè)表格要么是一張圖。搜集來的所有資料必須轉(zhuǎn)化成這個(gè)出口里的內(nèi)容才允許“存下來”否則看完就關(guān)。這個(gè)強(qiáng)制措施逼著你做信息篩選和歸納——如果你連這條資料是否對(duì)當(dāng)前問題有幫助都沒想清楚那它大概率不重要。實(shí)際試過之后你會(huì)明顯感覺到拆解的深度不在于看了多少份資料而在于能否把每一份資料都消化成自己那套結(jié)論的一個(gè)證據(jù)。資料是磚但你不負(fù)責(zé)囤磚你負(fù)責(zé)蓋樓。4.6 坑六只有輸入沒有輸出時(shí)間花了卻無(wú)沉淀最后一個(gè)坑也是最難克服的一個(gè)拆了很多東西但從不輸出。有人覺得自己理解了就不用寫有人在等“完全搞懂了再寫”有人在趕下一件事兒。但事實(shí)是沒有輸出你的拆解就只是一次性的腦內(nèi)體驗(yàn)過一兩周就煙消云散下次遇到類似場(chǎng)景你還得從零開始拆。我現(xiàn)在給自己定的規(guī)矩是上手拆一個(gè)東西就必須留下一個(gè)可復(fù)用的產(chǎn)物。這個(gè)產(chǎn)物不一定是文章可以是一段注釋完整的代碼、一張模塊關(guān)系圖、一份問題清單甚至只是一篇幾百字的復(fù)盤。關(guān)鍵是它要能讓一個(gè)月后的你看完后不需要重頭再拆一遍就能回憶起核心結(jié)論。如果不想寫文檔我建議你換個(gè)方式輸出把你拆到的內(nèi)容講給別人聽。講的時(shí)候卡住了或者對(duì)方聽不懂就說明你沒真正拆透。這個(gè)即時(shí)反饋比任何自我感覺都要可靠。我個(gè)人練reverse-skill已經(jīng)好幾年最大的體會(huì)是這個(gè)能力一旦形成你看世界的方式都會(huì)變看到好產(chǎn)品、好文章、好方案第一反應(yīng)永遠(yuǎn)是“它是怎么被做出來的”而不是“哦挺好的”。如果你也想建立這套思維方式我建議你從明天開始找一個(gè)天天都在用但從未細(xì)看過的網(wǎng)頁(yè)打開開發(fā)者工具花四十分鐘拆一遍就拆一個(gè)登錄框。拆完這第一輪你就真正踏上這條路了。