Update piping example
This commit is contained in:
parent
9bda724a68
commit
a8c6a4bb7e
1 changed files with 59 additions and 49 deletions
104
README.md
104
README.md
|
@ -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),
|
||||||
|
),
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
Reference in a new issue