如何寫出令人驚嘆的設(shè)計(jì)文檔?

一份好的設(shè)計(jì)文檔需要提供清晰的問題描述、整體的概要設(shè)計(jì)、涵蓋各個(gè)細(xì)節(jié)的詳細(xì)設(shè)計(jì)等。
這篇有趣的英文小短文通過一個(gè)簡(jiǎn)單的小例子介紹了Google工程師是怎么寫設(shè)計(jì)文檔的。本文為中文翻譯。原文鏈接如下:https://reurl.cc/ZrVD2A
寫文檔是我在谷歌學(xué)到的最重要的技能之一。在谷歌,文檔被用來(lái)討論問題、作為真實(shí)的信息源、組織知識(shí)。在我工作過的其他公司中,沒有一家對(duì)如何使用文檔進(jìn)行協(xié)作有這樣深刻的理解。
這篇文章就是關(guān)于我在谷歌如何寫設(shè)計(jì)文檔的一個(gè)例子,這是一個(gè)真實(shí)的項(xiàng)目,用于在新冠疫情期間控制健身房現(xiàn)場(chǎng)人數(shù)。即使在新冠疫情結(jié)束后不需要預(yù)約健身房了,也可以訪問GitHub上的源代碼[1]。為了讓這篇文章更有趣,現(xiàn)在每個(gè)人都可以在谷歌文檔[2]上進(jìn)行評(píng)論,而且谷歌文檔的格式也比Medium支持的要好。
問題描述
在新冠疫情期間,要求健身房控制現(xiàn)場(chǎng)會(huì)員總數(shù),要求會(huì)員在去健身房之前先在網(wǎng)站上預(yù)訂。預(yù)約需要提前兩天,從午夜開始。例如,2021年04月01日的預(yù)訂將在當(dāng)?shù)貢r(shí)間2021年03月30日00:00 AM開放。
這個(gè)健身房里的游泳池提供的位置非常有限。我嘗試了好幾次,都沒能預(yù)定到早上6點(diǎn)的時(shí)間,后來(lái)工作人員告訴我,由于需求量很大,必須在午夜預(yù)訂。但是熬夜到半夜會(huì)打亂我的生物鐘,所以我沒法接受。
而且我覺得雇人做這件事也很不好,因?yàn)樵趦?nèi)心深處,我認(rèn)為早睡是健康高效生活方式的核心習(xí)慣,用金錢剝奪別人的好習(xí)慣是不道德的。在被告知沒有別的辦法之后,我決定寫一個(gè)程序來(lái)為我做預(yù)訂。
我個(gè)人認(rèn)為用機(jī)器人來(lái)做工作是對(duì)別人的不公平,所以我對(duì)這個(gè)決定一點(diǎn)兒也沒感到自豪。相反,我認(rèn)為健身房應(yīng)該提高一些場(chǎng)地的價(jià)格。但這顯然超出了設(shè)計(jì)文檔的范圍,而且是非常主觀的想法。
需求
自動(dòng)提前兩天在半夜預(yù)訂健身房 程序啟動(dòng)后不需要人工交互,應(yīng)該具有容錯(cuò)性,能夠進(jìn)行合理的重試 可以在Mac電腦上運(yùn)行 用戶可以指定用戶名、密碼、預(yù)約的項(xiàng)目、日期和時(shí)間等
不在考慮范圍內(nèi):
只提前1或2天預(yù)訂,或當(dāng)天預(yù)訂 容忍操作系統(tǒng)或網(wǎng)絡(luò)問題 在預(yù)約服務(wù)器停止運(yùn)行后還要能夠工作 在網(wǎng)站結(jié)構(gòu)(HTML)改變后,還要能夠工作
概要設(shè)計(jì)
瀏覽器自動(dòng)化 vs 模擬請(qǐng)求
瀏覽器自動(dòng)化是指通過程序來(lái)控制真實(shí)的瀏覽器,并在GUI上自動(dòng)化操作。模擬請(qǐng)求是指讓程序通過HTTP與服務(wù)器交互,這個(gè)程序就像是一個(gè)Web瀏覽器(而不是控制一個(gè)瀏覽器)。
考慮到下面幾點(diǎn),我認(rèn)為瀏覽器自動(dòng)化比模擬請(qǐng)求更好:
[優(yōu)點(diǎn)] 瀏覽器自動(dòng)化啟動(dòng)了一個(gè)真實(shí)的瀏覽器實(shí)例,所以我們知道程序運(yùn)行時(shí)發(fā)生了什么,它使調(diào)試和開發(fā)更加容易。 [優(yōu)點(diǎn)] 網(wǎng)站需要JavaScript加載控件,而這較難通過編程實(shí)現(xiàn),可能需要控制一些渲染引擎。 [缺點(diǎn)] 瀏覽器自動(dòng)化依賴于HTML結(jié)構(gòu),而模擬請(qǐng)求依賴于HTTP API,API相對(duì)穩(wěn)定,不太可能改變。
顯然利大于弊。
系統(tǒng)概述

