Refactoring in the Frontend: Ideas and Reflections
Refactoring in frontend development is essential for various reasons. Firstly, it enhances the user experience by speeding up user interaction, reducing loading times, and improving accessibility.
Modernizing design is another crucial factor as design trends and standards continually evolve. Updating the interface’s appearance can keep the application attractive to users. Additionally, refactoring the visual aspects often leads to an improvement in the underlying code. This not only facilitates future maintenance but can also optimize system performance and scalability.
In our dashboard, a clear example of usability improvement lies in the manual user review process. Currently, users can choose between various states and accept or reject a user while adding reasons for acceptance/rejection.
During the dashboard redesign, we encountered some challenges. What should we do with frameworks integrated into our design? What about custom elements that repeat throughout the code with minor variations?
Bootstrap
Bootstrap is a framework that facilitates and expedites frontend development, which is why it was decided to use it since we are a small team.
When redesigning the frontend, we encountered Bootstrap’s rigidity; adapting a card element, for example, to the new design involved overwriting Bootstrap component classes. Finding the correct classes to modify is not trivial. Furthermore, the code becomes less readable as Bootstrap uses CSS rules with considerable specificity to ensure that styles defined by the framework are applied correctly and are not easily overridden by custom or inherited styles.
As a compromise solution, we have tried to rid ourselves of Bootstrap dependency in all our components. However, certain components like tables (navigating data tables is non-trivial, and implementing it with a small team would be like reinventing the wheel) have been retained, with efforts made to adapt them as closely as possible to the new design.
Reusable components
In the design of modern web applications, we often encounter common elements such as buttons that are repeated across multiple views and components. From a basic button that can contain text, an image, or be disabled, to various variations based on design and functionality needs.
The repetition of code when laying out the same button multiple times can lead to fragmentation in the project and make change management difficult, such as modifying colors or spacings, which require searching and updating each instance of the button throughout the codebase.
To address this challenge, the creation of reusable components is essential. By encapsulating the logic and appearance of a button in a component, we reduce code duplication and accelerate the development of the application.
However, creating reusable components can be a demanding task, especially for small teams. The time required to design and adjust a reusable component with all its possible variations can be significant. Additionally, as the component evolves and adapts to new needs, its complexity may increase, requiring continuous maintenance.
Living design
The design of a component or view is a dynamic process: as implementation progresses, changes may arise due to technical difficulties or user feedback while interacting with the user experience (UX).
It is crucial to determine when to share the design with the development team for implementation. If shared at a very early stage, such as due to the need to deliver functionality to the client, subsequent changes in the design may have significant impacts on implementation. The code may no longer align with the requirements of the new view, or the changes may not be well received by the development team, potentially leading to frustration throughout the team.
Therefore, the more mature a design is before reaching the development team, the fewer development/review iterations will be needed to finalize a view.
Testing network
Although changes may primarily be visual, refactoring is not limited solely to the styling part (CSS and HTML). Often, it involves decoupling code to maintain component cohesion and responsibility, resulting in the creation of simpler and easier-to-maintain components.
Having a limited number of tests during refactoring can significantly slow down the process. The practice of “edit and pray” becomes a reality, where changes made do not guarantee the integrity of the existing code. This necessitates thorough Quality Assurance (QA) review covering all possible cases to ensure that previous functionality remains intact.
To avoid this scenario, an effective strategy is to develop tests as refactoring progresses. Although this approach can provide greater security, it should be noted that if the code is highly coupled, extensive, or relies on multiple components, the refactoring process can become slow and even frustrating. Highly coupled code is often complex to test and may require a careful approach to unravel its dependencies.
Naming conventions
When styling a webpage, the names we assign to classes play a crucial role. Classes with non-descriptive names like “class1” or “style2” lack meaning and fail to provide information about the function or purpose of the code, making it challenging to understand and maintain in the long term.
It’s important to strike a balance in the specificity of class names. Overly detailed names can tightly couple the class to the HTML structure, making the CSS code fragile and complicated to maintain. For example, using classes like “button-red-width” may become problematic if there’s a decision to change the button design in the future.
Finally, it’s advisable to avoid defining styles directly in HTML. This hampers the code refactoring process since styles aren’t associated with a specific class and can be hard to find in the style section. Keeping styles in separate CSS files facilitates code organization and maintenance since all styles related to a specific component or design are located in one place.
Conclusion
In conclusion, refactoring in frontend development is an essential practice to enhance user experience, optimize system performance, and ensure long-term code maintainability. From modernizing design to creating reusable components and establishing a robust testing network, each step in the refactoring process contributes to a more efficient and adaptable frontend. Recognizing challenges such as framework rigidity and the need for clear naming conventions enables us to address issues proactively and ensure agile and sustainable frontend development. Ultimately, refactoring not only improves the technical quality of the code but also enhances the quality of the user experience, making it a fundamental practice for any frontend development project.