網易雲音樂基於 C2D2C 的「無損」設計協同

雲音樂技術團隊發表於2023-03-04

作者:彧瑾

以下全文是筆者根據在 GMTC 大會 上的演講稿整理而來,特為沒能去現場的朋友們獻上~

大家下午好,今天我要和大家分享的主題是《網易雲音樂基於 C2D2C 的「無損」設計協同》。

按照慣例,在開始之前,我先作一個簡單的自我介紹:

我今天分享的大綱分為 4 個部分,分別是:

  • 背景和問題
  • 基於 C2D2C 無損設計協同的介紹
  • 方案設計與技術挑戰
  • 總結與展望

背景和問題

什麼是(大前端)設計協同

在開始之前,我們先明確一個概念:就是什麼是(大前端)設計協同?

我的理解,所謂(大前端)設計協同,簡單來講,就是在設計師開發的合作下,將產品需求轉化成程式碼的過程。

然而,在實際的設計協同中,往往存在一些令人頭疼的問題。

設計協同中存在的問題

拿雲音樂來說,首先,設計資產是透過人肉管理的,設計規範也是人肉同步,而且不同的設計團隊之間設計標準不一,設計資產存在重複建設。

而開發作為設計的下游,則會連鎖受到影響。具體體現在:

  • 對於同一個元件,因為規範的不同導致重複開發;
  • 像換膚這樣的三端聯動場景,開發也不得不重複實現三套。
  • 最後,由於開發側需要人肉還原設計稿,效率較低,容易造成開發資源瓶頸。

此外,設計和研發除了在各自領域記憶體在問題外,彼此間的串聯也存在問題。具體為:

  • 在開發前,由於設計和開發彼此間存在 GAP,在一些邊界問題和能力範疇等問題上會反覆對焦,溝通成本大
  • 在開發過程中,開發需與設計就細節頻繁溝通,工作效率低
  • 開發完成後,因為開發人員長期處在 時間緊任務重 的「趕工式」狀態,導致最後的視覺還原度低,設計驗收效率低

如果我們對以上問題進行分類和總結,就會發現,設計協同中的問題基本可分為「溝通問題」和「效率問題」,而且彼此間互有重疊,相互交錯。

比如設計資產的人肉管理,既會導致「溝通問題」也會導致「效率問題」。

傳統的解決之道

為了解決上述問題,業界傳統的做法一般是採取以 設計系統 為中心的「有損」設計協同。

具體做法是提供 兩套 元件庫,一套是給設計用的 Sketch 或 Figma 元件庫,一套是給開發用的 React 或 Vue 元件庫。

確實,透過設計系統能在一定程度上解決「溝通」和「效率」的問題。但是這種做法會在無形中造成設計意圖傳遞的損耗,為什麼這麼說呢?

這是因為,在以設計系統為中心的解決方案之中,設計規範存在兩套相互獨立的實現,分別對應為設計資產和元件程式碼,而且彼此不同源。

這就導致了設計意圖從設計師傳遞到開發者存在比較多的「資訊損耗」,而這種「損耗」必須透過 人的溝通 才能解決,引入了不確定性和時間成本

「有損」設計協同之殤

現在,我們總結一下:「有損」設計協同來的問題主要有三個。

  • 首先,維護成本較高。因為我們需要同時維護設計和開發 2 套元件庫;
  • 其次,協作效率低。因為資訊損耗的存在,所以,設計和開發需要透過反覆溝通來消除不確定性;
  • 最後,區域性的效率比較低。具體表現在,設計師在做稿時,仍然需要較為頻繁的手改文案,調整佈局;而開發在還原 UI 時,則需要手擼程式碼,人肉去還原。

我們知道,徹底解決一個問題關鍵,在於找到其癥結所在。

癥結在哪裡

造成「有損」設計協同出現問題的本質原因,就是因為設計和開發的工具體系缺少統一的協作語言。

設計師使用的是設計語言,而開發者使用的是開發語言,彼此不同源,設計意圖的傳遞不可避免存在損耗。

設計協同新思路

所以,為了徹底解決此問題,最好的做法就是從工具側打通設計和開發,統一協作語言

為此,我們基於此思路,提出了 基於 C2D2C 的無損設計協同

基於 C2D2C 無損設計協同的介紹

C2D、D2C 簡介

首先,和大家簡單介紹一下什麼是 C2D 和 D2C。

所謂 C2D,全稱是 Code2Design,也就是將程式碼轉成設計稿。

