React Native - How to approach design collaboration with Figma
Tags: javascript, typescript, react, reactnative
Published: 2022-06-22 18:42:33

Welcome to my React Native series - and also my very first blog post!

This article is mostly focused on how to improve the designer-developer collaboration workflow through some simple, yet powerful tooling (that could apply just as well for other types of projects). 

It also focuses on how to setup your app and codebase in order to have as little friction as possible while your design is scaling.

As many design and engineering teams out there try to scale their design integration they inevitably face bottlenecks in their internal communication and their combined output.

Good design tools emerged not a very long time ago and a few started to make noise in the UI design and collaboration arena (like [Figma](www.figma.com), [Zeplin](https://zeplin.io/) and a few good others). 
To keep this short, we'll pick Figma and run with it. 


```
☝🏻 A few remarks before we start:

1. Our technical solution should accommodate most design systems and collaboration tools out there. 
2. Many of these tools already have good first-party exporting features or a curated set of plugins that achieve the same goal - exporting your design assets (namespaces, colours, artefacts, symbols, typography etc).
```


## Acknowledging challenges

1. If left unchecked or uncoordinated, the back-and-forth chatter between design and engineering can become a dreaded task (lost Slack threads, outdated e-mails, lost and unmaintained knowledge base pages or internal websites, etc.).
2. If you have a design system in place, you actually have many moving parts that need to sync back into your implementation - which is very often an overlooked process by managers, engineers and product owners.
3. It just becomes very tedious and error prone to coordinate the implementation or check for updates on potentially hundreds of individual elements.

## The high level solution

We will automate just about every aspect of integrating the design assets back into the codebase, essentially building a "translation machine" if you will, that reads designs assets and outputs specialised files from each design system part.

As you guessed it, we'll be writing our own custom CLI tooling to do a couple of things: fetch our design export, parse, validate and generate fixtures used throughout our codebase. 

So take this step to really think about how these pipelines should work and how much effort you want to invest in maintaining them.

If your designer does not use a tool like [Figma](www.figma.com) or [Zeplin](https://zeplin.io/) to manage their designs, you should really try to encourage the adoption - it will make both of your lives a lot easier.

These tools will enable us to follow with ease most of the granular and subtle changes done to the design system like:  typography metrics, colours, theming, glyphs.


Here are some quick points:

1. For the designer:

	1. Easier to organise and document the actual work
	2. Faster ways of obtaining approval from key stakeholders
	3. Easier to propose, organise, share and update assets.
	4. Exporting is a breeze. 

2. For the developer:
	1. Easier to inspect and comment on any design decision or change.
	2. Easier and on point discussions around the actual assets.
	3. Easy integration with the design system's assets and other fixtures.

## The ingredients

For our example we'll pick the Figma design tool plus the following:
	
1. A third party plugin for [Figma](www.figma.com) called [Design Tokenizer](https://www.figma.com/community/plugin/767048666042724266/Design-Tokenizer) which can help us export in one step all of our text styles, colours, effects information.

	The reason why I've chosen this plugin for Figma is because I (or the designer) can easily export everything in one go - it even has a cute "Serious Mode" toggle. Plus, the format of the output file is JSON - which makes it very easy to read for non technical folks.

	For things like shapes, I would recommend exporting the contents depending on your own needs - but this is a separate topic that I'll address in a future article. 

	After we generate the final design token export file, we can now have to start thinking about what we want to get from this file and how it can actually help us automate the entire process.
	
	To keep this article short, we will only try to cover the export of the colours and text styles. The importing part is completely up to you to figure out as you basically have complete control at this point.

2. CLI to automate everything:
In order to automate our extraction process example we will need to build a relatively small CLI tool that is able to work both locally or as a cloud function. It is important to keep the scope limited. Bellow are listed the  capabilities that we want to add to this tool:

	1. Find and retrieve the correct "Design Token export" file by date, version, etc. - very important. 
Saves you a lot of "Uh, oh, where is the correct file" moments."
	2. Parse and validate the file contents - It is very useful to check that the shape of the exported data is what you actually need before feeding it further.
	3. Dynamically create the final fixture files (typography, colours, etc.) that will be used in our app.
	4. Write a test to validate that input sample files and output fixtures match.


* For this example we will use Google Drive's API to setup the retrieval of our target files as most companies setup their own workspace on top of GSuite and it works really well for most. 

Bonus tip - What I recommend doing is making a shared company working folder specifically targeted for both product and engineering collaboration - this is what dictates your absolute paths when you setup your CLI app.

For instance, I will most often need to retrieve the latest version of a design file export or a specific one based on particular attribute like the creation date.


## Define the output that we want

As a best practice I'll recommend starting with designing the shape of the exported data that I want to use in my projects.

I'll think of something that is both scalable and easy to work with. 
In the case of typography and colour information, I recommend the JSON format for its readability and flexibility. 

On the plus side, you'll get the added bonus later to automatically convert these fixture to constants in one step, through [Rollup](https://rollupjs.org) setup - but that will be a story for another time.

What I usually like to do, is to populate these files with metadata that will help me get a better context for what has been generated and what is actually "latest" used by the app, hence the prefixed keys "__info", "__timestamp", "__timestampUnix". These will prove to be a valuable source for clarifications during debugging, especially if you choose to apply this metadata strategy to other types of fixtures.

1. "colours.json"

```jsonc
{
  // All your color namespaces from Figma will be here in a flat structure
  "White": "#ffffff",
  "Black": '#000000'
  "Grey1": "#f0f0f0",
  "Grey2": "#cccccc",
  "Grey3": "#878787",
  "DarkGrey1": "#363636",
  "__info": "This file was generated by a tool. Please use this tool again to regenerate it.",
  "__timestamp": "Friday, March 22, 2022 1:53 PM",
  "__timestampUnix": 1647949980000
}

```

2. "typography.json"

The following JSONC example illustrates a breakdown of the typography per platform. Depending on how you choose to manage the typography in your app, the output will obviously be different depending on your needs. 

I usually break it down like in the next example, because I tend to build a single core library for both web and native projects to consume.

This will scale development and builds individually from that point on, plus it gives me complete flexibility over a particular platform, as everything is contained.

If you want me to document how to build and configure such a library, please leave a comment and I'll be more than happy to explain the entire process of setting up everything on how to reason about it.

```jsonc
{
  "web": {
   // Same structure, but different configuration for the web platform.
  },
  "android": {
   // Same structure, but different configuration for the Android platform.
  },
  "ios": {
    "Heading": {
      "letterSpacing": 0.3,
      "lineHeight": 38,
      "fontSize": 32,
	  "fontFamily": "Lato-Thin",
    },
    "BodyRegular": {
	  "letterSpacing": 0.5,
      "lineHeight": 22,
      "fontSize": 16,
	  "fontFamily": "Lato-Regular",
    },
  }
  "__info": "This file was generated by a tool. Please use this tool again to regenerate it.",
  "__timestamp": "Friday, March 22, 2022 1:53 PM",
  "__timestampUnix": 1647949980000
}

```


This is completely optional, but adding support for Typescript for your fixtures is a very  powerful idea. 

Remember that the types and interfaces also need to keep up with the design system changes - not just your fixtures, meaning that our CLI tool needs to be able to also re-generate `types` and `interfaces` associated in case something major changes, you will thank yourself later.


## Setting up our CLI project

Now that we know what we want in our fixtures, it is time to see how we will setup our CLI project since this tool will do most of the heavy lifting. 

I've covered in the beginning that I would like to use this tool locally or on the server and as such I've chosen to write it for the Node environment. 
Some notable mentions that I used in this project are:

1. ["googleapis"](https://github.com/googleapis/google-api-nodejs-client) - For the Google Drive integration.

2. ["lodash"](https://github.com/lodash/lodash) - It is optional, but there will be a lot of chaining and tranforming going on, it will help me keep the routines code neatly packed and organised.

3. ["moment"](https://github.com/moment/moment) - There's a lot of logging for the console since this is a CLI tool. Think about it for when a certain task has started, ended, errored out etc. It generally helps me output human readable dates to console or reports. Also, since I usually like to create automated text reports with a stats for the designer and engineering team Slack channels.

4. ["spinnies"](https://github.com/jcarpanelli/spinnies) - Since we have quite a few work pipelines (importing files, exporting files), it is nice to show progress in realtime. This is very cute way to show customised progress in your output.

5. ["table"](https://github.com/gajus/table) - Produces a string that represents array data in a text table. It allows me to easily create automated stats for Slack channels with all the things that where covered by this tool. What got deleted, what was added, Who triggered the export tool etc, you can really go wild with what you want to output. This is important to keep the team in sync and minimise the error rates or miscommunications cross department. 

 As you can see from the file structure, we want to keep everything as basic as possible. Of course you're free to create your own conventions but I found this structure to work best, even when multiple export types are used:

```
      
├── README.md

├── output

│   ├── colours.json

│   ├── typography.json

│   └── types/**

├── package.json

└── src

 ├── const.ts // Export ever

 ├── figma.googledrive.ts // Google Drive integration for all Figma exports.

 ├── figma.utils.ts // Various utilities specific for processing Figma exports.
 
 ├── utils.ts // Global utilities for file, folders, output, etc.
 
 ├── index.ts // Main function
 
```

Now I won't go into actual code that glues everything together, but I will write the basic main function, and I'm sure you can work your way up from there (but do let me know if you want me to write a post about that in detail 😄)
	
```typescript
// index.ts

async function main() {

    await downloadAssetsFromGoogleDrive(/* temp path */)
	
    try {
        const file = await findFigmaDesignFileExport(/*path*/)

        await generateTypescriptInterfaces(file, /*output typescript path */)
		
        await generateTypographyFixture(file, /*output typography.json path */)
		
        await generateColoursFixture(file, /*output colours.json path */)
		
    } catch (error) {
        console.error('Something went wrong', error)
    }
	
	// Always remember to cleanup after your process finished
    await rmdir(/* temp path */)
}

```

As you have probably figured it out by now from the names of the functions, the process is pretty straightforward. 


## Wrap-up 

Congratulations on getting this far! 
From now, the following process should work without any hiccups:

You have your designer/product person upload their export file into a Google Drive folder (chosen for the rich API and commonality in this example), then our CLI tool will scan regularly that folder and will spit out testable, versioned and consistent fixtures for your application.

I can't really appreciate how many hours (but it is in the hundreds range) I've saved with this automated approach in all of my project. 

It is fast, reliable and most of all transparent.

I hope you enjoyed it, please comment and like and if you like the content, please let me know or let's discuss it on Twitter.

👋 Hey, if you want to buy me a coffee, here's the [Link] (https://www.buymeacoffee.com/alexandrughinea)