<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Alan B Smith on Medium]]></title>
        <description><![CDATA[Stories by Alan B Smith on Medium]]></description>
        <link>https://medium.com/@alanbsmith?source=rss-d9498cd91fed------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*jOFepAF5N0lN5SQ5U2hFSQ.png</url>
            <title>Stories by Alan B Smith on Medium</title>
            <link>https://medium.com/@alanbsmith?source=rss-d9498cd91fed------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:11:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@alanbsmith/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[On Design System Support]]></title>
            <link>https://alanbsmith.medium.com/on-design-system-support-8dc8041f4679?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/8dc8041f4679</guid>
            <category><![CDATA[ux-design]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[design-systems]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Fri, 26 Aug 2022 05:22:56 GMT</pubDate>
            <atom:updated>2022-08-26T05:42:12.405Z</atom:updated>
            <content:encoded><![CDATA[<h4>Having a Support Mindset</h4><h3>Overview</h3><p>We spend a lot of time supporting teams, and I think it’s one of our design system’s biggest strengths. Specific processes often are tied up in institutional contexts that don’t translate well, but I‘d like to share a bit about having a support mindset as a Design System Engineer. Having great support is one of the key reasons our design system engineering team has been so successful at Workday. We listen to developers, we understand their concerns, and when they need help, we take care of them. I thought of four key aspects that drive how we think about support.</p><blockquote><strong>Side note</strong>: If you were hoping for information about processes, you won’t find much here. But I don’t want you to leave empty handed. If you haven’t read <a href="https://medium.com/u/799c7c7840a">Nathan Curtis</a>’ post on <a href="https://medium.com/eightshapes-llc/design-systems-support-6722b6d9a259">Design System Support</a>, I’d highly recommend it.</blockquote><h3>We Start with Empathy</h3><p>Imagine you’re a developer.</p><blockquote>You’re using our components, code you didn’t write, to build a new feature. Maybe you’re familiar with our library, maybe not. You’ve tried to make it work on your own, but something still isn’t coming together. Maybe you’ve read the docs, looked at our source code, but you’re still stuck. You had dreams of being productive during your heads-down time today, but this is a blocker. You finally reach out to the design system support channel, and hope someone can help you sort through it.</blockquote><p>Starting with empathy means we start by thinking about how a developer got to the point of asking a question. We understand that feeling. And now we have an opportunity to turn a confusing, frustrating situation into something good where they feel supported, productive, and maybe learn something new along the way.</p><h3>We Celebrate Questions</h3><p>Our support channel is our primary catch-all for teams. It provides a safety net when our design system docs, code, or specs fail our consumers. Maybe we omitted some key material, or made a bad assumption, or created a counter-intuitive component API. Our support channel provides a bit of coverage for those problems, <em>but it only works if people reach out</em>. If they don’t ask, they’ll resort to either hacking something together, or building something from scratch. Either creates more work for everyone down the road. We want to encourage people to reach out and ask questions. And when they do, we want to make sure they know we appreciate them asking.</p><ul><li>You found a bug? <strong><em>Thanks for raising that!</em></strong></li><li>You don’t understand the docs? <strong><em>Appreciate the feedback!</em></strong></li><li>You don’t know how to build with our components? <strong><em>Let’s work it out!</em></strong></li><li>You created a sandbox and filed an issue? <strong><em>You absolute legend!</em></strong></li></ul><p>Giving people a small nudge encourages more of the behavior we want and helps us build a more sustainable system. They made the right choice reaching out to support; let’s be their biggest fan.</p><h3>We Build Community</h3><p>Support is about more than answering questions — we’re building a community around our design system. Part of being connected to the system means teams have access to our docs, design specs, and code that they would otherwise have to create and maintain themselves — that’s huge on its own. But it also means that when they have a problem using our system, we have their back. They’re a part of the tribe along with all our other consumers, and we have a collective responsibility to make sure everyone succeeds. One of my favorite things to see is when teams help each other work through problems together. Support resolves individual issues, but it also continuously reaffirms this pact we have with our consumers.</p><h3>We Work on Two Levels</h3><p>As systems thinkers, we handle support on two levels: addressing the immediate concern, and adjusting the larger system forces that caused the issue. How we go about both is important. An example might be helpful to illustrate:</p><blockquote>Over the past two months, several developers from different teams have raised questions about how to customize icon colors</blockquote><p>The immediate concerns are:</p><ul><li>Understanding their use case</li><li>Verifying the solution makes sense</li><li>Showing them how to customize icon colors</li></ul><p>The larger system concerns could be:</p><ul><li>Assessing how well our docs explain how to customize icon color</li><li>Updating our component to make icon color modifications more intuitive</li><li>Understanding why product designers are opting for custom icon colors</li></ul><p>These two processes often begin concurrently, but they are handled very differently. Consumers will likely only care about the immediate concern, and it’s our job to resolve that efficiently. But we also have to think about the larger system concerns if we want to create a more sustainable system.</p><h4>Addressing the Immediate Concern</h4><p>This is always our immediate focus. Someone is blocked, or feels blocked, and we need to figure the best path for them to move forward. Whatever questions or objections we have about the larger system forces that created this situation are irrelevant to the person currently stuck. That said, once you understand the issue, it’s always good to pause and ask whether this <em>should</em> be done instead of rushing into solutions for how it <em>could</em> be done. Developers are often the last to know about what’s coming down the pipe, and sometimes they get stuck having to implement unfortunate product and design choices. Sometimes to be supportive, you need to hold your nose and help a developer through that less-than-ideal situation. But there are a few hard stops:</p><ul><li>This would create an inaccessible or non-inclusive experience</li><li>This would create something completely divergent from our design system</li><li>This would create serious technical limitations for other consumers</li></ul><p>Outside of those situations, our job is to find a way to resolve the immediate issue efficiently, in a way that aligns with our standards, and creates the least amount of technical debt for that team. Once you’ve resolved the immediate concern, you can raise larger concerns that created the issue with that team.</p><h4>Addressing Larger System Concerns</h4><p>Almost every issue has at least one larger system concern behind it. While you need to somewhat ignore it to help someone move forward, you can definitely use back channels to highlight the issue as an anecdote for a larger, internal conversation. Addressing bad system behavior with a system-level solution is more effective, but it also typically takes much longer to resolve. Think of this as a non-blocking, asynchronous process. We can start the internal conversation now, but we don’t want it prevent a team from having resolution, if possible. We have the ability to shift the system, they have to work within it and deal with it as it exists today.</p><h3>Conclusion</h3><p>Your design system will likely never be in quite the shape you or your consumers wish it was. Great support systems can be a safety net to cover those gaps and help teams feel supported. My experience has been that processes always evolve with your system, but having a support mindset is a constant.</p><h3>Thanks for Reading!</h3><p>I wrote this to help solidify my thoughts, but I hope it was helpful for you as well. If you enjoyed this, you might also enjoy <a href="https://twitter.com/_alanbsmith">following me on Twitter.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8dc8041f4679" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rethinking Component Libraries]]></title>
            <link>https://alanbsmith.medium.com/rethinking-component-libraries-45bc100c3216?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/45bc100c3216</guid>
            <category><![CDATA[design-systems]]></category>
            <category><![CDATA[component-libraries]]></category>
            <category><![CDATA[systems-thinking]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Mon, 17 Jan 2022 18:33:19 GMT</pubDate>
            <atom:updated>2022-01-18T17:17:13.069Z</atom:updated>
            <content:encoded><![CDATA[<h4>Part Two | Understanding Costs</h4><h4>Intro</h4><p>This is the second of three articles discussing how to think about component libraries. In <a href="https://alanbsmith.medium.com/rethinking-component-libraries-1573d5cf98eb">Part One</a>, we talked about redefining the value of shared component libraries. Now we’ll talk about understanding costs — another often misunderstood aspect of component libraries. This is not meant to be an exhaustive list, but rather common forces that shape shared libraries. Specifically we’ll discuss:</p><ul><li>Library size</li><li>Component complexity</li><li>Adoption rates</li><li>Organization volatility</li></ul><p>Understanding how these costs behave allows me to look beyond the code and discern what makes a shared component library effective as well as common points of failure. I hope reading this will be helpful for you as well.</p><h4><strong>Understanding Costs</strong></h4><p>I’d like to start by saying that building an in-house component library is not cheap. It is very expensive and taxing to do well, and it is even more costly when executed poorly. <em>It is not the budget option</em>. If you need a lower-cost solution, you’re much better off choosing one of the many great external libraries available. Should you instead choose to build a custom shared component library, do it because your organization sees the potential value as worth the significant investment needed to make it work. We’ll return to this concept again, so it’s worth saying here:</p><p>The purpose of understanding costs is not to find cheap solutions. Instead we’re optimizing for a point where we are able to maximize the library’s value while also keep costs sustainable.</p><h4>Library Size</h4><p>Size is often the largest cost contributor for a component library. Many maintainers find themselves in a position where they’ve added too many components, and the cost of maintaining the library becomes unsustainable. We’ll talk more about how to avoid that fate when we discuss optimizations in Part Three. There are a few things to note before we dive into the details of this relationship:</p><ul><li>Each component in your library has its own intrinsic cost</li><li>A component’s cost is not necessarily fixed and can often be adjusted</li><li>The library’s total cost is more than the sum of the components’ cost and is relative to your team’s capacity to absorb it</li></ul><p>The early growth stage is most common time for teams to balloon their library size. There is typically a high degree of volatility: API patterns are developing, the governance model is in its infancy, and there’s strong pressure to keep up with consumer requests. All of these factors can cause maintainers to overshoot the library’s critical mass and run too hot for too long. This inevitably results in large breaking changes and a lot of volatility for consumers. But the volatility’s impact is diminished in this stage because of lower adoption rates, which we’ll discuss later. If maintainers are able to find their feet in time, the end of the early growth stage is the best time to make and learn from those mistakes.</p><p>There is no perfect size for a component library. But you’ll find that as you add more components, each new component will have a diminishing return on value over cost, especially as the components become more complex. Again, the goal is to optimize for value while managing costs.</p><h4>Component Complexity</h4><p>Component complexity is another large cost driver for libraries. Complexity isn’t necessarily bad, but it does need to be properly managed. Some components are solving complex problems: Focus management, list systems, and stacking order immediately come to mind. And components need to absorb that complexity to provide a high-level of value to consumers. You can usually reduce a component’s complexity, but only up to a certain point before you start to significantly deteriorate value. And it’s important to recognize that effective systems will still require a significant cost to manage those complex problems.</p><p>The cost of complexity can also grow as components are modified to support new use cases. The cost of new functionality is frequently distorted by only accounting for the effort to add it the library. But as a component’s complexity increases, it becomes more resistant to change. And this resistance compounds the cost of maintenance over time. So while the cost to add new features was relatively cheap, the total cost to the library can be quite large.</p><h4>Adoption Rates</h4><p>As your library becomes more established and grows in value, your adoption rates should go up. We can think of adoption as a combination of the total number of consumers and their saturation of usage. That rate is a common metric for shared libraries, and it’s really exciting to see it go up. But it also comes with associated costs. As consumers use your library more heavily, they’ll be increasingly coupled to your team. And each new team will have new requirements, evolve differently, and inevitably file more issues. This cost is deceptive because its growth is not linear. The mechanisms that worked well at one level will be entirely ineffective at the next. You’ll constantly need to recalibrate and retool to keep pace.</p><p>The other challenge with this cost is that it can drive the previous two costs: library size and component complexity. There will always be a gap between what consumers want in the shared library and what you’re able to sustainably support. This creates a constant pressure to add more complexity to existing components or add new components as adoption grows. Sometimes the cost is justified, but you’ll always need to weigh it against the value being added.</p><h4>Organizational Volatility</h4><p>We can think of organizational volatility as a company’s or organization’s rate of change over time and how that change impacts teams. A very high rate of volatility is usually described as “thrash” and leaves a lot of confusion and frustration in its wake. But any growing organization will experience some level of volatility. The company can shift priorities, reorganize teams and ownership, or decide to merge or be acquired with little notice. All these changes can generate costs for teams and your library. Managing the cost of volatility is always challenging because there is little that can be done to control it directly.</p><p>But while it is an uncertain and unwieldy cost, it is also a huge opportunity for creating value. As stated previously, helping teams become more resilient and adaptive to change is the key value of a shared code library. But it goes beyond the code, which is something we’ll talk more about in the next article.</p><h4><strong>Thanks for Reading!</strong></h4><p>Understanding how costs behave for shared component libraries has been incredibly valuable for me, and I hope this was useful for you as well. Part Three will focus on how to manage these costs and optimize for adaptability to deliver a high-value library. I’m writing these posts as I have time and headspace, so I’m not sure when I’ll finish the last post. But if you have questions or just want to say thank you, <a href="https://twitter.com/_alanbsmith">you can find me on Twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=45bc100c3216" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rethinking Component Libraries]]></title>
            <link>https://alanbsmith.medium.com/rethinking-component-libraries-1573d5cf98eb?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/1573d5cf98eb</guid>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Tue, 11 May 2021 14:39:59 GMT</pubDate>
            <atom:updated>2022-01-30T09:46:54.153Z</atom:updated>
            <content:encoded><![CDATA[<h4>Part One | Redefining Value</h4><h4>Intro</h4><p>This is the first of three articles discussing aspects of shared component libraries, whether in a design system context or otherwise. Specifically, we’ll look at how we define value, understanding cost, and how to build for the future. This article will focus on how we think about the value of a shared component library. I find the value of shared components is often misunderstood and misrepresented, and it deserves a bit of redefinition before we can talk about the other aspects.</p><h4>Redefining Value</h4><p>When folks describe the value of a shared component library, they often talk about a few common attributes: UI consistency, development speed, efficient prototyping, etc. Those are certainly valid outputs of a well-built component library, but they are also a bit short-sighted. Why? Because while reducing the cost of initial implementation is an important aspect of development, it only represents a fraction of the lifecycle of any successful product UI. If we were building static interfaces or the lifespan of a product was relatively short, initial speed and consistency would be the absolute measure of a component library’s value. But active product UIs are dynamic environments that change continuously as teams respond to user feedback, test out new features, and deprecate old ones.</p><p>Because of this dynamic environment, I prefer to focus on a different metric to assess the effectiveness of a component library: resilience, or “How well does the library allow teams to adapt to change over time?” Resilience is a common metric for evaluating the success of a system. The human body is a successful system because of how well it adapts to different environments over time. Conversely, transportation systems are often (rightly) criticized for their inability to adapt to population growth and rate of deterioration.</p><p>All that to say: The initial gains from time and effort saved during implementation are quickly lost if the library becomes a stumbling block for building the next iteration. While product teams need to focus on their current iteration, a shared library team’s job is to help them build the next.</p><p>This is where most component libraries fall short. It’s a tremendously challenging problem. How can we build components for UI that doesn’t yet exist? How can we support the future of multiple products, all of which have their own needs and trajectories? How can we design our library in a way that reduces the cost of change over time?</p><p>It would be useful to know the future state for any given product with enough lead time to stay ahead, but that is often a (laughable) impossibility. Instead it’s helpful to think about <em>how product UIs change over time. </em>While client-side applications are in a constant state of change, they do not change at the same rate. The application-level business logic (authentication, authorization, data fetching, et al) usually remains fairly intact over time. The UI logic layer (checkout flow steps, modal logic, etc) will change more frequently as features evolve or are deprecated. But the most frequent changes happen at the markup structure and styling level.</p><p>Optimizing for adaptability means we need to think differently about how we build components. We will talk more about particular ways to optimize components to be adaptable in the third article. But first we need to understand the costs, which will be the focus of <a href="https://alanbsmith.medium.com/rethinking-component-libraries-45bc100c3216">Part Two</a>.</p><h4>Thanks for Reading!</h4><p>Redefining the value of a shared component library in this way has been a useful heuristic for how I think about what to prioritize and where to grow. I hope this was helpful for you as well. This series is not yet complete, and I’m writing these posts as I have time and headspace, so I’m not sure when I’ll finish the last post. But if you have questions or just want to say thank you, <a href="https://twitter.com/_alanbsmith">you can find me on Twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1573d5cf98eb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enforce, Enable, & Empower]]></title>
            <link>https://alanbsmith.medium.com/enforce-enable-empower-191a4741803b?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/191a4741803b</guid>
            <category><![CDATA[design-systems]]></category>
            <category><![CDATA[design-process]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[systems-thinking]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Fri, 05 Mar 2021 07:43:12 GMT</pubDate>
            <atom:updated>2021-03-05T18:18:06.823Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="highway roads illuminated at night by cars and street lights" src="https://cdn-images-1.medium.com/max/1024/0*8H6PKROxp5v0Y4MQ" /><figcaption>Photo by <a href="https://unsplash.com/@amarnathtade?utm_source=medium&amp;utm_medium=referral">Amarnath Tade</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p><em>Understanding the spectrum of control in design systems</em></p><h3>Introduction</h3><p>When describing a design system, I usually default to <a href="https://www.chelseagreen.com/product/thinking-in-systems/">Donnella Meadows’s definition of a system</a> (which I’m paraphrasing) as interconnected elements that have a shared function or purpose. That’s an oversimplification, but it’s a good starting point. When talking about a design system, we often focus on the elements; the components, specs, docs, tooling, maintainers, consumers, et al. But I’d like to talk a bit about trust and control as a dyadic interconnection that binds these elements together. Systems are dynamic and complex structures that often behave in ways we don’t expect, and design systems are no exception. As design system maintainers, we work to create a cohesive experience across products and platforms, and we constantly wrestle with how to best support teams. How we think about trust and control affects our interactions with those teams. This interconnection usually expresses itself in three ways: enforcement, enablement, and empowerment. I’ll talk about these three, but it’s important to note that you likely have aspects of each.</p><h3>Enforcement</h3><p>Enforcement keeps control with maintainers. And while enforcement typically has a negative connotation, it can be positive and highly effective when used well. Barriers between traffic lanes and railings along steep winding roads prevent tragic accidents and are appropriate uses of enforcement mechanisms.</p><p>But we usually hear about enforcement in design systems when control is too aggressively applied. Product teams complain (often rightly) that the design system is too rigid and doesn’t account for their product’s needs. The system maintainers are labeled “design police” and accused of stifling creativity. Conversely, maintainers feel the system is far too dynamic and needs to be reined in. As they feel control slipping away, the instinctive reaction is to tighten their grasp. Unchecked, this creates a reinforcing feedback loop where products continue to work outside of the system because “it doesn’t work for them”, and maintainers try to lock it down to maintain control. This heavy-handed approach to enforcement erodes trust, isolates teams, and detracts from the design system’s overall purpose: supporting teams to create a cohesive experience across all products and platforms.</p><p>The main problem with this approach is that the locus of control is being held entirely by the design system maintainers. It also creates two additional problems: enforcement is an incredibly expensive approach and it is decreasingly effective. You need a massive amount of time and energy to enforce a design system. And as you lean into enforcement, knowingly or otherwise, your efforts have a diminishing return as teams abandon your system.</p><p>If you find your team stuck in this enforcement feedback loop, the best way out is to take steps to deescalate. Remember that enforcement is a method that is best used sparingly. What are the steep cliffs that need guardrails, and what can be better managed with some helpful signs along the road?</p><h3>Enablement</h3><p>Enablement shifts control toward consumers. This approach works really well when you want consumers to have a level of choice but not be burdened with the details. To keep with the automotive analogy, civil engineers design and build roads and bridges to enable transportation for the public. There is a level of customization: some roads are built to handle large amounts of traffic and others are created to take advantage of scenic landscapes. But individual drivers don’t choose the specific pathways or materials. This arrangement also ensures they get the freedom of not having to build or maintain the roads themselves.</p><p>Enabling teams to move quickly without much initial effort is one of the most frequently stated benefits of a design system. And enablement is often driven by really positive mechanisms. Maintainers have established a good relationship with the teams they support, they have open channels of communication, and they’re highly responsive to resolving issues. New design systems start with a small footprint and must rapidly expand their surface area to be a viable service. In this scenario, enablement is a quick strategy to determine where consumers’ immediate needs are without too much concern for bloat. But as a design system matures, it reaches the limits of that approach.</p><p>This is a critical pivot point for a design system, and also where maintainers make significant mistakes. When a team raises an issue, maintainers respond quickly to resolve it. But because they’re now approaching a critical mass, that reflexive action has a larger impact to the system. As this behavior is repeated, maintainers overextend the system to an unsustainable level. The insidious aspect of this enablement trap is that the short term stats look amazing. “This sprint we resolved 30 issues, released 10 variants, and added 16 new icons.” It’s only after the fact that the cost of those choices are discovered: As the system balloons in complexity, maintainers have significantly less capacity to support teams. It can also have the inverse effect for maintainers. As they feel growth of complexity, they become too deliberative and support requests are forwarded to an endless backlog.</p><p>That said, enablement is still an effective strategy. But as a system matures, it should be used more judiciously. There will always be bugs to patch, new components to assess, documentation to clarify, and assets to add. Some of those tasks will inevitably be blockers for teams and need to be resolved quickly without much discussion. But having processes in place that allow maintainers more space to deliberate the issue, possible solutions, and the overall impact is critical to building a resilient system.</p><p>If you find yourself in an enablement trap, examine your intake processes and your system structure. A healthy level of enablement allows maintainers to provide a quick, synchronous responses<strong>*</strong> while also allowing for a more deliberative, asynchronous discussion about solutions to happen in the background.</p><blockquote><strong>Note:</strong> “Responses” are typically different than “solutions.” Responding is about triaging a situation quickly with little-to-no change to the existing system. And that is often enough to get a team unblocked. If the response is suboptimal for consumers or the system overall, that’s when a more deliberative, asynchronous discussion around systematic solutions are appropriate.</blockquote><h3>Empowerment</h3><p>Empowerment shifts control further toward consumers, and it can only be sustained in a high-trust relationship. These are the road signs: “Steep grade ahead, use low gear” and “Chains required when lights flashing.” While there may be separate enforcement mechanisms to discourage bad actors, the signs themselves leave full control with drivers. And drivers have to trust that signs are communicating accurate and actionable information.</p><p>Empowerment is the hardest trust dynamic to build and sustain for design systems. That is partly because of the nature of trust; it is hard won, easily lost, and requires continuous attention to maintain. But while it is elusive, it is also the most potent. Empowered teams are able to harness the system to evolve their products in a way that is harmonious with other products and meets their specific needs. The design system propels them forward, and they reciprocate by revitalizing and evolving the larger ecosystem.</p><p>Balancing support and autonomy is a challenging task, and it’s important to note that an empowering dynamic for one team could feel like abandonment for others. A high-degree of freedom comes with a lot of responsibility, and some consumers may feel that tradeoff is too burdensome. A team’s size, culture, and maturity can all affect how they feel empowered. It’s very helpful for maintainers to understand and empathize with where specific teams fall along that spectrum. It also means that as the system supports more teams, they’ll need to develop layers of support that provide more flexibility for high-trust, autonomous teams and more structure for dependent teams. A good example of this is how some engineering teams we support want to find examples they can grab from documentation and slightly modify for their use case, while other teams want low-level parts to build more custom interfaces for their users. Each approach is empowering for teams, so we support them both.</p><p>Empowerment can descend into chaos quickly if it lacks the proper governance. Similar to the road signs, there is nothing stopping teams from ignoring guidelines. This is not a dynamic I would recommend for design system teams that are still settling their governance model. Experienced maintainers may be able to stay ahead of the curve, but inexperienced consumers will often make unfortunate choices. Focus on establishing good processes and trust first and then work up to empowerment as needed.</p><h3>Conclusion</h3><p>Enforcement, enablement, and empowerment exist along a spectrum of control. Understanding that spectrum and how those mechanisms affect behavior allows us to more effectively support teams as design systems maintainers. There is no singular best approach, and each has its own place. You need guard rails, roadways, and street signs to have a resilient system. How you decide to balance those mechanisms will depend on maintainers, the design system, and the teams they support. And because systems are dynamic, this evaluation will be a recurring, evolving process.</p><h3>Thanks for reading!</h3><p>I wrote this mostly to help solidify my thoughts, but I hope it was helpful for you as well. If you enjoyed this, you might also enjoy <a href="https://twitter.com/_alanbsmith">following me on Twitter.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=191a4741803b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Component Hierarchy]]></title>
            <link>https://alanbsmith.medium.com/understanding-component-hierarchy-d5ce153acab3?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/d5ce153acab3</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[design-systems]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Fri, 04 Sep 2020 20:31:51 GMT</pubDate>
            <atom:updated>2020-09-04T20:31:51.400Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Njvdjhfg9BTjmiDf76F2Gg.png" /><figcaption>An example component hierarchy</figcaption></figure><h3>Overview</h3><h4>Structure</h4><pre>├ Primitives<br>├ Elements<br>├ Compositions</pre><h4>Understanding the Hierarchy</h4><p>The main purpose of the hierarchy is to provide a focused scope of responsibility for individual components and meaningful relationships between them. This allows components to be composed in ways that provide a healthy balance of structure and flexibility. Without structure the components become misaligned and inconsistent. But without flexibility, the components become brittle and tightly constrained in their use. For a healthy component library, you need both.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*gdXB3vA1SSulbf-wsu1pHA.png" /><figcaption><em>A spectrum of high flexibility and low structure to low flexibility and high structure. Primitives, Elements, and Compositions roughly taking up a third of the scale.</em></figcaption></figure><p>If we think of flexibility and structure as a spectrum, different types of components will live along that scale. Primitives at the bottom of the hierarchy are the most flexible. And as you move up in the hierarchy to Elements and Compositions, components become less flexible and more structured. This allows more specific, opinionated components within your library to be consistent, while also providing space for lower-level components to maintain their flexibility.</p><p>But these components do not exist in isolation. The hierarchy also establishes meaningful relationships between them. Elements are used to build Elements, which are composed to create Compositions. For example, this LeftNav is a Composition of a Box Primitive and Nav, List, ListItem, Link Elements.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df2cec0f3467602ad5604d1c66dd3cf4/href">https://medium.com/media/df2cec0f3467602ad5604d1c66dd3cf4/href</a></iframe><blockquote><strong>Note:</strong> This Composition would likely take a prop like items and map over them to create each ListItem, but to keep the example straight-forward, I’ve omitted that.</blockquote><p>These relationships allow LeftNav to be an opinionated instance of its structure. However, if we needed to create another instance that allowed Icons to be paired with the Links, we could compose the Primitives and Elements instead of modifying this instance to support it. We’re providing flexibility and structure through composability.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/39ddf73a654599618798c4e2fe08e3f5/href">https://medium.com/media/39ddf73a654599618798c4e2fe08e3f5/href</a></iframe><h3>Primitives</h3><p>Primitives are our lowest-level component abstraction. They are only constrained by their purpose and our tokens and theme values. Because they are so flexible and can be formed into many different Elements, there are relatively few of them. They are solely responsible for visual concerns. They don’t think about different states or behaviors.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/704a9ab8c828db63fc6b45ed3c82c0da/href">https://medium.com/media/704a9ab8c828db63fc6b45ed3c82c0da/href</a></iframe><p>In the internal library you’ll want to use Primitives often to create other Elements and Compositions, but external consumers likely won’t use them directly as often as other components. To understand why, let’s look at an example, Stack. Stack is an opinionated layout Composition. It exists to help create vertical rhythm (spacing) between elements.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e1be06badaf7a544b1de3da71ee93acb/href">https://medium.com/media/e1be06badaf7a544b1de3da71ee93acb/href</a></iframe><p>By using Stack, its child element Stack.Item, and the space prop, we can quickly create even spacing between each element. But if that doesn’t work for our use case, we could use the lower-level Element, Flex, that it’s built upon. Flex is a layout component that knows about our spacing scale and how to use CSS <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox">Flexbox</a> for aligning items. Let’s say instead of even spacing between all elements, we need a little more space around the middle child.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cab7d4b548857179e3b613a20566fc2e/href">https://medium.com/media/cab7d4b548857179e3b613a20566fc2e/href</a></iframe><p>Great! Not too much more work. And if for some reason we needed even more control, we could use our lowest-level Primitive, Box.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c8d9c85fb2b154a5c7ba163637e7adb6/href">https://medium.com/media/c8d9c85fb2b154a5c7ba163637e7adb6/href</a></iframe><blockquote><strong>Note:</strong> This high degree of customization also comes with a responsibility to use them in ways that are harmonious with the rest of the library. You still have the safeguards of using system values, but you should know how to keep UI coherent.</blockquote><h3>Elements</h3><p>Like their <a href="https://en.wikipedia.org/wiki/Chemical_element">chemical counterparts</a>, Elements cannot be broken down into a simpler substance without losing their essential characteristics. They are closely aligned to HTML elements but are not limited to them. While they are still highly flexible, they are more constrained to a particular instance. Some will have particular variants and states, but they typically will not have behaviors. They can be used in a variety of contexts and are only concerned with their own internal attributes. In the LeftNav example above, these are the Nav, List, ListItem, Icon, and Link Elements. You can also extend Elements to create more specific instances. For example, we could have a NavLink that activates a variant when it&#39;s the current route:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4f20fefe6bc162b4c8112a866b5fd90e/href">https://medium.com/media/4f20fefe6bc162b4c8112a866b5fd90e/href</a></iframe><h3>Compositions</h3><p>Compositions are our highest-level component abstraction. They can be composed of Primitives, Elements, or, in some cases, other Compositions. While they have distinct parts, they also have associated behaviors. Some example behaviors are: how and where a popup appears and disappears, how a dropdown menu responds to keyboard commands, and how a side panel opens and closes. These behaviors are often connected to states (open, closed, hover, focus, etc) and accessibility attributes. Ideally, all of these behaviors, states, and accessibility attributes are composable as well. This allows us to build dropdown menus to exhibit the some of the same behaviors as our tooltips even though the UI is completely different. You could build entirely new compositions with behaviors from several existing compositions and have them feel cohesive. Let’s add a little to our LeftNav example from earlier.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ecbd35dcda962295709f3e7d9173c5bf/href">https://medium.com/media/ecbd35dcda962295709f3e7d9173c5bf/href</a></iframe><h3>Wrapping Up</h3><p>The component hierarchy focuses the component’s scope of responsibility, creates meaningful relationships between components, encourages composability, and provides balance between flexibility and structure in our component library. This empowers external teams to build and evolve their UI more effectively and allows maintainers to more sustainably support them.</p><h3>FAQ</h3><blockquote>“How are Primitives, Elements, and Compositions different from <a href="https://bradfrost.com/blog/post/atomic-web-design/">Atomic Design</a>’s Atoms, Molecules, and Organisms?</blockquote><p>To me, Primitives are a lower level than AD’s Atoms, though I understand that’s subjective. Elements are effectively Atoms and Molecules are Compositions. <em>(Tokens would be subatomic particles, but we can talk about that another time.)</em> I also think anything large enough to be considered an “Organism” is too large to live in a component library. It makes more sense for that to live in a product application.</p><p>The distinction between Primitives and Elements is that Elements are one type of thing (Button, Icon, Paragraph, etc), and Primitives have the flexibility to be lots of types of things. If we want to use a cellular analogy: Elements are a single type of cell (skin, brain, blood) and Primitives are closer to stem cells.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d5ce153acab3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Parable of the Talents]]></title>
            <link>https://alanbsmith.medium.com/the-parable-of-the-talents-a89e0714d88d?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/a89e0714d88d</guid>
            <category><![CDATA[blacklivesmatter]]></category>
            <category><![CDATA[christianity]]></category>
            <category><![CDATA[racism]]></category>
            <category><![CDATA[white-privilege]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Thu, 04 Jun 2020 16:50:00 GMT</pubDate>
            <atom:updated>2020-06-04T16:54:34.753Z</atom:updated>
            <content:encoded><![CDATA[<p>an open letter to white folks</p><p>I’ve been thinking a lot about Jesus’ <a href="https://www.biblegateway.com/passage/?search=Matthew+25%3A14-30&amp;version=ESV">Parable of the Talents</a>¹ and how it relates to us today. If you’re not familiar, I’ll give you a short summary:</p><blockquote>A man is going on a long journey and entrusts three servants with talents (money) before he leaves. To the first he gives five talents (~100 years’ wages for a laborer). To the second he gives 2 talents (~40 years wages). And to the third he gives one talent (~20 years wages). Upon returning the man settled accounts with his servants. The first servant with five talents doubled his money and was praised by the man. The second with two talents also doubled his money as was praised. The third however hid his talent in the ground for fear of losing it. The man called him wicked and lazy for not even investing it with bankers where it could at least gain interest.</blockquote><p>I’ve wrestled with this parable a lot lately. And while its message is for everyone, I’d like to direct it specifically to White folks for a minute, myself included.</p><p>Privilege is a loaded word, and it makes a lot of White folks upset. It can make you feel like you didn’t work hard for what you have, but that’s not what it’s about. You can work hard and be privileged. It’s right there in the parable. Some servants were given more than others, and there’s no indication that the amounts were based on merit. And that doesn’t mean they didn’t work hard with what they had. It’s hard to double your money. They likely had to be prudent about their investments and work diligently to deliver such a large gain. And good on them for doing so! The man praised them when he returned.</p><p>You may not feel like you have a lot privilege. You might make just enough, or stretch it to make not enough work. You may not be a social media influencer with tens of thousands of followers. You might not be in a prominent position at your company. But everyone is given something, some privilege. And here’s the message:</p><blockquote>One day we’re going to have to settle up and answer for what we did with what we’ve been given. There’s no way around that. Whether you feel like you have a little or a lot, you’re going to have to give an account for it.</blockquote><p>White folks, it’s not enough for us to simply believe racism is wrong. It’s not enough for us to believe police brutality and corruption are wrong. It’s not enough for us to believe a system that treats us better than people of color is wrong. It’s not enough to be silent. The servant who hid his talent in the ground did so out of fear. It is scary to confront racism, to look it in the eye and see the injustice. It is deeply unnerving to know that you largely escape those challenges <a href="https://kinginstitute.stanford.edu/king-papers/documents/i-have-dream-address-delivered-march-washington-jobs-and-freedom">not by the content of your character, but by the color of your skin.</a>² I feel that fear. But we will be held accountable for our actions, and if you bury your privilege in the ground and do nothing with it, that is antithetical to the message of Jesus.</p><p>The lesson of this parable is being a good steward of your privilege. So what can you do? Speak up. Use your privilege and influence to support people of color and speak out against racism. Maybe you’re afraid to say something wrong or ignorant, and you might. Your message might be off-key, but not speaking up against something so wrong is far worse. You can also call or email your city officials, you can <a href="https://www.house.gov/representatives/find-your-representative">contact your legislators</a>, and <a href="https://www.vote.org/">in November you can vote</a>. If you have the means, you can <a href="https://www.joincampaignzero.org/">donate to charities that advocate for people of color</a>. And you can <a href="https://www.maxwellboise.com/read">educate yourself</a>. Listen to people of color and read books about systemic racism.</p><h4><strong>Reading</strong></h4><ul><li><a href="https://www.amazon.com/dp/1631494538">The Color of Law</a> by Richard Rothstein</li><li><a href="https://www.amazon.com/dp/0812993543">Between the World and Me</a> by Ta-Nehisi Coates</li><li><a href="https://www.amazon.com/dp/0525509283">How to Be an Antiracist</a> by Ibram X. Kendi</li></ul><p><em>¹ Matthew 25:14–30<br>² Reference to MLK’s “I Have a Dream” address</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a89e0714d88d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Component API Design]]></title>
            <link>https://alanbsmith.medium.com/component-api-design-3ff378458511?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/3ff378458511</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[web-design]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Mon, 08 Jul 2019 13:01:01 GMT</pubDate>
            <atom:updated>2019-07-08T13:01:01.205Z</atom:updated>
            <content:encoded><![CDATA[<h4>guidelines for building shared components</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xSsqAX5D45JVXrnJ" /><figcaption>Photo by <a href="https://unsplash.com/@d_mccullough?utm_source=medium&amp;utm_medium=referral">Daniel McCullough</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Overview</h3><p>This is a high-level description of API guidelines for shared components. It is intended to provide a general framework for creating resilient and adaptable components. These guidelines are derived from three main concepts:</p><ul><li>Make the right choices easy</li><li>Make incorrect choices obvious</li><li>Provide helpful off-ramps</li></ul><h3>Make the Correct Choices Easy</h3><p>Documentation is great, but if users are constantly scouring the docs and source code to remember how to use shared components, that’s an indication of inconsistent APIs. Ideally, the library should teach you how to use it as you interact with it. There’s an interaction design hierarchy that describes this well:</p><p>Interactions should be first <strong>intuitive</strong>, then <strong>discoverable</strong>, and last <strong>standardized</strong>. *</p><p><em>* Summarized from </em><a href="https://www.amazon.com/Design-Everyday-Things-Revised-Expanded/dp/0465050654"><em>The Design of Everyday Things</em></a><em> by Don Norman</em></p><blockquote>Note: While there is a hierarchy of preference, these qualities are also interdependent. We should design our components to be intuitive and discoverable and standardized.</blockquote><h3>Intuitive</h3><p>Building intuitive APIs is challenging. You usually have to rely on an existing natural mapping or some prior context. But even then, there will almost always be some amount of time required for memory to be established. However, there are a few things we can do to make APIs more intuitive and guessable:</p><p><strong>Shared APIs across common components</strong></p><p>Creating shared APIs across components reduces the amount of context needed users to become proficient with the library. While more complex components will have inevitably have more component-specific props, there are ways to consolidate them. For example:</p><p>This Accordion component uses a component-specific object to structure its contents.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nUiTlsk3rlm3czuc2NwqmA.png" /><figcaption>High-level Accordion Component Example</figcaption></figure><p>FeatureList also has its own component-specific object, but it uses the same config prop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U76OwxwMdKbg4TXk9osTBA.png" /><figcaption>High-level FeatureList Component Example</figcaption></figure><p>Lower-level components will have more common props that can be used to modify them. For example:</p><p>This is a standard Button using the danger variant to modify its styling.</p><pre>&lt;Button variant=&quot;danger&quot;&gt;Cancel Your account&lt;/Button&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FdMpnhYL7vJJFu_Cojoprg.png" /><figcaption>Button Component Example</figcaption></figure><p>Alert also uses the variant prop and danger value.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AaxNbGavBKVcO0pzwgcjGQ.png" /><figcaption>Alert Component Example</figcaption></figure><p><strong>Leveraging existing APIs</strong></p><p>We can also leverage familiar, existing APIs to reduce cognitive load. For example:</p><p>This AccordionTitle component uses React’s children prop to render child components (as opposed to using a custom content or title prop. This might seem like a minor point, but I&#39;ve found that as your component library grows, remembering one-off prop names such as title becomes much more challenging.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kH_knpWOqtWpolxAwL-jhg.png" /><figcaption>Accordion Header Component Example</figcaption></figure><p>We can also leverage familiar CSS style attributes and HTML attributes to reduce context:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x7edDPmpT_uVMxDQjFkU-g.png" /><figcaption>Text and Button Example Component Examples</figcaption></figure><h3>Discoverable</h3><p>Discoverability is a powerful tool that helps users learn the library while using it. We can accomplish this in several ways:</p><blockquote>Note: While there is a preferred hierarchy, each is interdependent. We should incorporate self-disclosure, documentation, and readable source code into our library.</blockquote><p><strong>Self-disclosure</strong></p><p>This is the most preferred option for discoverability. Components self-disclosing or hinting at their API provides guidance in the user’s immediate context. There’s no need to hop into external documentation or source code to figure out how to interact with them.</p><p>TypeScript and IDE plugins provide helpful mechanisms that aid self-disclosure. Whenever possible, we should leverage these options first.</p><p><strong>Documentation</strong></p><p>Along with self-disclosing component API, we should provide external documentation. Component docs are intended to support direct-users (engineers and designers) They should include information for using the API, but also higher-level information about when to use the component.</p><p><strong>Source code</strong></p><p>Source code should be a last resort for discoverability. If users are regularly digging into code to understand how to use a component, that’s a flag for poor design. However, these situations do occur, and we should plan for them by optimizing readability. If unintuitive choices had to be made or a temporary patch had to be employed, we should add a comment alongside that code. We should also file an issue for that problem if one does not already exist. Another way to make source code more readable is a standard file structure, which will be discussed in another post.</p><h3>Standardized</h3><p>Ideally, we should build standards around intuitive choices (common API patterns and leveraging existing API conventions), but sometimes those choices are not clear. In those situations, we should create well-documented standards for those APIs. It’s important to remember that each new standard is additional context a user will need to keep in their head to interact with the library. We should keep limit the number of standards to reduce cognitive load for users.</p><h3>Make incorrect choices obvious</h3><p>Non-obvious mistakes are a significant source of friction when interacting with components. Someone unknowingly misuses a component and it passes code review, only to realize the mistake much later. This could be a misleading prop or a non-standard modification to the component’s structure of styling. The best way to reduce mistakes is by following the guidelines above and making the correct choices easy. If our components are intuitive and discoverable, we should reduce the number of mistakes overall. And if our standards are clear enough, misuse should be clear in code review. However, there are other options for making incorrect choices obvious.</p><h3>Type-checking</h3><p>Typing props not only provides discoverability, but also warnings during misuse. We should make types specific as possible without being overbearing. An example would be listing out Badge variants in a type instead of simply allowing strings.</p><h3>Consistent styling patterns</h3><p>One of the most common ways to misuse a component is styling. While users are often blamed for these mistakes, it’s often a symptom of vague patterns for modifying styles. Providing consistent and clear styling patterns helps users make the correct choice but also makes misuse obvious in code review.</p><h3>Deprecation warnings</h3><p>All code has a half-life and deprecations happen. We should provide helpful warnings to users when a component or prop is being deprecated and how to migrate. There should also be levels of deprecation to help users prioritize updates.</p><h3>Provide helpful off-ramps</h3><p>When you drive along the highway, there are normally paved off-ramps with helpful signs every few miles. You’ve probably also seen mad-made dirt paths where enough people have driven through the median to get off the highway because of frustration and impatience. There’s a good lesson for component libraries here:</p><p><em>If you don’t provide helpful off-ramps, people will make their own.</em></p><h3>Handling edge cases</h3><p>Shared components should be built to accommodate normal use cases and occasional edge cases. Some maintainers make the mistake of wanting to cover every edge case, but this creates several problems:</p><ul><li>Components become rigid and brittle as they support more cases</li><li>Components become more challenging to maintain and update</li><li>Component APIs become more opaque to users</li></ul><p>Put simply, too many off-ramps create chaotic driving conditions and only increase maintenance costs. But there will always be edge cases we don’t anticipate, and people will always attempt to make their own off-ramps. This isn’t because they are poor drivers or have malicious intent. The road was not designed to accommodate their situation.</p><p><em>How can we design a solution to handle these unanticipated cases?</em></p><h3>Composability</h3><p>Components should be built in a composable way. By that I mean, larger, more complex components should be built using smaller, simple components. And those larger components should export those sub-components. This will allow users to drop a level below the higher abstraction and compose the sub-components in a way to meet their use case. This is the preferred solution as it allows users to resolve their issue in a way that is still consistent with the library. For example, let’s say my default Accordion component doesn’t quite fit my particular use case (I need an icon by the Accordion’s title). Because it’s composed of sub-components, I can do this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*afgkLAUI35p_iYaSkdASuw.png" /><figcaption>Composable Accordion Component Example</figcaption></figure><h3>Clear communication</h3><p>We should create a clear channel of communication where maintainers can help users move forward with their issue. If a solution is not clear for a user to solve themselves, they should reach out to the maintainers. This process will be discussed further in another post, but the purpose of this communication channel is triaging the problem and help the user move ahead quickly. We might have to make a sub-optimal off-road, but we’ll do it together and document it.</p><h3>Thanks for Reading!</h3><p>You can find me on <a href="https://twitter.com/_alanbsmith">Twitter</a> and <a href="https://github.com/alanbsmith">GitHub</a>. If you enjoyed this, you should also subscribe to my newsletter! <a href="https://tinyletter.com/alanbsmith">https://tinyletter.com/alanbsmith</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ff378458511" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sustainable Design Systems]]></title>
            <link>https://alanbsmith.medium.com/sustainable-design-systems-52edce0b62a9?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/52edce0b62a9</guid>
            <category><![CDATA[systems-thinking]]></category>
            <category><![CDATA[design-systems]]></category>
            <category><![CDATA[design]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Tue, 25 Jun 2019 13:12:28 GMT</pubDate>
            <atom:updated>2019-06-25T13:12:28.184Z</atom:updated>
            <content:encoded><![CDATA[<h4>decoupling purpose from outputs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*S4Pn-ebLoSrW6esX" /><figcaption>Photo by <a href="https://unsplash.com/@lemondyt?utm_source=medium&amp;utm_medium=referral">Marko Horvat</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>What are Systems?</h3><blockquote>Note: This article references several concepts from systems thinking, most of which are derived from <a href="https://www.amazon.com/Thinking-Systems-Donella-H-Meadows/dp/1603580557">Thinking in Systems: A Primer</a> by Donella H. Meadows. If you’d like to learn more about systems thinking, I would highly recommend it.</blockquote><p>We can think of any system as a collection of interconnected elements that serve a purpose or function. Let’s use a campfire as an example. We have elements: wood (fuel), oxygen, and heat. And those elements are interconnected. If you deprive the fire of fuel or oxygen, it decreases the heat. And if you increase the heat, you deplete oxygen and fuel more quickly. This system also has outputs: heat, light, smoke, and sound. Sometimes the outputs are the purpose, but usually they serve a larger purpose. In the context of a campfire, light, smoke, and heat are not the purpose of the system. It’s likely we started this campfire to provide warmth and comfort, or to prepare food, or to have a nice place for conversation. We’ll revisit this later, but hopefully that’s an approachable system analogy.</p><p>How does this relate to design systems? We can break down a design system into the same parts. It has elements: components, docs, tools, designers, engineers, product owners, and the organization it supports (to name a few). Those elements have interconnections. Often the organization provides the context and parameters for the system, and the designers, engineers, and product owners use tools to build the implementation. As you might have guessed, with a system this complex, there are subsystems within the system. For example, the design team is a smaller system, with its own elements, interconnections, and purpose. The same is true of the engineering and product teams. All of these interconnected sub-systems create complex behaviors which drive the overarching purpose and function of the design system. It’s important to note that a system’s stated purpose might not be its actual purpose. You can structure a system with the one intended purpose, but it might serve a completely different purpose in the end. But with that said, what should be our intended purpose for a design system? Why are design systems valuable?</p><p>Advocates for design systems often mention:</p><ul><li>increased UI consistency across teams</li><li>faster development time</li><li>fewer bugs</li><li>increased focus on higher-level concerns (app performance, UX, etc)</li></ul><p>Those are all great benefits and valuable metrics. They’re tangible selling points that are easily explained regardless of someone’s familiarity with design systems.</p><p><em>The problem with over-emphasizing these qualities is that they are essentially outputs of the system, not its purpose.</em></p><h3>Decoupling Purpose from Outputs</h3><p>If the purpose of my campfire is producing light, smoke, and heat, I’m only focused on making the flames bigger. I can add an accelerant (gas, alcohol, etc) to the flame and see a sudden burst of output. But I can’t easily control or sustain the output with my input. The accelerant causes the flame to consume more oxygen and increase in temperature. But when my accelerant is exhausted, the flame can’t be sustained. Hopefully the system can bounce back, but the system might have become too imbalanced to recover.</p><p>Similarly, it’s very challenging to optimize your inputs to achieve the outputs of a design system. It’s too complex, and as a maintainer, there are too many variables that are out of your hands. If you try to over-optimize for UI consistency, you’ll end up with a system that is too rigid or can’t adapt to consumer needs. If you over-emphasize development speed, you’ll likely sacrifice quality.</p><p><em>Instead, we should optimize for resilience and adaptability.</em></p><h3>Optimizing for Sustainability</h3><p>Any successful system is able to adapt to change and bounce back, and this is the real value of a design system. UI changes rapidly, and you have no idea what your applications will look like in six months to a year. For example, I’ve been at SendGrid for nine months at the time of writing this. Our team has completely rewritten the same application twice already, and we will likely rewrite it again in the next year. I could guess what it will look like, but I honestly have no idea. And if you’ve been working in software long enough, you’ve probably had a similar experience. If you’re optimizing for your outputs, you’re likely building for the UI you have today, but that likely won’t help you sustain your system. You’re throwing accelerant on the fire without thinking about how to make the system sustainable.</p><p>A design system is a large investment, and the only way it becomes a net win for your organization is if it can help you manage change over time. It needs to be adaptable enough to evolve with you as your needs change. And when your processes are disrupted, it needs to be resilient enough to bounce back and recover. Consistency, performance, and fewer recurring issues are all valuable outputs, and those metrics should be a part of your feedback loop. Who cares if your design system is resilient if it doesn’t help ensure consistency or improve development speed? But when structured properly, those outputs feed the sustainability of your system as a reinforcement loop. As engineers experience faster development, product owners see fewer bugs, and designers see more consistency, they become more invested in building a sustainable system. In short, track your outputs for metrics, but be careful not make them your purpose.</p><h3>Thanks For Reading!</h3><p>You can find me on <a href="https://twitter.com/_alanbsmith">Twitter</a> and <a href="https://github.com/alanbsmith">GitHub</a>. If you enjoyed this, you should also subscribe to my newsletter! <a href="https://tinyletter.com/alanbsmith">https://tinyletter.com/alanbsmith</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=52edce0b62a9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Problem with CSS]]></title>
            <link>https://alanbsmith.medium.com/the-problem-with-css-ecc9df00d440?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/ecc9df00d440</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Mon, 01 Apr 2019 22:01:36 GMT</pubDate>
            <atom:updated>2019-04-01T22:27:07.325Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*soZQDmIGPGS1Iy-c" /><figcaption>Photo by <a href="https://unsplash.com/@henrikeikefjord?utm_source=medium&amp;utm_medium=referral">Henrik Eikefjord</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4>Is Actually Humans</h4><p>The problem with CSS conventions is that they rely on developers to manually maintain them with a high degree of accuracy to be effective. This problem is compounded as styles grow. Each developer needs to know more context in order to effectively style UI. That’s why “<em>You should just write good CSS</em>” is an insufficient response to “<em>How do we keep styles maintainable?</em>” Even developers who write great CSS are challenged with an ever-growing problem.</p><p>All that to say, the problem with CSS isn’t CSS, it’s humans. We can only keep so much in our heads, and sharing that knowledge across teams, even teams who really care about consistent styling is really hard. You can argue that the cascade is a design flaw, but I’d disagree. We’re scaling CSS in ways no one could have imagined at its inception. And to manage that scale, we need better tools.</p><p>When engineers have to spend an inordinate amount of effort thinking about basic styling, we’re wasting their time and talent. But we’re also wasting our designers’ talent as well. Instead of thinking about higher-level user experience, they’re checking spacing and color. Typography, spacing, color, etc. should largely be solved problems. Yes, there are instances where more thought needs to be given, but if we have an effective system, those should be few and far between.</p><p>Often the benefits mentioned when discussing effective systems are the bottom of the barrel. I want to free up engineers and designers to think about higher-level concerns that actually make our customers lives better. I want to build better experiences instead of being lost in the details.</p><p>I don’t have any problem automating my deploy processes, or letting npm handle my dependencies, and I’m good with JavaScript managing my CSS. Those may seem like disparate concepts, but they’re not. My brain only has so much capacity, and I’d rather let code figure out how to maintain styles.</p><p>If you enjoyed this, you should also read <a href="https://twitter.com/SiTaggart">Simon Taggart</a>’s <a href="https://www.simontaggart.com/2019-01-11-im-super-good-at-css-and-i-dont-recommend-the-cascade-dont-@-me/">article</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ecc9df00d440" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Composite Component Pattern]]></title>
            <link>https://alanbsmith.medium.com/composite-component-pattern-6331ebcbe07b?source=rss-d9498cd91fed------2</link>
            <guid isPermaLink="false">https://medium.com/p/6331ebcbe07b</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[redux]]></category>
            <dc:creator><![CDATA[Alan B Smith]]></dc:creator>
            <pubDate>Tue, 26 Mar 2019 05:07:44 GMT</pubDate>
            <atom:updated>2021-03-02T19:04:04.804Z</atom:updated>
            <content:encoded><![CDATA[<h4>Coupling Containers to their Concerns</h4><h3>Overview</h3><h4>Purpose</h4><p>This document was created to clarify details about the composite component pattern and component responsibilities. It also includes examples and testing guidelines. The patterns described here are intended to be general guidelines, not requirements, and are intended to be used when reasonable. The purpose of establishing these patterns is to provide enough structure for consistency but also allow flexibility for adaptation. Regardless of the author, code structure should feel consistent but not necessarily uniform.</p><h4>Composites</h4><p>Borrowing from <a href="https://en.wikipedia.org/wiki/Composite_material">composite materials</a>, which combine two or more different materials to create a single superior material, the composite pattern combines connectors, components, blocks, and elements to create self-sufficient UI sections.</p><p>Composites are made up of three general component types: connectors, components, and blocks / elements. Their distinctions are based on their responsibilities:</p><ul><li>Connectors - responsible for application state</li><li>Components - responsible for UI logic and markup structure</li><li>Blocks &amp; Elements - responsible for styling and formatting</li></ul><h4>Example</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8CgdOXMFo5QO8k2K" /><figcaption>An Example Twitter Profile Card</figcaption></figure><blockquote>Note: I am not one of Mr. Goldblum’s seven followers, but I needed to use the badge as an example for this post. This is actually a mock I created in Sketch. <em>👩‍🎨</em></blockquote><p>A ProfileCard composite fetches data for <a href="https://twitter.com/jeffreygoldbIum">Jeff Goldblum</a> and the current user via the connector, which it passes down to the component. The component determines whether the current user and Jeff follow each other and render the components and markup based on that logic. The blocks and elements format Mr. Goldblum’s information and apply styling.</p><h4>File Structure</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7aad43ecb88787a7feb7b9831513b02/href">https://medium.com/media/c7aad43ecb88787a7feb7b9831513b02/href</a></iframe><h3>Connectors</h3><h4>Overview</h4><p>Connectors are small containers that are collocated with the components they serve. They provide the application data and state needed for their client components. They also provide handlers for dispatching asynchronous actions. The implementation could be as small as a simple HOC, context provider, or use React hooks. It could also have a smarter implementation using a component with lifecycle methods.</p><p>To understand connectors it’s helpful to compare them to page-level containers. In the early days of Redux, page-level containers were a really common pattern. A single container would connect to the store and provide all the application state needed to render that page. This pattern is great for smaller applications without a lot of complex state to manage. Most components are agnostic about how they get their data and can be solely responsible for rendering logic.</p><p>The problem with this pattern is that it scales poorly if you need to handle a large amount of complex application state and data. The container becomes bloated and difficult to test and maintain.</p><p>Connectors follow many of the same patterns as page-level containers, but are focused on a smaller portion of UI. This simplifies their dependencies, and helps them better serve their components.</p><h4>Responsibilities</h4><ul><li>Fetching application state for client components</li><li>Shaping data for components</li><li>Providing handlers for dispatching actions</li></ul><h4>Example Use</h4><p>A ProfileCard needs Jeff Goldblum’s account info and list of followers as well as the same information for the current user from application state. The connector is responsible for fetching that data, shaping it for the component, and filtering out what the component doesn’t need.</p><h4>Testing Guidelines</h4><p>While a unit test for a connector could verify that it provides the expected props in isolation, it’s probably more beneficial to write integration tests for the entire composite instead. As the connector’s primary purpose is to provide data for the components in the composite, an integration test would be more effective in validating that behavior.</p><h3>Components</h3><h4>Overview</h4><p>Components are probably what you think of when you think about traditional React components. They are in charge of UI logic, establish markup structure, and might or might not be stateful.</p><p><strong><em>NOTE:</em></strong><em> Because styling logic is handled by blocks and elements, components shouldn’t have related styles. Their only job is rendering logic. There might be Storybook for the component, but it shouldn’t think about styles itself.</em></p><h4>Responsibilities</h4><ul><li>Handling UI logic</li><li>Markup structure</li><li>Passing props to children</li></ul><h4>Example Use</h4><p>The ProfileCard needs to determine whether to display the “Follows You” badge on Jeff GoldBlum’s user card as well as the ‘Following’ text for the call-to-action button. After receiving the information it needs from the connector, it’s responsible for the logic to make those decisions and pass along information to its child components.</p><h4>Testing Guidelines</h4><p>Because components are only in charge of rendering logic, you can focus your tests on that behavior. Shallow rendering and injecting props to mock out the various states of the component is sufficient.</p><h3>Blocks &amp; Elements</h3><h3>Overview</h3><p>Inspired by <a href="http://getbem.com/">BEM</a>, blocks and elements are our lowest level component abstractions. They are solely responsible for styling and formatting markup. A block is itself a component, and it contains elements, which are the smallest parts of our UI. Some elements are standalone and do not live within the context of a block (Links, Buttons, etc.).</p><h4>Responsibilities</h4><ul><li>Applying styles</li><li>Formatting information (dates, currency, numbers, etc.)</li></ul><h4>Example Use</h4><p>The ProfileCard needs to format the numbers displayed in the user info section. For numbers greater than 10,000, it should use the “10.1K” format, otherwise it should use comma-separated values. It also needs to style the Card block and the elements contained within. The blocks and elements are responsible for managing these behaviors.</p><h4>Testing Guidelines</h4><p>Because these components have little to no logic, they should not be unit tested. Regression tests with snapshots are sufficient, but are not required if they are captured in a higher-level snapshot.</p><h3>Thanks for Reading!</h3><p>If you enjoyed this, you can find me on <a href="https://twitter.com/_alanbsmith">Twitter</a> and <a href="https://github.com/alanbsmith">GitHub</a>!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6331ebcbe07b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>