Selenium[3]是一個(gè)提供瀏覽器自動(dòng)化解決方案的軟件庫(kù)。我們的程序?qū)⒂肞ython編寫,并通過Python API控制Selenium,Selenium則通過它的Gecko驅(qū)動(dòng)程序控制Firefox。
Caffeinate[4]是一個(gè)阻止操作系統(tǒng)進(jìn)入睡眠狀態(tài)的程序。如果系統(tǒng)休眠,程序?qū)o(wú)法在半夜運(yùn)行。
詳細(xì)設(shè)計(jì)
用戶輸入
用戶名、密碼、日期等都是從命令行參數(shù)中輸入的。
重試
程序?qū)⒉东@所有異常(頁(yè)面未加載等)并重試100次直到預(yù)訂成功,成功的預(yù)訂通過確認(rèn)DOM元素進(jìn)行識(shí)別。
瀏覽器選擇
我們需要使用主流瀏覽器之一。我考慮并測(cè)試了Chrome、Firefox和Safari,Safari和Chrome都需要額外的步驟來(lái)使用相應(yīng)的Selenium驅(qū)動(dòng)程序,所以我選擇了Firefox。它也需要一些來(lái)自操作系統(tǒng)設(shè)置的認(rèn)證,但只需要在最初幾次確認(rèn)就可以了。
日志
程序自動(dòng)執(zhí)行瀏覽器操作,就像是由用戶發(fā)起的一樣。本質(zhì)上,它將在循環(huán)中執(zhí)行以下操作:
查找某個(gè)元素 對(duì)元素進(jìn)行操作(輸入文本、選擇選項(xiàng)或單擊) 等待預(yù)期結(jié)果,然后返回1
因此,每個(gè)日志記錄將有兩項(xiàng)內(nèi)容:
執(zhí)行了什么 在等待什么
這樣的日志記錄將使調(diào)試變得容易。
保持電腦持續(xù)運(yùn)行
如果操作系統(tǒng)在程序啟動(dòng)到午夜之間進(jìn)入休眠狀態(tài),則程序在午夜就無(wú)法運(yùn)行了,Caffeinate可以防止這種情況發(fā)生。它是一個(gè)命令行工具,我們?cè)赑ython中把它作為子進(jìn)程啟動(dòng):
subprocess.Popen([‘caffeinate’,?‘-d’,?‘-w’,?‘%d’?%?os.getpid()])
定位控制
Selenium提供了一組方法[5]來(lái)訪問特定的DOM元素,其中xpath的表達(dá)能力最強(qiáng)。因此,我們將使用find_element_by_xpath來(lái)定位DOM元素,如按鈕、輸入框等。
只要有可能,我們寧愿依賴DOM的內(nèi)部文本來(lái)定位它們。相對(duì)于DOM結(jié)構(gòu)和屬性(類名等),內(nèi)部文本的優(yōu)勢(shì)并不是說(shuō)它不太可能更改,而是如果它們發(fā)生更改,更容易調(diào)試。當(dāng)然,我們必須對(duì)DOM結(jié)構(gòu)做一些假設(shè),比如我們需要點(diǎn)擊class='control'分區(qū)(div)下的class='logon'的第二個(gè)按鈕。
等待頁(yè)面加載
在發(fā)送每個(gè)HTTP請(qǐng)求后,程序需要等待加載頁(yè)面(通常是2~5秒,是的,這個(gè)站點(diǎn)很慢)。這是由WebDriverWait API[6]完成的。例如,以下代碼將等待120秒,直到??被加載并成為可被點(diǎn)擊的按鈕。
book_btn?=?WebDriverWait(driver,?120).until(EC.element_to_be_clickable((By.XPATH,?“//button[@ng-reflect-router-link=’/Appointments’]”)))
如果按鈕在120秒內(nèi)加載失敗,將引發(fā)異常。
更多的實(shí)現(xiàn)細(xì)節(jié)
選擇正確的日期。假設(shè)我們想預(yù)定4月14日,我們無(wú)法在預(yù)訂日歷上選擇文本為‘14’的單元格,因?yàn)?/14的單元格有類似的屬性。當(dāng)前月份的單元格必須包含有class cal-in-month。
調(diào)整月份。預(yù)訂日歷顯示的是當(dāng)月的當(dāng)天,而不是我們打算預(yù)訂的月份。如果兩天后就是下個(gè)月,這就會(huì)有問題。因此,我們必須添加另一個(gè)步驟實(shí)現(xiàn)在這個(gè)邊界情況下選擇正確的月份。
操作流程
假設(shè)我想預(yù)訂4月14日的游泳池,需要在4月11日的任意時(shí)間運(yùn)行以下命令:
python?book.py?--username?xxxxxx?--password?xxxxxx?--day?14?--time?‘5:00?PM’?--sport?small_pool
程序?qū)⒚啃菝?秒鐘被喚醒檢查一次時(shí)間,這個(gè)檢查不會(huì)有任何明顯的CPU消耗。Caffeinate將阻止操作系統(tǒng)進(jìn)入睡眠狀態(tài),直到午夜時(shí)分。
在4月12日午夜,它將啟動(dòng)Firefox瀏覽器,并自動(dòng)完成預(yù)訂。之后,Caffeinate進(jìn)程和主進(jìn)程都將退出,操作系統(tǒng)將正常進(jìn)入休眠狀態(tài)。
4月12日的早上,我會(huì)看一下日志,看看預(yù)訂是否成功。
一個(gè)有趣的事實(shí)
競(jìng)爭(zhēng)確實(shí)非常激烈,通常在第1分鐘預(yù)約就結(jié)束了。每個(gè)時(shí)段總共只有6個(gè)名額,毫無(wú)疑問,在早上6點(diǎn)預(yù)訂是不可能的。
來(lái)源:DeepNoMind
歡迎關(guān)注“Java引導(dǎo)者”,我們分享最有價(jià)值的Java的干貨文章,助力您成為有思想的Java開發(fā)工程師!
