Note: Similar to last month, this installment of Designgineering Chronicles is not only WiH (i.e. Written in Haste), but more like WiMH, i.e. Written in Major Haste. Literally, I sat down at a coffee shop 4 hours ago and this is what happened! No editing! Okay, bye, and happy reading.
It’s really happening!!!
Wow! Lots has come together over the past month. In a big way. Design systems are now a thing at PMC! And all because I followed Brad Frost’s three simple steps for starting a design system at a big company:
- Make a thing (for PMC, the IndieWire pattern library)
- Show that it’s useful (I guess people liked it!)
- Make it official (read on!)
It’s been an exciting process! And I must say, there has been much less friction than I anticipated in getting to step 3. I’ve been meeting with the design team for a while now, and they have been on board, but working in a systems-oriented way is a big shift in mentality for how to handle engineering and the project management workflow. I expected to have to do more convincing and pitching, but nope! PMC gets it.
With that, I’m going to jump right in. No time for a recap of last month’s installment of the Chronicles.
Cantaloupe Redesign
One of PMC’s larger brands has had a redesign in the design and planning phase for quite some time. I’m not sure if it’s okay to reveal the brand, so for the purposes of this blog post, we will call it Cantaloupe.
Traditionally, PMC has brought on agencies to do large redesigns. Right when I started, PMC was finishing up the redesign of RollingStone.com with XWP, a leading WordPress VIP agency. Once the designs are mostly complete, technical requirements are assembled in an RFP (Request for Proposal) that is then sent out to a handful of agencies PMC has worked with in the past.
The technical requirements give the bidding agencies an relatively clear idea for the scope of the project. Traditionally, these were mostly back-end requirements β PMC has a wealth of back-end “core tech”, or a host of WordPress plugins for sharing back-end and structural code β and the front-end implementation was left up to the agency. Over time, this has resulted in very “snowflake-y” front-ends that are difficult to work with.
For the Cantaloupe redesign RFP, I was asked to contribute requirements for front-end. First of all, it was an exciting milestone to be included in this early conversation, and secondly, somewhat panic inducing. While I’d already completed a lot to include β CSS architecture and naming conventions and a core webpack configuration β there was a lot I still needed to figure out, most notably: sharing markup between the theme and pattern library, storing centralized SCSS and JS (and determining what should be centralized), and how the heck to set that up for success on a project I wouldn’t be directly involved with.
Then, something magical happened!
PMC decided to do the Cantaloupe redesign in house and I would be leading the front-end!!!! Now that’s a milestone!!!
Clarity Conf
The timing for all of this was so perfect. Right after I found out about the new plan for Cantaloupe, I was heading to Clarity Conf in New York City, a conference all about design systems. PMC paid for my conference ticket, travel, and the workshop “Design Systems at Scale” with Nathan Curtis!!!
While it might be a given that an employers to pay for a conference or two, this is new to me. I’d been self-employed for basically all of my career until PMC, and assembling an expense report for reimbursement was novel and, um, great. My employer is investing in me! This conference, in particular, really shows that PMC is on board with all of the new things I am introducing. And here’s the obligatory link to PMC’s job openings π.
Anyway…back to Clarity Conf. What can I say? I was in a room of 600 people that not only understood exactly what I do, they were doing basically the same things at similarly sized companies! I am at the beginning of my design systems journey, and it was so, so cool, inspiring, and validating to talk to other designers and developers that had been in my position a couple of years ago. Major props to Jina Anne for putting together such a fantastic conference and community.
I took away so much valuable information from both Nathan’s workshop and the conference, but I must say the biggest takeaway was…wait for it…clarity. Whomp.
But for real. After the conference and conversations at Clarity, the aspects of my work where I felt lost or unsure of myself, I now feel confidence and, well, clarity.
Design systems vs. pattern libraries vs. style guides? At last, I get it!
The Informal Pitch
Around mid-December β freshly returned from Clarity Conf (stay tuned for a blog post of notes!) β I met with the head of PMC’s product department, let’s call her J. My manager and another design system ally high up in the chain of command were also in the meeting for support which was really nice. The intention of the meeting was to help J better understand the work I’ve been doing and how it might fit into the workflow at PMC. While I was a bit nervous and bumbled over my words a bit, I got the point across, and J was like, “Sounds good, let’s do this”.
Of course, there is a lot more that a verbal go-ahead that makes a design system a real thing, but again, major milestone! Here is the outline I put together for my presentation β feel free to adapt this to your own informal pitch.
After presenting to the head of product, I did a “PEP Talk” which is our department’s bi-weekly knowledge sharing meeting where one person gives a presentation about their niche of work at PMC. That document above has a link to my slides for the talk. If you can’t access it for some reason, send me a message!
Back to Cantaloupe
This project will be the contents of the next three Designingeering Chronicles at least, so let me get some basic info out of the way.
Our Team
The internal Cantaloupe redesign project team includes me, leading front-end, a back-end / overall tech lead, a project manager, and a product manager. The back-end lead is AS, a very senior PHP engineer who is also the Director of Development and who has been with PMC a long time. I’ve mentioned before that PMC has excellent project and product managers…no exceptions here! SPS is our project manager and DR is on product.
I haven’t worked with any of these folks specifically before, and they are all very experienced. I’ve already learned a ton, and am honored to be included in this mix!
Project Goal
The primary project goal, of course is to get it done. A secondary goal, is to have Cantaloupe be the next generation of the work started in IndieWire. PMC is accustomed to accumulating back-end core tech as part of project build outs, and this is basically the same thing, but for front-end. In his talk at Clarity Conf, Dan Mall calls these pilot projects for design systems.
Pre-Development Planning
A huge advantage for this secondary goal is the month or so we’ve had to prepare before development officially started. Part of that was figuring out what kind of additional development resources we would need to complete the project, and as the front-end lead, that was up to me for front-end.
I am so happy with how this worked out. I narrowed down my needs to three things:
- Work with a consultant and/or senior FE engineer with lots of design systems experience at the onset of the project
- Mid-level FE engineer during the project, and some oversight from the consultant during development
- Post-project consultation to plan out next steps with folks from #1
At Nathan Curtis’ workshop at Clarity Conf, I spoke with some folks from the Gap about their design system, and they spoke very highly of working with Sparkbox, an agency in Ohio. I had met Rob Harr from Sparkbox back when I lived in Pittsburgh a few years ago, and I have learned a ton from their blog, the Foundry.
I got in touch with Sparkbox via their contact form, had a call with Rob, who then had a call with SPS and DR, and fast forward just three weeks…the project is under way with Sparkbox! It’s just so cool when something works out.
Preparing for the Consultation
As soon as I knew we would be working with an agency, I started preparing on-boarding documentation, and I must say, keeping up with the Designgineering Chronicles has proven useful! My primary goal with the documentation was to convey the thought, work so far, and overall direction that has already gone into PMC’s future design system. The documentation consisted of:
Docs: Background
This section included:
- Conclusions from the research I did when I first started
- An outline of problems a design system should solve
- Potential advantages β i.e. aspects of PMC that would make it easier to build the system.
- Potential challenges β i.e. aspects of PMC that might cause challenges down the line.
- Summaries of “Initiatives”, or the smaller projects and trials I’ve done since I started. If you’ve been reading this series, those might be familiar β including the Hollywood Life Tipline Widget, the IndieWire pattern library, of course, the video showcase on RobbReport, and the PMCSS standards documentation. I noted the success and reception of each of these initiatives.
Docs: Principles
These were more implementation focused and, actually, I’ll just paste them in here:
- The pattern’s schema is the single source of truth, linking back-end and front-end
- Anomalies are handled with configuration vs. overrides
- Clarity over brevity
- Developing new UI with the system is the default; it’s easier to develop with it than without it
- Writing new CSS or JavaScript is a last resort
- Embrace the strangler vine approach to refactoring
- Developer documentation is accessible from the code-base
- Accommodate one-offs and tight timelines with well-thought out processes
- Support development outside the system when in a pinch
- Representative local data and speedy page loads are critical for quality UI development
- UI development occurs separate from the WordPress environment
- Accessibility and performance is provided by the system wherever possible
- Embrace progressive enhancement principles to serve appropriate experiences to older browsers
Docs: Scope
This section included the users of the design system. In the current case, the only PMC employees using the actual system would be engineers since we are building out a software product first. In the future designers will use the system directly, but for now, engineering is translating the designs into a system.
The next part of the scope section of the docs, is the immediate scope:
- CSS framework / utility system
- “Front-end workshop” / pattern library or static environment for UI development
- A system for sharing Twig markup with the static environment and production WordPress theme (remember the Twig parser from last month? Yep, we’re doing it.)
- Build utilities (pmc-build-utils)
- Design tokens
- Publishable, functional components (i.e. those containing JS)
The future scope of the system will include a Sketch library, documentation site, and fully theme-able components. The far future scope includes things like email templates, UX patterns, and a CSS solution for doing A/B testing with Optimize (this could enable UI tests to be developed as needed, outside of the usual engineering workflow…which could be a bad idea or good idea).
Docs: Architecture
The final section of the docs reviews the architecture of the design-system-so-far. This includes our CSS architecture, JS architecture, and a summary of the approach to templating which has matured a great deal over the past few weeks (more on that in a moment!).
What I need(ed) help with
I’ve been largely directing this initiative based on online reading and my own intuition β from the consultant, I wanted either confirmation of the current direction, or recommendations for correcting the course of what’s been started so far.
The specific things I had questions about were (literally copied this from our Slack with Sparkbox!):
- Review architecture of theme patterns, markup integration, JS architecture, and emerging SCSS utility framework.
- Define processes: What is the development workflowβ¦
- for creating a pattern?
- for using a pattern?
- for assembling patterns into modules?
- for bailing on the system if the timeline requires it?
- Establish practices for testing and versioning
- Prioritize work to be done to best prepare for the rtCamp engineer beginning on Jan. 14:
- What are the most critical things to document?
- Customizing the KSS builder to show the JSON schema (or even convert that to PHP) instead of Twig markup
- What are the most valuable SCSS utilities to add to pmc-packages?
- Development tooling β how can we better use webpack and Node to require less specialized knowledge for using the system? e.g. automate imports and dependency management β this is probably a post-project conversation, but there might be some quick wins.
On-site with Sparkbox in Dayton!
I happened to still be in Pittsburgh as the project kicked off, and I went to Sparkbox’s beautiful office in Dayton, Ohio for two full days of design system strategizing.
Sweet, sweet validation
On our first day, we reviewed the information from the docs and the architectural work that has been done so far. I’m not sure why I’m so amazed that I haven’t been doing anything egregiously wrong, but I amazed. I also think this is testimony to Sparkbox’s approach and understanding of design systems β there is no one way to make a design system, and Sparkbox was very attuned to listening to both my and PMC’s specific needs and operational nuances.
Ticketing for the Win
At the end of our first day and into the second, we came up with and prioritized a set of JIRA tickets for the systems-oriented work to be done. Our approach would be to build high value CSS utilities, a CLI tool for scaffolding a pattern, investigate performance considerations, and investigate visual regression testing.
On each ticket, we included a traditional story statement e.g. “As a PMC engineer, I want to …”, followed by a statement of value that would help others on the Cantaloupe team to understand the context of each ticket e.g. “Building out X will benefit PMC with Y.” Each ticket finished with a “Definition of Done” and gave each a story points estimate. We met with the Cantaloupe team on the second day to review the tickets and answer any questions.
We didn’t get to any development until the end of the second day β I think I’d anticipated more development time, but I am so glad we used the time to plan and prepare. I am continually realizing and appreciating how important project management is β spending that 15 minutes crafting a well written ticket can save hours and hours later on. Again, props to Sparkbox for encouraging this!
Pair Programming
While I have pair programmed before, it has always been on an as-needed basis, not as a proactive strategy for development. Sparkbox does lots of pair programming! The engineer from Sparkbox and I have been pairing on the creation of Sass mixins for generating utility classes, and I can see how beneficial the practice is. After Cantaloupe, I hope to implement more of this at PMC. It make so much sense!
Development Notes
I want to finish up this post β which has been largely process and organizational commentary β with some development tidbits that are super fun to work on.
Test-Driven Sass Development with True
The architecture for the CSS utilities is as follows:
- Develop “utility class generator” mixins in
pmc-packages
, a repository that is installed in the theme as a node_module. - The generator mixin accepts an array of values, or tokens, from the theme, and outputs “on-demand” utility classes.
- The partial that calls the mixin is included in a webpack entry poin
Here’s an example of the color generator:
// pmc-packages/patterns/01-tools/mixins/generators/_color-class-generator.scss
@mixin _color-class-generator( $property, $colors, $color_list: () ) {
@if $property != 'color' and $property != 'background-color' {
@error "`#{$property}` is not a valid value for $property. It must be either 'background', 'color', or 'background-color'.";
}
@if type-of($colors) != 'list' {
@error "`#{$colors}` is not a valid value for $colors. It must be a list.";
}
@each $name in $colors {
$property_name: $property;
@if $property == 'background-color' {
$property_name: 'background'
}
@if map-get($color_list, $name) {
$color: map-get($color_list, $name);
.pmc-u-#{$property_name}-#{$name} {
#{$property}: $color;
}
} @else {
@error "`#{$color_list}` does not contain #{$name}.";
}
}
}
And it’s corresponding test, written with True:
// pmc-packages/patterns/01-tools/tools.spec.scss
@include test-module('Color Generators') {
@include test('@mixin _color-class-generator') {
@include assert {
@include output {
$semantic_list: (
brand-red: red,
);
@include _color-class-generator(
'background-color',
(
brand-red,
),
$semantic_list,
);
}
@include expect {
.pmc-u-background-brand-red {
background-color: red;
}
}
}
}
}
The generator is then wrapped in a namespaced mixin to indicate it outputs CSS:
// pmc-packages/patterns/07-utilities/_u-colors.scss
@import '../setup';
@mixin pmc-u-color( $colors, $color_list ) {
@include _color-class-generator( 'color', $colors, $color_list );
}
// pmc-packages/patterns/07-utilities/u-background.scss
@import '../setup';
@mixin pmc-u-background( $colors, $color_list ) {
@include _color-class-generator( 'background-color', $colors, $color_list );
}
And here is an example of how the generator is called in the WordPress theme’s SCSS files:
// theme-folder/assets/patterns/07-utilities/u-background.scss
@import '~@setup';
@import '~@pmc/utilities/u-background.scss';
// $semantic_color_list refers to the list of colors in /assets/src/patterns/00-settings/colors/colors.scss.
@include pmc-u-background(
(
brand-red,
),
$semantic_color_list,
);
Will it work? Well…the tests pass, so yes! An especially cool part in this color generator, is that a developer cannot add in random hex codes or names to the $color_list
parameter. They must be added in map of tokens in the settings/color section of the CSS architecture. A, from Sparkbox, refers to this as good friction, or friction that encourages proper use of the system. Love this stuff! My calling!
webpack Directory Aliasing
A big win for the above is making using of directory aliases in the projects webpack configuration via resolve.alias
in the webpack configuration object. That looks like this, and eliminates the need for a long path pointing to node_modules/pmc-packages
:
webpack: {
resolve: {
alias: {
'@pmc/mixins': path.resolve( __dirname, 'node_modules/pmc-packages/patterns/01-tools/mixins' ),
'@pmc/functions': path.resolve( __dirname, 'node_modules/pmc-packages/patterns/01-tools/functions' ),
'@components': path.resolve( __dirname, 'src/patterns/04-components' ),
'@objects': path.resolve( __dirname, 'src/patterns/05-objects' ),
'@modules': path.resolve( __dirname, 'src/patterns/06-modules' ),
}
}
// ... etc ...
Pattern Architecture
Per usual, this post is starting to get long but I want to include a few more development notes. First, let’s take a look at the new anatomy of a pattern in Cantaloupe (copying this from the onboarding docs). This is an example of a component which is our version of an “atom”. These files would reside in theme/assets/patterns/04-components/c-pattern/
index.js
β webpack entry. Import pattern styles and any JS.c-pattern.scss
β The base styles, modifiers, and KSS documentation for the pattern.c-pattern.json
β The schema for the pattern. The JSON entries map to the data expected in a PHP partial.c-pattern.twig
β Markup for the pattern built with restricted Twig. Everything in the JSON file should have a reference in this file. This file will be parsed, and a corresponding PHP template generated.
The next level up from a component is an object. If pattern includes another pattern, it’s an object. In o-tease.twig
(our word for a bit of test next to an image), for example, we see something like this:
<article class="o-tease {{ modifier_class }}">
{% if o_tease_url %}
<a href="{{ o_tease_url }}" class="u-display-contents">
{% endif %}
<div class="o-tease__primary {{ o_tease_primary_classes }}">
{% include "../../04-components/c-title/c-title.twig" with c_title %}
</div>
<div class="o-tease__secondary {{ o_tease_secondary_classes }}">
{% include "../../04-components/c-figure/c-figure.twig" with c_figure %}
</div>
{% if o_tease_url %}
</a>
{% endif %}
</article>
Yes, there are some ugly file paths in there β unfortunately, there appears to be a bug in KSS and Twig.js that breaks Twig directory aliasing. Or I am missing something which is entirely possible. In any event, the shiny, new π±β¨ Twig parser β¨π± takes this Twig and generates a corresponding PHP template that looks like this:
<?php
// This is a generated file. Refer to the file located at /stuff/wp-content/theme/assets/src/patterns/05-objects/o-tease/o-tease.twig for adjusting this markup.
?>
<article class="o-tease ">
<?php if ( $o_tease_url ) { ?>
<a href="" class="u-display-contents">
<?php } ?>
<div class="o-tease__primary ">
<?php \PMC::render_template( get_stylesheet_directory() . '/template-parts/components/c-title.php', $c_title, true ); ?>
</div>
<div class="o-tease__secondary ">
<?php \PMC::render_template( get_stylesheet_directory() . '/template-parts/components/c-figure.php', $c_figure, true ); ?>
</div>
<?php if ( $o_tease_url ) { ?>
</a>
<?php } ?>
</article>
Wowza! Yes, this works! Then, in a template β e.g. index.php or what have you β the PHP partial can be called like this:
<?php
$o_tease_demo_data = [
"c_title" => [
"c_title_text" => "This is a PHP version of the object in o-tease.json"
],
"o_tease_url" => "#",
"o_tease_primary_classes" => "",
"o_tease_secondary_classes" => "",
"c_figure" => [
"c_figure_crop_class" => "pmc-u-crop-2x3",
"c_figure_alt_text" => "Thumbnail image",
"c_figure_image_url" => "https://picsum.photos/100/100",
"c_figure_caption_text" => "Here in o-tease"
]
];
\PMC::render_template( get_stylesheet_directory() . '/template-parts/objects/o-tease.php', $o_tease_demo_data, true );
?>
That PHP object is exactly the same as the JSON object in o-tease.json, thus adhering to our principle of “the pattern’s schema is the single source of truth”. I even made a little array-converter.php that takes in the JSON object and spits out the PHP object!! Look at me, a real programmer! And utilities can be added to the entries indicating classes
in the above object to customize the appearance of o-tease
in different contexts.
… is that all?
I told you a lot has come together this month! Gosh, design systems are just so fun and exciting and I’m having the grandest time. I mean, it’s Saturday goddammit and I’ve been writing this blog post for almost four hours. Meh. I hope someone actually reads this and it is helpful! Either way, my instinct is that these Chronicles will be valuable someday β they’ve already proven their worth when I put together the on-boarding docs for Sparkbox.
What’s Coming Up
Although I am exhausted and hungry and want to be done writing this post, I will conclude with the customary “What’s coming up”:
- Well…building out Cantaloupe and using the baby system!
- Pairing with A on a CLI tool to scaffold a pattern
- Teaching the mid-level engineer how to use the system
- Fixing a bug with
foreach
in the Twig parser that might make me question the parser in the first place β hopefully there is a reasonable solution - Fine tuning the workflow for splitting up back-end and front-end in tickets β I didn’t write about this yet, but will do as we test out how it will work. Major, major props to SPS and DR, the project/product mangers on Cantaloupe for not only understanding what we are doing, but being very game for experimenting!
- Ah, I definitely need to write about
.pmc-grid
, our progressively enhanced CSS Grid utility/algorithm! I just love CSS, in case you didn’t know.
Also, I will try, try, try to write a Chronicle at 0.5 months this time to hopefully catch up on what isn’t in here and to get the month increments back to whole integers.
Okay, now in the very immediate future, I think I will see if my friend Jessie wants to get an afternoon beer! Major congratulations to myself for sitting down and writing this friggin thing.