而 D2C,則是其逆過程,將設計稿轉成程式碼。

「無損」設計協同的核心

而無損設計協同的核心,就是藉助 C2D 和 D2C,用程式碼及其衍生物統一協作語言

具體而言,設計師藉助 C2D,將設計意圖表達成設計語言,這裡的設計語言不僅包含圖層資料,還包含圖層所對應元件的後設資料資訊,包括元件名,元件的配置引數。

然後開發者藉助 D2C,透過消費圖層和元件後設資料,將設計語言表達成開發語言。

因為在元件後設資料中包含了完整的設計意圖,所以從理論上講,這就實現了設計意圖的無損傳遞。

「無損」設計協同的優勢

與有損設計協同相比,無損設計協同的優勢體現在 3 個方面:

  • 首先,是維護成本低。因為只需在開發側維護一套元件庫即可。
  • 其次,是協作效率比較高。因為設計細節無損儲存在後設資料中,免去了反覆確認。
  • 最後,是區域性效率比較高。因為設計師可以利用 C2D 快速生成設計稿,開發者利用 D2C 快速還原 UI。

方案設計與技術挑戰

那要怎麼實現基於 C2D2C 的無損設計協同呢?接下來,將會和大家詳細介紹我們的方案設計與技術實現。

產品全景圖

現在,呈現在大家面前的,是雲音樂 C2D2C 的產品全景圖。

最下面是設計規範,基於設計規範我們構建出了整套元件體系,覆蓋 H5、RN、iOS、Android 四個平臺,在實現上,透過共享 Design Token 保證了 UI 的一致性。

而所謂 Design Token,可以將其理解成一種將元件樣式與程式碼解耦的實踐:先將用於控制元件樣式的顏色、字號、圓角、邊距等設計要素抽離成變數(也就是 Design Token),然後在實現上,透過引用 Design Token 來實現元件樣式,這樣不僅可保證三端元件 UI 的一致性,還能很容易地實現諸如動態換膚、品牌風格改版等「高階功能」。

基於元件體系,我們構建了 C2D2C 的工具體系,包括 C2D 和 D2C 兩大關鍵能力,以及基於此的 Sketch 和 Figma 外掛。

最後,我們將 D2C 的出碼與低程式碼平臺進行打通,最終形成了 C2D2C 協同流程的閉環。

核心流程

整體 C2D2C 的協同流程可以簡化成下面這張圖:

首先,業務設計師利用 C2D 外掛搭建出業務設計稿,然後交付給 業務大前端開發。

業務大前端開發拿到設計稿後,利用 D2C 外掛,便可以產出目的碼。

然後 D2C 外掛便將程式碼推送到低程式碼平臺,進行二次開發和調整,完成之後,便可以透過釋出平臺進行釋出上線了。

C2D2C 功能演示

這裡有一個一分多鐘的演示影片,大家可以跟隨著我,一起來感受一下:

https://crazynote.v.netease.c...

首先,我們的設計師開啟 figma 的 C2D 外掛,從外掛的元件皮膚中拖拽出一個 Tab 元件,拖拽完成後,可以選中元件並喚起配置皮膚進行相關的配置。

隨後,我們按照相同的做法,拖拽出一個底部導航欄、一個大圖卡片、一個圖文卡片和一個文字卡片。

頁面搭建完成後,我們便可以開啟 figma 的 D2C 外掛,D2C 外掛有一些配置項,可以分別配置 D2C 的目標平臺,頁面佈局等引數。

然後我們將此頁面與低程式碼應用進行,最後點選生成,程式碼就會被推送到遠端 gitlab 倉庫。此時,我們點選線上開發,便可跳轉到低程式碼平臺,進行二次開發。

我們可以透過搭建的方式進行二次調整,也可以直接透過原始碼進行二次開發,且二者之間是可以互轉的。

經過剛才的演示,相信大家對 C2D2C 已經有了一個整體上的理解。接下來,我將會就一些比較關鍵的點,展開講講我們是如何實踐的。

跨平臺的外掛架構

因為我們的設計外掛覆蓋了 Sketch 和 Figma 兩個平臺,為了降低開發成本,我們設計了跨平臺的外掛架構。

跨平臺的核心思路其實比較簡單,就是用 Web 來承載 UI 和業務邏輯。

我們可以把外掛分成 端容器Webview,容器負責渲染和通訊,Webview 負責 UI 和業務邏輯。

但是這樣做會存在一些挑戰:

