The craft of component design
How to design a component library that scales with projects, designers and developers?
The success of an application is not a question of technology, libraries or frameworks. In the user’s eyes, it is not the technical aspects that make the difference, but the quality of the experience and the interface. So, it is essential that everyone who is involved in developing a product can work to the best of their abilities and bring their own culture and sensitivity to the party. Creating an environment specifically structured to encourage designers and developers to work together is difficult, but worthwhile. This is because allowing these figures to work in brief and iterative cycles on a particular function or product feature optimises the workflow, as well as enhancing its quality. These results can be attained by creating a component-based system. In other words, taking a website or app and breaking it down into reusable elements by defining some or all of its aspects, such as style, semantics and functions.
Many of the problems that had emerged in our team over the years were solved by shifting to a modular approach and focusing on system consistency. These include the sensation of “danger” when adding a function to a site and the real sense of panic that would arise in the aftermath of a technology update. Releasing updates and improvements has now become much easier thanks to the reusability of the components. And we have become more accurate and efficient in adjusting scripts and styles following transversal technological project alignments. Debugging, optimisation and testing have all been improved too.
This transformation has not been painless and we have had to experiment widely with different tools, methods and personal relationships. We have made several mistakes along the way and sometimes we have had to first slow down to then achieve important successes remarkably quickly. This article contains a number of insights into how to choose the technologies that best suit your team, as well as explaining how we have built a structure that allows our artisan-style setup to maintain, update and develop websites, applications. Design Systems and Microfrontends with a solid, shared code base, made up of more than one hundred components.
Recognising work environment conditions, interpreting the team’s needs and understanding those of the customer. Examples of methodology and moments for sharing.
The first and biggest mistake you can make when developing components is to think that all you need is a framework to develop components. Like every method, it’s not enough to apply the rules. You need to combine them with the environment and, above all, the people in it, to obtain a satisfying result from all points of view. Design, development, communication and every area in the workshop play an essential role in making a project successful. This is why they all need to share their needs, solutions and information.
When communication works properly:
- Developers who have a project to implement also know why certain decisions have been taken. They can therefore establish with greater clarity which components need to be created and which improved, as well as planning updates and introducing new tools.
- Designers know how their project will be implemented and can provide specific instructions for certain aspects. They can count on a collection of designed and documented components to create prototypes or system updates.
- Designers and developers know the needs of the customer and not just the results they need to achieve. They are therefore more receptive and more proactive. Both have the expertise to identify weak points in the communication of certain products or the customer’s own image.
In some environments, where this level of sharing may be difficult between departments and/or smart workers it is essential that the tools adopted are able to overcome communication problems. Everyone who works on a particular project must be able to access the design choice back history quickly and without having to trawl through threads or implementation details.
Moments for sharing are therefore essential not only to solve problems linked to processes, but also to monitor the efficacy of the communication. For teams that already use Agile methodology, the retrospective plays an essential role in achieving this. It allows the team to collect and manage workflow problems promptly, plan training moments (tech talks, resource and example gathering) and assess the tools that are already in use and the innovations to be added.
More in general, the use of a framework like Scrum is strongly recommended for the kind of processes that follow an iterative process with regular release flows to avoid congestion, technological degeneration and centralised skills – the worst enemies of a component system.
Above all, in the initial trial period, collecting feedback from colleagues is crucial. Moreover, the greater the team spirit, the more solid and effective the system will become. In a certain sense, it can also be said that the quality of the components reflects the stability of the professional relationships between the people who designed and implemented them.
Assessing the talent of individuals, improving the feeling for the project and understanding how the ecosystem works for formulating times, identifying lines of action and assessing solutions.
One of the myths that surround technique is that people who develop it to a high level must have unusual bodies to begin with. As concerns the hand, this is not quite true. [...] The fingers can engage in proactive, probing touch without conscious intent, as when the fingers search for some particular spot on an object that stimulates the brain to start thinking.
Richard Sennett, The Craftsman, 2008
Just as Sennett presents the craftsman’s hand as expressing talent and sensitivity in the way it recognises the quality and functionality of a material, a developer can set a component code in a way that not only performs the functions it was created for, but also enhances the project thanks to its quality and efficiency.
Even if it is impossible to possess the technical skills required to handle the entire system of components, the professionals who work on it must share the concepts and functions that govern it, as it is through this knowledge that they can express their talent. Every developer’s key “talent” is therefore linked to the complexity of the computational problem that has to be resolved, but in the capacity to identify a solution to improve the entire project (or in this case, the system of components) by combining the different workshop “areas”.
A developer who is aware of the design decisions that have been made, can also spot problems before implementing them, just as an expert designer can recognise and find simple solutions to complex technological problems. When designers and developers work together, the quality of the components is drastically improved thanks to a level of sensitivity that covers the entire project and this allow all the details to be implemented in a single cycle. In fact, moving part of the development process to the design phase allows more comprehensive and consistent specifications to be written. Moreover, sharing the competencies that are applied in this phase is also a moment of professional growth for both figures, as it builds both a common vocabulary and a common approach for future projects.
Just as there can be different types of components in an interface or application, there can also be multiple implementations. The team must therefore define the structural differences of the possible applications in order to recognise the approach that is most consistent with the system. For example, having adopted the breakdown into atoms, molecules and organisms proposed in Atomic Design (Brad Frost, Atomic Design, 2016), our team identified for each category the aspects to be processed in terms of graphics, navigation, functionality and accessibility:
Atoms: are the simplest elements of all, so they are also the most reusable. They do not define specific actions or check whether they have been implemented. Instead, they simply suggest how to interact with the element. In the case of a button, all the states such as focus or pressed are defined, but no click action conduct is linked to it. We generally process this type using only primitive HTML elements (that are accessible by definition). This includes identifying the basic states required to define the component.
Molecules: slightly more complex than atoms, these define elements where the type of user interaction is more mapped. Here, too, wherever possible, we use the complex structures in HTML to define micro-templates that implement the rules of accessibility with linear navigation. When we work on a form, we check that the combined use of label and input is correct, and that placeholders and alternative texts for the assistive tools are present. The graphic aspect, on the other hand, is limited to describing the layout of the elements.
Organisms: at this level we are pretty sure how the user will interact with the component, so we can set up an alternative form of navigation instead of a linear one, and decide which actions it has to perform. The template will probably be definitive and semi-static, so a remote access programmatic interface must also be designed in order to customise certain aspects with a controlled set of options and properties and a system of events or callbacks so functions can be added.
Thanks to this kind of breakdown, it is easier for designers and developers to understand the functionality and competencies of the component they are implementing. As both formal and structural aspects can be described, in the design phase it is important to define in which contexts the element can be used in, understand how it can evolve from a graphic perspective and where the visual aspect still needs to be defined within the product. All this should be done focusing solely on the element’s functionality. By working on the abstraction of these aspects, the levels of implementation required for each component can be defined and solid, but streamlined foundations can be created for a system that has to evolve rapidly and consistently.
To implement a calendar view of a series of events, our team worked on creating a basic component made up of one organism only that uses atoms like labels and buttons and molecules like the detail of the event on which the navigation experience needs to be constructed. This then allowed us to insert the component in different sites simply by applying the graphic design rules to the atom elements and streamlining the update and validation process which otherwise would have become too lengthy in situations where the formal aspect was intrinsically combined with the structural one.
Languages, tools, machines and accessories that help the developer, designer and customer. Useful and essential documentation.
The automatic accessibility and coding style validators that help designers and developers in their daily tasks are extremely useful also in other fields, like training and sharing. They can also be used by the team as a support when changing methodology, for example, in a shift from a top-down flow to an iterative one.
This is why it is so important that the choice of tools and technology is made within the team who will have to use them. This step requires documentation and freedom of experimentation and method. Sometimes it is worth creating your own tools instead of forcing the team to use one they don’t think is practical. Other times you will need to recognise when problems are caused by a lack of familiarity. And in other situations, again, you may need to lower the functionality or potentiality threshold of these tools to make them even more usable.
The more a tool is integrated in the process, the more effective it is. When we developed DNA, we needed a library to define web components that would not impose a pattern established by other developers, but would be based on our own thought patterns instead. It also had to be versatile, given the mixed nature of the team, and able to evolve in line with our rhythms.
Using automatic validators, whenever possible, even if implemented at a basic or incomplete level, is a great help for any design/development team. In the special case of component development, the most important tests are those which check that the Application Programming Interface (API) is operating correctly, that the element’s accessibility rules are observed and whether there are any graphic regressions.
Validators are not only check tools, but sharing and training tools too. Integrating rules regarding the use of a programming language via a linter or setting a required standard of accessibility allow new specifications to be assimilated directly in the work context.
On one hand, if the results of pair programming are evident in terms of quality in the programming panorama, the practice of working in pairs with a designer is much less common, but just as effective. If you are used to working with different tools, the fact of focusing on a common artefact, whether that is a graphic proposal or the implementation of a component, is a good way of dealing with the formal and structural aspects in their entirety. In the same perspective, choosing a common tool is increasingly more effective than a connection tool that would add a further step and which may become a potential obstacle to communication and sharing.
To further encourage integration, setting a DevOps flow to automate operations improves the development experience, reduces the risk of mistakes and allows designers to adjust the code more confidently. Even if most of the processes take place in an isolated environment, to run certain checks, you will need to verify the conduct of the component directly in the website. This is why every component constitutes a module that can be unhooked from the entire system to be tested in a validation environment without requiring an update of the entire library. Every time there is a change, the continuous delivery system publishes an updated version of the element on a remote register (in our case NPM) which the validator can access to download the specific version to test. The aim of this mechanism is to reduce manual operations, the risk of mistakes or incompatibility and the time required to perform validation, even when this involves performing an urgent release to solve a problem.
Pull Requests are another practice that in the long-term brings a number of benefits to the update and maintenance process of a component. Appointing a member of the team to gradually review the consistency of the system improves the interoperability of the elements and simplifies their documentation. Code reviews, function validations and automatic tests are useful for checking that all the acceptance criteria, even the implicit ones, are observed before introducing a change to the component system.
Compiling technical documentation always benefits the team, but doing it for a system of components can also reduce the gap between the designer’s work and that of the developer. Thanks to tools like Storybook, that allow design choices to be integrated with a preview of the element, project access points can be simplified and the risk of misalignment between design and implementation can be avoided.
Workflow should also be taken into account when choosing the tool for documenting the project. As, if the solution chosen is not integrated with the process it risks deteriorating over time. At the same time, tools whose contents are impromptu and closely linked to context, like Slack and various chats should also be avoided. Some software is useful, however, like Confluence (as it can be integrated with Jira) and Basecamp.
In the past, the forced separation of design and development imposed the construction of fragile bridges that were difficult to use and which no one wished to cross or fix. Building bridges requires significant investments in both resources and the time taken for these two figures to communicate. But when workshops are set up, the efficiency that sharing brings offers numerous benefits in terms of both time and quality. Today, the work of a developer is still seen only in terms of its engineering input, whereas the role of a designer is often defined as “creative”. Even if these aspects characterise the work of both figures, they are not enough to describe what they bring to a project when they work together. This is demonstrated in its entirety when a component-based development flow is adopted, where the skill of the professionals lies in implementing a solution that is consistent, functional and enjoyable for both users and those working on the project.
In line with the principles of Agile methodology, component-based development requires design, development and release cycles and brief, carefully targeted tests that seek to improve the product through a genuinely iterative and collaborative approach.