<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DadCod</title>
    <description>The latest articles on DEV Community by DadCod (@dadcod).</description>
    <link>https://dev.to/dadcod</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1224773%2F539fd393-8417-4597-806e-78a191630fb0.png</url>
      <title>DEV Community: DadCod</title>
      <link>https://dev.to/dadcod</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dadcod"/>
    <language>en</language>
    <item>
      <title>Building a design system</title>
      <dc:creator>DadCod</dc:creator>
      <pubDate>Mon, 22 Jan 2024 21:00:39 +0000</pubDate>
      <link>https://dev.to/dadcod/building-a-design-system-52a</link>
      <guid>https://dev.to/dadcod/building-a-design-system-52a</guid>
      <description>&lt;p&gt;I explore the evolution, key components, and practical challenges of creating a cohesive design system, offering valuable guidance for developers and designers alike.&lt;/p&gt;

&lt;p&gt;When I began researching design systems, I was surprised to discover the numerous definitions of what a design system actually is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx3k69yk6di14ly6cakh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx3k69yk6di14ly6cakh.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you asked me to define a design system, my answer would have varied depending on the year. Ten years ago, I would have described a design system as a CSS library or a style guide for writing CSS and structuring HTML. Five years ago, I might have said it’s a set of components used to build applications. Recently, with the rise of design systems like Material and Fluent, their descriptions have become more abstract, almost likened to a superhero entity rather than a mere framework. Let’s attempt to clarify what a design system really is.&lt;/p&gt;

&lt;p&gt;As an engineer, I understand the purpose of a style guide and CSS frameworks. It’s tempting to simply view a design system as a library of components. However, a design system should offer more than that: its components must be coherently designed and consistently implemented, not just assembled from various sources into a shared library. A design system provides clear guidelines on the appearance, implementation, and integration of components. It defines not only what a component is used for but, perhaps more importantly, what it should not be used for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdy54esdich14i53beoz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdy54esdich14i53beoz.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beyond these technical aspects, for me, a Design System (DS) serves as a common language bridging design and development. A well-crafted system not only empowers designers to engage with coding but also enables engineers to participate in the design process. Realizing this might sound a bit abstract, let’s delve into the more concrete details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvxa6kt4kqin18wy5wxd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqvxa6kt4kqin18wy5wxd.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve discussed components and guidelines, which are a solid foundation. However, a Design System (DS) encompasses much more than just these elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i7r7d1jcujm9vorvzy8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i7r7d1jcujm9vorvzy8.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There should be an even more granular aspect to the components of a Design System (DS). These are the tokens. Tokens represent the smallest parts of the design system, serving as the fundamental building blocks of the components. The most apt definition I’ve come across is that tokens are context-agnostic primitive values that define visual styles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgweqe6ylju6zwoya34m5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgweqe6ylju6zwoya34m5.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above the components, we have page layouts. These layouts serve as the structural backbone, or the skeleton, of the page. They define the grid system and the spacing between components. To achieve a consistent layout, it’s essential to:&lt;/p&gt;

&lt;p&gt;Know Your Use Case: Understand the purpose and utilization of the information on the page.&lt;/p&gt;

&lt;p&gt;Prioritize Your Content: Strategically organize content to emphasize the most crucial information.&lt;/p&gt;

&lt;p&gt;Group Related Content Together: This ensures efficiency and ease for users when navigating and interacting with the content. Beyond guidelines, another critical aspect is the presence of documentation and playgrounds. A golden rule in design systems is: if it’s not documented, it doesn’t exist. Playgrounds provide a practical space where you can observe components in action, understanding their usage and behavior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem0032z5834zd56ntpzu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem0032z5834zd56ntpzu.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How does the user interact? Which devices are being used? What environments do these interactions occur in? At what times do users typically engage with the system?&lt;/p&gt;

&lt;p&gt;Let’s spend a few minutes discussing interaction models, as well as the voice and tone of user interfaces, highlighting their importance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam8fm4etnmlw8xf6gnf9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fam8fm4etnmlw8xf6gnf9.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is an Interaction Model? An interaction model addresses how users interact with a system, considering the devices used, the environments in which these interactions occur, and the timing of these interactions.&lt;/p&gt;

&lt;p&gt;Take, for example, my company, which develops software for managing medical centers and patient engagement. Here’s a typical user flow: Before taking an exam, a patient needs to fill out a form. Our platform sends an SMS with exam preparations and a link to the online form. The patient has the flexibility to complete parts of the form online and the remainder on paper at our center. Additionally, there’s a screening form that the patient may need to answer, which is also used by the technologist.&lt;/p&gt;

&lt;p&gt;This scenario presents various environments, devices, and communication mediums through which the patient interacts with our product. It’s crucial to ensure the patient feels comfortable and confident with these interactions. For instance, the paper forms should mirror the look and feel of the online forms to facilitate a smooth transition and avoid patient confusion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw6z2hnwqjcid745xpeg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw6z2hnwqjcid745xpeg.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building on the previous example, we can see that the voice and tone of the product are also crucial. Different communication formats require tailored approaches. For instance, SMS messages need to be short and concise, while forms demand thoroughness and clarity. In screening forms, an empathetic and supportive tone is essential. However, across all these formats, it’s important to maintain a consistent language that builds trust and confidence in the product.&lt;/p&gt;

