在以前的文章中,曾經提過“技術人員的價值,不在於你能寫出多麼優美的程式碼,也不在於你能設計出一個多麼大而全的高屋建瓴的架構,而在於你實實在在的解決問題的能力,在於你使用技術手段服務於業務的能力”。
最近一段時間,因工作中遇到一些現象,讓我重又想起這句話,並且試圖思考如何來提高解決問題的能力,有沒有一種方法論的手段或者技術性的框架來實踐?
先羅列一兩個遇到的現象:
-
某同事彙報,測試提了一個Bug,當某個使用者繫結的卡資訊超過50個的時候,後臺顯示資料就會出現混亂,問能不能限制繫結的卡不超過50個。我問:資料顯示出現混亂是什麼意思?答:不清楚;我再問:為什麼超過50個就會混亂了,少於50個有沒有可能出現混亂,造成混亂的原因是什麼?答:不知道。我說你先去搞清楚什麼叫“混亂”,然後再搞清楚為什麼會出現“混亂”再來說解決辦法。經過與測試人員的一番溝通後,跟我反饋說不是顯示混亂,是顯示不全,自己通過檢視實現是因為在服務端做了字串拼接,超過多少就被截斷了。
-
某同事在抱怨,這個問題很難復現,我不知道怎麼解決,要不要把這塊整體優化下算了。我問他你優化的目的是什麼,是優化目前實現的流程、結構?還是通過優化來解決這個難以復現的問題?答:來解決這個問題。我說你問題都沒定位到,怎麼通過優化來解決,不怕老問題沒解決,優化出新的問題出來了?
你有沒有也曾經說過或聽過“這個問題太複雜了, 我解決不了”,“這個功能我沒辦法實現”,“我也不知道為什麼會出現這個問題”之類的話語。
以上的現象與話語,可能都是一個人解決問題的能力或方式方法還不成熟的體現。那麼如何來提高解決問題的能力,我想首先需要先從思維方式或思維習慣上尋求改變。在網上看到有這麼一篇文章——《How to think like a programmer — lessons in problem solving》(文章地址見文末參考部分),介紹了通過5個步驟來幫忙人們建立高效解決問題的思維框架。本文以這5個步驟為基礎,結合自身的理解與體會進行介紹。
“這個國家的每個人都應該學計算機程式設計,因為它會教你如何思考”
像程式設計師一樣思考
像程式設計師一樣思考,到底意味著什麼,需要如何來做?
像程式設計師一樣思考本質上來說,是一種更為有效的解決問題的方法。
解決問題的能力是一項元技能
什麼叫元技能?
類比於後設資料——描述資料的資料叫後設資料,我理解元技能就是提升技能的技能,就是說當你掌握瞭解決問題的能力,你就可以通過這種能力去提升其它各項專業技能。
解決問題的能力也是最重要的能力,比精通程式語言,除錯能力,以及系統設計能力都更為重要。
提高解決問題能力的方法
我們平時解決問題的方式可能是:
- 嘗試一種解決方案。
- 如果這種解決方案無效,再嘗試另一種方案。
- 如果還是沒有用,重複第二步直到你碰巧把問題解決了。
這種方法被作者 Richard Reis 定義為解決問題最糟糕的方式。因為它不但浪費時間,而且能不能達到目的還得看運氣。
經過對優秀程式設計師在程式設計時的思維框架的分析,作者總結出提高解決問題能力的最好方法包括:
- 有一個處理問題的框架
- 按照這個框架反覆練習
那麼,當你遇到一個新的問題時,該如何來解決?
第一步:理解
遇到問題時,我們應該先要弄明白問題本身。大部分情況下,問題之所以難解決只是因為你沒真正理解它們(很多時候是出於溝通的不充分),理解問題是解決問題的第一步。
如何確定自己是否真正理解一個問題?
最有效的方法是,嘗試用自己的語言來說出它,看有沒有邏輯漏洞。當你能講清楚一個問題時,說明你理解了它。優秀的程式設計師程式設計時,一般都會寫下自己遇到的問題,畫出流程或序列草圖,或同產品經理、其它開發人員、測試人員等一起討論確認。這個過程,就是在確定自己對問題的理解有沒有偏差。
“如果你不能用簡單的語言來解釋一個事情,那意味著你根本就沒有理解它” —— Richard Feynman
面對一個新需求時,你應該瞭解這個需求產生的場景——什麼人,在什麼時候通過執行什麼操作,來達到什麼目的?這個場景及其中的行為邏輯是否合理,設計是否存在漏洞,然後帶著問題來與需求提出方討論確認,而不是斷章取義或不經任何思考直接編碼開幹。不做程式碼的搬運工,要做有思想的程式設計師。
同樣,面對一個 Bug 時,你應該首先了解這個 Bug 產生的場景——什麼人,在什麼場景,通過什麼操作會產生這個問題?要追本溯源,定位問題的本源在哪裡。
我認為定位問題的本源比解決問題更重要!因為你只有正確地找到了問題的癥結,才有可能去解決它,而解決辦法卻可能有多種。且從花費的時間來說,定位問題往往會佔整個解決問題時間的一半以上。
如果沒有找到問題的本源,只是頭痛醫頭腳痛醫腳,那麼可能不僅對解決問題無事無補,甚至還可能引進新的問題。常見的頭痛醫頭腳痛醫腳的處理方式包括,CPU佔用高了,記憶體溢位了——升級伺服器配置(可能過兩天又得升級了!);介面超時了——增大超時時間(可能導致使用者投訴或其它依賴的服務級聯超時),等等。
那麼日常工作中,如何來定位問題的根源?對於一般問題來說,可能通過檢視日誌大致就能找到問題所在,對於比較棘手的問題,針對問題的性質一般可通過如下方法進行定位:
- 對於易復現的問題: 常用的就是 Debug,通過 IDE 斷點來跟蹤資料的流轉與變更,一個個環節檢查資料輸入輸出是否正確來進行排查。可藉助條件斷點、異常斷點等技巧來提高 Debug 效率。
- 對於不易復現的問題:可通過對比法——對比其它地方的類似功能或實現,尋找兩者之間的差異,差異之處往往就是問題所在;分析法——走讀整體流程程式碼,捋清各個環節的邏輯,分析定位問題;日誌法——在各個關鍵環節新增日誌,將場景映象下來,當下次復現的時候,通過分析日誌定位問題。
第二步:計劃
理解了問題,接下來就是解決問題的方案。沒有明確的方案計劃時,不要輕易去著手解決問題,不要寄希望於碰運氣矇混過關。許多開發人員習慣於快速掃一眼需求,就開啟 IDE 開始壘程式碼,壘完發現要麼與需求不符,要麼漏洞百出。
制定計劃,就是制定解決問題的戰略步驟。
不論面對需求還是 Bug,都應該好好計劃你的解決方案。設計好解決方案中的各個環節,如業務需求的資料表設計、介面設計、流程邏輯,Bug 修復的具體實施步驟。並給自己一點時間思考與預演,該解決方案可能存在的漏洞與影響有哪些,除了這樣處理,還有沒有另外更好的解決方案。
在沒有想清楚解決方案時,不要直接上來就擼程式碼,暫停一下,給你的大腦一些分析問題和處理資訊的時間。
第三步:分解
這是思維框架中最重要的一步。
分解,就是化繁為簡,就是我們常說的分治思想,拆分法——將大問題拆分為若干個小問題,然後逐個擊破各個小問題,再合併總結。微服務架構,MapReduce 演算法,都是這一思維(或思想)的體現。
不要嘗試一次解決一個複雜的大問題,而應把複雜的大問題分解成若干個簡單的小問題(或子問題),從最簡單的子問題開始(最簡單意味著你知道怎麼解決它或它更容易被解決,也或者這個子問題的解決不需要依賴於其它子問題),一個一個逐步解決。一旦你解決了所有的子問題,把它們串聯起來,一般就意味著你解決了之前的那個複雜的大問題。
分解問題的能力是解決問題的基石。這也是優秀的程式設計師在程式設計中最常用到的技能,對於他們來說,分解問題的能力,要比程式語言的熟練度、系統設計等技術更為重要。
第四步:卡殼了怎麼辦?
當你理解了問題,做出瞭解決方案的計劃,將複雜問題分解為子問題後,在處理子問題時依然卡殼了怎麼辦?
首先,淡定!然後告訴自己,這很正常,每個人都會遇到。
優秀程式設計師或解決問題的高手,與普通人之間的差別就在於,他們對問題更有求知慾,更有耐心,他們的注意力更多地是在如何解決問題上,而不是為此惱火或甩鍋發牢騷。
當遇到卡殼的情況時,可以試試這幾種方法:
-
Debug:與前面定位問題一樣,一步一步除錯,直到找出究竟哪裡出錯了。
“Debug 的藝術關鍵在於你究竟讓軟體幹了些啥,而不是你以為你讓軟體幹了些啥。”—— Andrew Singer -
重新評估問題:退回去,從另一個角度重新審視問題,別讓自己迷失在細節裡,有時候我們容易迷失在具體的細節中而忽略了更一般的原則。重新評估問題的另一種途徑是推倒重來,可以刪除(回滾)所有已做的事,重新開始,有時這是非常行之有效的方式。
-
搜尋解決方案:利用搜尋引擎找到類似問題的解決辦法,向他們學習。使用搜尋引擎需要學會提煉關鍵字,關鍵字越有代表性,越容易找到答案。對搜尋結果應該抱著參考的態度,而不是照搬,要明白為什麼如此這般處理就能解決問題,並在解決問題後能依次延伸瞭解其上下游或相關知識,比如SQL查詢慢,發現是索引未生效,則可以延伸瞭解都有哪些場景會導致索引失效;比如併發問題,則可以依此瞭解如何保證執行緒安全,同步機制,鎖機制等相關知識。事實上,即使問題已經解決,你也可以經常這麼做,因為這樣你可以從其他人的解決方案中及上下游知識中學到更多。
-
尋求支援:當通過以上方法都無法獲得解決辦法時,向你的同事、上級或朋友求援,如果是開源專案,到開源社群、技術群,或 github 的 issue 列表中發帖求援。
-
記錄問題與解決方案:將你本次遇到的問題與最終的解決方案用(電子)筆記本記錄下來,便於後面回顧或參考。
第五步:練習
羅馬不是一天建成的,你也不可能期盼通過解決一兩個問題就能成為解決問題的高手。但是,如果你能以學習的態度來尋求問題的解決辦法,通過以上四個步驟來建立一套解決問題的思維框架,每一個問題的處理都是提高你能力的機會。那麼距離成為一個解決問題的高手,就只差一步了,那就是:練習,練習,再練習。在問題中練習,訓練你的思維方式與習慣。
“我不害怕一次練習1000個踢打動作的人,但我害怕將一個踢打動作練習1000次的人”
總結
其實,解決問題的能力,不論在IT技術領域,還是在其它各個領域,都是一種最基本的技能。當你在說出“這個問題我解決不了”,“這個問題我沒辦法定位”前,試試本文介紹的理解、計劃、分解、卡殼時怎麼處理的建議方法,多一些耐心,一步步實踐,說不定慢慢就看到曙光了。按照這個處理模式或習慣,在日積月累的問題處理中,你可能已在不知不覺成為了解決問題的高手。
參考:
原文地址:http://blog.jboost.cn/think-like-a-programmer.html
[轉載請註明出處]
作者:雨歌,可以關注作者公眾號:半路雨歌