設計稿自動生成可用頁面的展望
立足
三年前剛開始做 Sketch 生成代碼插件時,定位的就是原型工具,不是可用頁面。我當時認為直接由設計稿生成可用代碼是走不通的,原因有兩個:
- 當時的前端自己都還處在爭論用什么框架的時期,得先解決了這個問題設計工具才可能生成被大部分開發者接受的代碼。
- 設計語言與編程語言差異比想象中的大。
關于第二點這里詳細說明一下。設計稿中的圖層通常表達的是離人眼前后順序,前面的覆蓋后面。而圖層的分組也只是為了管理而已,沒有邏輯上的聚合關系。如下圖,背景的紅色圖層與形狀圖層是平級的,沒有展示出包含關系。

并且在設計中常常會按類型而不是按邏輯歸屬把一些東西放在同一圖層,這樣設計師在修改的時候比較容易批量操作。而在前端的組件化中,組件幾乎一定是按邏輯功能劃分的。而組件的層級表達也是邏輯上的包含關系。這種關系只有一部分能和視覺上的從前到后匹配。以 React 為例,很多組件層級的表達就不是前后關系。


因此,想要實現視覺上到邏輯上的完美轉化,只有兩種可能,一是按邏輯的要求約束視覺上的圖層、分組使用。二是靠機器學習之類的方式去智能識別(社區已有開源項目)。
第一種方式其實技術上可行,但是不人性。兩個方面,一是給設計師造成了巨大的學習成本。這個巨大指的不是設計師學不會,而是指規則有可能因為開發者設計得不完善或者不夠簡便,使得設計師要做很多他自己無意義的額外操作。例如本來設計師一個圖層可以畫完的元素,在規則的要求下要進行分組分層。二是這些規則很可能忽視了設計師的需求,例如之前所提到的同一圖層管理同一類元素的的問題。我有嘗試使用社區內的一些方案,從設計師的角度來說,那種體驗就像:

第二種方式當時雖然有想過,但是沒有深入去探索,原因也是當時的前端變化太快,我認為找不到足夠穩定的樣本能去訓練。
有了以上結論后,我想到了雖然直接生成可用頁面不行,但是生成原型還是有可能的。設計師和前端的溝通成本也是一個需要解決的問題。最常見的就是設計師需要告訴前端某個元素 hover 上去是什么效果,點擊是什么效果等。這些東西既然設計師已經畫出來了,那么能不能把這個表達的方式自動化掉,省去人工溝通的成本。像 Axure 之類的原型工具就有類似的功能。只是這些工具一般都定位給產品做最初的原型設計,缺少了視覺上的細節,不能完全取代設計師和前端的溝通。
因此我開始做從視覺稿到原型的 Sketch 插件 Blade。這個插件雖然也在一定程度上要求設計師按某種規則來設計,但是這種規則對設計師已經是有意義的了,能省去他的口頭描述。
旁觀
在開發完第一版后,由于工作的調動就沒再維護了。后來更是由于 Sketch 升級后的 api 變化導致不能用了。讓我比較意外的是這兩年間持續不斷地有人開 issue,寫 email 希望我繼續更新。我在 issue 中委婉的表示項目已經不再維護,大家可以試試社區的其他方案。但社區的其他方案屈指可數,并且方向和定位其實也都不太相同。
按我所接觸的順序一一介紹一下。
Marketch,也是生成 html 文件,但是專注于標注功能,方便前端同學取位置和樣式信息。這個定位非常精確,讓前端不再需要自己裝 Sketch。

從 Sketch 的生態體系看來其實插件可以分成兩大類,一類是用來方便設計師的操作的,例如快速生成一些常用的元素,如頭像、地圖等。另一類就是擴展設計之外功能,例如生成標準、原型。對個人開發者來說開發前一類的插件難度比較小,而且收益很明確。而后者相對來說難度和收益就都不樂觀了。在后來我再看到的第二類插件中,幾乎都是團隊進行開發的。例如 Framer 和 Proto.io。

