Harry Blue
Harry Blue

Reputation: 4502

Combining Functions to be more 'Functional' w/ JavaScript

I have some (pseudo) code that looks as follows

const { search, hash } = window.location // get search / hash from url
  const tokenParts = queryParams(search || hash) // create an object
  const { id_token, access_token } = tokenParts // extract from object
  const isSessionValid = validateSession(id_token) // check exp time etc and return true / false

  if (isSessionValid) {
    store('id_token', id_token)
    store('access_token', access_token)

    window.history.replaceState(null, null, window.location.pathname)
  }

I see this pattern a lot in the codebase I am working on, call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable....and so on until you have required value you require to move the program execution on.

From what I have read, functions should really, do-one-thing - rather than these massive, complex beats that can be difficult to test.

My question is, in the case of the pseudo code above, how can this be refactored into a function that returns the result of another function and so on?

I think I need something like

const sessionisValid = validateSession(window.location)

validateSession = ({search, hash}) => (queryParams(search || hash))=> hasTokenExp({id_token})

But I do not understand...

  1. If this is how function programming / composition should work
  2. Is the best approach
  3. If I am just over complicating things

Upvotes: 0

Views: 74

Answers (1)

Bergi
Bergi

Reputation: 664538

call a method with a value, assign that value to a variable, pass that variable into another method and assign the result to another variable... and so on until you have required value you require to move the program execution on.

This is totally fine. You're building on big function from multiple small functions - exactly how you should do it in functional programming. The variables are just necessary for the wiring.

What you have shown is not a massive, complex beast, it's very clear and clean code. It's easy to test all the individual small functions on their own if you want.

And because all those functions are pure and your variables are immutable, it's really easy to refactor your code from

const { search, hash } = window.location // get search / hash from url
const { id_token, access_token } = queryParams(search || hash)
const isSessionValid = validateSession(id_token) // check exp time etc

if (isSessionValid) {
    store('id_token', id_token)
    store('access_token', access_token)

    window.history.replaceState(null, null, window.location.pathname)
}

to

function getSession({search, hash}) {
    const { id_token, access_token } = queryParams(search || hash)
    return {
        id_token,
        access_token,
        isSessionValid: validateSession(id_token)
    };
}

const { id_token, access_token, isSessionValid } = getSession(window.location);
if (isSessionValid) {
    store('id_token', id_token)
    store('access_token', access_token)

    window.history.replaceState(null, null, window.location.pathname)
}

but unless you can use getSession in multiple places or you need this layer of abstraction for code organisation, the refactoring is unnecessary.

how can this be refactored to use function composition?

It can't really. Function composition works only when the result of one function are fed into another function and nowhere else. But in your code, access_token and id_token are used in multiple places. While it is possible to express this in pointfree style, it's complicated, slow and too abstract. Variables are much easier to use here.

I see this pattern a lot in the codebase I am working on

What exactly is the pattern? Whenever you see duplicated code, you might want to abstract out the common parts. But you need to be evaluate how many common parts and how many distinct parts there are in the code blocks. While always possible, often it's not worth it.

Upvotes: 1

Related Questions