Repository
https://github.com/stonecoinproject/stonem-frontend
Pull Request
https://github.com/stonecoinproject/stonem-frontend/pull/49
Continuing with the development of the STONE masternodes web-client, our previous update added the masternodes manager screen alongside some very vital constructs and reusable architectural patterns.
However, for any software project to stay healthy, scale and remain relevant, smart and efficient practices must be adopted. The masternodes screen inadvertently added some poor code practices to the source base as evidenced in the CodeClimate report above.
The analytical report indicated the code contained as much as 3 code smells (poor practices) and 16 duplications. If not quickly and carefully tackled, these poor practices may quickly compound till you are staring down on a mountain of technical debt.
To tackle some of these issues, I got to work. I realized the 3 code smells detected were actually due to the unusually LOC (Lines of Code) length of methods contained in the wallet manager suite of components. To actively get this solved, I decided to split large functions into smaller functions so the below sample piece of code goes from this monumental entity:
const transactionItem:React.SFC<transactionItemProps> = ({
amount,
brand,
children,
date,
hasNegativeIndex,
title,
time,
...props }) => (
<ToggleProvider
render={({
isOn,
doToggle,
}) => (
<Card
border={2}
borderColor={ isOn ? theme.colors.blue : theme.colors.bordergray}
borderRadius={theme.radiusSizes[1]}
p={3}
onClick={doToggle}
style={{
cursor: 'pointer',
}}
{...props}
>
<Flex>
<Box
mr={3}
width={1 / 5}
>
<Image width={1} src={brand} />
</Box>
<Box width={1}>
<Box width={1}>
<Flex width={1}>
<CapsText
fontSize={3}
mb={3}
width={1 / 2}
>
{title}
</CapsText>
<CapsText
fontSize={3}
mb={3}
textAlign={'right'}
width={1 / 2}
>
{time}
</CapsText>
</Flex>
<Flex width={1}>
<CapsText
color={hasNegativeIndex ? 'red' : 'placeholdergray'}
fontSize={3}
mb={2}
width={1 / 2}
>
{amount}
</CapsText>
<CapsText
color={'placeholdergray'}
fontSize={3}
mb={2}
textAlign={'right'}
width={1 / 2}
>
{date}
</CapsText>
</Flex>
</Box>
</Box>
</Flex>
<Box style={{
height: isOn ? 'auto' : '0',
overflowY: 'hidden',
}}>
{children}
</Box>
</Card>
)} />
);
...to the much more sane smaller function:
const transactionItem:React.SFC<transactionItemProps> = (props) => {
return (
<ToggleProvider
render={({ isOn, doToggle }) => (
<Card
borderColor={ isOn ? theme.colors.blue : theme.colors.bordergray}
onClick={doToggle}
{...transactionItemCardStyles}
{...props}
>
<Flex>
{renderBrand(props.brand)}
<Box width={1}>
{renderHeading(props.title, props.time)}
{renderMetaInformation(props.amount, props.date, props.hasNegativeIndex)}
</Box>
</Flex>
<Box style={{
height: isOn ? 'auto' : '0',
overflowY: 'hidden',
}}>{props.children}</Box>
</Card>
)} />
);
};
With this strategy fully employed, I was able to eliminate all code smells reported by CodeClimate.
To take care of duplicates, I did a little research and realized a bulk of my code duplication came from writing code that iterates through an array and renders data from the array. This looked like a really good time to abstract this monotonous routine and I decided to employ Typescript generic React components that could be overloaded with props and use a custom renderer.
I created the src/generics
directory and added the GenericList.tsx
component.
import * as React from 'react';
export interface GenericListProps<T> {
/** Items to be members of the list. */
items: T[];
/** Callback method to render the items. Allows us delegate rendering for each consumer. */
itemRenderer: (item: T, index: Number) => React.ReactNode;
}
/**
* Generic class that serves as an abstraction for list item iterators.
*/
export default class GenericList<T> extends React.Component<GenericListProps<T>, {}> {
constructor (props:GenericListProps<T>) {
super(props);
}
render () {
const {
items,
itemRenderer,
} = this.props;
return (items.map(itemRenderer));
}
}
So running iterations now looks like this:
// Import the base generic list class
import { GenericList } from '../generics'
export class WalletTransactionItemList extends GenericList {}
Then in a consumer class.
// ...previous code
render () {
return (
<WalletTransactionItemList
items={app.transactionData}
itemRenderer={renderWalletManagerTransactionItem}
/>
)
}
And this handles our iterations and iterables pretty well.
With all these implemented, we were able to get a clean slate from CodeClimate which feels pretty good. Pictured below is the code health analysis from Code Climate.
What's next?
- Provide further code documentation for existing components.
- Create responsive, mobile-first enhancements for the client.
- Add authentication and coin node creation functionality.
Thank you for your contribution. The post is of very high quality where you have explained it very nicely. This contribution adds significant value to the project since refactor is really needed whenever the project gets big, also the Wallet manager Screen looks great.
The code is of very high quality though as mentioned in the previous feedback you can try to remove hardcoded data from the code.
If you would like further explanation of the given score, then you can just ask.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Chat with us on Discord.
[utopian-moderator]
Thanks @codingdefined excellent review.
Thank you for your review, @codingdefined! Keep up the good work!
Congratulations @creatrixity! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :
Click here to view your Board
If you no longer want to receive notifications, reply to this comment with the word
STOP
To support your work, I also upvoted your post!
Hi @creatrixity!
Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server
Hey, @creatrixity!
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!