&lt;p&gt;In the slide’s example, the voice used in an error message plays a significant role in building trust with users. It helps the product stand out and maintain consistency by reflecting the brand’s personality. The tone of the message, incorporating elements like empathy and humor, adds clarity and a personal touch to the product, enhancing user engagement and experience.&lt;/p&gt;

&lt;p&gt;YouTube short on the building blocks of a DS:&lt;br&gt;
&lt;a href="https://www.youtube.com/shorts/Lo3H9jFNSxg"&gt;https://www.youtube.com/shorts/Lo3H9jFNSxg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have a clearer understanding of what a design system is, let’s discuss whether we should build one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm13su5qowefd5gfvh835.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm13su5qowefd5gfvh835.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key to answering whether to build a design system lies in asking yourself a series of questions. Are there ‘villains’ lurking in the shadows of your project? Are you grappling with recurring problems that seem unsolvable? Think of these villains as well-defined and clearly identified problems. In the realm of design systems, these challenges are often quite evident. The goal is to highlight these issues and address them effectively — like bringing in a hero to vanquish these villains.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9dq2eoqf5v4kx7johik.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9dq2eoqf5v4kx7johik.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s start by identifying our villains.&lt;/p&gt;

&lt;p&gt;Inefficiency&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftbz78ygbv61qqhzzwj0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftbz78ygbv61qqhzzwj0.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Redundant Component Creation: One major issue is the repetitive building of the same components. This not only consumes valuable time and resources but also leads to inconsistency across the project. Multiple Changes Required: Another challenge is the need to make changes in several places for a single update. This can lead to errors and inconsistencies, making the process inefficient and cumbersome. Costly Redesigns: Redesigning components or sections of a project can be an expensive affair. It’s not just about the direct costs; it also involves the time and resources spent in redoing work that could have been done correctly the first time. To put it in perspective, “…the inefficiencies that a medium-sized team might manage are disastrously wasteful for a team of our size.” This statement underscores the amplified impact of inefficiency in larger teams, where the scale of the project magnifies every redundant task and misstep.&lt;/p&gt;

&lt;p&gt;Insecurity&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figg6ucnalzgtxqslskxm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figg6ucnalzgtxqslskxm.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Lack of Confidence in Building and Designing: A common issue is the uncertainty developers and designers face when creating new components. This lack of confidence can stem from a variety of sources, such as unfamiliarity with the overall design language or uncertainty about the project’s direction. Unclear Best Practices: Another factor contributing to insecurity is the ambiguity about best practices. Without clear guidelines, team members may question whether they are following the most efficient and effective methods in their work. Reuse of Components: Often, there is uncertainty about the reusability of existing components. Developers and designers might not know if they can, or should, reuse components, leading to unnecessary duplication of effort. Component Suitability: Frequently, team members are unsure if there already exists a component that fits their specific use case. This uncertainty can lead to the creation of redundant components or the misuse of existing ones, affecting the coherence and efficiency of the project. These insecurities, while seemingly minor, can significantly impede the progress of a project, leading to delays, decreased productivity, and a fragmented design approach.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhp6x8938zcr350h7re9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhp6x8938zcr350h7re9.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do the components look? How do they function within a form? How does the form fit into the overall layout? And how do these scenarios play out across different interaction models?&lt;/p&gt;

&lt;p&gt;Inconsistenc&lt;br&gt;
y&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v5rtrq0qh8d3xfz96f4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v5rtrq0qh8d3xfz96f4.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Varied Approaches to Similar Actions: A key issue is when the same user actions are executed differently across various parts of the application. This lack of uniformity can stem from different team members interpreting design guidelines differently or from updates that don’t get uniformly applied across all components.&lt;/p&gt;

&lt;p&gt;Impact on User Confidence: This inconsistency can lead to users losing confidence in the product. When users encounter different behaviors for similar actions, it disrupts their learning and adaptation process. They might find themselves having to relearn how to perform tasks they previously understood, leading to frustration and a diminished user experience.&lt;/p&gt;

&lt;p&gt;Increased Cognitive Load: Inconsistent design increases the cognitive load on users as they navigate through different parts of the application. Instead of a seamless interaction, users are forced to constantly adjust to varying interfaces and controls, which can be both confusing and time-consuming.&lt;/p&gt;

&lt;p&gt;Challenge in Maintaining Brand Identity: Consistency is also vital for maintaining a strong and recognizable brand identity. Inconsistent design elements can dilute the brand’s message and make the product feel disjointed, ultimately affecting the overall perception of the brand. Addressing these inconsistencies is crucial for providing a smooth, user-friendly experience that enhances confidence and satisfaction with the product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pqjc9qpv553mc8o45r5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pqjc9qpv553mc8o45r5.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Design Support is Essential:&lt;/p&gt;

&lt;p&gt;Need for a Dedicated Team or Freelancers: Effective design systems require dedicated support — be it a team solely focused on the system, freelancers bringing fresh perspectives, or passionate individuals championing the cause. This dedicated attention ensures the system’s continuous improvement and alignment with the project’s goals.&lt;/p&gt;

