DEV Community

Cover image for 10 Concerns & How we can make the whole React codebase cleaner
Ashish Surana
Ashish Surana

Posted on • Edited on

10 Concerns & How we can make the whole React codebase cleaner

Creating a project from scratch is easy but shipping features after some time become very difficult and that comes with a cost of delays, bugs and eventually a broken product.

"It is not enough for code to work. So if you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read." - Robert C. Martin

Alt Text

Wow, this looks like a great tip, but how to make code readable especially when it already became a big ball of mud and every change is getting disastrous day by day. While working on a React.Js applications, we went with these strategies and principles:

"Of course bad code can be cleaned up. But it's very expensive." - Robert C. Martin

1. Linting and Prettification
The perfectly indented file is the first step of code readability. We added eslint rules and extended airbnb configuration with some relaxation like 'import/prefer-default-export' because it makes difficult to rename function at all places. We also tweaked arrow-body-style, so that we can add breakpoints and debug the function if needed. And other minor changes like react/jsx-filename-extension

2. Absolute Imports

Alt Text
Importing functions, constants, components, is an integral part of building a JavaScript Application. But what in case of a deeply nested directory structure? We end up with writing import {getUser} from &../../../store/users/action. To get rid of this, we configured our create-react-app setup by specifying NODE\_PATH=src and we became free from dot/slash clutter and this was another little step.

3. Decoupling React components (Separation of Concerns)
Passing props to deep levels in React application becomes a bottleneck after 2-3 levels. We decoupled such props ladder and refactored components in a way so that they could be rendered with zero or minor dependency (with the help of redux). We also added Error Boundaries so that any failure doesn't propagate till the highest level.

4. Reusable components (Don't Repeat Yourself)
Alt Text
Creating reusable components was a key thing in improving readability. We developed Modals, a theme for the app, Cards, Error Components, and other basic building blocks. And reused to maintain consistency and writing less code. We also focused on reusing code blocks at a granular level like filtering an array, transforming some API response, etc.

5. Props Validation of components
Alt Text
Adding props validation gave us a great advantage about the required, not required, string type, boolean type props. It gave us the flexibility to reuse easily and move components from one file to another for refactoring lengthy files.

6. Keeping business logic at one place (Keep It Simple Stupid)
If we talk about KISS, It's a little difficult to maintain in the frontend code base and it mostly contains major part of business logic. Hence we created Container components that assemble multiple pure components and renders the desired complex design implementation. By this approach, our helper components were as dumb as they could be. These pure components were free from any business logic and could be tested very easily at a later point in time.

7. Config at a Single Source
While engineering a product, we often get a requirement to drive the features based on different configurations. We kept it at the highest level and all the features were referenced by that singleton object. We also added the transformation to change the data modeling to ensure ease of access to the nested properties of a config data Object.

8. Functional approach (Single Responsibility Principle)
Testing is the only way to maintain the readability of code through out the journey. But unit testing requires major shift in the way we think and write code. It becomes very easy if we have pure functions in our code and follow the principles of immutability that prevents unwanted side effects. Functional approach is a value-oriented programming paradigm. We can use small pure functions that follow the Single Responsibility Principle (SRP) and do only one thing at a time. We can use multiple such pure functions to get the required result.

9. Variable naming and writing comments
Alt Text
Naming variable and function is the most underrated this I realized, We must spend enough time on deciding the names and there should not be any room for ambiguity. Comments are just an excuse for writing bad code. Writing them can never be a good practice as it becomes a liability to update comments on future code changes and consequently. However, In the case of complex business logic, it is justified to write comments. But our focus must be on writing clear, expressive and obvious code.

10. Enforcing rules so that code gets cleaner by every change
Alt Text
After doing these major changes in codebase we put checks in our CI pipeline and integrated Jest using Enzyme to improve unit test coverage. We also integrated cypress for integration testing. We are having eslint, cypress, jest stages in our pipeline. Every change in codebase must ensure the success of these 3 stages.

We are sure and confident in delivering features faster than ever without breaking anything. And yes, Now we don't say "It works" frequently. We will continue to make codebase cleaner than ever day by day. All the refactoring in our product is inspired by the book ' Clean Code by Robert C. Martin'.
And here I conclude with this quote

"Clean code always looks like it was written by someone who cares. - Robert C. Martin"

Hence, refactor your code and show care towards your product and show some ❤️. please!

Top comments (4)

Collapse
 
ibibgor profile image
Oscar

For the comments tip you gave, I have to say that we in our team allow comments. But they should not explain what is done at a specific code block but explain WHY it was done that way. Maybe it's a little hacky solution but necessary because of dependencies. Therefor other developer should not waste time on trying to refactor some code only to realise that this code is "the currently best option"

But: Nice post! I'm happy that we do the most of those patterns and tips ourself already :)

Collapse
 
ashishsurana profile image
Ashish Surana

Absolutely correct. 100% Agree with you. Comments are not a bad practice at all, but enforcing comments above every single function, variable declaration leads to bad code. We are also following comments for a business logic explanation so that other engineers can quickly get the context and understand the use case.

Collapse
 
ronnewcomb profile image
Ron Newcomb

Depending on codebase, #5's propTypes has been replaced by "use Typescript".

Good article though.

Collapse
 
ashishsurana profile image
Ashish Surana

Yes, Using Flow and Typescript gives you way more flexibility and advantages as compared to propTypes because they can be beneficial in pure functions as well as react components.
Thanks a lot for opinion.