解決問題通用方法論

AndroidTraveler發表於2019-05-29

本文公眾號「AndroidTraveler」首發。

今天跟大家講講解決問題通用的一個方法論。

在實際開發過程中,我們不可避免的會遇到一些 bug。

那麼對於 bug 或者我們沒有遇到過的問題,怎麼處理呢?

本篇層層遞進,一步一步跟你講解。

各位如果有其他方法或者補充的歡迎留言交流。

如果全篇看完,你發現自己平時就是這麼處理的,那麼恭喜,你有自己的一套處理問題的方法論。

本次講解以本人 Android 開發(演示程式碼之類的)為例進行講解,但是都是通用的。

1. 根據奔潰棧資訊

這個其實是解決問題或者 bug 最直接的方式了。

尤其是奔潰棧資訊可以直接定位到專案裡面具體檔案具體報錯位置時。

比如下面的空指標異常:

2019-05-24 13:41:10.031 15019-15019/com.nesger.androidproject E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.nesger.androidproject, PID: 15019
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nesger.androidproject/com.nesger.androidproject.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
        at com.nesger.androidproject.MainActivity.onCreate(MainActivity.java:13)
        at android.app.Activity.performCreate(Activity.java:7183)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6944) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 

可以很明顯的看到是空指標異常導致的,而且根據奔潰棧資訊可以定位到具體的檔案,從下面這一行

        at com.nesger.androidproject.MainActivity.onCreate(MainActivity.java:13)

可以看出奔潰發生在 MainActivity.java 這個檔案的 onCreate() 方法。具體在該檔案 13 行。

具體的原因根據奔潰棧也可以看出是使用 null object 去呼叫 equals 方法。

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference

程式碼裡面也確實是這樣:

解決問題通用方法論

除了空指標,諸如 IndexOutOfBoundsException 也是常見的,都可以通過奔潰棧資訊快速解決。

2. 善用搜尋引擎

假設你的問題不能通過棧資訊直接得到解決,那麼接下來就是善用搜尋引擎。

一般搜尋引擎一級入口就是 Google、百度等。

實際上問題的解決方法是在二級入口,比如 Stack Overflow、簡書、掘金等網站上。

所以如果你熟悉或者一級入口沒有找到,可以直接在二級入口進行搜尋。

搜尋的時候注意一些小技巧,舉個例子:
在 Android 裡面一些實現可以在 xml 配置,也可以通過程式碼動態設定。

如果你的目標是要獲取程式碼動態設定的,一般在你搜尋的關鍵資訊之後加上 programmatically

3. 通過官方渠道

官方渠道其實指的是官網或者官方論壇。

舉些我學習 Flutter 過程中解決問題的例子。

在原生專案嵌入 Flutter 的時候,參考的是 Flutter 在 GitHub 上面的 WIKI。

解決問題通用方法論

在執行出現 crash 時,解決是通過 Flutter 在 GitHub 上面的 Issues。

解決問題通用方法論

所以我這裡就是到 flutter 官方的 GitHub 專案上面去尋找問題的解決方法。

4. 深入原始碼分析

當上面三個方法都不能解決你的問題時,這個時候你就要結合具體業務進行具體分析,然後深入原始碼找到本質問題,進行對應處理。

比如我之前寫過的一篇文章:

zxing 如何識別反轉二維碼

遇到的問題就是業務需要識別反轉二維碼。

前面提到的三個方法論都不能解決,屬於很小眾的需求。

這種情況下我就分析了一下需求。需求是二維碼的識別,而二維碼識別核心就是影像獲取和解碼。那麼通過分析原始碼的解碼過程,是不是就可以解決這個問題呢?最後證明是可以的。

又比如說我們的業務使用了 GraphQL,而官方 GraphQL 並沒有提供對 Flutter 的直接支援。

這個時候我在 GitHub 上面發現了一個倉庫:https://github.com/zino-app/graphql-flutter

解決問題通用方法論

這個倉庫提供了 Flutter 對 GraphQL 呼叫的支援,但是實際測試過程中發現有個問題,那就是錯誤沒有回撥。

這個時候我通過深入原始碼,列印日誌,發現錯誤確實有被 catch,但是沒有回撥回來,說明可能回撥裡面的程式碼有問題。

因此我通過實際例子測試並提了一個 PR,最終程式碼合併解決了這個問題,當然也幫助其他遇到這個問題提 issue 的小夥伴。

所以遇到問題你可以提 issue 被動等待作者解決,也可以主動出擊,分析原始碼,通過實際例子證明程式碼存在 bug,需要修復。

PR:https://github.com/zino-app/graphql-flutter/pull/162

5. 請教他人

這個之所以放在最後是因為,這個方法是一把雙刃劍,用的好你會成長,用不好你會給自己加上枷鎖。

我們先說說好的一方面:
假設你按照前面 4 個方法論依然沒法解決這個問題,那麼你可以請教他人來解決這個問題。如果他人知道這個問題的解決方法,那麼你不止滿足於這個問題的解決,事後你還需要進行總結。
總結為什麼他人可以解決這個問題:
是經驗問題?
還是有一些其他渠道你之前沒有考慮?
是否更新完善上面的解決問題方法論?
通過這樣的不斷總結,你後面需要請教他人的次數會越來越少。或者真的你解決不了需要請教他人的時候,可能他人也不清楚。因為他的方法論你都熟悉了,而你也是如此去完善的。

接下來說說不好的一方面:
假設你遇到問題,你就請教他人,解決問題之後就不理了。後續有問題依然如此迴圈往復,那麼結果你得到的就是依賴性。假設後面有類似問題存在,而別人沒空回答你,你就不知道要怎麼辦了,因為你沒有一套自己解決問題的方法論。而且因為你之前已經善於依賴別人解決問題了,因此你現在會很迷茫,不知道如何下手。再者,大家都很忙,你請教他人,他人不一定會回答你,至於什麼時候回答你,以及答案是否正確,都是不可預知的。

假設我們要幫助別人,我還是提倡授人以漁而不是授人以魚。

最後我再說一下關於請教他人這個問題:
別人沒有義務幫你解決問題,所以如果別人沒回答你的問題,這是正常的。
如果別人回答你的問題,解決你的問題你可以表示感謝,沒有解決也不用吐槽。
最好的方式還是自己解決問題。

總結:
1. 根據奔潰棧資訊
2. 善用搜尋引擎
3. 通過官方渠道
4. 深入原始碼分析
5. 請教他人

解決問題通用方法論

相關文章