During my initial attempt to create an application that streamlined the printing of guest receipts at a hotel, I was oblivious to the significance of structured designs and file organisation. Following a year, the hotel management requested me to augment the application’s functionality. However, the suboptimal structure I had initially instituted was so precarious that starting anew was the only way forward. It was comparable to the childhood game of Mine Sweeper where making any small adjustment posed a significant risk of crashing the entire application. Despite two more attempts, I could not seem to get it right and therefore decided to enlist the services of a professional developer, which was financed by the hotel. Today, I lament the blundered approach I employed earlier and remorse for the inconvenience it caused our customer.
I want to express my gratitude to Brad Frost, who originally conceived and presented the Atomic Design concept. His insights have significantly impacted my programming methodology, helping me to think beyond the immediate problem and discover more efficient resolutions.
This blog intends to provide an original viewpoint to developers on how to organise the front end of their applications. The principle idea of Atomic Design is to break down complex user interfaces into simpler, more manageable components, resulting in a consistent and more structured user interface. Employing this method offers developers more freedom and adaptability in creating a versatile and scalable design, thereby making it easier to maintain.
Employing React’s Components
React has revolutionized the software development industry with its component-driven approach. However, I’ve noticed that several React-based applications fail to follow principles like Don’t Repeat Yourself (DRY), likely because the React Documentation lacks definitive guidelines for design patterns. Nonetheless, the technique of composition is highly recommended, and the React Documentation illustrates how to use it effectively to achieve diverse degrees of component specialisation.
Although these concepts are widely applicable to numerous web development frameworks, I opted for React while working on this project, considering its popularity. Although Facebook considers React to be a user interface library, I’ll avoid this discussion for another post.
Following the React front-end design approach, the UI/UX design team will offer the development team mockups for implementation. Using the Atomic design system, the components can be divided into fundamental particles (atoms), molecules (molecules), cells (cells), templates (pages), and documents (documents), forming the foundation of the hierarchical structure.
Why Opt for Atomic Theory?
I was introduced to the Atomic Design system while working on a vast React Single Page Application. Since there was a need for many bespoke components, existing CSS frameworks and libraries did not provide the requisite tools. Consequently, some components had to be created from scratch, utilising HTML elements and specialised CSS. The notion of having a central repository that contains all essential components was highly appealing and significantly expedited the development process.
Brad Frost, who created Atomic Design, likened web design to Chemistry, utilising the term “atoms” for the elementary components of an HTML webpage. Developers can utilize those elements to organise more intricate structures in various ways. The comparison can be found in Chemistry classes, where pupils study matter and living organisms by deconstructing them into individual parts. As a result, this same approach can be applied to any webpage, enabling developers to effectively assess and comprehend its structure.
When designing effective user interface designs, it is essential to employ Atomic Design principles. This approach concentrates on integrating distinct components, such as atoms, molecules, organisms, templates, and pages, to create a harmonious and coherent design system. Utilising this technique, designers can produce an interface that is both efficient and user-friendly, catering to its intended audience’s requirements.
Atoms are the essential elements of user interface (UI) components, including buttons, titles, input fields, and text. Together, they form the foundation of all of our modules, and breaking them down any further would make them unusable. Molecules are fundamental clusters of UI components designed to work in partnership. For example, an HTML Textfield may comprise numerous text inputs, a label, and an error message, while a Search Box may include both TextInput and Button components. UI organisms, however, are sophisticated entities composed of multiple diverse components, including molecules, atoms, and even other organisms, responsible for constructing different portions of an interface.
The design’s content structure can be deduced by examining the component arrangement within a template. Templates are basic blueprints of a page, devoid of any actual content. Pages, however, are concrete representations of design patterns that demonstrate how an interface functions with genuine data. Both templates and pages integrate the elemental building blocks of life, matter, and the universe, which establish the foundation of the user interfaces of a diverse range of software programs. When all of these components are combined, they create the user interfaces of our software applications.
Utilising the components we’ve been discussing, we can now create a rudimentary directory structure for our hypothetical codebase. It’s crucial to remember that folder placement can differ from one codebase to the next, hence it’s essential to communicate with your team members before making any modifications. In the above diagram, we have a Components folder that contains all of our front-end components, while a UI folder is where I store my smaller design elements separately from page-level configurations.
Among the most common concerns raised by my colleagues was the necessity to distinguish between the internal state of a component and the React application’s business logic. An example of a component’s internal state is the open/closed status of a dropdown menu button. To ensure precision, we should treat our components as if they were mock components but with the additional capacity to modify their states according to the properties we pass to them.
The building of this application’s components can be carried out independently of the rest of the program, enabling a more comprehensive evaluation and inspection with the aid of external sources such as a style guide before integration. As a result, a considerable dependence on the back-end application’s functionality will not be necessary for the front-end development.
When patterns have been established, the construction process can be hastened, resulting in greater adaptability in terms of design adjustments. Reusing components and designs from previous projects allows us to ensure a high degree of consistency.
Now that we have connected our Cascading Style Sheets (CSS) to specific components, our ability to manage it has substantially improved. Therefore, it is recommended that we only display the CSS required for the rendered components, which may vary depending on your application’s design.
When dealing with components that don’t exist within a specific context, utilising media queries can be challenging since the container housing them’s dimensions aren’t known. Since components are unaware of their own width, any resizing must be done in response to changes in the physical dimensions of the page.
Introducing layout components that encompass your components, resizing them as necessary, is a potential solution to this problem. To do so, we will incorporate CSS layout features like flex and grid into these layout components.
As seen in the above images, our app is in its basic form and requires a dependable approach to keep its components up-to-date. To achieve the best possible outcome, it’s important to distinguish between personal convictions and professional determinations (separation of concerns). Doing so will make it easier to pinpoint and resolve any code errors as the project progresses. Several strategies can be implemented to achieve this goal. In my opinion, the most effective ones are Higher-Order Components (HOC) and populating pages with arbitrary states via props. Additionally, the application’s state could consist of a sequence of API calls dispatched across various parts of the program. React-Hooks and the Render Props technique can also be utilised to further optimise the solution.
To illustrate, suppose each section of your system is symbolised by an empty bottle identical in colour and size to the one depicted in the image below, and each bottle is filled with a distinct hue of liquid. Updating your components’ state can be likened to altering the colour of the liquid in each bottle, if necessary, making updating your components’ status straightforward.
Suppose I fill my bottles halfway with red liquid initially but later opt to fill them with a different hue – if the colours don’t blend well, I may face problems. Furthermore, if I must substitute the existing colour with one of a different shade, it may become more challenging to refactor the code and reuse the view once business logic has already been implemented.
The approach I arrived at is…
React is impartial to technology and does not dictate how projects should be organised, but it’s typically recommended to limit the number of folder levels within a project to three or four. Certain features, such as aliases that are available in tools like Jest, Webpack, and Babel, may aid in resolving relative imports and reducing the intricacy of import statements.
This fantastic article by Katia Wheeler can be an initial reference for anyone keen on learning about Redux.
You may be interested in this relevant article: The Best React JS Books of 2023 According to Software Developers