這兩個工具的共同點是都已經脫離了 Sketch 體系,變成了獨立應用。以導入的方式來整合 Sketch/Photoshop 等工具的產出物。但定位也仍然是可交互的原型產品。直到 Launchpad 出現,才算得上我知道的第一個定位于生成可用頁面的 plugin。

從 Lauchpad 所提供的功能看來,生成頁面功能非常簡單,只有簡單的鏈接、表單,還不涉及到復雜的交互邏輯。生成的代碼也不能二次開發。但是 Launchpad 做成了一門生意,并且好像運營得還不錯。從跟我進行郵件溝通的設計師中,我也發現了不少想要直接建站的需求。再回過來看我之前認為這條路不能成功的兩個原因,反思一下是我想錯了嗎?
第一個原因是我認為生成的代碼必須要前端能接受才行。Launchpad 沒有提供二次開發這個能力,似乎就回避掉了這個問題。但同時也就限制了能力。
第二個原因是設計語言和編程語言的差異。同樣的,縮小了需要覆蓋的場景,不提供二次開發,也使得對設計師造成的負擔最小化。
這樣看來不是對錯的問題,而是本來定位就不一樣。我在思考這個問題的時候其實并沒有區分場景,定位的是從簡單頁面到復雜的單頁應用應該都能適用的情況。Launchpad 提供了一個新思路,就是縮小場景后能實現一部分。
前面列舉的相關的插件都是從設計的角度出發制作的。而不久前 Airbnb 的 react-sketch 插件則提供了一個新的角度。

它的目標是設計資產的管理。它的能力是將組件這種設計資產從代碼導入到 Sketch,同時也能從 Sketch 導出到代碼。所以即可以說站在了設計師的角度也可以說是站在了前端的角度。在知乎上有一個評價 react-sketch 的問題。前兩個回答非常的透徹。讀者可以看一看。回答里提到的這種工具在真實團隊的適用并不樂觀,我有同感。因為它站在了一個新的角度看問題,那么必須也得有一個站在同一角度的新角色(設計工程師?)出現才能顯示出它的價值。否則單獨對設計師、對前端,都會感覺意義不大。
同樣,react-sketch 也提供了一個新思路,就是以設計資產這個維度來實現代碼和設計元素的統一是有一定價值的。這種統一,其實也就是能互相轉換。
投石
僅僅對 Sketch 插件演變的觀察還不足以引發對文題的新思考。真正的機緣來自于最近一兩年做框架和可視化搭建平臺的經驗。仍然回顧最初我認為不能成功的兩個原因,或者說兩個問題,看看經過這兩年,是否發生了新的變化。
順著上一節講到的設計資產的思路,我們先看第二個設計語言與編程語言的差異問題。以組件的維度來統一設計與代碼,其實本質上是對設計的一種補償。既然設計師需要遵守統一的約定來使用或者修改組件的設計,不能再按照個人的習慣,那就讓這種約定的負擔減到最小,即由插件來自動生成,不需要額外記憶。同時將資源的全自動管理作為補償提供給設計師。用工具來管理可以通過團隊的平臺進行共享,如果未來整個團隊需要升級或者統一的修改,就能通過工具來統一完成,不再需要人肉同步。
再進一步,由于組件本身是一個邏輯單位。雖然設計師在設計師可能不遵從邏輯單位,但是在接受信息,與他人溝通時仍然是以邏輯單位為準的。這樣在設計工具上其實可以做更多方便設計師的功能。例如能“快速選擇所有按鈕、表單、幻燈片等組件的圖層進行批量修改該”等。用技術的方式置換掉設計師們以往人肉提升效率的習慣。
這樣,通過轉換一點點角度,主動為設計師做一些改變,第二個問題看起來是可以解決的。
再看第一個問題,產出什么樣的代碼才能讓前端接受。首先,至少在支付寶內部,前端框架的爭論幾乎已經沒有。大家已經普遍接受了 React 及其生態體系。然而實際編寫的 React 代碼中,通常原子類型的組件會被包裝成相應的業務組件,有業務邏輯。而最頂層也只會看到相應的幾個業務組件。不像在設計稿中,所有組件都是原子的,頂層可見的。想到這里時,忽然意識到這也不再是個問題,因為在可視化的搭建平臺中,我們已經使用的是一種平鋪的,頂層可見的組件結構。只要有合適的應用層框架,在頁面結構比較穩定的情況下,它是能解決問題的。如下圖中右下角的組件樹,表示的就是類似圖層的平鋪方式。