&lt;p&gt;Building and Maintaining a Strong Brand: A robust design system plays a crucial role in brand building. It requires a harmonious blend of good design and development practices. The design system becomes a visual and functional representation of the brand, making it crucial to the brand’s identity and perception.&lt;/p&gt;

&lt;p&gt;Consensus and Vision for Brand Consistency: Achieving a consistent brand image through your design system requires a shared vision and consensus among all stakeholders. This unified approach ensures that every design element aligns with the brand’s ethos and messaging.&lt;/p&gt;

&lt;p&gt;Adaptability to Change and Expansion: As the brand evolves and market needs change, the design system should be flexible enough to adapt and expand. This adaptability is key to staying relevant and effective, ensuring that the design system grows with the brand and continues to meet user expectations. In essence, having strong design support and a clear brand vision are vital. They ensure that the design system not only serves its immediate functional purposes but also contributes to building and maintaining a strong, adaptable brand identity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm594p8g0tbxcrbdqfgnu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm594p8g0tbxcrbdqfgnu.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s begin by exploring the foundational element of the design system: the tokens. These tokens are critical as they represent the core building blocks, setting the stage for the overall look and functionality of the system.&lt;/p&gt;

&lt;p&gt;Let’s take a deep dive into the world of tokens to understand what they are and how they’re utilized in design systems. Tokens play a crucial role in various aspects:&lt;/p&gt;

&lt;p&gt;Efficient Management of Design Systems: Tokens streamline the management process of design systems. They act as the fundamental elements that can be reused and repurposed, simplifying the design process and ensuring uniformity across different projects or components.&lt;/p&gt;

&lt;p&gt;Facilitating Translation from Design to Development: Tokens bridge the gap between design and development. They provide a common language that both designers and developers can understand, ensuring that the visual intent in the design phase is accurately translated into the development phase.&lt;/p&gt;

&lt;p&gt;Ensuring Consistency Across Product UI: Perhaps most importantly, tokens help maintain a high level of consistency across a product’s user interface. By defining and standardizing visual and stylistic elements, they ensure that the user experience is cohesive and harmonious, regardless of where in the product the user is.&lt;/p&gt;

&lt;p&gt;By exploring the purpose and utilization of tokens, we can better appreciate their significance in creating and maintaining effective and efficient design systems.&lt;/p&gt;

&lt;p&gt;Let’s walk through a collaboration scenario between a designer and a developer and see how tokens can help us.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgt5450q2j8dglj099zla.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgt5450q2j8dglj099zla.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without tokens, communication between engineers and designers can often be inefficient. For instance, an engineer might ask the designer for the color of the text. The designer responds, ‘It’s Flat Onyx.’ This description, however, isn’t immediately useful to the engineer, who needs the specific hex value. Upon request, the designer provides it: ‘#FFB549.’ The engineer then applies this color and moves on to the next task.&lt;/p&gt;

&lt;p&gt;A week later, the designer decides to change the color. Previously, without tokens, this would mean the engineer having to update the color in as many as 10 different places, a time-consuming and error-prone task. This scenario underscores the inefficiency of working without a standardized system like tokens.&lt;/p&gt;

&lt;p&gt;This is precisely where a token proves invaluable. The designer assigns the name ‘Flat Onyx’ to the hex value ‘#FFB549’ in the form of a token. The engineer then utilizes this token in the code. If the designer later decides to change the color associated with ‘Flat Onyx,’ they only need to update the token’s hex value. The engineer doesn’t have to make any changes in the code, as the token automatically reflects the new color value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftn7zljt9vkkjnci15d5o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftn7zljt9vkkjnci15d5o.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have the ability to establish our global tokens, which serve as foundational elements in our design system. These tokens can represent a wide array of values, including colors, typography, spacing, shadows, borders, and more. By defining these elements as tokens, we create a unified and consistent set of design standards that can be easily applied and modified across our entire product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0s443t63v5hfohkyj7y3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0s443t63v5hfohkyj7y3.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As days pass, our engineers diligently work on implementing new features. Now, we have an array of elements like buttons, toggles, and checkboxes, all styled using the global tokens. However, the designer decides that the buttons need a tweak — specifically, the text color should be changed to white. Upon receiving this update, the engineer reviews the designs and realizes a challenge. With a sigh of ‘Oh my stars!’ he faces the task of manually updating the styles for each button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmalcirb6e1xn8vs2dzbs.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmalcirb6e1xn8vs2dzbs.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where another layer of tokens becomes highly beneficial. We can introduce various levels of alias tokens, such as semantic tokens and component tokens. Semantic tokens are those used across multiple components. For example, a token for text color could be applied universally. On the other hand, component tokens are specific to a single component. A token for the color of button text is a good example. By using these different token types, we gain the flexibility to either update all components universally or target a specific component for changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmosvkzxcg0lolvm0yqf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmosvkzxcg0lolvm0yqf.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s useful to establish a naming convention for semantic tokens, ensuring they are easily recognizable. For instance, we can incorporate aspects like sentiment, usage, prominence, and interaction into the naming of our tokens. This approach helps in quickly identifying the purpose and application of each token.&lt;/p&gt;

