As a small, bootstrapped company, we’re always looking for ways to simplify our internal workflows.
Code changes that add new features or fix bugs tend to get a lot of attention, with lead time being one of the four DORA metrics.
However, people often overlook workflows that cross department boundaries, like updating the public website for a SaaS product.
We want our website to have high-quality graphics that accurately depict our product.
In the past, we’ve made each one manually with Figma. However, this has become increasingly time-consuming and slowed down the cycle times for marketing tasks.
To address this constraint, we’ve adopted Design as Code (DaC) – making visual asset production self-service for the marketing team.
DaC drastically sped up the workflow for updating site graphics in exchange for up-front engineering work. This graphic – which I created in 60 seconds with our new DaC system – shows the effect:
This article offers tips for rolling out Design as Code on your team to speed up visual asset production.
What is Design as Code?
Previous discussions of Design as Code have focused on applying version control and review processes to design artifacts. While a good first step, this falls short of actually defining design artifacts with code, which is what we’re talking about here.
Design as Code also shouldn’t be confused with Design to Code, which involves converting design files into CSS, HTML, etc. This goes in the opposite direction and is more like “Code as Design.”
I actually tried one of these systems – anima – and it was a mess. The code seemed okay at first, until I put it in version control and made a tiny change to the design. The diff was enormous and completely impossible to merge with other changes. These systems only work if you use the code as-is, which isn’t really feasible for production web applications.
Instead, Design as Code means defining design elements with code and then programmatically generating the visual assets you use in your application or website.
What is the designer’s role with Design as Code?
Design as Code is actually a boon for designers because it lets them spend more time on design and less time on repetitive image creation.
To understand what the designer does with Design as Code, consider the following graphic, which we’re now generating with DaC on minware’s website:
There’s a lot of important work for the designer to do here, such as specifying the fonts, color scheme, icon system, element spacing, corner rounding, etc.
We still created an original version of this graphic in Figma to experiment with these parameters and produce the initial design concept.
However, with Design as Code, the designer no longer has to build and export different versions of this graphic every time we want to show different chart contents.
What is the engineer’s role with Design as Code?
The front-end engineer plays a much larger role with design-as-code than in a traditional design implementation.
In a traditional workflow, the engineer takes the design files from the designer and implements the component structure and styles for the page layout.
However, for complicated static graphics (like the chart above), the designer usually provides rendered images.
With Design as Code, the engineer implements code that will generate rendered graphics from a simple specification, which can be kept in a content management system (CMS).
We specify the chart above entirely in JSON, which is editable with live preview in a CMS. To make things real, here is the actual JSON for that chart:
Our Design-as-Code system then converts that JSON into an SVG image that can be used anywhere. The end result is similar to what a designer would export, but it’s fully automated.
Why not just use screenshots?
Instead of exporting files from a design tool, you could take screenshots of your application.
Some people do this, especially if they don’t have a full-time designer.
Before DaC, we did this at minware for many of our graphics.
The biggest issue with this approach is that it’s not actually as easy as you think.
You have to make sure the browser window is the exact right size to get screenshots of a particular dimension. If you want screenshots that are big enough that they look good when downsized to different resolutions on different pixel-density monitors, then you also have to use browser zoom, which further complicates things.
Getting components like charts into the right configuration within your application can be tricky too. It often requires a test environment where you can wire up specific sample data. Otherwise, you have to edit the content in a browser debugger to do things like replace real customer information with example text.
Then there’s the issue of updating images when your application changes. For every visual update, you have to regenerate all of your screenshots. (Or not, and have an out-of-date marketing site.)
Finally, compared with SVGs (which are vector-based), static images are a pain to work with. To keep them from being blurry, they need to be high-resolution, and then you need a complex system for downsizing them on the back end based on how large they will appear on the page. (If you don’t, they’ll be blurry, or load slowly.) Also, static images will always be larger and take longer to transfer over the network.
Why not just use application components?
Another thing you may be wondering is “If you’re showing this chart on our website, don’t you have an application component that displays the same thing?”.
We do, and this is a good question. Making application components flexible enough to use statically is a legitimate approach for implementing Design as Code. It can also save time by eliminating the need for a second DaC implementation for each component.
However, using real application components presents a few challenges.
The first is performance. The actual component we use to render charts in our application is complex because it handles all sorts of scenarios, like different data ranges, axis labels, and legend items. It also handles hovering over points, clicking to drill down, animation, etc.
Using the application component to render the figures on our home page would make our load time unacceptably slow.
Our Design-as-Code rendering function is much faster and smaller than our application component, but lacks features and guardrails in the application we don’t need for static examples, like handling text overflow or paging large lists of legend series.
For landing pages, you may also want to do things visually that you don’t do in the application, like scale, rotate, transform, or blur the graphics. You might also want to simplify the elements (e.g., our real charts have an extra line of detailed text that we cut from the DaC component), or expand and add a drop shadow to “pop out” a sub-component.
In the end, making your components do double-duty for the application and for static pages will lead them to not be really optimal for either one.
How can you implement Design as Code?
Your approach for adopting Design as Code will vary depending on your particular application and the types of graphics that you want to create.
For minware, we just needed to produce SVG graphics for charts in our application UI. You can easily output SVG instead of HTML elements using React. The key difference is that you become responsible for positioning everything (including measuring text) instead of being able to rely on CSS.
So, we just created components that progressively rendered the other components inside of them – eventually accumulating and outputting the nodes as an SVG.
SVGs seemed easiest because they were the most portable, but you could also use a canvas-based rendering system like react-canvas or react-konva.
However you implement rendering, the most important decision is how you structure the input. It should give internal users (e.g., people on the marketing team) flexibility while abstracting the details.
Obviously, your input could just be a list of exact line positions, but that wouldn’t really make things easier.
The JSON specification from earlier provides a good example of how to strike a good balance.
Takeaways
Hopefully you learned something and can save time with Design as Code in your organization.
However, the true message is larger than that: workflow optimization isn’t just for engineering; it’s for the whole organization (though help may be needed from engineering).
Engineering leaders who adopt lean process metrics like DORA to optimize software delivery should look beyond their team as well – there may be significant opportunities to help the whole organization move faster.