adding the final version of the CRC post

This commit is contained in:
Julien Calixte
2022-12-24 12:53:18 +01:00
parent 9a0ae14fc5
commit d32974f05e

View File

@@ -1,7 +1,7 @@
--- ---
title: CRC Cards as training material title: CRC Cards as training material
layout: post layout: post
date: 2022-12-03 date: 2022-12-24
draft: true draft: true
--- ---
@@ -81,10 +81,7 @@ export const UserBookmarks: FunctionComponent<Props> = ({ user }) => {
<Title title={i18n('bookmark.user_bookmarks')} /> <Title title={i18n('bookmark.user_bookmarks')} />
{isLoading {isLoading
? <TilesSkeleton animation={tilesAnimation} numberOfTiles={16} /> ? <TilesSkeleton animation={tilesAnimation} numberOfTiles={16} />
: <BookmarkItem : <Bookmarks data={bookmarks} />}
key={bookmark.id}
data={bookmark}
/>}
<PrimaryButton <PrimaryButton
text={i18n('bookmark.add_bookmark')} text={i18n('bookmark.add_bookmark')}
@@ -134,7 +131,7 @@ const newBookmark = await fetch(`/users/${user.id}/bookmarks`, {
// ... // ...
``` ```
Only the `user id` is necessary, why not just give the user id instead of the whole object? That will be our first simplification <OrderTag order={1} />. Only the `user id` is necessary, why not just give the user id instead of the whole object? That will be our first simplification .
> We'll simplify at the very end, once we'll be finished with our CRC card. > We'll simplify at the very end, once we'll be finished with our CRC card.
@@ -161,14 +158,15 @@ Without being a rule of thumb, I like to count how many `use` there are in the c
"Display user bookmarks", "Display user bookmarks",
"fetching bookmarks", "fetching bookmarks",
"handling async processes (loading and error state)", "handling async processes (loading and error state)",
"handling add bookmark modal visibility", "display 'add bookmark' button",
"handling 'add bookmark' modal visibility",
]} ]}
collaborators={["Home.tsx"]} collaborators={["Home.tsx"]}
/> />
### The ugly responsability ### The ugly responsability
The main problem I see in the `UserBookmarks` component is not about the component itself, it's more on one of its children: `TilesSkeleton`. It's doing a good job for the user experience but it's asking too much for the parent to be able to use it: `UserBookmarks` doesn't care about animating the skeleton. <OrderTag order={2} /> The main problem I see in the `UserBookmarks` component is not about the component itself, it's more on one of its children: `TilesSkeleton`. It's doing a good job for the user experience but it's asking too much for the parent to be able to use it: `UserBookmarks` doesn't care about animating the skeleton.
```tsx ```tsx
const tilesAnimation = gsap.to({ const tilesAnimation = gsap.to({
@@ -188,17 +186,54 @@ const tilesAnimation = gsap.to({
"Display user bookmarks", "Display user bookmarks",
"fetching bookmarks", "fetching bookmarks",
"handling async processes (loading, error)", "handling async processes (loading, error)",
"handling add bookmark modal visibility", "display 'add bookmark' button",
"handling 'add bookmark' modal visibility",
"Defining TilesSkeleton animation",
]}
collaborators={["Home.tsx"]}
/>
## What do we keep?
Now that we listed the responsabilities, it is time to know what do we want to keep by defining the main responsability of the `UserBookmarks` in one and sentence.
> `UserBookmarks` retrieve and handle the _user_ bookmarks with an additional button to add it.
That's it. Having a simple sentence defining what's the component does is the purpose of this exercice. Definetely difficult when we first read it, it is now a pretty concise and acceptable responsability we want `UserBookmarks` to have.
Let's display the responsabilities that doesn't quite respect the definition.
<CrcCard
name="UserBookmarks"
responsabilities={[
"Display user bookmarks",
"~ fetching bookmarks",
"handling async processes (loading, error)",
"display 'add bookmark' button",
"⚠️ handling 'add bookmark' modal visibility",
"⚠️ Defining TilesSkeleton animation", "⚠️ Defining TilesSkeleton animation",
]} ]}
collaborators={["Home.tsx"]} collaborators={["Home.tsx"]}
/> />
And here its final CRC Card:
<CrcCard
name="UserBookmarks"
responsabilities={[
"Retrieve bookmarks",
"handling async processes (loading, error)",
"display user bookmarks",
"display 'add bookmark' button",
]}
collaborators={["Home.tsx"]}
/>
## Simplification ## Simplification
Once we said all that, let's relook our component. Once we said all that, let's relook our component: less responsability and less hooks.
### <OrderTag order={1} /> only necessary prop ### Has only necessary prop
```tsx ```tsx
interface Props { interface Props {
@@ -218,13 +253,56 @@ export const UserBookmarks: FunctionComponent<Props> = ({ userId }) => {
// ... // ...
``` ```
### <OrderTag order={2} /> not responsible of child's animation ### Is not responsible of child's animation
```tsx ```tsx
// removing the magic number at the same time // removing the magic number at the same time
<TilesSkeleton numberOfTiles={MAXIMUM_BOOKMARKS} /> <TilesSkeleton numberOfTiles={MAXIMUM_BOOKMARKS} />
``` ```
### Does not fetch itself user bookmarks
```tsx
// ...
const { bookmarks, refetch, isLoading, error } = useUserBookmarksQuery({
userId,
})
// ...
```
### Does not handle `AddBookmark` modal
Here we only remove code
## The final version
```tsx
interface Props {
user: User
}
export const UserBookmarks: FunctionComponent<Props> = ({ user }) => {
const { bookmarks, refetch, isLoading, error } = useUserBookmarksQuery({
userId,
})
return <div className="user-bookmarks">
<Title title={i18n('bookmark.user_bookmarks')} />
{isError
? <ErrorMessage>An error occured</ErrorMessage>
: isLoading
? <TilesSkeleton numberOfTiles={16} />
: <Bookmarks bookmarks={bookmarks} />}
<AddBookmarkButton onNewBookmark={() => refetch())} />
</div>
}
```
## Final thought
What a
## Playground ## Playground
Do you want to create your own CRC cards? Do you want to create your own CRC cards?