首先, Sketch 和 Figma 外掛視覺互動不一致。這主要是由外掛 API 能力的限制以及配色差異導致的。

其次,Sketch 和 Figma 外掛容器與 Webview 的通訊方式不統一,圖層的渲染邏輯也存在差異。

所以,如何才能用一套架構 Cover Sketch 和 Figma 兩個平臺呢?

為此,我們對外掛的架構進行了分層設計,分為底層的執行時、作為容器的渲染層、負責通訊的協議層、業務邏輯層,以及負責 UI 展示的檢視層。

透過這樣的合理分層,Sketch 和 Figma 便可以完全複用業務邏輯程式碼,同時也能根據平臺的不同,進行單獨的適配。

設計稿配置化方案

回到外掛本身,在前面的部分我也提到過,我們希望外掛能夠幫助設計師提效,從繁瑣的文案和佈局的調整中解放出來。

為此,我們實現了基於 C2D 的設計稿配置化方案:

配置化的核心是動態表單 + 後設資料繫結。從設計師視角來看,配置行為可以分為「首次配置」和「二次配置

首次配置時,使用者直接從外掛中將所需要的元件拖拽出來,透過 C2D,將目標元件轉成圖層資訊,同時將元件的配置資訊,也就是元件後設資料繫結到圖層上。

二次配置時,當使用者點選圖層時,會觸發外掛從圖層讀取元件後設資料,並利用動態表單渲染出配置皮膚,這樣使用者便可以實現二次的配置

所以,設計稿配置化的核心,就在於如何去做 C2D。

C2D 技術選型

我們知道,C2D 的本質是程式碼轉成設計稿,在業界,目前做 C2D 一般有兩種思路

一種是將 Sketch 或 Figma 作為 React 的一個端,利用類 RN 的語法,渲染出設計稿,比如 airbnb 的 react-sketchapp;

另一種思路,則是直接將元件的 html 轉設計稿,比如 ant-design 的 html2sketch。

第一種方案要求我們針對 Sketch 或 Figma 適配一套元件庫,比較優雅,但是成本較高,也會帶來後續維護的問題

第二種基於 html 的方案則與具體的技術棧無關,通用性強

在綜合考慮成本和收益後,我們最後選擇了第二種方案。

對 Sketch 而言,由於其釋出的時間早,C2D 的生態相對成熟,基於 html 的開源方案有 html-sketchapp、html2sketch,但是 html2sketch 作為後來者在還原度上更佳,所以我們選擇 html2sketch 作為 Sketch 的 C2D 方案。

而 Figma 由於是 2016 年釋出的,相對年輕,其 C2D 的生態還不夠成熟,基於 html 的開源方案有 figma-html,但是其還原度做的還不夠好,所以我們參考了 figma-html 的思路,選擇了自研 html2figma。

html2figma 實現原理

html2figma 的本質,其實就是 DSL 的轉換,將描述網頁 UI 的 html,轉換成描述 Figma 設計稿的 Schema。

具體而言,就是將 html 的元素,比如 div 標籤、p 標籤、svg 標籤,對映成 figma 的 frame 節點、文位元組點和向量節點。

對於除 svg 外的常規節點而言,轉換的過程就是將元素 CSS 的屬性對映成 節點的屬性。

不管是 html 還是 figma 的 Schema,由於二者在描述 UI 上都具備完備性,所以這種屬性的對映從理論上講,是完全沒有問題的。

我們可以舉一個例子進行說明:

比如,我們有一個 div 元素,透過 CSS,讓它成為了一個直徑為 80px,顏色為紅色的圓。

我們則可以將其轉換成 Figma 的 Frame,長和寬分別為 80px,填充色為紅色,圓角為 40px。

可以看到,轉換之後,二者在視覺上完全一樣。

但是 SVG 比較特殊,SVG 的解析比較複雜, SVG 本身可以看成一門獨立的 DSL。Figma 官方可能也是考慮到這點,為了保證 SVG 渲染的一致性,提供了直接將 SVG 字串 轉換成向量圖形的 API。

所以針對 SVG 的轉換就變的異常簡單了,不用解析,直接原封不動傳給 figma 即可。

舉個例子,比如,這裡有一個音符的圖示,我們直接獲取其 svg 原始碼,然後轉交給 figma 進行渲染,轉換之後,二者在視覺上完全一樣。so easy!

剛才和大家講完了 C2D 是如何實現的,那 D2C 又是如何實現的呢?

D2C 方案設計

D2C 的本質