&lt;p&gt;For example, a token could be named ‘selected-text-default-color,’ clearly indicating its use and function.&lt;/p&gt;

&lt;p&gt;To prevent the engineer from having to manually update tokens in the code, we can utilize a tool like Style Dictionary. Our design tool, Figma in this case, can export the tokens as a JSON file and commit them to a repository. We then employ Style Dictionary to generate the tokens in the required format and automate the commit to the repository. This process simplifies the engineer’s workflow significantly. They simply need to pull the latest changes, and voilà, they have the updated tokens.&lt;/p&gt;

&lt;p&gt;YouTube short about tokens:&lt;br&gt;
&lt;a href="https://www.youtube.com/shorts/cf_zVovyzyw"&gt;https://www.youtube.com/shorts/cf_zVovyzyw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftho2wkpiaoeptog638t4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftho2wkpiaoeptog638t4.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve established our tokens, it’s time to start constructing our components. It’s crucial to clearly define each component’s purpose, specifying what it is intended for and, equally importantly, what it should not be used for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vjp8hi0zurqkr2ayfk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vjp8hi0zurqkr2ayfk.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s delve into API design for components. What constitutes the API of a component? It’s essential to define how the component is used, including its inputs and outputs. Consistency in naming is crucial to avoid confusion. A good rule of thumb is to use prefixes, which helps prevent name collisions. Additionally, it’s advisable to limit the number of inputs and outputs to maintain simplicity and clarity in the component’s functionality.&lt;/p&gt;

&lt;p&gt;Avoid using functions or complex objects as inputs for your APIs. Additionally, consider carefully when to utilize imperative APIs versus those that are configuration-based. This decision can significantly impact the simplicity and efficiency of your API’s interaction model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8epeor0woyjw83faxp6u.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8epeor0woyjw83faxp6u.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regarding dependencies, it’s advisable to limit or avoid relying on external dependencies beyond the essential framework. Where possible, consider building components in-house or using headless components. This approach helps in minimizing potential conflicts and inconsistencies, ensuring a more streamlined and reliable system&lt;/p&gt;

&lt;p&gt;When it comes to tooling, it’s beneficial to begin with the tools provided by the framework itself. These tools typically come equipped with best practices, optimizations, and backward compatibility right out of the box. Leveraging these built-in features can lead to a more efficient and effective development process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5ufejiclemkx9n2cbda.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5ufejiclemkx9n2cbda.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
In terms of testing, it’s crucial to incorporate several key practices:&lt;/p&gt;

&lt;p&gt;Utilize Rendering in Unit Tests: This ensures that components render correctly and function as expected.&lt;/p&gt;

&lt;p&gt;Set Up Linting and Formatting: These tools help maintain code quality and consistency, making it easier to identify and fix errors.&lt;/p&gt;

&lt;p&gt;Implement Template Checking: Regularly check templates for errors or issues that could affect performance or user experience.&lt;/p&gt;

&lt;p&gt;Verify Input Types: Ensure that all inputs are correctly typed to prevent unexpected behavior or errors.&lt;/p&gt;

&lt;p&gt;Ensure Template Safe Navigation: This helps in avoiding runtime errors by ensuring that templates gracefully handle null and undefined values.&lt;/p&gt;

&lt;p&gt;Consistent Naming Conventions: Maintain clarity and ease of understanding with consistent naming across your codebase.&lt;/p&gt;

&lt;p&gt;Schematics:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuhac9zkqkh5vwsllfxv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffuhac9zkqkh5vwsllfxv.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installation: Detailing the procedures and requirements for properly installing the design system.&lt;/p&gt;

&lt;p&gt;Migration: Outlining the steps and best practices for transitioning existing projects or elements to the new design system.&lt;/p&gt;

&lt;p&gt;Generator: Providing tools or scripts that facilitate the automatic generation of components or code within the design system framework.&lt;/p&gt;

&lt;p&gt;In addition to the core elements, several other crucial components live within a design system:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcwzcv5l15xevtporwa0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcwzcv5l15xevtporwa0.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Documentation: Comprehensive guides and references that detail the design system’s components, usage, and best practices.&lt;/p&gt;

&lt;p&gt;Live Code Playground: An interactive environment where developers can experiment with code and see the immediate effects within the design system.&lt;/p&gt;

&lt;p&gt;Usage Examples: Practical demonstrations of how components and elements can be utilized within projects.&lt;/p&gt;

&lt;p&gt;Platform Guidelines: Specific instructions and standards tailored to different platforms to ensure consistency and optimal performance.&lt;/p&gt;

&lt;p&gt;UX Guidelines: Principles and rules that guide the user experience design, ensuring that the system is user-friendly and intuitive.&lt;/p&gt;

&lt;p&gt;Storybook: This tool provides a unique space where developers can experiment and play around with components, without the need for local installation. It’s incredibly beneficial for several reasons:&lt;/p&gt;

