Hide the constant, abstract the code
Tags: javascript, programming, react
Published: 2021-03-13 20:19:09

--- series: Do I need this constant ---

We like to use constants, put them in some shared files and use them everywhere. Although, it happens that we don't recognise when not only the constant repeats, but also how the constant is used repeats.

## Let me tell you about some error message

Somewhere deep in the source code, repeats an import, in this import, on top of many files, there is a "nicely" named constant `STANDARD_ERROR_MSG`.

Deep in all these files, there is also the use of the constant, the same, exactly the same in all of them:
```jsx
import {STANDARD_ERROR_MSG} from 'constants';
// usage
<Error message={STANDARD_ERROR_MSG} />
```
Why my precious constant, why you need to be exposed to all these files, not better to sit in one spot? Some privacy would do, why everybody need to know you, my precious constant.

### Precious constant hiding
```jsx
const Error = ({message = "This is my precious error message"}) => 
  <p>{message}</p>;

// usage in code
<Error />
```
No constant anymore, but also one import less in every file using `<Error />`, no more copy/pasted props.

### Implicit default value, bleh

Ok, some of you can say, previous was explicit and now we have implicit default value. True, but we can make it explicit and still not use the shared constant.

```jsx
const Error = ({message}) => 
  <p>{message}</p>;

const StdError = () => <Error message="Std eror" />
```
We can go forward and make other kinds of errors:
```jsx
const PermissionError = () => <Error message="No permission" />
const AuthError = () => <Error message="Not authenticated" />
```
After that we don't import constants, instead we import reusable components.

## The story about groups

Developer task requires different logic for different users groups. No problem, said developer, no problem at all. Firstly as every good developer should, he checked how we distinguish users in the code base, and there he found:
```js
import {Group} from 'constants';
// 3 times in the code base
user.groups.includes(Group.Marketing)
// 9 times in the code base
user.groups.includes(Group.IT)
// 22 times in the code base
user.groups.includes(Group.Management)
```
So let's add another use of these, shall we? No! No! Shouted developer. We copy the same logic, import the same constants, and we use these constants in the same way everywhere. I can do that better, said developer with a big dose of faith.

Let's name this, in other words, let's make abstraction from available use examples. Firstly abstract the calculation/logic:
```js
const isGroupMember = (group) => (user) => user.groups.includes(group);
```
Ah, developer wants to look smart by this function returning another function.  But looks like this has a reason:
```js
// not exposed private enum
enum Group {
  Marketing,
  IT,
  Management
}
const isMarketingMember = isGroupMember(Group.Marketing);
const isITMember = isGroupMember(Group.IT);
const isManagmentMember = isGroupMember(Group.Management);
```
Wow, this clever developer made `isGroupMember` in such a way, that it is a factory for functions which address specific group. Clever!

> Pay attention that we do apply first argument to `isGroupMember` and we get out function which takes `user` as argument and has pre-populated group already. In FP terms we would say `isGroupMember` is curried function, and we partially apply it.

Now the codebase has:
```js
// 3 times in the code base
isMarketingMember(user)
// 9 times in the code base
isITMember(user)
// 22 times in the code base
isManagmentMember(user)
```
No constant use, but new primitives in form of functions, no copy/paste of logic. Our developer can play some games in the evening, he has earned that.

## Check my status

Paid or not, the question should be ask in the code, so it is:
```js
import {PaymentStatus} from 'constants';
payment.status === PaymentStatus.Completed
```
And we check like that in ten places maybe, but will be more. All these places need to import the constant, and make the check. Abstraction will save us again:
```js
const isPaymentComplete = (payment) => 
  payment.status === PaymentStatus.Completed
```
No constant imports, no need to remember which field compare to which status (people using TS can say now - this argument doesn't apply to TS, and I agree), everything nicely abstracted and we have our new primitive.


## Domain Specific Language

All these functions `isManagementMember`, `isITMember` or `isPaymentComplete` are our new primitives, and can be used in the codebase. They abstract implementation details, and we can focus on the higher business rules. Using constants without reusing the logic will not level up the abstraction, the detail remains. If we see the same constant used in the same way few times in the codebase, maybe it is a place for our new domain primitive expression?