Update piping example

This commit is contained in:
Scott Picquerey 2022-04-01 11:21:53 +02:00
parent 9bda724a68
commit a8c6a4bb7e

104
README.md
View file

@ -30,14 +30,17 @@ complete each is detailed in the comments.
## code style guide ## code style guide
For readability purpose, we replace `ReaderTaskEither` by `rte`
- Use `flow` instead of `pipe` when possible - Use `flow` instead of `pipe` when possible
```typescript ```typescript
// Bad // Bad
const myFunc = (user: User) => pipe(user, getUserName, formatUserName); const formatUserPhoneNumber = (user: User) =>
pipe(user, User.phoneNumber, User.formatPhoneNumber);
// Good // Good
const myFunc = flow(getUserName, formatUserName); const formatUserPhoneNumber = flow(User.phoneNumber, User.formatPhoneNumber);
``` ```
- Avoid using `boolean` method `match` when unecessary - Avoid using `boolean` method `match` when unecessary
@ -45,63 +48,70 @@ const myFunc = flow(getUserName, formatUserName);
```typescript ```typescript
// Bad // Bad
const myFunc = (condition: boolean) => pipe( const triggerEmailCampaign = ({
condition === true, user,
...emailSettings
}: {
user: User & EmailSettings;
}) =>
pipe(
user.nationality === 'FR',
boolean.match( boolean.match(
() => doSomethingOnFalse(...), () => triggerGlobalEmailCampain({ to: user.email, emailSettings }),
() => doSomethingOnTrue(...) () => triggerFrenchEmailCampaign({ to: user.email, emailSettings }),
) ),
); );
// Good // Good
const myFunc = (condition: boolean) => { const triggerEmailCampaign = ({
if (condition === true) { user,
return doSomethingOnTrue(...); ...otherProps
}: {
user: User & OtherProps;
}) => {
if (user.nationality === 'FR') {
return triggerFrenchEmailCampaign({ to: user.email, emailSettings });
} }
return doSomethingOnFalse(...); return triggerGlobalEmailCampain({ to: user.email, emailSettings });
}; };
``` ```
- Split piping from logical actions - Avoid nested pipes
> Why? Mixing them makes it harder to understand and read the code. We want to favor the usage of atomic methods that do not know anything about the piping > Why? They lower global understanding of the code. We allow ourselves 2 levels of piping maximum per function and tend to do atomic functions instead
```typescript ```typescript
// Bad // Bad
const myFunc = () => pipe( const renewUserToken = (user: User) =>
rte.Do, pipe(
rte.bind('aggregate', () => getAggregateById(...)), user.token,
rte.bindW(...), option.match(
..., () => AuthClient.createToken(user),
rte.chainW(({ aggregate }) => pipe( (token) =>
aggregate.something, flow(
doSomething, AuthClient.renewToken(user),
doSomethingElse, rte.chainW(({ newToken }) =>
... pipe(newToken.hash, user.updateToken, rte.chainEitherKW(storeUser)),
)
), ),
rte.chainW(storeAggregate), ),
); ),
);
// Good // Good
const myFunc = () => pipe( const updateUserToken = (user: User) => (newToken: Token) =>
rte.Do, pipe(newToken.hash, user.updateToken, rte.chainEitherKW(storeUser));
rte.bind('aggregate', () => getAggregateById(...)),
rte.bindW(...),
...,
rte.chainW(doEverything),
rte.chainW(storeAggregate),
);
// Best const renewAndUpdateUserToken = (user: User) =>
const buildProps = (...) => pipe( flow(
rte.Do, AuthClient.renewToken(user),
rte.bind('aggregate', () => getAggregateById(...)), rte.chainW(({ newToken }) => updateUserToken(user)),
rte.bindW(...), );
...
); const renewUserToken = (user: User) =>
const myFunc = () => pipe( pipe(
buildProps(...), user.token,
rte.chainW(doEverything), option.match(
rte.chainW(storeAggregate), () => AuthClient.createToken(user),
); renewAndUpdateUserToken(user),
),
);
``` ```