&lt;p&gt;Interactive Environment: Developers can interact with components in real-time, providing a hands-on understanding of how each element functions within the system.&lt;/p&gt;

&lt;p&gt;Usage Examples: Beyond just checking bindings and events, Storybook allows developers to see components in action, offering practical usage examples. This helps in understanding how these components behave in real-world scenarios.&lt;/p&gt;

&lt;p&gt;Application Paradigms: It aids in exploring different paradigms of your application, such as modals, to determine the best implementation strategies.&lt;/p&gt;

&lt;p&gt;Reusable Components: In this isolated environment, developers can focus on creating components that are not only functional but also reusable across different parts of the application. Storybook essentially serves as a laboratory for developers to test, iterate, and perfect components before they’re integrated into the main application.&lt;/p&gt;

&lt;p&gt;Key Considerations to Keep in Mind:&lt;/p&gt;

&lt;p&gt;Flexibility Over Conformity: Avoid forcing applications to strictly adhere to your library. Allow some flexibility for specific needs and contexts.&lt;/p&gt;

&lt;p&gt;Graceful Exception Handling: Instead of allowing exceptions to disrupt the user experience, handle them gracefully and thoughtfully.&lt;/p&gt;

&lt;p&gt;Prioritizing Accessibility: Always remember to design with accessibility in mind. It’s not just a feature, but a fundamental aspect of inclusive design.&lt;/p&gt;

&lt;p&gt;Regular SSR Testing: Test for Server-Side Rendering (SSR) early and frequently. This helps in identifying and resolving potential issues well in advance.&lt;/p&gt;

&lt;p&gt;Avoid Premature Additions: Be cautious about adding new features or components until there’s a definitive need or use case for them. This helps keep the system lean and relevant.&lt;/p&gt;

&lt;p&gt;Direct DOM Manipulation: Refrain from directly manipulating the Document Object Model (DOM), as this can lead to performance issues and conflicts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvovj4mvn2wpkgc5yy478.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvovj4mvn2wpkgc5yy478.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we reach the end of our journey through the labyrinth of design systems, it’s clear that the challenges — the ‘villains’ lurking in the shadows of our projects — are formidable. They come in the guise of inefficiency, inconsistency, and a myriad of other obstacles that can thwart even the most experienced teams. But fear not, for in every story filled with villains, there emerges a hero. In our narrative, this hero is the design system we’ve meticulously crafted.&lt;/p&gt;

</description>
      <category>ui</category>
      <category>webdev</category>
      <category>designsystem</category>
      <category>ux</category>
    </item>
    <item>
      <title>From Greenfield to Minefield and back</title>
      <dc:creator>DadCod</dc:creator>
      <pubDate>Tue, 16 Jan 2024 19:31:21 +0000</pubDate>
      <link>https://dev.to/dadcod/from-greenfield-to-minefield-and-back-56ef</link>
      <guid>https://dev.to/dadcod/from-greenfield-to-minefield-and-back-56ef</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8fEx7i9TOEY"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;a href="https://dadcod.es/blog/from-greenfield-to-minefield"&gt;original post&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The dream
&lt;/h2&gt;

&lt;p&gt;Imagine starting on a brand-new project. It's a blank canvas, no legacy code, no one to blame.&lt;br&gt;
It's up to you and your team to build a state-of-the-art application.&lt;br&gt;
As months go by and new colleagues join, they open the project and can't help but stop every few minutes, not to troubleshoot,&lt;br&gt;
but to admire the code you've crafted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5d4xorqyn5vd3vv52nd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5d4xorqyn5vd3vv52nd.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;Unfortunately, this ideal scenario is rare, but perhaps the insights I share here can help make it a reality for you.&lt;br&gt;
Let's walk through our project's timeline together and identify potential pitfalls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57zxbczm4cn29i7p26mg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57zxbczm4cn29i7p26mg.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  DISCLAIMER
&lt;/h2&gt;

&lt;p&gt;This isn't a step-by-step guide on how to build and scale a project from scratch.&lt;br&gt;
Instead, I'll share our journey, the key decisions we made, the problems we encountered, and our solutions.&lt;br&gt;
The focus will be on technical aspects, and while touching upon architectural topics,&lt;br&gt;
I'll avoid definitive statements, offering a more philosophical perspective instead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69a9g5ufzm4g5msory4x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69a9g5ufzm4g5msory4x.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Project timeline
&lt;/h2&gt;

&lt;p&gt;Using the project timeline as a framework, I'll highlight key decisions, milestones, team size, and challenges we faced.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsm82bu8ldjpg5h68p6ob.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsm82bu8ldjpg5h68p6ob.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing a framework
&lt;/h2&gt;

&lt;p&gt;This is one of the controversial topics that I won't go into much detail about, but I will share my experience and the reasons why we chose Angular. For context, the project is a web application used by doctors and patients. It's a medical platform designed to help doctors manage their patients' health.&lt;/p&gt;

&lt;p&gt;The project began in late 2019. The initial members of the team were mostly backend (BE) oriented, with experience in Java and Spring. Angular was a logical choice for us because its mental model is similar (i.e., class components, services, dependency injection) and the language, TypeScript, is also similar. As a small team, the assistance of BE developers was invaluable, making Angular a sound choice.&lt;/p&gt;