說到 D2C,大家首先想到的可能就是阿里巴巴的 imgcook,或者是京東的 Deco,特別是 imgcook,大家耳熟能詳的原因,是因為它率先實現了將 AI 應用在 D2C 上,而且取得了不錯的效果。

這可能就會造成一種誤解,認為 D2C 就一定要用到 AI,其實不是的。

因為 D2C 的本質是將設計意圖還原成程式碼,所以 D2C 的關鍵就在於如何讓機器理解設計意圖

對於一張圖片而言,因為它是非結構化,它所包含的資訊完全蘊含在其二維畫素平面內,對於這種場景,用 AI 去做 D2C 是非常合適的,但是成本會比價高,因為會涉及到大量的標記和模型的訓練工作。

如果是對於 Sketch 或 Figma 的設計稿而言,因為其本身是結構化的,所以將其轉換成程式碼是完全可行的,社群的很多外掛都可以做到這點。

但是,真正的難點在於物料識別,也就是如何識別圖層,將其與元件庫進行關聯。

基於後設資料的 D2C

相信講到這裡,細心的朋友已經能明白,之前在做 C2D 的時候,為什麼要在圖層中繫結後設資料了呢?其實就是用來做物料識別的。

所以,我們的 D2C 方案,就是基於 後設資料 的 D2C:

原理並不複雜,基於 C2D 的產出的設計稿,我們會解析設計圖層和後設資料,同時進行物料的識別,最後還原成程式碼。

比如,對於 Button 而言,C2D 在生成設計稿時,會為圖層繫結元件的後設資料,包括元件名、元件 Props,API 文件等,D2C 時,直接讀取元件後設資料,翻譯成程式碼即可,其間不會丟失任何的設計細節。

沒有後設資料怎麼辦?

但是,對於雲音樂而言,除了標準化的產品功能頁面外,還有一類頁面場景,它們就是雲音樂特色的活動頁面,其創意性強,難於標準化。

相信大家在朋友圈或多或少見過他們的身影,比如戀愛人格測試活動,摸魚計算器活動,以及大家喜聞樂見的年度報告。

那對於這類缺少後設資料的設計稿要如何處理呢?

我們的做法也相當直接:既然你沒有後設資料,那我就人為補上後設資料

我們透過約定,在設計稿的結構、作圖和命名上進行規範。

對於設計稿的結構,我們會將其規範為頁面、元件和素材三部分,每部分承載各自的功能,彼此間不交叉。

對於作圖規範,則要求設計師具備元件化的思維,將複用的 UI 抽象成元件或元件變體,並透過變體的引數進行區分。這樣的做的理由是讓最後產出的程式碼的可讀性和質量更高。


最後是命名規範,也比較簡單:就三條:

  • 如果是完整頁面,則名稱前新增 # 字首進行標識;
  • 元件名要遵循語義化原則,不能使用特殊符號,這主要是為了方便生成元件名程式碼
  • 如果某個區塊想做為切圖展示,則直接利用 Fimga 進行標記即可。

做完以上工作後,設計稿的後設資料就算新增完成了,可以執行 D2C 了:

PPT 右側就是剛才摸魚活動的設計稿 D2C 生成的程式碼:可以看到,生成的程式碼有元件的劃分、有合理的佈局結構,具備較強的可讀性和二次開發的能力。

大家可能會好奇,這麼漂亮的程式碼是如何生成的?接下來,我將會和大家一起來揭秘。

D2C 核心流程

下面這張圖是 D2C 的核心流程圖,總體流程分為 4 步:

首先,拿到設計稿後,會經過圖層預處理進行圖層精簡。

緊接著,執行 UI2Schema,生成與平臺無關的中間產物,期間,會有一個可選流程,做佈局的最佳化,主要功能是將絕對定為佈局轉為相對定位。

然後,執行 Schema2Code,生成目的碼。

最後,進行二次開發和標準最後是上線。

我們先看第一步,圖層預處理。

圖層預處理的主要目的是精簡圖層,降低 D2C 的複雜度。

因為對於一個圖層而言,如果包含後設資料,則證明它能夠被識別成一個已知的元件,其子圖層已沒有太多價值,可以被完全被移除掉。

所以,圖層預處理,能在很大程度上降低圖層解析的複雜度。

圖層精簡完後,就到了第二步 —— UI2Schema 。

UI2Schema 主要目的是將設計稿轉成與平臺無關的中間產物,這裡的平臺既包括 Sketch/Figma 這樣的設計平臺,也包括 React、RN 這樣的程式碼平臺。

