這里涉及到的系統(tǒng)是一個(gè)7年的遺留系統(tǒng),技術(shù)棧是.NET MVC2宏悦,即將被客戶淘汰。這篇博文的主題無關(guān)技術(shù)本身包吝,文中談到的技術(shù)細(xì)節(jié)也不是什么高大上的饼煞,更多的是想記錄因這件事情觸發(fā)的非技術(shù)思考。
早上7點(diǎn)45分來到公司诗越,我坐在辦公桌旁邊開始考慮今天的工作事項(xiàng)砖瞧。想到客戶一直抱怨的電子表單系統(tǒng)在產(chǎn)品環(huán)境上8000多個(gè)無法重現(xiàn)的錯(cuò)誤日志就亞歷山大,“替換成微軟類庫也并不一定解決問題嚷狞,客戶又在搗亂块促。今天一定要和夏夏阿哲一起看看這個(gè)問題,優(yōu)先級(jí)得提上來”床未,我心里暗自的想著竭翠,并把它加到了待辦事項(xiàng)的第一條,優(yōu)先級(jí)標(biāo)為高薇搁,截止時(shí)間是今天斋扰。
開了個(gè)好頭,但遭遇IE-Only問題
開完早會(huì)后啃洋,我和夏夏了解了問題上下文传货,然后開始分析錯(cuò)誤日志。我倆驚訝的發(fā)現(xiàn)裂允,其中7000多條錯(cuò)誤日志是發(fā)生在表單導(dǎo)航部分损离!夏夏說哥艇,“就先從它開始吧绝编。” 我倆很快統(tǒng)一思路,瞄準(zhǔn)這幾個(gè)頁面就開始搭建環(huán)境嘗試問題的復(fù)現(xiàn)十饥。
按下遇到的各種環(huán)境問題不提窟勃,這個(gè)錯(cuò)誤很快就在IE瀏覽器(文中統(tǒng)稱IE)上重現(xiàn)了,而且只在IE上才有這個(gè)問題:頁面缺少Anti-CSRF Token逗堵,導(dǎo)致請(qǐng)求被拒絕秉氧。“哎蜒秤,這不錯(cuò)汁咏!”,夏夏用他一貫的幽默風(fēng)格說道作媚。我想:是的攘滩,好兆頭,萬事開頭難纸泡,我們似乎開了個(gè)好頭漂问,然而這怎么好像又是IE啊,真不靠譜女揭。
更不靠譜的e.preventDefault?
時(shí)間已經(jīng)轉(zhuǎn)眼到了10點(diǎn)半蚤假,我們開始嘗試定位代碼,尋找問題的根源吧兔。咦磷仰,貌似看起來頁面前進(jìn)后退的按鈕觸發(fā)了Form的POST請(qǐng)求,而服務(wù)端收到的請(qǐng)求中并沒有Token境蔼。那么“我們頁面AntiCSRF Token是怎么產(chǎn)生的呢芒划?”我問夏夏,夏夏說:“嫻靜欧穴,你看這個(gè)js文件”民逼。
<code>
form.submit(function() {
if ("AntiCSRF-TOKEN" element not exists) {
form.append( input 'AntiCSRF-TOKEN' with value)
}
});
</code>
“哦,橫切了一刀”涮帘,我說拼苍。夏夏說:“恩,你說的太對(duì)了调缨!是在所有Form提交時(shí)自動(dòng)追加Token”疮鲫。我想這看起來沒問題,在早期系統(tǒng)中經(jīng)常這樣干弦叶。那么是誰動(dòng)了我的Token呢俊犯?
11點(diǎn)了,我們的診斷工作緊張而有序的繼續(xù)進(jìn)行著伤哺,分析各種可能出現(xiàn)的異常路徑以及可能性燕侠。各種測(cè)試驗(yàn)證貌似都沒有問題者祖。“這不應(yīng)該呀绢彤。夏夏七问,我們?cè)诶锩婕由蟚.preventDefault,不讓它提交茫舶,手工測(cè)測(cè)看械巡。”這時(shí)我開始亂入饶氏,懷著試試看的態(tài)度對(duì)夏夏說讥耗。心想,怎么有些像回到了5年前工作在這個(gè)系統(tǒng)上的狀態(tài)疹启。夏夏改了代碼并編譯運(yùn)行葛账,奇怪的事情發(fā)生了:Form提交成功,并且錯(cuò)誤被修復(fù)了Fと省籍琳!不光開了個(gè)好頭,好像我們還中彩蛋了的感覺贷祈。
我和夏夏都驚呆了:“這怎么可能趋急?” 夏夏說∈铺埽“是啊”呜达,我說,“e.preventDefault不是應(yīng)該阻止提交嗎粟耻?” 暗想我就是最近一段時(shí)間沒寫前端代碼而已查近,世界變化這么快?我和夏夏又過了一遍Anti-CSRF Token處理代碼挤忙,做了各種嘗試霜威,仍然沒有頭緒。即使e.preventDefault可以解決問題册烈,但我們?nèi)匀徊恢绬栴}根源戈泼。誰動(dòng)了我的Token!
又是IE瀏覽器實(shí)現(xiàn)的問題?
思維似乎有些短路了赏僧,我便建議:“我們來求助一下網(wǎng)絡(luò)吧”大猛。果然StackOverflow上發(fā)現(xiàn)了同樣的問題,IE上Form提交時(shí)丟失動(dòng)態(tài)添加的字段淀零,不過是IE9版本挽绩。看完了推薦的答案很是吐血 -- IE兼容模式驾中?熟悉IE的程序員都知道唉堪,這基本可以作為修復(fù)IE問題的萬能解藥模聋。
夏夏說,“那我們來試試”巨坊。修改代碼運(yùn)行系統(tǒng)撬槽,叮此改,問題也被修復(fù)了趾撵!天哪,IE啊~~~各種黑在我的心里飄過共啃,IE的瀏品又一次被拉低了(如果它有的話)占调。好吧,微軟的實(shí)現(xiàn)總是跟別人不一樣移剪。于是我開始尋找各種微軟的文檔究珊、論壇,補(bǔ)丁網(wǎng)站纵苛,反饋網(wǎng)站剿涮,IE Google group試圖從里面找到更多的討論和證據(jù),然各種同樣的討論貼最后都指向了兼容性這個(gè)文章攻人,貌似取试,就是IE的問題。然而沒有找到明確的官方支持讓我們?nèi)匀徊惶_定怀吻。
同時(shí)瞬浓,在這眾多的相似問題中還有一個(gè)現(xiàn)象引起了我們的注意:網(wǎng)絡(luò)似乎只報(bào)了IE9的問題,而我們是IE9以上都有這個(gè)問題蓬坡,似乎不太對(duì)”猿棉。我們繼續(xù)翻閱著代碼進(jìn)行各種嘗試,思路再次陷入了僵局屑咳。到底是誰動(dòng)了我的TokenH蕖!
時(shí)間過的很快兆龙,已經(jīng)晚上6點(diǎn)多了位迂,解決方案是什么?產(chǎn)品環(huán)境的問題怎么辦详瑞?我和夏夏糾結(jié)著:“那要不就這樣掂林,我們先用第二個(gè)方案把產(chǎn)品問題修了......”。是啊坝橡,需要趕緊修復(fù)產(chǎn)品環(huán)境的問題泻帮。然與此同時(shí),沒能最終找到懸案的罪魁禍?zhǔn)鬃屛覀z糾結(jié)萬千计寇。
這講不通奥嘣印脂倦?
正好這時(shí)強(qiáng)哥背著電腦包從外面走了進(jìn)來,和他聊起了這個(gè)問題元莫,強(qiáng)哥說:“這不大對(duì)啊”赖阻,經(jīng)過一番討論,在夏夏離開去討論另一個(gè)問題的時(shí)候踱蠢,強(qiáng)哥終于搶到了鍵盤火欧。同樣的復(fù)現(xiàn)步驟和思路最終也得到了同樣的IE兼容性的解決方案等等【ソ兀“但這說不通拔帧?”強(qiáng)哥不斷的重復(fù)著這句話企锌。心中不解的疑惑使得我們?nèi)齻€(gè)又重新加入了新一輪的分析中:“等等榆浓,好像這里執(zhí)行了兩次,第一次失敗撕攒,而第二次就成功了”陡鹃,強(qiáng)哥敏銳的撲捉到了又一絲新的線索,事情好像有了新的轉(zhuǎn)機(jī)抖坪。
Form提交了兩次萍鲸?
“我們?cè)賮碜ヒ幌掳纯础保南恼f柳击。打開Fiddler猿推,重現(xiàn)問題。果不其然捌肴,同一個(gè)請(qǐng)求出現(xiàn)兩次蹬叭,第一次失敗,第二次成功状知。問題轉(zhuǎn)移了:“為什么會(huì)出現(xiàn)重復(fù)提交呢秽五?” 時(shí)間一分一分的過去。已經(jīng)晚上8點(diǎn)多了饥悴,我的肚子很餓坦喘,胃有些隱隱作疼。辦公室里也只有少數(shù)一部分人了西设,沙沙幫我們找來了救命的小浣熊瓣铣。這個(gè)時(shí)候,我們?nèi)齻€(gè)都不約而同的看到了下面這篇Stackoverflow的帖子:
強(qiáng)哥說贷揽,“這好像沒關(guān)系棠笑,他這代碼寫的不對(duì),F(xiàn)orm上的按鈕是Submit類型禽绪,還綁定Click去提交蓖救『楣妫”夏夏說,“是的循捺,代碼問題斩例〔彼眨” 氣氛似乎有些緩和恍涂,強(qiáng)哥隨口說盾计,“不會(huì)碍庵,我們就是這么干的吧?”
真相大白
突然踩身,空氣好像被凝固了一般,夏夏和強(qiáng)哥對(duì)視x秒。強(qiáng)哥說牺勾,“要不咱查查代碼”。夏夏說阵漏,“我也覺的得查查”驻民。我說,“這怎么可能履怯? 這是基本知識(shí)好不好”回还。然后夏夏就真的打開代碼庫查了起來。幾分鐘后叹洲,只聽夏夏:“@#¥%%@#%&&”柠硕。 強(qiáng)哥也湊了過去,然后從椅子上“跳”了起來运提,我默默的在一旁畫圈圈蝗柔,原來是你這廝動(dòng)了我的Token!!!。
“懊癖谩癣丧!我也知道為什么e.preventDefault能解決問題了”,我拍著桌子說道栈妆。夏夏和強(qiáng)哥互相看了一眼胁编,哈哈大笑:“因?yàn)樗傻袅艘淮巍鳞尔!?/p>
問題的罪魁禍?zhǔn)拙瓦@樣找到了嬉橙,我們通過Git提交歷史也知曉了這個(gè)問題是在解決按鈕多次點(diǎn)擊問題時(shí)引入的。然故事并沒有在此結(jié)束寥假,找出罪魁禍?zhǔn)椎呐d奮激動(dòng)過后市框,帶給我們?nèi)齻€(gè)更多的是凝固的空氣和沉悶的心情。夏夏說昧旨,“這真是打臉拾给∠榈茫”是的,在這一點(diǎn)上沒什么可矯情的蒋得。
你離它只有一步之遙
在回家的地鐵上级及,我們?nèi)齻€(gè)臭皮匠仍然在交換那酸甜苦辣的各種復(fù)雜心情,反思和討論我們的工作以及白天錯(cuò)過了什么额衙。這讓我記起了那個(gè)關(guān)于吃饃的故事:第一個(gè)饮焦、第二個(gè)、第三個(gè)窍侧、在吃第七個(gè)饃的時(shí)候飽了县踢,并不意味著我們能抹殺前六個(gè)饃的功勞,只吃第七個(gè)饃就可以了伟件。然現(xiàn)實(shí)的情況下很多人在第六個(gè)饃的時(shí)候就放棄了硼啤。我和夏夏在整個(gè)的過程中,就像警察找到了失蹤的物品和一只替罪羊斧账,疑團(tuán)仍然沒被打破谴返。整個(gè)事情并不正常,甚至e.preventDefault的行為都很詭異咧织。事出反常必有妖嗓袱,而最終的我們不管怎樣其實(shí)選擇的都是放棄。
如果重來习绢?
科學(xué)需要的是嚴(yán)謹(jǐn)渠抹、懷疑和批判的態(tài)度,軟件工程也是一樣闪萄。在問題面前梧却,我們需要嚴(yán)謹(jǐn)?shù)膽B(tài)度并拋棄既有的偏見,抽繭剝絲桃煎,不放過一絲的線索直到找到那個(gè)動(dòng)了我們代碼的爬蟲篮幢。
“IE總有各種稀奇古怪的問題,出問題也是它自己的問題为迈,要不其他瀏覽器為啥沒問題三椿?”帶了這樣的有色眼鏡去解決問題,會(huì)遮擋住我們敏銳的眼睛葫辐,誤入歧途搜锰。也許我們并沒有真正在解決問題,只是在給自己的偏見找到一個(gè)借口而已耿战。
只有這些嗎蛋叼?
我們常說作為ThoughtWorks作為一家服務(wù)公司要具備專業(yè)化的服務(wù)精神,工作中要具有專業(yè)精神,然什么是專業(yè)化狈涮?我們常說作為技術(shù)是ThoughtWorks的核心競爭力狐胎,我們要追求技術(shù)卓越,然什么是卓越歌馍?這次事件給我上了深刻的一課握巢。
我想,在交付壓力面前松却,在客戶挑戰(zhàn)面前暴浦,我們對(duì)于問題的響應(yīng)度和處理方式反映了我們的專業(yè)度有多少。
當(dāng)我們修復(fù)一個(gè)產(chǎn)品問題的時(shí)候晓锻,是不是把這個(gè)問題解決了就結(jié)束了歌焦?
當(dāng)我們無法解決一個(gè)產(chǎn)品問題的時(shí)候,是不是將問題拋給客戶砚哆,“我加了點(diǎn)日志過兩天再看看”独撇,就結(jié)束了?
當(dāng)我們無法解決一個(gè)第三方技術(shù)問題的時(shí)候窟社,是不是一個(gè)簡單的“要升級(jí)”就結(jié)束了呢券勺?
當(dāng)交付壓力一次次被當(dāng)做不能技術(shù)卓越的擋箭牌绪钥,當(dāng)面對(duì)各種無奈與挑戰(zhàn)的時(shí)候灿里,是不是經(jīng)常說“算了,就這樣吧”程腹。那你有沒有發(fā)現(xiàn)匣吊,悄然間我們的專業(yè)化服務(wù)底線一次次的被觸碰。與此同時(shí)寸潦,我們技術(shù)前進(jìn)的步伐也已經(jīng)悄悄的停了下來色鸳。
三指規(guī)則:當(dāng)你用一個(gè)手指指向別人時(shí),注意另外三個(gè)手指所指向的方向见转。-溫格伯
我們那些還可以做得更好命雀?我們的客戶面臨什么樣的問題?我們還能做些什么來幫助他們解決這些問題斩箫?如果讓我只選擇一個(gè)品質(zhì)來提升我們的專業(yè)服務(wù)精神吏砂,那就是“死磕到底”。
死磕到底
死磕是什么乘客?普通話就是“較勁兒”狐血、“不達(dá)目的不罷休”的意思。
死磕就如凌晨四點(diǎn)洛杉磯的科比易核,就如他成名后依然每天完成800個(gè)投籃的高強(qiáng)度訓(xùn)練以保持專業(yè)的水準(zhǔn)匈织。
死磕就如邏輯思維羅振宇每天堅(jiān)持6:30發(fā)60秒語音,每周發(fā)優(yōu)酷視頻。
死磕就如這次事件中的強(qiáng)哥缀匕,一次次從問題中找到線索找到根源纳决。
試想一下如果沒有強(qiáng)哥的加入,真相可能就會(huì)被淹沒乡小。他們所展現(xiàn)的是與常人所不同的專業(yè)精神和匠人精神岳链,而這種精神是為客戶創(chuàng)造價(jià)值的根本!
寫在最后
當(dāng)面包成為習(xí)慣的時(shí)候劲件,甚至有時(shí)會(huì)有夾心的時(shí)候掸哑,當(dāng)抱怨成為習(xí)慣,當(dāng)環(huán)境變得越來越舒適的時(shí)候零远,會(huì)讓人忘記初心苗分,喪失競爭和生存的動(dòng)力。
“Stay Hungry牵辣,Stay Foolish” 與諸君共享摔癣。
2016年3月23日特寫此文紀(jì)念。