&lt;p&gt;Another important point is that we don't have dedicated architects. We are all equally responsible for the architecture of the project. When making a technical decision, we follow an RFC (Request for Comments) process. Typically, the person with the most experience and interest in the topic writes the RFC, and then we discuss it as a team to make a decision. This approach has its pros and cons. On the plus side, everyone is involved in the decision-making process and takes responsibility for the outcomes. However, it can be time-consuming, challenging to please everyone, and sometimes there's no clear right answer.&lt;/p&gt;

&lt;p&gt;In this case, Angular also made sense because it was quite mature and opinionated at the time. For instance, if you need a router, Angular provides a built-in one; for HTTP requests, there's a built-in service; and for testing, it's all built-in as well. Had we chosen React, we would have had to spend more time on the initial setup and make more decisions about the project's architecture.&lt;/p&gt;

&lt;p&gt;Moreover, Angular had been quite stable for a couple of years, with new updates being backward compatible (a lesson they likely learned from AngularJS). In contrast, React was constantly evolving (e.g., class components then functional components, hooks, server components, etc.), with many breaking changes.&lt;br&gt;
A great article on that topic is &lt;a href="https://betterprogramming.pub/i-almost-got-fired-for-choosing-react-in-our-enterprise-app-846ea840841c"&gt;this one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The other options at that time didn't seem as reliable.&lt;/p&gt;
&lt;h3&gt;
  
  
  About frameworks
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“…web dev is a pop culture with no regard for history\, dooming each successive generation to repeat the blunders of the old\, in a cycle of garbage software\, wrapped in ever-escalating useless animations\, transitions\, and framework rewrites.”&lt;br&gt;
a quote from a favourite &lt;a href="https://www.baldurbjarnason.com/2021/100-things-every-web-developer-should-know/"&gt;blog post&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The framework is just a tool which helps you get the job done. Think about what suits better the business case and helps you build the features that you need. It is easier learning new framework then making the wrong framework fit your case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphzf67898ldhylh8qfna.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphzf67898ldhylh8qfna.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing a testing framework
&lt;/h2&gt;

&lt;p&gt;As I mentioned earlier, Angular comes with a built-in testing framework called Karma.&lt;br&gt;
Karma is a test runner that operates in the browser.&lt;br&gt;
However, it spawns a new browser instance for each test, which tends to be slow.&lt;br&gt;
Therefore, we decided to switch to Jest, a test runner that operates in the command line.&lt;br&gt;
Jest is generally easier to integrate with CI/CD pipelines and is reputed to be faster. It also offers a lot of features right out of the box.&lt;/p&gt;

&lt;p&gt;To be honest, I'm not entirely sure if we made the right choice. We found ourselves spending a considerable amount of time optimizing the tests to run faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgquxrztuhw2rig1ivq5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgquxrztuhw2rig1ivq5.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my experience, testing is often overlooked, but it's crucial, especially in large, evolving projects.&lt;br&gt;
Setting up a solid testing framework from the start makes writing tests easier and more effective.&lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing repository structure
&lt;/h2&gt;

&lt;p&gt;The company grew, and I joined 🎉. We split into two teams and faced the decision of choosing an approach for our repository.&lt;br&gt;
We opted for a monorepo, bringing together the backend (BE) and frontend (FE) code.&lt;br&gt;
This strategy allowed us to move swiftly, enabling us to create merge requests (MRs) that encompassed changes in both areas.&lt;br&gt;
It facilitated easy code sharing, as we had a shared library for common code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd84eac3u5zk144u2mz3d.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd84eac3u5zk144u2mz3d.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We chose nx as our tool to manage the monorepo.&lt;br&gt;
It offers several beneficial features, such as enforcing module boundaries, creating a dependency graph, and building and testing only the projects affected by changes.&lt;br&gt;
The configuration process is straightforward - you simply add your project to the nx.json file, and you're all set.&lt;br&gt;
Additionally, nx provides linting and formatting right out of the box.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nx.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"implicitDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"angular.json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;".eslintrc.json "&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projects"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patient-portal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"staff-portal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"refmd-portal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;--&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.eslintrc.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"@nrwl/nx/enforce-module-boundaries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"enforceBuildableLibDependency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"depConstraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sourceTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"onlyDependOnLibsWithTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;As our team grew, we began developing a new part of the product and needed to add another project.&lt;br&gt;
To make it easier, we created a shared library for common code, so we could quickly reuse components, services, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi7m8xly2cin2kmuda9w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi7m8xly2cin2kmuda9w.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this method had its limits. It was fine at first, but as we grew, it started to cause some problems, especially with testing.&lt;br&gt;
In Angular, you can do two kinds of tests. One is pure unit tests where you test just the component by itself, mocking the parts it depends on.&lt;br&gt;
The other is integration tests where you test the component with all its connected parts, like mocking HTTP requests in the real app setting.&lt;br&gt;
We often found integration tests more useful because they let us see how components worked together in the app.&lt;/p&gt;