那為什麼要這麼做呢?是因為我們的面臨的場景比較複雜。

在設計側 ,Sketch 和 Figma 都在使用,端側,React、RN、 iOS、Android 都需要支援。

所以,透過中間層抽象之後,就可以實現跨設計平臺和跨端

剛才也提到,UI2Scehma 中有一個可選流程的,那就是佈局最佳化。雖然是可選流程,但是對於最終生成程式碼的可讀性而言,卻是頗為關鍵的

我們可以舉個例子進行說明。

PPT 左側有一個設計稿,包含 ABCD 四個節點,如果不進行佈局最佳化,那麼整個頁面將是一個扁平的結構,生成的是絕對定為的程式碼。雖然還原度能夠保證,但是可讀性比較差。

而佈局最佳化的過程,則是對 ABCD 進行分組,首先將頁面分為 ABC 和 D 兩行,然後將 ABC 分為 A 和 BC 兩列,最後將 BC 分為 B 和 C 兩行。

分好組後,透過新增三個佈局容器,形成行列巢狀結構,這樣最終生成的程式碼將符合開發者的直覺,具備較好的可讀性。

不難發現,做佈局最佳化,其實就是在做行列分割,那具體要如何實現呢?

整個流程,其實可以分為 5 步。

首先,我們需要獲取到待處理的節點座標

然後,進行節點關係的處理:判斷它們是處於包含、還是相交還是相離關係:

  • 如何是包含關係,則將被包含的節點作為其子節點處理;
  • 如何是相交關係,則將兩者看做一個整體,且其中一個相對於整體作絕對定位處理;
  • 如果是相離,則不做額外處理。

節點關係處理完成後,則是做二維空間投影,找到行列分割的依據

比如,透過縱向投影,我們就知道了 ABC 和 D 是屬於不同的兩行;透過橫向投影,我們就知道了 A 和 BC 屬於不同的兩列。

接下就是做行列分割了,其主要工作就是依據二維投影資訊,新增布局節點,進行分組。

最後就是樣式的計算,生成包括 Flex 佈局、絕對定位以及 Margin 偏移量的樣式資訊。

Schema 生成後,下一步便是 做 Schema2Code,也就是多端程式碼的生成。

值得注意的是,為了能夠支援生成多端程式碼,我們在 Schema 中標註的元件其實是虛擬元件,在轉換成程式碼時,會查詢維護的一份元件對映表,最後將其轉換成真實的元件。

程式碼生成後,便可以進行本地或線上開發。線上開發同時支援視覺化搭建和原始碼開發,並且二者之間可以相互轉換。

對於 iOS 和 Android 而言,因為技術上的限制,目前暫僅支援本地開發。

C2D2C 的技術細節就先聊到這裡,接下來,將會做一個簡單的總結與展望。

總結與展望

目前基於 C2D2C 的工作流已經打通,協同流程已經閉環,現已在雲音樂 4 大場景進行了落地,包括活動、商城、會員和音樂人。

平均能為設計師提效 25%,研發提效 33%,協同整體提效 38%。

當然,C2D2C 未來在雲音樂還有很長的路要走。

首先,C2D2C 的能力需要持續的完善,並建設相應的規範和標準,作為底層能力進行下沉,賦能兄弟團隊,幫助解鎖更多的平臺側玩法,比如為 H5/RN 搭建平臺 和 Native 動態下發平臺提供出碼服務。

此外,C2D2C 還需要接入除基礎元件之外的更多物料,協同各業務組一同建設物料生態,使整個物料生態越來越繁榮。

最後,在 C2D2C 核心能力、物料生態和平臺側玩法三駕馬車的共同作用之下,無損設計協同將形成一個增強迴路,共同放大 C2D2C 的價值。

最後,打個小廣告~

我們將會在 今年 Q1 開源 C2D2C 的基石,也就是雲音樂自研的海豚 RN 元件庫。

它是一個高質量的 RN 元件庫,基於 TS 和 Hooks 實現,具備強大的主題配置能力。

它包含 50 多個元件,經過了內部 100 多個專案的驗證,大家可以期待一下!

最後,感謝大家的時間,謝謝!

本文釋出自網易雲音樂技術團隊,文章未經授權禁止任何形式的轉載。我們常年招收各類技術崗位,如果你準備換工作,又恰好喜歡雲音樂,那就加入我們 grp.music-fe (at) corp.netease.com!

相關文章