關於馮老師
- 大名:馮老師
- 小名:真男人
- 英文名字:TrueMan
- 年齡:未知
- 座右銘:就這???
在我們公司,一提起馮老師,那可謂無人不知,無人不曉。
訂單申請不了售後了,怎麼辦呢?—— 找馮老師。
倉庫稽核按鈕不見了,怎麼辦呢?—— 找馮老師。
衛生間馬桶堵了,怎麼辦呢—— 找馮老師。
可以說,在我們公司,找馮老師就是「政治正確」。找馮老師,比 ChatGPT 還好使。
不過,即使聰慧如馮老師,也會有踩坑的時候。本系列文章,我們就來細數馮老師踩過的那些「坑」。
馮老師的困惑
週一下班後,我已經收拾好東西準備下班了,馮老師略顯踟躕地走過來,用戲謔的語氣對我說:「來來來,架構師,考你個問題,看看你水平怎麼樣」。
聽到這裡,我大抵猜到馮老師又遇到問題了—— 他平時都是喊我小喬的。
我放下書包,剛準備去他那裡,又突然想到了什麼,忙收住腳步。我開啟了我的記賬本:
附錄(PB 兌換規則及收費標準):
「馮老師,你還欠我 4PB 呢。」
「先記賬上就行。」
「好的。按技術服務標準收費,現在是六點零一分,算你六點鐘吧。」
馮老師似乎並不關心收費問題,畢竟對於吃慣了四個菜的人來說,這些都是毛毛雨。
「你來看,我給你描述一下問題。」
「同樣的程式碼,我程式碼在本地和測試環境都正常,但是上線以後,報了一個常量未定義的錯誤,這可能是什麼問題呢?」
我思考片刻,快速捕捉馮老師言語中的重要資訊:
- 直接報錯:常量未定義;
- 本地和測試環境正常,正式環境報錯;
- 正式環境和測試環境程式碼一致。
神探皮拉夫登場
帶著這些所謂的「結論」,我開始了「破案」過程。
我需要做的就是,從上述「線索」出發,一一排查每一條「線索」的真實性。沒錯,在真相大白之前,我只相信我眼睛看到的東西,其他聽到的「證據」在沒有得到證實之前,我都稱之為「線索」。
關於同樣的程式碼在不同環境下表現不同,無外乎以下兩種情況:
- 程式碼問題;
- 環境問題。
環境包括程式碼執行的編譯環境,資料庫環境等外部條件。這裡經過排查,測試和正式環境都是一致的。而且報錯提示是常量未定義的問題,並非環境問題導致。所以,環境問題的嫌疑基本可以排除。
接下來,我們把重點放在程式碼差異的排查上。
由於程式碼都是經過 jenkins 自動部署釋出的,經過對比核心程式碼以後,發現經過釋出的程式碼和測試環境並無差異。除了自動部署的程式碼,還有一部分程式碼是不走釋出的,因為這部分程式碼屬於各環境的環境變數及配置資訊,所以這部分程式碼需要手動維護更新。
接下來,就是排查這部分程式碼的問題了。
可是,馮老師信誓旦旦地告訴我:「環境變數也是一樣的,我都檢查過了,不用看。」
環境沒有問題,程式碼也沒有問題 —— 常量不存在?一定是見鬼了。
「你確定常量都是一樣的嗎?」
「你還不相信我。。。來,你來看。」
馮老師開啟線上和測試環境的變數給我看(常量定義在了入口檔案index.php
中,框架用的ThinkPHP 5.0
):
正式環境 index.php
define('BIG_KENG', 'IF YOU JUMP, YOU ARE DEAD.');
//========== tms 電子面單 ==========
define('TMS_HOST', 'http://tms.aaa.com');
測試環境 index.php
//========== tms 電子面單 ==========
define('TMS_HOST', 'http://tms-test.aaa.com');
看著確實沒什麼區別。「這個 BIG_KENG 是個什麼東東?」,我隨口一問。
「那個不用管,別人定義的,和這裡沒有關係。」
「哦。」
「常量未定義還有可能是定義常量的檔案出現了語法問題,其他常量能用麼?」
「能用。」馮老師信誓旦旦地對我說。
「列印一個我瞧瞧。」
「還不相信我。。。這就給你看。」馮老師很不情願地給我列印了一個其他定義的常量 —— 確實可以正常輸出。
「那真的是見鬼了。。。」
往往到了這種兜兜轉轉又回到起點的時候,我都會想起福爾摩斯對華生說的那句話 —— 排除其他一切可能,最後剩下來的,就算再不可思議,也必定是真相。
我決定再把目光回到index.php
這個「重大嫌疑人」身上。
果不其然,真相還就真被我給發現了。
揭秘時刻
當我一拍桌子的時候,馮老師頓時慌了神,怔了一下,臉上隨即露出了不可思議又略帶嫉妒的笑——「快說,怎麼回事?」
每當這個時候,我感覺如果不是噸位大一些的話,我都能飄起來。沒有什麼事是比在馮老師面前炫耀戰果更有成就感的了。
馮老師目不轉睛地盯著電腦螢幕,我甚至能聽到他緊張的心跳。
我把滑鼠選中了以下這行程式碼:
define('BIG_KENG', 'IF YOU JUMP, YOU ARE DEAD.');
「這是誰寫的程式碼?Tell me。」
馮老師似乎對我這突如其來又貌似八竿子打不著的問題有些不耐煩:「別人寫的啊,人家寫的也沒問題啊,格式都對啊。」
「你列印下試試,看看能正常列印麼。」
馮老師似乎對這看上去 100% 無疑義的問題不屑一顧:「這還用列印麼,肯定沒問題啊,這都是線上正常在跑的,你到底行不行啊。」
「先列印下看看吧,馮老師。萬一不行呢?」我耐心勸導著馮老師。
馮老師心中雖然不情願,但還是照我說的做了。
「擦嘞!!!什麼情況」馮老師一臉的不可思議,兩隻眼睛瞪的像銅鈴一樣,幾乎要迸出來了。
「不可能吧,看不出來哪有問題啊?」馮老師似乎還是沒有發現端倪,儘管真相就在他目之所及的程式碼上方。
我沒有說話,只是用滑鼠把下面的程式碼給圈了出來:
// 載入框架引導檔案
require __DIR__ . '/../thinkphp/start.php';
define('BIG_KENG', 'IF YOU JUMP, YOU ARE DEAD.');
//========== tms 電子面單 ==========
define('TMS_HOST', 'http://tms.aaa.com');
馮老師看了半晌,還是沒看出問題來:「沒看出有啥不妥的啊?BIG_KENG 定義的沒啥問題啊。」
見馮老師還是沒 Get 到我的點,我讓他關注下面這行程式碼:
// 載入框架引導檔案
require __DIR__ . '/../thinkphp/start.php';
「我想讓你看的是它,馮老師。」
「start.php
怎麼了,不要告訴我你不知道它是啟動檔案?」
我嘆了口氣:「你去開啟這個start.php
,看看它到底幹了些啥。」
馮老師照我說的開啟了start.php
:
namespace think;
// ThinkPHP 引導檔案
// 1. 載入基礎檔案
require __DIR__ . '/base.php';
// 2. 執行應用
App::run()->send();
檔案內容不多,只有三行程式碼。這次不等馮老師張口,我便提前給他科普了:「start.php
是啟動檔案,包含了啟動應用的操作。而你的常量定義在了啟動檔案後面,當然就不起作用了。」
「那測試環境為啥……」
//========== tms 電子面單 ==========
define('TMS_HOST', 'http://tms-test.aaa.com');
// 載入框架引導檔案
require __DIR__ . '/../thinkphp/start.php';
「靠!!!」
馮老師沉思了大概有半秒鐘,瞬間又換了一副小人得志的嘴臉:「行了,行了,我以為多大問題,就這???」。
我微微一笑,因為我已經習慣了這樣的馮老師。
「你們是真的坑,這不能用的程式碼也往線上發,這不坑人麼。」馮老師還在發著小牢騷。
「人家都掛了牌子了啊,你自己不看就往下跳,這賴誰。」
「哪寫了?」
「BIG_KENG。。。這還不夠明顯???」
馮老師起身,搖著頭,撅著嘴,念念叨叨地揚長而去,只留給我一個不屈的背影。
我看了一眼手機,此時剛好六點十五分。於是我在記賬本上又記下了一筆 —— 替馮老師處理線上環境變數問題,耗時二十分鐘,收費 4PB。
總結大會
十分鐘前,一切看著不可思議。
十分鐘後,一切看著又不過爾爾。
很多時候,不是我們的眼神不夠犀利,而是在面對近在咫尺的問題前,我們總是習慣性地自我肯定及否定 —— 我們遲遲走不出圈子,不是因為邁不開腳,而是因為我們從來不覺得自己就站在圈子裡。
就像馮老師遇到的這個問題一樣,明明別人已經標了「BIG_KENG」了,馮老師卻偏偏還要跟著 JUMP。明明已經在「坑」裡了,卻還信誓旦旦地說:這怎麼可能會是個「坑」呢?
就像至尊寶,戴上金箍只需要一秒,而摘下來,卻要一萬年。
本作品採用《CC 協議》,轉載必須註明作者和本文連結