教你如何做需求調研:忽略極端情況
英文原文:Not handling edge cases, making them explicit instead
寫 accidental entities 系列文章之初,我們跟著一個顧問公司為一個汽車租賃公司開發一套軟件。當時他們已經完成了新車注冊部分的功能。計劃中的下一步是讓顧客能在系統中預訂。
我們爭取到了租賃公司的 CEO 抽出一小時時間給我們介紹預訂系統流程。
CEO: 我想這個會議用不了一個小時。預訂流程非常簡單。你們對預訂流程有什么看法?”
Us: “是這樣,就我們的理解——也不是很復雜——客戶下了訂單,我們為車分配租賃期,用郵件通知客戶,這就完成了。”
CEO: “等一下,可不是這么簡單。我們收到訂單后,首先要確認客戶的信用卡。”
Us: “我們如何確認?”
CEO: “不是讓你們確認。我們有一個第三方的電子認證系統,由它來做這些;這個系統會檢查信用卡是否有效,是否有能力支付。”
Us: “如果信用卡被系統拒絕,會發生什么?”
CEO: “這簡單,我們取消訂單,通知客戶。”
Us: “如果信用卡通過審核,會怎樣?”
CEO: “那就預訂成功。”
Us: “這里有個問題。在客戶下訂單時我們要立即分配車輛嗎?”
CEO: “當然不是!信用卡的驗證需要時間;如果最終信用卡被系統拒絕,我們會因此造成業務損失。”
Us: “哦,如果這期間另外一個人也預訂了這輛車,怎么辦?”
CEO: “這是一個很好的問題。在過去,這種問題很少發生,但確實有過;我們也許要注意這種極端情況。”
Us: “那發生這種重復預訂情況后如何處理?我估計你們肯定不希望取消第二個訂單,放棄這個客戶,對吧?”
CEO: “當然不想,我喜歡你的思考方式!有幾種做法;如果他們預訂使用車的期間只重疊 30 分鐘左右,我們什么都不做。當客戶來取車時,我會向他抱歉,解釋有一點點延遲,我們會用一些措施安撫他。如果重疊期再大,而且有更大更好的車在空閑,我們 會給他提供免費升級。當我們沒有更好的車可用時,我們會讓最出色的銷售員打電話給他,說服他。有時我們會給他打折,他們通常會很高興再等幾個小時,而不是 去找另外的車。我們盡量避免訂單被取消,我們希望樹立一個有求必應的好口碑。”
Us: “哦,有趣。如果讓我自己琢磨估計會浪費不少時間才明白這個過程。你說這事情很少發生。看起來要想能正確的處理這種重復預訂的事情并不是很容易,是否可以 目前不處理這種極端情況,讓人工處理這種事情?我們可以把這輛車標識為重復預訂,讓系統給出提醒,請求人工處理。Backoffice 有這種工具,他們對處理這種重復預訂的事很有經驗。把這個問題放一放,可以使系統提前幾個星期上線。”
CEO: “我很欣賞你的這個想法,讓我們的第一個版本盡量精簡。真的沒有必要立即讓系統能夠自動處理這種事情。這并不是說系統功能不夠強大。系統還是要記錄每個重復預訂的情況,這是有用的信息。我們能做的這些吧?”
Us: “是的,這并不困難。”
跟 CEO 交談之后,我們開發一個代碼模型。
在我們的第一次迭代中,一個訂單有多個顯示效果,每種效果表示一種訂單狀態。這樣做的好處是,可以手工的在各種狀態間切換,當信用卡被拒絕時,你不能接受預訂….反之就是正常模式,或一些其他操作,這些不是我們這篇文章的重點。
var booking = new Booking ( bookingId, carId, new Customer (new CreditCard ("343705171682875"), new CustomerName ("Jef", "Claes")), new Period (DateTime.Now.AddDays (1), DateTime.Now.AddDays (4))); var bookingWithVerifiedCreditCard = booking.CreditcardVerified (); var doubleBooking = bookingWithVerifiedCreditCard.Double ();每次狀態的改變都會觸發一個事件。如果我們輸出事件,運行下面的代碼將會看到下面的信息。
(EVENT) BookingCreditCardVerificiationPending
(EVENT) BookingCreditCardVerified
(EVENT) DoubleBooked
BookingCreditCardVerified 事件觸發我檢查重復預訂。
public class BookingCreditCardVerifiedHandler : IHandle { private readonly IBus _bus; public BookingCreditCardVerifiedHandler (IBus bus) { _bus = bus; } public void Handle (BookingCreditCardVerified @event) { _bus.Send (new DetectDoubleBooking (@event.BookingId)); } }
如果發現重復預訂,我讓系統顯示提醒,通知我們。可以通過郵件,或 Backoffice 里的一個提醒,或其他的。
public class DoubleBookedHandler : IHandle { public void Handle (DoubleBooked @event) { NotifyHumans (); } private void NotifyHumans () { } }
盡管技術上的實現并不是很特別,我想它已經向我們展示了事件系統如何起作用,如何將責任分發到相應的負責單位。
通常人們有個誤解,認為我們有計算機,它們應該解決我們的所有問題,甚至一些極端情況。極端情況——根據定 義——只會發生在極端條件下,缺少一定的投入,用常規的方式很難處理。通過手工處理極端情況,用戶可以進行人工干預,決定什么才是應付這種問題的做好做 法。這樣做我們可以快速的讓系統上線,減少了代碼編寫,最終能讓客戶更滿意。通過統計這種極端情況的發生頻率,我們能夠按照實際情況來決定是否值得去投資 處理這些極端情況。