Goldman Sachs launched the Goldman Sachs Design System in February 2020 as part of our OneGS initiative. The Design System defines the visual styles, interaction patterns, and user experience guidelines to build modern websites and products for desktop and mobile experiences that unify the client experience across Goldman Sachs.
As a small example of attention to detail, the first iteration aligning the UI Toolkit to the Design System ensured that we had a consistent visual "look and feel", but the two products were not yet using consistent principles or vocabulary. Component features in the Design System did not necessarily match the APIs and implementation in the UI Toolkit. These discrepancies were natural as the products had grown organically, but it was not the quality of experience that we wanted to deliver to our designers and developers.
The UI Toolkit is an evolving product that leverages open source and custom-made components to solve the common use cases and patterns in financial web applications. Our early focus on delivery to establish the product and meet developer needs did not afford us the chance to take a holistic look across all of our components, so we exposed different styles of API patterns and conventions. As a result, developers using the early version of the UI Toolkit would need to continually check the documentation to look up which features and APIs were available on each component. This added overhead to the development process when using the UI Toolkit to build an app.
For instance, the color property from the old UI Toolkit APIs was a prime example of how lacking standardization can harm the developer experience. At that time we still leveraged Bootstrap under the hood, so values like primary and danger were acceptable as "colors" on many of our core components, such as Alert and Button. Other UI Toolkit components like Badge also had a color property, but here it accepted standard colors like purple or light-blue. Developers who had used the Badge color API were unpleasantly surprised to discover that passing purple to the Button color API (which only accepted 'primary' or 'secondary') failed silently and rendered a button without any background color.
<Badge color="purple" /> // This works since 'purple' is an acceptable parameter to Badge, as seen above. <Button color="purple" /> // Fail, no background color was rendered, as seen above.
We had many other examples of component features not quite lining up with each other. Aligning the UI Toolkit components to visually match the new GS Design System gave us an appreciation for the breadth of features that we support across the system. Having the full picture of what we were offering also gave us the perspective into why some components supported certain features, or even certain API values, that others did not.
For example, the color property used across the components was trying to do 3 things:
This also explained why our components restricted certain values for the 'color' property:
Old APIs: Too many definitions of color.
APIs become intuitive when they do what you expect them to do, and they do it consistently.
The Little Manual of API Design is an excellent resource to get started building APIs with an awesome developer experience. The Manual outlines 5 characteristics to achieve when developing APIs:
In the months following the launch, the UI Toolkit underwent a major transformation where we applied these principles and other software best practices to offer a set of component APIs that were intuitive to both designers and developers.
Before we could begin thinking about the best way to redefine our technical APIs, our designers and developers collaborated on a standard set of feature terminology that would be easily understood across designers and developers. By performing these exercises together, we improved the quality of new designs and decreased our time to market.
The engineering principles of "easy to learn and memorize", "hard to misuse", and "easy to extend" came in extremely handy here. We were able to break up features that were initially mutually exclusive in the GS Design System components by separating them out into individual properties. Breaking out features into shareable concepts also helped us find new opportunities to enhance existing components:
The result of this collaboration led to the publication of our Design System Concepts. The concepts serve as a backbone for both the GS Design System and UI Toolkit to ensure component consistency across different systems. With this as a guide, refactoring the component APIs became a relatively straightforward exercise.
As a practical example, let's step through how we refactored the overloaded color property from the old APIs. As noted earlier, color was being used to represent 3 things: an action hierarchy, a status, and a standard color. This violates several of the characteristics of good APIs described in the Little Manual of API Design. APIs that are easy to learn and memorize "use the same name for the same concept, and different names for different concepts". Our color API was merging 3 concepts into one property, which made it confusing for developers to use properly. The color property also did not promote the hard to misuse characteristic, because developers would often try to provide standard colors as values and be forced to check the docs to learn that options like 'primary' or 'success' were the accepted values.
When redefining the APIs to solve this issue, we decided to refactor the old color API into three separate properties that can influence the final color of a component. The new APIs focus on the purpose of when each of these features would be needed on a component:
Applying these new APIs to our components helped tighten their feature set to better reflect each components purpose. Button accepts action type and an optional status, but not the generic color property. Alert only needed status, and Badge can accept either status or color depending on its context. The new APIs also makes it easier to talk about the components with our designers and users in a way that mirrors their technical implementation. We can have conversations about the 'error' status Alert, the 'primary' action Button on the page, and the notification on the screen tagged with a 'purple' colored Badge.
The code becomes simpler as well:
<Alert status="error" /> <Button actionType="primary" /> <Badge color="purple" />
Hey, this sounds like English! And I can actually remember these prop names without needing to look at the docs every time!
Even better, when developers using the UI Toolkit decide to add an Avatar component to their app and find that it supports the color property, they know this prop will accept 'pink' or 'purple' just like the Badge. They can also infer that the Input component will accept 'success' and 'error' for its status prop, based on how status works in the Alert component. Adding consistency and predictability to the UI Toolkit APIs has enabled developers to infer their behavior with minimal reliance on the technical documentation.
Here are a few takeaways from our journey that you can apply to your own teams and products:
1. Understand your business and product
Knowing the market you operate in and the full set of features your product provides to users will enable you to make better technical decisions. Determining what your product does is the first step, but discovering why it does what it does will empower you to transform it.
2. Drive change together with your business
Change is scary. When software changes it often means more work for your users in the short-term, since people need to readjust their work habits and get used to new user interfaces. You may encounter a lot of user or business resistance when you start proposing software changes. Embrace their concerns and involve them in the discussions that will impact their workflows. You'll be surprised by the insights your users bring to the table when you collaborate.
3. Learn and apply software engineering best practices
Writing software that other people want to use takes practice. Leverage the wisdom of other engineers and consult early with peers to get feedback. References like the Little Manual of API Design, Clean Code, and Refactoring are great resources to explore.
See https://www.gs.com/disclaimer/global_email for important risk disclosures, conflicts of interest, and other terms and conditions relating to this blog and your reliance on information contained in it.