The Art of Code: Avoiding Common Pitfalls in Software Development

Photo by saeed karimi on UnsplashA Guide for React and JavaScript DevelopersIn my journey as a developer and mentor, I’ve seen my fair share of code — the good, the bad, and the “who approved this?” variety. Whether in interviews, PR reviews, or produc…


This content originally appeared on Level Up Coding - Medium and was authored by Goldin Evgeny

Photo by saeed karimi on Unsplash

A Guide for React and JavaScript Developers

In my journey as a developer and mentor, I’ve seen my fair share of code — the good, the bad, and the “who approved this?” variety. Whether in interviews, PR reviews, or production codebases, certain patterns emerge that distinguish seasoned pros from novices. Today, let’s talk about two fundamental principles: Don’t Repeat Yourself (DRY) and the Single Responsibility Principle (SRP).

Case 1: Memoization

During interviews, I often ask candidates to write a memoization mechanism. Here’s a typical response:

const expensive = (a, b) => {
console.log(a, b);
return a + b;
}

const memoized = () => {
const cache = {};
return (a, b) => {
if (cache[`${a}.${b}`]) {
return cache[`${a}.${b}`];
} else {
const newRes = expensive(a, b);
cache[`${a}.${b}`] = newRes;
return newRes;
}
}
}

const expensive2 = memoized();

expensive2(2, 3);
expensive2(2, 3);

It works. It gets the job done. But it’s not the best way to do it. And when I ask, “Would you push this as-is to a pull request?” many confidently say, “Sure, why not?”

Here’s why not.

Breaking DRY and SRP

The code above repeats the key generation logic and has hidden repeatability in the return statements. Let’s break it down:

  1. Key Generation: We generate the key ${a}.${b} thrice. If the logic for key generation changes, we must update it in multiple places.
  2. Return Statement: We return the cached value directly in the if statement but use an intermediate variable and assignment in the else statement, which can be refactored to:
const newRes = expensive(a, b);
cache[`${a}.${b}`] = newRes;
return cache[`${a}.${b}`];

And the duplicate return statement is now visible.
To adhere to DRY and avoid return repeatability, we can refactor the code:

const expensive = (a, b) => {
console.log(a, b);
return a + b;
}

const memoized = () => {
const cache = {};
return (a, b) => {
const key = `${a}.${b}`;
if (!cache[key]) {
cache[key] = expensive(a, b);
}
return cache[key];
}
}

const expensive2 = memoized();

expensive2(2, 3);
expensive2(2, 3);

By defining the key once and simplifying the return logic, we make our code cleaner and more maintainable.

Case 2: Redux and Component Logic

Let’s talk about Redux and keeping business logic out of React components. Here’s an example of a submit handler with multiple dispatches and a complex useEffect:

const handleSubmit = () => {
dispatch(updateSomeEntity);
if (someCondition) {
dispatch(updateSomeOtherEntity);
}
dispatch(updateThirdAffectedEntity);
};

const someEntity = useSelector(someEntitySelector);
const someOtherEntity = useSelector(someOtherEntitySelector);

useEffect(() => {
/**
* Lines and lines of simple logic to draw some true/false result
*/
setIsSomeComplexCondition(resultOfTheLongComputation);
}, [someEntity]);

We can refactor this to follow SRP more closely:

  1. Encapsulate Dispatch Logic: Create a dedicated action for handling the submit logic.
  2. Combine Selectors: Use a single selector to return both entities.
  3. Extract Business Logic: Move the unnecessary coupling of the complex calculation with the React lifecycle and move it out of the useEffect.
const handleSubmit = () => dispatch(handleComponentSubmit);

const { someEntity, someOtherEntity } = useSelector(moreSpecificSelector);

useEffect(() => {
setIsSomeComplexCondition(computeComplexCondition(someEntity));
}, [someEntity]);

We are still unnecessarily coupled with the React lifecycle. We can say that isSomeComplexCondition is a derivation of someEntity , so we can move this into the return result of our selector.

const handleSubmit = () => dispatch(handleComponentSubmit);

const { someEntity, someOtherEntity, isSomeComplexCondition } = useSelector(moreSpecificSelector);

By moving business logic into a selector and using a dedicated action for the submit, we keep our code organized and easier to manage.

For more insights on how structuring your data properly can enhance the performance of your React application, check out my blog post: “Mastering React Performance: Immutability and Memoization Explained”.

Case 3: Component Responsibilities

Finally, let’s discuss component responsibilities. Consider this component:

const EditTodo = ({ canEdit }) => {

if (!canEdit) {
return;
}

return (
// ...
);
};

And then requirements change, and we end up with another condition:

const EditTodo = ({ canEdit, canView }) => {

if (!canEdit || !canView) {
return;
}

return (
// ...
);
};

This is a slippery slope. As requirements change, we keep adding conditions to our component. This violates SRP. A component should have a single responsibility: to render UI based on props.

I like to joke about this with an illustration of one worker at a construction site yelling to another, “Hey, you! Yes, you! I don’t need you!”

How do we fix this? If the logic we are using is meant only for rendering, this business logic, of when to render, should be moved to the parent component. So if you want to conditionally render the EditTodo component, you can do it in the parent component:

const allowedToUse = canEdit && canView;
{allowedToUse && <EditTodo />}

This way, the EditTodo component is only responsible for rendering itself based on the props it receives.

But it might be that the properties passed are not for rendering logic and you do need to prop drill them down and use them as one. In this case too, no need for the child to be aware of the types of conditions that create the actual condition it is interested in, in this case allowedToUse.

In this case too, we would combine the conditions at the parent level and pass the result as a single prop to the child:

const allowedToUse = canEdit && canView;
<EditTodo allowedToUse={allowedToUse}/>

Conclusion

These principles are not just for show. They help us write better code, make our codebases more maintainable, and help us avoid bugs. By adhering to DRY and SRP, we can write cleaner, more organized code that is easier to understand and maintain. What is great about these principles is that they are universal and can be applied to any language or framework. It works as a mindset whenever approaching a problem.

Next time you’re coding, consider if you’re following these principles. It can make a significant difference in the quality and longevity of your code.


The Art of Code: Avoiding Common Pitfalls in Software Development was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Goldin Evgeny


Print Share Comment Cite Upload Translate Updates
APA

Goldin Evgeny | Sciencx (2024-07-28T17:02:42+00:00) The Art of Code: Avoiding Common Pitfalls in Software Development. Retrieved from https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/

MLA
" » The Art of Code: Avoiding Common Pitfalls in Software Development." Goldin Evgeny | Sciencx - Sunday July 28, 2024, https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/
HARVARD
Goldin Evgeny | Sciencx Sunday July 28, 2024 » The Art of Code: Avoiding Common Pitfalls in Software Development., viewed ,<https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/>
VANCOUVER
Goldin Evgeny | Sciencx - » The Art of Code: Avoiding Common Pitfalls in Software Development. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/
CHICAGO
" » The Art of Code: Avoiding Common Pitfalls in Software Development." Goldin Evgeny | Sciencx - Accessed . https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/
IEEE
" » The Art of Code: Avoiding Common Pitfalls in Software Development." Goldin Evgeny | Sciencx [Online]. Available: https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/. [Accessed: ]
rf:citation
» The Art of Code: Avoiding Common Pitfalls in Software Development | Goldin Evgeny | Sciencx | https://www.scien.cx/2024/07/28/the-art-of-code-avoiding-common-pitfalls-in-software-development/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.