&lt;p&gt;The trouble was, for integration tests, we had to bring in all the modules a component used.&lt;br&gt;
This got tough when a component used a lot of modules.&lt;br&gt;
The easiest way seemed to be using the shared module, so we could get all dependencies in one go.&lt;br&gt;
But this meant we were bringing in a bunch of stuff we didn't really need, and that problem started to become pretty obvious...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69g6yatku0719z9ea6nj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69g6yatku0719z9ea6nj.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main lesson for us was to keep a close eye on our tests, especially how long they take to run.&lt;br&gt;
If the test time starts increasing, we need to understand why.&lt;br&gt;
We found ourselves having to redo our tests, making sure we only used the modules we really needed.&lt;br&gt;
We also got stricter with reviewing merge requests for unit tests, to avoid including modules we didn't need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v2ucahvzodnk2g7ovec.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v2ucahvzodnk2g7ovec.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Library strategy
&lt;/h2&gt;

&lt;p&gt;With our monorepo setup, we had to be extra careful about how projects depended on each other.&lt;br&gt;
Our shared library turned into a kind of catch-all place where everything ended up.&lt;/p&gt;

&lt;p&gt;Anyhow, this big-brain library strategy started to "shine" when we had to add yet another project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7inn2ogun668sq65579.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7inn2ogun668sq65579.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the shared library started to become a mess. There was stuff that Project1 and Project2 needed but Project3 didn't, and vice versa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqfy0mtghsjf98sxnb65.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqfy0mtghsjf98sxnb65.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We needed to divide the shared library into two parts: one for sharing resources across all projects, and the other for sharing between specific projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rbfcjp94o9p1biiltg6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rbfcjp94o9p1biiltg6.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This approach wouldn't scale well. Although it was easy at first to keep up the pace, it presented some challenges.&lt;br&gt;
We were finally forced to rethink our strategy.&lt;/p&gt;

&lt;p&gt;To sum up the takeaways:&lt;br&gt;
Having one large shared library is definitely not the way to go if you want to scale. You end up not only importing things you don't need but also making it hard to find stuff.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7f77thwv8gmg9bhrgfk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7f77thwv8gmg9bhrgfk.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what is the solution? As with everything in software development it depends and there are tradeoffs.&lt;br&gt;
The engineers from the team have all worked with different approaches and we had to find a common ground.&lt;br&gt;
The first and most common one that we all had experience with was one library per component.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft369kyr1dzcko26kp6bv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft369kyr1dzcko26kp6bv.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My personal experience with that approach was quite extreme: one library per component, each separated into a different repo and exposed as an npm package in an internal registry.&lt;/p&gt;

&lt;p&gt;It was a nightmare to develop, test, and maintain. I recall the npm link often not working as expected. Versioning wasn't clear, and the release process was cumbersome.&lt;br&gt;
In the end, it typically turned out that every consumer needed the latest version anyway.&lt;br&gt;
I believe others had similar experiences, leading us to decide on a different approach.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh8xk29rgt346xnjtq6p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh8xk29rgt346xnjtq6p.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We evaluated the DDD (Domain-Driven Design) approach, as we were already using it in some areas of the backend.&lt;br&gt;
The advantage of DDD is its ease in separating domain logic, but this is effective only with clearly defined context boundaries.&lt;br&gt;
In our case, we were concerned about the potential for excessive overhead.&lt;br&gt;
We feared frequent refactoring and moving code around just to align with the DDD principles.&lt;br&gt;
Therefore, we decided to explore the nx approach.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy6tld0cc5tvpn49k3vz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy6tld0cc5tvpn49k3vz.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We would organize libraries by context. More specifically, we would have feature, UI, data access, and utility libraries.&lt;br&gt;
This way, if we have some clearly defined bounded contexts, we can encapsulate them into fully functional feature libraries.&lt;br&gt;
Otherwise, we can distribute reusable blocks across UI and data access libraries.&lt;br&gt;
This approach seemed like a good middle ground.&lt;/p&gt;

&lt;p&gt;The key takeaway here is: once you need to share code between projects, it's crucial to think about structure.&lt;br&gt;
If you don't, you're merely postponing the problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6o484mg1liyxnio0eg8x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6o484mg1liyxnio0eg8x.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Testing
&lt;/h2&gt;

