突如其來(lái)的需求
公司最近要上線一個(gè)新產(chǎn)品儡毕,準(zhǔn)備開(kāi)個(gè)小型的發(fā)布會(huì)做一波推廣盛撑。離發(fā)布會(huì)還有一周時(shí)植阴,產(chǎn)品經(jīng)理突然跑過(guò)來(lái)說(shuō)本次發(fā)布的是產(chǎn)品的內(nèi)測(cè)版本,用戶需要有邀請(qǐng)碼才可以使用勤家。
這是一家剛開(kāi)始創(chuàng)業(yè)不久的公司腹尖,技術(shù)積累并不多,目前并沒(méi)有邀請(qǐng)碼系統(tǒng)伐脖。而本次發(fā)布的產(chǎn)品涉及到三項(xiàng)相互比較獨(dú)立的服務(wù)(都通過(guò)統(tǒng)一登陸系統(tǒng)校驗(yàn)用戶)热幔,所以如何在一周時(shí)間完成這個(gè)功能便成了一個(gè)問(wèn)題。
條件反射示設(shè)計(jì)
一周時(shí)間上一個(gè)邀請(qǐng)碼系統(tǒng)肯定來(lái)不及了讼庇,而且就算上了一個(gè)邀請(qǐng)碼系統(tǒng)绎巨,產(chǎn)品的三項(xiàng)服務(wù)都要進(jìn)行邀請(qǐng)碼服務(wù)接入改造,想想就知道這個(gè)方案的風(fēng)險(xiǎn)很大蠕啄。那么最快的方案就是改造統(tǒng)一登陸服務(wù)场勤,把邀請(qǐng)碼放在統(tǒng)一登陸里面,那么就可以達(dá)到有邀請(qǐng)碼的用戶才能登陸使用歼跟。
問(wèn)題是統(tǒng)一登陸系統(tǒng)服務(wù)整個(gè)公司的所有產(chǎn)品却嗡,不能因?yàn)樾掳l(fā)布一個(gè)產(chǎn)品,導(dǎo)致其它的產(chǎn)品也不能用嘹承。所以統(tǒng)一登陸里面除了加入一個(gè)邀請(qǐng)碼的業(yè)務(wù)邏輯以外窗价,還要加入一段判斷登陸來(lái)源系統(tǒng)確定校驗(yàn)規(guī)則的邏輯。
如鯁在喉的難受
很多人都號(hào)稱自己有代碼潔癖叹卷,然而最后都屈服于時(shí)間不夠的現(xiàn)實(shí)撼港。程序員大多有一個(gè)特點(diǎn),在寫下臟代碼的那一刻是很難受的骤竹,但因?yàn)闀r(shí)間緊迫帝牡,只能暫時(shí)先解決掉這個(gè)問(wèn)題,而少有人會(huì)等到有空后去重構(gòu)曾經(jīng)寫下的臟代碼蒙揣。
設(shè)計(jì)也一樣靶溜,如果迫于時(shí)間的壓力,做了一些丑陋的設(shè)計(jì),一旦系統(tǒng)上線之后罩息,還會(huì)再去修改設(shè)計(jì)的概率幾乎為零嗤详。而且重構(gòu)代碼還會(huì)有測(cè)試用例來(lái)保證正確性,重構(gòu)設(shè)計(jì)的風(fēng)險(xiǎn)和代價(jià)都要大的多瓷炮。
對(duì)于上面邀請(qǐng)碼的設(shè)計(jì)葱色,有幾個(gè)地方丑陋的很明顯。
- 邀請(qǐng)碼業(yè)務(wù)跟統(tǒng)一登陸業(yè)務(wù)沒(méi)有強(qiáng)相關(guān)性娘香,不該放在一個(gè)系統(tǒng)里苍狰。
- 服務(wù)校驗(yàn)規(guī)則的修改應(yīng)該由服務(wù)自己決定,不該放在統(tǒng)一登陸里烘绽。
做為一個(gè)有過(guò)幾年開(kāi)發(fā)經(jīng)驗(yàn)的人淋昭,我深刻的知道,一旦設(shè)計(jì)確定是這樣的安接,統(tǒng)一登陸系統(tǒng)很快就會(huì)變的臃腫不堪响牛。因?yàn)橐坏┯辛艘粋€(gè)丑陋的設(shè)計(jì),那么其它丑陋設(shè)計(jì)也會(huì)進(jìn)入的理直氣壯赫段。系統(tǒng)的熵增抵抗性全無(wú)呀打。
深思熟慮后行動(dòng)
其實(shí)可以把此次需求分解成三段業(yè)務(wù)邏輯。
- 邀請(qǐng)碼生成
- 用戶邀請(qǐng)碼綁定
- 用戶是否有邀請(qǐng)碼的校驗(yàn)
邀請(qǐng)碼生成
關(guān)于邀請(qǐng)碼生成糯笙,可以手工生成贬丛,也可以寫個(gè)小程序生成,然后導(dǎo)入系統(tǒng)给涕,也可以系統(tǒng)自動(dòng)生成豺憔,這是一個(gè)很獨(dú)立的功能,沒(méi)有耦合關(guān)系够庙。所以對(duì)設(shè)計(jì)決策影響不大恭应。
用戶和邀請(qǐng)碼綁定
這里需要考慮的是綁定功能在哪里實(shí)現(xiàn),綁定關(guān)系放在哪里耘眨?上面說(shuō)過(guò)邀請(qǐng)碼的業(yè)務(wù)和統(tǒng)一登陸的業(yè)務(wù)是無(wú)關(guān)的昼榛,所以綁定功能不應(yīng)該放在統(tǒng)一登陸里,那也沒(méi)有更合適的其它系統(tǒng)可以放剔难,那么就新建一個(gè)邀請(qǐng)碼系統(tǒng)來(lái)放這段邏輯胆屿。那么綁定關(guān)系看起來(lái)也理所當(dāng)然放在這個(gè)邀請(qǐng)碼系統(tǒng)了。
校驗(yàn)用戶是否綁定邀請(qǐng)碼
似乎理所當(dāng)然的這段邏輯應(yīng)該放在邀請(qǐng)碼系統(tǒng)里偶宫。各個(gè)使用到邀請(qǐng)碼的系統(tǒng)通過(guò)調(diào)用服務(wù)來(lái)校驗(yàn)用戶非迹。但這樣的設(shè)計(jì)其實(shí)是有問(wèn)題的,統(tǒng)一登陸系統(tǒng)現(xiàn)在是合理了纯趋,邀請(qǐng)碼系統(tǒng)也是合理的憎兽,客戶端系統(tǒng)看上起也是合理的冷离,使用哪些服務(wù)就調(diào)用哪些服務(wù)的接口。
然而整個(gè)系統(tǒng)的架構(gòu)卻是不合理的纯命∥靼客戶端如果需要知道它調(diào)用的每個(gè)服務(wù)所屬的系統(tǒng),隨著系統(tǒng)增多扎附,整個(gè)系統(tǒng)架構(gòu)會(huì)固化蔫耽,難擴(kuò)展结耀。
較為合理的設(shè)計(jì)
現(xiàn)在客戶端系統(tǒng)的用戶校驗(yàn)是使用統(tǒng)一登陸系統(tǒng)的服務(wù)留夜,那么最好所有關(guān)于用戶校驗(yàn)的服務(wù)都通過(guò)統(tǒng)一系統(tǒng),用戶是否綁定邀請(qǐng)碼只是校驗(yàn)服務(wù)接口中的一個(gè)參數(shù)图甜。
前面說(shuō)過(guò)邀請(qǐng)碼跟統(tǒng)一登陸無(wú)關(guān)碍粥,而現(xiàn)在又說(shuō)要在用戶驗(yàn)證里校驗(yàn)邀請(qǐng)碼,這不是前后矛盾嗎黑毅?其實(shí)不然嚼摩,統(tǒng)一登陸確實(shí)跟邀請(qǐng)碼沒(méi)有強(qiáng)關(guān)聯(lián)關(guān)系,但用戶校驗(yàn)應(yīng)該提供用戶屬性校驗(yàn)的功能矿瘦,而用戶是否綁定邀請(qǐng)碼枕面,只有用戶的某個(gè)屬性而已,所以統(tǒng)一登陸應(yīng)該支持這個(gè)功能缚去。
具體的實(shí)現(xiàn)
- 用戶通過(guò)不同的注冊(cè)方式潮秘,可以攜帶不同的注冊(cè)信息。
- 統(tǒng)一登陸在用戶注冊(cè)成功之后廣播有新用戶注冊(cè)的消息出來(lái)易结,并攜帶上額外的注冊(cè)信息枕荞。
- 驗(yàn)證碼系統(tǒng)訂閱新用戶注冊(cè)的消息,收到到校驗(yàn)注冊(cè)信息中是否有邀請(qǐng)碼搞动,如果有則嘗試綁定用戶和邀請(qǐng)碼躏精。如果綁定成功,廣播一個(gè)用戶屬性更新消息鹦肿,新增用戶的邀請(qǐng)碼屬性矗烛。
- 統(tǒng)一登陸系統(tǒng)訂閱用戶屬性變更消息,收到后更新用戶的屬性信息箩溃。
- 統(tǒng)一登陸系統(tǒng)提供的校驗(yàn)服務(wù)里可以攜彈參數(shù)校驗(yàn)用戶的屬性信息沉衣。
后期如果邀請(qǐng)碼不是通過(guò)注冊(cè)是填寫,而是注冊(cè)之后再去綁定持偏,只要在邀請(qǐng)碼系統(tǒng)提供一個(gè)綁定功能蹂喻,然后綁定成功后廣播消息即可,統(tǒng)一登陸系統(tǒng)不用做修改开泽。
后期邀請(qǐng)碼功能要下線牡拇,統(tǒng)一系統(tǒng)也不需要做修改,客戶端系統(tǒng)的校驗(yàn)服務(wù)不校驗(yàn)用戶屬性即可。
總結(jié)
從接到需求到開(kāi)始實(shí)現(xiàn)惠呼,設(shè)計(jì)一共做了兩次修改导俘。雖然設(shè)計(jì)看上去是更合理了,但是怎么來(lái)證明呢剔蹋?或者所謂的更加合理只是你的一家之言旅薄,只是因?yàn)槟闶沁@個(gè)設(shè)計(jì)的決策者和實(shí)現(xiàn)者,這種設(shè)計(jì)更符合你的審美而已泣崩。
審美當(dāng)然很重要少梁,但是我們還需要理性來(lái)分析為什么說(shuō)更加合理。
對(duì)比第一次設(shè)計(jì)矫付,我們可以發(fā)現(xiàn)它違反了開(kāi)閉原則
凯沪,用戶屬性每一次變更都需要修改統(tǒng)一登陸系統(tǒng),這次是邀請(qǐng)碼买优,下次可能又是優(yōu)惠碼或者別的什么妨马。而我們最后的設(shè)計(jì),用戶屬性的變更可以通過(guò)新增一個(gè)相應(yīng)的系統(tǒng)來(lái)完成杀赢,統(tǒng)一登陸系統(tǒng)不用任何修改烘跺。
對(duì)比第二次設(shè)計(jì),我們可以發(fā)現(xiàn)它違反了迪米特法則
脂崔,客戶端系統(tǒng)需要知道它每一個(gè)校驗(yàn)邏輯的服務(wù)提供者是誰(shuí)滤淳。而我們最后的設(shè)計(jì),客戶端始終調(diào)用同一個(gè)校驗(yàn)服務(wù)脱篙,通過(guò)不同的參數(shù)來(lái)表達(dá)不同的校驗(yàn)邏輯娇钱。
點(diǎn)題
從題目可知,我不僅僅是想寫這一次設(shè)計(jì)的思考過(guò)程绊困,更想探討的是當(dāng)我們面對(duì)一個(gè)臨時(shí)性需求時(shí)文搂,我們應(yīng)該如何應(yīng)對(duì)?
臨時(shí)性需求從來(lái)不會(huì)少秤朗,而對(duì)于創(chuàng)業(yè)型公司更是常態(tài)煤蹭。實(shí)際中我看到太多這樣的例子來(lái),來(lái)了一個(gè)臨時(shí)需求取视,然后在各個(gè)涉及到的系統(tǒng)里增加一段臨時(shí)代碼硝皂。
其實(shí)你要寫的業(yè)務(wù)邏輯是一點(diǎn)也沒(méi)少,你節(jié)省下了新建一個(gè)系統(tǒng)的時(shí)間和調(diào)整原先系統(tǒng)結(jié)構(gòu)的時(shí)間作谭。但你又付出了什么呢稽物?
- 新建一個(gè)系統(tǒng)的時(shí)間,涉及到公司的一些技術(shù)基礎(chǔ)設(shè)施折欠,現(xiàn)在有很多開(kāi)源的技術(shù)可以用來(lái)構(gòu)架這些基礎(chǔ)設(shè)施贝或。也有很多創(chuàng)業(yè)公司在提供這方面的服務(wù)吼过,直接購(gòu)買就可以用了。
- 調(diào)整原先系統(tǒng)結(jié)構(gòu)的時(shí)間咪奖,
流水不腐
盗忱,如果你的系統(tǒng)在遇到不支持的需求時(shí)會(huì)合理的調(diào)整,那么系統(tǒng)的結(jié)構(gòu)會(huì)向好的方向發(fā)展羊赵,調(diào)整也會(huì)越來(lái)越順暢趟佃,對(duì)業(yè)務(wù)的支持也會(huì)越來(lái)越好。反之則會(huì)越來(lái)越固化昧捷。
我們都知道技術(shù)債務(wù)
是怎么回事闲昭,不要欺騙自己說(shuō)之后再去修改。當(dāng)遇到一個(gè)臨時(shí)性需求時(shí)料身,提取出里面非臨時(shí)性的邏輯汤纸,調(diào)整你的系統(tǒng)衩茸,使它合理的實(shí)現(xiàn)這段業(yè)務(wù)邏輯芹血。把臨時(shí)性的部分放到臨時(shí)性系統(tǒng)里去。