我們對平鋪的組件結構,抽象出了數據樹的概念。通過對數據樹的操作,可以完美的控制整個組件樹,也就是整個應用。而一些上升到應用框架層的高級功能,例如表單的校驗等,也是建立在數據樹上的。有了數據樹,實際上就等于有了真個頁面的邏輯入口。下圖展示著在調試模式下,用戶可以直接看到的數據樹。

要進行二次開發,生成的代碼不一定要符合手工編碼規范,甚至不一定要可讀啊!
我們完全可以把生成的界面看做是一個黑盒子程序,只要能保證二次開發者能通過 api 進行控制就夠了!(詳見前端服務化——頁面搭建工具的死與生)。而這種方式所能支持的應用復雜度,其實也就是對應的邏輯編寫方式能支持的應用復雜度,不再和界面本身有關。
至此,兩個問題都已有了解決方案,在可視化自動生成這條路上算是投出了一個新石子。
絮語
從設計到代碼的自動化其實可以看做是可視化平臺的最后一塊補全。截止到今日,之前的可視化搭建平臺已經支持了 56 個系統,在無前端參與的情況下輸出了1000+的頁面。鏈路完成了從研發到自動化測試再到上線。測試工具效果如圖:

如果成功加上設計鏈路的話,可以暢想的頁面開發場景是:
- 簡單的展示類頁面能從設計稿直接上線。
- 需要交互邏輯的,由前端在生成的代碼上補全邏輯。錄制測試用例,然后上線。
- 如果設計有樣式上的修改,不影響邏輯,那么設計改完之后能自動重新回歸測試并上線,不再需要前端參與。
- 如果有邏輯變化,平臺能通過 diff 設計稿得到組件的改動,再通過語意分析得到影響的邏輯代碼范圍。
搭完這條流水線,就會產出足夠規范的樣本,或許就能作為足夠好的人工智能原料,實現讓自己下崗的夢想。
同樣,想要參與到這件事的讀者可以找我來聊聊 ariesate@outlook.com。
答讀者問
最近收到了一些非常高質量的讀者提問,摘取部分整理到這里(部分回答也重新進行了修改):
問:
從組件層面的沉淀感覺無法在效率上獲得更大的突破了。但是對于功能降級到類似CURD頁面的可視化搭建,我都發現有大量潛在的問題,可能歸根結底就是“靈活性”和“高效率”之間的平衡。后臺類系統最大的問題倒不是展示層的標準化,也不是展示層是如何拖拽產生。 最大的問題就是“界面數據層面以及相關邏輯的錯綜復雜的關系”。例如:一個日期組件的展示,可能是和前一個分類Select的選擇有關,而這個分類Select的值又可能是某個異步接口動態獲取,而這個異步接口又可能是其它組件的query拼裝而成。 我不排除,構建一個完整的邏輯數據控制流程,并提供復雜的配置界面可以解決這一系列的問題。但如果這種方式帶來了超大的配置成本,是不是反而不如直接投入前端人力?傳統手寫代碼的方式,至少開發者面對是自己直接可控的代碼,雖然代碼量會更多,但更直觀也更以維護,而不是一坨黑盒。
答:
在面對真實場景時,確實遇到了“靈活性”與“高效率”權衡的問題。靈活性意味著絕大部分場景倒要考慮到,那必定系統意味要提供各種各樣的能力去解決各種各樣的問題,同時也就意味著會提高學習成本。在前端框架中 Angular1 的設計其實就是一個例子,他所提供了 service、filter 等各種機制雖然能覆蓋足夠的場景,但也讓學習成本陡升。而我們在搭建這個系統時,提出的方案其實算是繞過了這個問題。我們的方案是:提供一種“漸進式的、易擴展的、程序可讀”的抽象,目標是讓后端能做前端的事。先解釋下方案。
漸進是指,這個系統對于一些簡單的頁面,讓他確實能把頁面搭一搭,配置一下組件數據就完成了(很多類似系統都是提供一個“配置數據源”的方式來做的)。而對于復雜的頁面,系統又能提供一些其他方式,例如寫一些簡單的邏輯代碼來處理邏輯。簡而言之,就是隨著用戶對用戶處理的場景進行一個復雜度的分級,升一級就提供一些新的方案給他解決遇到的新的問題。這里面的關鍵在于,方案應該是盡量向下兼容的。例如在 http://www.rzrgm.cn/sskyy/p/6496287.html 中最后提到的組件數據樹的這個方案,這是最底層的,用戶用邏輯代碼來操作數據源本身可以解決任何問題,這在簡單的場景中已經足夠用了。但是在一些更復雜的場景、例如“先要查詢一下表單中的每一項是否都已驗證,再決定發不發請求”等場景時,讓用戶一個一個讀組件數據很不方便,那我們就在這個基礎上對用戶的邏輯代碼中注入一個 form 的對象,這個對象上的方法能幫他快速讀取表單組件數據。但本質上,還是基于原本的組件數據樹。這樣對用戶來說無論哪種場景,無論代碼怎么寫,都是兼容的。學習是一點一點遞進的。
同樣,易擴展指的也是和漸進一樣的場景,只不過描述的對象是開發者。有了上述的這個統一操作數據樹的方案,我們就可以不斷的增加新的輔助對象(稱為util),來處理不同的場景。例如發送 ajax 時組件自動呈現 loading 狀態等。有了易擴展的特性,才能是系統以最小的成本去適應不同的場景,同時也提供了讓第三方開發者來為平臺提供能力的可能。
最后的“程序可讀”則是保障系統穩定、應用不失控的關鍵。我們的系統中一開始就定好了用戶寫的代碼只是對“組件事件”的響應代碼,并且如何操作組件數據樹、如何使用util都是有嚴格規定的。有了這個基礎,我們就可以對用戶的邏輯里的意圖有非常強了解,例如我們現在可以通過掃描代碼來在運行前就直接提示,哪個組件會受到哪些邏輯的影響。組件改了名字,哪些邏輯代碼也要改等等。同樣的,通過 debug 狀態下對 api 包裝等手段,還能做到更強大的調試功能。這也是對“用戶積累一定經驗后,憑什么放棄靈活性,繼續用你的系統”的回答,因為用戶放棄的靈活性,我們可以為他提供更強的保駕護航。
最后,回到前面的話題,我非常同意 “靈活” 和 “高效” 是天平的兩端。但其實可以不去糾結這個事情。之前有一本講交互設計的書給了我很大的啟發,其中提到要把用戶設想成“聰明但是很忙的人”。“聰明”意味著你給他抽象如果比較常見或者簡單,他是能夠很快掌握的。忙意味著你要從他的角度思考,當掌握了這個抽象之后,怎么樣能加速他的工作,或者能提供給他什么途徑讓他能自己加速自己的工作。只要達成了“讓聰明人很快的干完了事”,其實就算成功了,用不了你產品的人可能就真的不適合用你的產品。從這個角度去想就會發現,以前糾結的“靈活和高效有矛盾”的原因是,高效里面有“聰明人的高效”和“蠢人的高效”。“蠢人的高效”意味著你什么都要封裝好給他,這會和“靈活”相悖。所以放棄掉“蠢人的高效”,也就不用考慮這個問題了。
問:
從設計稿直接上線可用的代碼,其實最難的是需要設計師來配合,因為這會給他們增加約束,如何來處理這個問題?
答:
相比于具體的技術問題,這個問題其實確才實是最難解決的。我在文章里其實稍微提到了點,約束是“自動化”的關鍵,是無法避免的。在 airbnb 的這篇文章 https://airbnb.design/building-a-visual-language/ 中也提到了這個。既然無法避免,那最關鍵的就是這種約束如何為設計師也帶來好處。我們的文章里提到了對設計師的約束其實只有一個:“要以某種指定形式來規范圖層,例如命名,這樣才能將圖層和要生成的組件關聯起來”。我們現在已經啟動了這個項目,設計師是直接參與進來的,和他們交流中總結出來的對他們有價值的幾個關鍵點:
1. 流程上受益。如果平臺能保證只要設計師按規范出圖,那么最后上線的效果就一定和設計效果一樣的話,那設計師就不用在最后上線前復查真實頁面了。
2. 對設計資產的管理。“組件”這個概念其實是前端和設計師通用的,前端通常是以代碼庫的方式來管理組件,而設計師目前缺乏相應的工具或者規范。如果設計稿里能通過程序讀出設計師使用了什么組件,如何使用的,那么我們就有機會為設計師去也去做一些設計資產管理的工具。例如設計的組件庫管理工具,當整體設計風格升級時,能自動告訴設計師哪些頁面上相應的組件也要升級,如果設計的搞好,甚至可以自動升級視覺稿。
3. 滿足設計師的產品心。如果這個系統穩定性、易用性好到一定程度的話,設計師其實也有機會直接作出可以用的產品。這本身對設計師也是很大的誘惑。
除了上述這些具體的點,其實最重要的是要讓設計師直接參與進來編程系統的設計者,這樣自然就破除了職能之間本身存在的隔閡。
問:
為什么會想到做這樣的東西,另外什么時候開源?
答:
這幾年無論是做框架還是工具,我一直是朝著提升 web 應用的研發效率這個方向前進的。在見證了前端新的基礎技術(瀏覽器環境、語言)和框架的不斷變革后我意識一點:
“對個人來說其實不存在研發效能的問題”。因為一個人能處理的問題有限,同樣要用到的東西也是有限的,工具不好用換一個就是。編程理念不對學點新東西就是。但是對于大公司來說,問題就發生了質變。首先,資源的不對等會產生“短板效應”,例如前端人不夠,不可能因為這個拖累整個產品的研發吧?所以有的部門加班,有的閑。再例如職能劃分的過細、流程太長導致中間的溝通成本急劇增加,也會極大拖累整體效能。
之前我一直在框架、工具中探索,“找到某種正確的抽象”、“實踐某種編程理念”,這其實都是針對個人的方案。而業界所看到針對團隊的方案普遍也就是建立“組件庫”、建立各種“發布平臺”、“監控平臺”等等。這些都是從提升“某個工具的復用能力”去解決的。而比較少看到專門針對流程的方案。見證了那么多框架、工具的興起和死亡之后。我認為從“流程自動化”的方向去解決問題才更能幫助大團隊和大公司解決問題。因此這篇文章里的其實最重要的并不是具體的實現技術,而是 “設計-研發-測試-部署” 的全流程串聯,并且在流程上實現自動化。關于這一點我會再單獨寫一篇文章,我們在 web 應用研發這個方向應該已經慢慢進入新的階段。也歡迎有興趣的讀者來信和我交流。我會持續更新到這篇文章中。
平臺會逐步以工具的形式開源,如果希望參與也可以先聯系我。
浙公網安備 33010602011771號