Weekly React Rundown

React and S.O.L.I.D. Principles: Building Robust Applications (Part 2)

A SOLID Approach to Engineering

Leandro πŸ€– πŸ‘Ύ πŸš€
4 min readFeb 19, 2024

Co-authored by Thays Casado

The image is of an open book titled β€˜Levelling Up with Liskov & Friends,’ designed to teach software development principles in an engaging way. It features colorful, cartoonish characters representing programming concepts, along with inviting diagrams, code snippets, and tech-related icons. The educational content is presented in a playful and accessible style.

1. Introduction

Welcome to the second article of our exciting series, "React and S.O.L.I.D. Principles: Building Robust Applications." For this piece, we'll continue developing our Task Management application while exploring the last three S.O.L.I.D. principles: Liskov Substitution Principle (L.S.P.), Interface Segregation Principle (I.S.P.), and Dependency Injection Principle (D.I.P.).

If you just landed on this article or are unsure what's happening, peek at the previous work here. You can find and download the source code from this repository.

2. Levelling Up with Liskov & Friends

This part of the project structure will focus on applying and leveraging each principle to enhance our current state. The expected outcome for this section is understanding the impact of the current design on our application.

The updated hierarchy can be seen below:

Hierarchical representation of the application.
src/
β”œβ”€β”€ components/
β”‚ β”œβ”€β”€ Filter/
β”‚ β”œβ”€β”€ TaskList/
β”‚ β”œβ”€β”€ TaskItem/
β”‚ β”œβ”€β”€ TaskDialog/
β”‚ └── Header/
β”œβ”€β”€ constants/
β”œβ”€β”€ state/
β”‚ β”œβ”€β”€ taskSlice.js
β”‚ β”œβ”€β”€ filterSlice.js
β”œβ”€β”€ hooks/
β”‚ β”œβ”€β”€ useTasksHook.js
β”‚ β”œβ”€β”€ useFiltersHook.js
β”œβ”€β”€ utils/
β”‚ └── taskUtils.js
└── App.js

2.1. Liskov Substitution Principle (L.S.P.)

  • Components Flexibility: Ensure that your TaskItem, TaskDialog, and other components adhere to standard interfaces or prop types. It will make them easily replaceable or extendable without affecting the parent components like TaskList or pages that use them.
  • Future Enhancements: As your application grows, you might introduce nef tasks (e.g., priority tasks, tasks with sub-tasks). The L.S.P. will guide the design so that these new components can be integrated seamlessly without modifications to existing components.

2.2. Interface Segregation Principle (I.S.P.)

  • Focused Hooks: In the hooks directory, you can create hooks that serve single responsibilities. We created the useTasks for fetching and managing tasks, and for this part, we will create the useFilter for filtering information out of a given list. This keeps your components lean and focused on their U.I. roles.
  • Decoupled State Management: The state directory houses Redux slices or similar state management logic, ensuring components only subscribe to the minimal state they need. For instance, this taskSlice.js is used by task-related components without forcing them to know about unrelated state parts, and we will create a new slice named filterSlice.jsto handle filtering logic separately. This allows for a more focused and modular approach to state management, where the component TaskList can interact with both slices to display tasks based on selected filters without being directly coupled to the filtering logic itself.

2.3. Dependency Inversion Principle (D.I.P.)

  • Decoupling Components from Direct Dependencies: Utilize the hooks and state directories to abstract the logic for data fetching, state management, and business rules. For example, useTaskService could abstract away the API calls, allowing components like TaskDialog to be more testable and flexible regarding data sources.
  • Enhanced Testability and Flexibility: With D.I.P., your components become easier to test and evolve. For instance, changing the backend API or switching state management libraries would have minimal impact on your component layer, which depends on abstractions rather than concrete implementations.

It's important to reinforce that this project does not implement a backend. If you want me to show you how you could simulate or integrate with one, let me know in the comments! πŸ‘‡

3. Conclusion

In the pursuit of building a robust and scalable React application, the transition from a basic project structure to one that incorporates S.O.L.I.D. principles has evolved. The updated structure, as shown above, is a testament to the transformative power of these principles.

With a nod to the Liskov Substitution Principle, components like TaskItem and TaskDialog are now designed to be easily interchangeable, promoting a seamless evolution as the application grows.

The Interface Segregation Principle has given rise to hooks like useTasksHook and useFiltersHook, which encapsulates specific functionalities, thereby streamlining components to their essential U.I. roles.

The Dependency Inversion Principle has further decoupled components from direct dependencies, paving the way for a codebase that is as testable as it is adaptable to change.

While the backend isn't part of this project's scope, the groundwork laid here provides a clear pathway for future integrations. Should there be an interest in backend simulations or integration techniques, the conversation can certainly extend in that direction.

Like what you see?

--

--

Leandro πŸ€– πŸ‘Ύ πŸš€

A Tech adventurer aiming to explore and share the latest advancements in technology. Do you want to join my guild and level up with me?