【編者按】美芽作為一個美妝視頻社區(qū),在 2 月份上線之后,極受女性用戶的歡迎。此次美芽 CTO 姚東旭在 UPYUN Open Talk 廈門場分享了美芽從零到一的整個產(chǎn)品生命周期,帶給創(chuàng)業(yè)公司很多值得借鑒的地方。
以下為正文
美芽在萌芽過程中,同很多初創(chuàng)產(chǎn)品一樣,有常見的三個特點:較小的用戶規(guī)模、快速的需求變化以及尚未完善的團隊。
1. 較小的用戶規(guī)模。雖然偶有例外,譬如“足跡”的爆發(fā)式增長,傳言 DAU 有 300 萬,而一般的產(chǎn)品不會有這種運氣;
2. 快速的需求變化。初創(chuàng)產(chǎn)品蘊含很多的不確定性。無法同時兼顧產(chǎn)品細節(jié),也無法在較短時間內(nèi)將功能極盡完善,因而通常情況下會盡快推向市場,以驗證想法的正確性;
3. 尚未完善的團隊。互聯(lián)網(wǎng)創(chuàng)業(yè)公司對于技術(shù)人員的強烈需求,與市場的供不應(yīng)求,有著難以消解的矛盾。加上創(chuàng)業(yè)公司無法高價請人,通常情況下的應(yīng)對之策只能是一人多用。
面對這樣的境況,相比較代碼的執(zhí)行效率或線上接口的響應(yīng)效率,更為注重開發(fā)效率是美芽的應(yīng)對之策。而影響開發(fā)效率主要包括三方面:一是溝通成本,以客戶端和后端同學的溝通為主;二是重復輪子,已經(jīng)有成熟的開源實現(xiàn)了,卻用自己的代碼重復實現(xiàn)了;三是過度設(shè)計。
1. 協(xié)議
在協(xié)議方面,很多項目在設(shè)計前后端交互協(xié)議時非常隨意,比如 /Post/Show/xx ,實現(xiàn)起來也沒有統(tǒng)一標準。
從請求無法明確看出該以哪種方式獲取數(shù)據(jù),客戶端同學必須詢問服務(wù)端,或者在文檔里清晰的描述出來。特別是對于新加入的開發(fā)者,需要一個熟悉的過程。比如刪除一個帖子,使用 DELETE 或 GET 方法,也并沒有統(tǒng)一的標準,針對這個問題,美芽是選用 REST風格。
REST可以翻譯為表現(xiàn)層狀態(tài)轉(zhuǎn)化,這里應(yīng)該還有個主語,那就是 Resource(資源),特指網(wǎng)絡(luò)上的具體信息,比如帖子和評論。美芽在設(shè)計客戶端請求接口的時候都是針對一個資源做操作。REST定義了一個對資源操作的標準,使用 HTTP 的四個動詞表示對資源的操作,GET,POST,DELETE,PUT。以用戶帖子為例:
GET /posts 獲取帖子列表,
GET /posts/id 獲取編號為 id 帖子的內(nèi)容,
POST /posts 發(fā)布帖子,
DELETE /posts/id 刪除編號為 id 的帖子,
PUT /posts/id 修改編號為 id 的帖子。
無論新加任何功能模塊,包括評論或點贊等都執(zhí)行這一標準。在開發(fā)客戶端的過程中,就避免了添加新功能時對接口做其他的約定。
以模型 Post 舉例,接口可以變成在獲取帖子時,將 id 傳過去,返回來就是需要的對象。帖子在后端或數(shù)據(jù)庫中的字段,在客戶端對應(yīng)的就是 Post 模型的屬性。
不再需要有文檔去介紹它,只需要自動生成一份數(shù)據(jù)庫字典就把所有東西解決了,少了很多中間成本。在客戶端要創(chuàng)建帖子就變得極其簡單,客戶端用定義好的方法請求到后端,服務(wù)端收到請求后就往數(shù)據(jù)庫里新建一個資源。美芽在客戶端接口設(shè)計的時候都是針對資源操作。
總結(jié)來說,接口設(shè)計面向資源、而非功能。在客戶端有各種功能和操作,在接口上面肯定不能所有的東西都按客戶端的要求設(shè)計,這樣會增加很大成本。我們在接口設(shè)計上只關(guān)注數(shù)據(jù),至于怎么操作是客戶端的事情,將數(shù)據(jù)和表現(xiàn)分離。
2. 流程
開發(fā)流程,剛出道的時候由于流程不完善,會出現(xiàn)各種問題,比如剛上線的代碼或剛修正了一個 Bug隨意發(fā)布,發(fā)布上去后又發(fā)現(xiàn)有問題。
針對這點,美芽制定了本地環(huán)境 - 開發(fā)環(huán)境 - 預發(fā)環(huán)境 - 生產(chǎn)環(huán)境四個環(huán)節(jié)。每個人在本地環(huán)境完成后將代碼提交,會自動發(fā)布到集成開發(fā)環(huán)境;預發(fā)環(huán)境的存在,是想在上線之前,在同樣的生產(chǎn)環(huán)境下,做終的確認,之后再更新到用戶環(huán)境中。
代碼管理的流程,從倉庫來說,首先有 master 和 dev 兩個長期分支,master 是主干分支,dev 是開發(fā)的集成環(huán)境 。當要修改 bug或者開發(fā)新特性時會新建一個新分支,問題修復后需要將這個分支 merge 到 dev 分支,需要上線時就合并到 master,這是一個特定的生命周期。
代碼在推向預發(fā)環(huán)境前要經(jīng)過其他成員的審核,審核之后才會合并。合并后使用 git hooks 工具,自動將代碼更新到預發(fā)環(huán)境,在App客戶端 內(nèi)部會做一些開關(guān)控制它用哪個環(huán)境。
在整個過程中,對所有同學都是透明的,我們使用了 Slack 作為消息樞紐,Slack 訂閱了 Github 通知事件。團隊里面的每一位成員,只要關(guān)注項目都會看到所有的動態(tài),包括特性上線、Bug修復等。還有一個工具 fabric, 這是一個 異常上報 組件,客戶端集成 fabric sdk后就可以將異常上報到 fabric,fabric再通知到 Slack, 團隊成員就能在 slack 中看到客戶端運行動態(tài)了。
框架
其一,為了保證開發(fā)效率,希望框架使用起來能夠足夠簡單,新的團隊成員也能夠很好地適應(yīng)。關(guān)于頗受爭議的 ORM 需要觀察它的適用情況,在用戶規(guī)模尚小、數(shù)據(jù)量較小時,ORM 能夠快速實現(xiàn)業(yè)務(wù)需求,而當量級漸長就該果斷舍棄;其二,框架必須保證功能強大,以盡可能減少開發(fā)量。基于以上的綜合考慮,美芽選擇選擇使用了以下PHP框架和工具:
2. DB migration,這個是修改數(shù)據(jù)表結(jié)構(gòu)的一個工具。剛剛提及的需求會較不穩(wěn)定,經(jīng)常會遇到字段的增減,而此類操作如果只是手動修改,并需要同步到其它環(huán)境,將極其不利于管理。DB migration 這個機制是用要代碼表示數(shù)據(jù)庫字段的增刪。
譬如在增設(shè)字段時,新增一個類表示對數(shù)據(jù)表的操作,其中,up 方法就是執(zhí)行修改,down 是回滾修改。等到上線時,就只需更新 PHP代碼,這就統(tǒng)一了表結(jié)構(gòu)的統(tǒng)一操作,所有的東西都用代碼呈現(xiàn),呈現(xiàn)又是文本,可以進行版本管理。人員對數(shù)據(jù)庫的所有操作都有紀錄。
3. Command。比如,開發(fā)一個命令行工具,讓用戶輸入一個名字,根據(jù)名字調(diào)用信息,需要包含輸入?yún)?shù),和選項參數(shù)以及輸出。Command 會將這些東西做包裝,不需要開發(fā)除了產(chǎn)品業(yè)務(wù)邏輯之外的東西。
4. Queue,進行很多操作時不能同步等待,比如推送一條消息,發(fā)布一條評論讓對方收到消息通知,肯定不能在請求里同步處理,而是要放到隊列里異步執(zhí)行,再推送到蘋果的服務(wù)器后推送到用戶。這個例子是項目中用的,我們添加隊列的時候只需在服務(wù)器上執(zhí)行一條命令打開這個隊列。
5. Tinker,這也是命令行的工具,可以做到在執(zhí)行這條命令的時候,把整個項目環(huán)境加載進去。而且是一個交互式的操作,比如要取一個對象就可以直接查詢,把信息打出來。相比較調(diào)試代碼時用url或者添加各種參數(shù),這種處理方式會非常方便。
6. 還有一個是對 Log 的處理,使用時只需要配置一下,在當前環(huán)境下需要打的 Log 級別,在代碼中直接使用即可,或者在生產(chǎn)中將這類信息都保留。
上面使用的每一項都不是太復雜,或者難度特別大,自己做也都可以。但在資源有限的情況下,初創(chuàng)團隊更重要的是投入更大的時間和精力在業(yè)務(wù)上。這個框架是集成了開發(fā)中一些通用的內(nèi)容,減少了很多額外的開發(fā)工作。
雖然看上去 Laravel 框架非常美好,但美好都是有代價的,Laravel 框架非常的慢。因為它提供了各種封裝、加載了很多東西,導致一個空的接口響應(yīng)時間也需要幾十毫秒。所以更適合量不大的初創(chuàng)產(chǎn)品。但與此同時,美芽也正在積極解決效率問題。
再來看 iOS 類庫,REST 只是定義了標準,而沒有提供完整的工具來實現(xiàn),通常服務(wù)端返回的是 JSON 格式數(shù)據(jù),客戶端將收到的 JSON 格式轉(zhuǎn)換成 NSDictionary,再由 NSDictionary 轉(zhuǎn)換成 NSObject, 這可能對應(yīng)到客戶端的一個 Model 或者一個具體對象;客戶端發(fā)請求到服務(wù)端時,就需要將 NSObject 轉(zhuǎn)化成 NSDictionary, 再轉(zhuǎn)換成 JSON 格式,然后發(fā)送到服務(wù)端。這個過程非常煩鎖,而且需要對每個類都實現(xiàn)一套 encode decode 的邏輯,而實質(zhì)上我們關(guān)心的只是 Value 而已。我們引進了 Mantle 庫,這個庫會幫你實現(xiàn)這一系列封包解包的過程。
再加上 TMCache AFNetworking 這兩個庫(前者用來實現(xiàn)快速的對象緩存,而后者基本上每個 iOS 程序員都熟悉的一個網(wǎng)絡(luò)框架),就能實現(xiàn)整個產(chǎn)品的 Model 層。
后介紹一套開源軟件 ELK(Elasticsearch Logstash Kibana),這一套軟件主要用來處理日志,進而分析問題,其中Elasticsearch 負責存儲+搜索、Logstash 負責搜集、Kibana 負責展示,通過 ELK我們可以隨時觀察事件的發(fā)生,并作出及時妥當?shù)奶幚怼?/span>
比如客戶端訪問服務(wù)器時返回系統(tǒng)繁忙這些錯誤,或者是帖子加載過慢這些問題都可以通過這一套軟件展示出來。雖然看似復雜,但實際操作卻極其簡單,現(xiàn)在我們主要分析程序內(nèi)部日志,Nginx access log 和 Nginx error log。
這些日志會先通過 logstash 采集,存儲到 ES 上,再通過 Kibana 展示出來。
同時,這一套工具還有對運營數(shù)據(jù)分析的支持。接入這套工具,美芽實現(xiàn)了各種業(yè)務(wù)的簡單統(tǒng)計,包括注冊統(tǒng)計、地區(qū)分析、時間分析、用戶活躍時間等等。接入 ELK 也是非常簡單的,只需將原始數(shù)據(jù)導入,調(diào)用一些查詢語句就可以展現(xiàn),只需要調(diào)用一下接口、填入統(tǒng)計數(shù)據(jù)即可,業(yè)務(wù)上不需要做什么操作和修改,更無需修改數(shù)據(jù)庫和代碼主邏輯。
美芽整體宏觀架構(gòu)如下圖所示:美芽用戶通過 APP 或者PC 版跟 Nginx 交互再訪問 API,這里所產(chǎn)生的日志都會寫文件,在文件寫入之后就會有 Logstash Agent 會翻譯成固定的格式存到 Elsearch, 同時 API 內(nèi)部也會將日志會先輸出到消息隊列中,由消息隊列再異步輸出到 Logstash Agent,Dashboard 會調(diào)用 kibana 的接口,以運營能接受的形式展現(xiàn)出來,如下圖:
會管理線上服務(wù)器的客戶端開發(fā),才是一名好運維
特別介紹下美芽的運維,盡一人多用之能事,運維也兼做開發(fā)。在代碼的上線流程中并不需要運維的參與,但軟件安裝、配置更新就需要運維處理。美芽的運維,主要是通過 Saltstack,用 YAML 來描述服務(wù)器的狀態(tài)。YAML 作為一種比較簡潔的數(shù)據(jù)格式,是純文本的,也就是說服務(wù)器的所有狀態(tài)都可以進行版本管理,服務(wù)器的狀態(tài)可根據(jù)每個版本里面的配置文件體現(xiàn)出來服務(wù)器當前是什么樣的狀態(tài)。
看下面一個簡單的示例,下圖是一個 logstash 的 saltstack 配置:
首先是有一個 master 節(jié)點,這是一個中心節(jié)點,然后有很多的 minion 節(jié)點需要被更新。
執(zhí)行以下一條命令就可以將所有的 minion 更新了,命令有兩個參數(shù),一個是 prod,是一個分組的概念,比如五臺服務(wù)器,把五臺服務(wù)器都放到分組里面;后面一個參數(shù) production, 代表生產(chǎn)環(huán)境。操作時,前半部分是針對五臺服務(wù)器做的工作。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個個人學習交流的平臺,網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對此聲明的最終解釋權(quán)。