&lt;p&gt;We got back on track and continued developing features, resulting in a functional part of the product.&lt;br&gt;
It was then time to test it with real users. This step was crucial to verify our assumptions and guide us in prioritizing upcoming features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p68af0gvs19rjbkmc6n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p68af0gvs19rjbkmc6n.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We didn't have to wait long before we got the first unexpected feedback.&lt;br&gt;
It became apparent that internet reliability in the medical centers wasn't as high as we had anticipated.&lt;br&gt;
Consequently, we needed to enhance the app's performance, ensuring it functioned smoothly even with poor internet connections.&lt;br&gt;
Specifically, we focused on improving load times and managing request timeouts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabxwpcaghujlpkz4188q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabxwpcaghujlpkz4188q.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Improving the FCP (First Contentful Paint) was a top priority, and a logical starting point was the bundle size.&lt;br&gt;
Our investigation into the bundle size revealed several surprises.&lt;br&gt;
Notably, about 20% of the bundle size came from moment.js, as our import method wasn't tree-shakeable.&lt;br&gt;
This meant we were including all the locales in our bundles.&lt;br&gt;
Additionally, for some of the npm packages like rxjs and lodash, not using es6 imports meant we had to include the entire package.&lt;br&gt;
These accounted for another approximately 7% of the bundle size.&lt;br&gt;
Therefore, by switching to es6 imports and properly tree-shaking moment.js, we could potentially reduce our bundle size by around 27%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fau1ct7dkh2jiph5ww5bl.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fau1ct7dkh2jiph5ww5bl.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another method to enhance UX is by achieving a faster FP (First Paint).&lt;br&gt;
One option is using SSR (Server Side Rendering), but it introduces considerable complexity.&lt;br&gt;
It requires a node server to render the app, necessitates working around browser APIs, and calls for cautious handling of URLs, among other challenges.&lt;br&gt;
Alternatively, we could manually inline the critical CSS and JS. We opted for this second approach, as it was simpler to implement and maintain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntvt0bycyn4sz5i9ig0o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntvt0bycyn4sz5i9ig0o.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another area for improvement involved request timeouts.&lt;br&gt;
Initially, if a request timed out, we displayed a generic error, leaving the user unaware of the specific problem.&lt;br&gt;
To address this, we decided to implement a linear backoff strategy. This approach allowed us to retry the request a few times before presenting the error to the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbcgfx0r3u9s8utnjs3k.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbcgfx0r3u9s8utnjs3k.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RequestIdHeader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failedRequestsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFailedRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestRetries&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;backoffInterval&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regularly review the bundle size every time you add a new npm package.&lt;/li&gt;
&lt;li&gt;Stay vigilant about core web vitals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to share another favorite quote of mine (from the same blog post I first linked to):&lt;br&gt;
&lt;em&gt;"Tight feedback loops are magic: live reloading is magical. Hot module replacement less so. With live reload, your development browser automatically reloads your dev page when your code changes. If you suck and your page loads slowly, then you suffer. Hot module replacement hides the pain and lets you pass the suffering onto the user."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8su2j3s1h7043jhcgz3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8su2j3s1h7043jhcgz3.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  State management
&lt;/h2&gt;

&lt;p&gt;The project was expanding rapidly. We were adding numerous features, components, and services.&lt;br&gt;
Eventually, we encountered our first complex state management issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg33k8xjr0p6gwf0i3zts.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg33k8xjr0p6gwf0i3zts.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Up until then, we had used a basic approach: employing a service that maintained the state and exposed it as an observable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StateService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
  &lt;span class="nx"&gt;state$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, we faced a situation where we needed to enhance PDF documents, which involved linking and categorizing pages, adding notes, creating entities for each page, and more.&lt;br&gt;
This task turned our simple approach into one cluttered with complex RxJS statements.&lt;br&gt;
We lacked set rules, such as ensuring the immutability of the state, handling side effects and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp740chv8lcv1c7nyq074.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp740chv8lcv1c7nyq074.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We had to rethink our approach to find a solution suitable for such complicated scenarios.&lt;br&gt;
All of us had previous experience with Redux in the form of ngrx, but we weren't fans of it.&lt;br&gt;
There was too much boilerplate, too much ceremony, and an excessive amount of code for simple tasks.&lt;br&gt;
It required all engineers to be well-versed in its use and even then, it was easy to create a chaotic mess.&lt;br&gt;
So, we decided to search for an alternative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2hg7tu5m7ku6l5o6n1t.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2hg7tu5m7ku6l5o6n1t.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We discovered Akita, which was lightweight, required minimal boilerplate, and integrated well with Angular's services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F172bb8rd8ulblvnl5a70.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F172bb8rd8ulblvnl5a70.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall, I'm glad we managed to survive for so long without a dedicated state management library.&lt;br&gt;
Navigating through the complexities and challenges of state management without this tool taught us invaluable lessons.&lt;br&gt;
We experienced firsthand the pitfalls to watch out for and gained a deeper understanding of the essential features and functionalities we truly needed in a library.&lt;br&gt;
This journey wasn't just about coping with the immediate difficulties; it was a learning curve that equipped us with the insights to make more informed decisions in selecting the right tools for our needs in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8jkfj4ppc2wyeb4s7co.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8jkfj4ppc2wyeb4s7co.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Along the way, we encountered numerous other decisions and challenges.&lt;br&gt;
These included questions like how to handle styling, logging, and observability, or whether to use MFE (Micro Frontends).&lt;br&gt;
We even tackled implementing our own design system (which I'll discuss in another article) and delved into improving UX and exploring different rendering strategies (also covered in a separate article).&lt;br&gt;
The journey was filled with such considerations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90omb7oc5nsetqeosuwh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90omb7oc5nsetqeosuwh.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope the insights shared in this article will help you sidestep some of the mistakes we made.&lt;br&gt;
Ideally, your greenfield project will remain flourishing for a longer period.&lt;br&gt;
And even if it does turn into a minefield, now you'll have a better idea of how to navigate through it.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
