I tend to this space for pet projects and the learning process, but today I will use it to vent a bit.

Before I jump into it, please, bear in mind I don't hold any particular grudge against functional programming –  or Ramda, for what it matters. My problem is not the paradigm, is the abuse of it.

In my latest gig, my team inherited a codebase that was heavily fp oriented.

It took me a bit to figure out my way around the code, and whlist I'm surely not the best programmer around, I also have quite a few years of experience and developed a decent code sense, so it was particularly frustrating not being able to just dive in.

The contractors setting it up used another repo as a blue print, and embraced fp in full, but in the meantime the company had moved away from it and our repo is kind of a unique in its kind.

Given that, it wasn't a particularly hard decision to comply to the direction set by the company and start our quest to burn Ramda with fire. And whilst I'm enjoying doing it, it's of course a strategic decision, not something we would've done in autonomy if the company hadn't already done that evaluation.

Enough with the anticipation, let's dive into the code...


const getMessageSender = R.pipe(
 R.toString,
 R.objOf('Message'),
 R.thunkify(this.sns.publish)
)
A rather simple example of something that could've been more readable
const getMessageSender = chunk => this.sns.publish({ Message: chunk.toString() })
#spoiler

const getApiClient = ({ config, sns }) =>
  R.pipe(
    R.always('api'),
    R.bind(config.get, config),
    R.tap(options => logger.debug({ options }, 'Initialising api client')),
    R.objOf('config'),
    R.mergeRight({ logger, sns }),
    api.getClient
  );

const client = getApiClient(options)()
Something slightly more complex, or is it?
const getApiClient = ({ config, sns }) => () => {
  const configObj = config.get('api')
  logger.debug({ options }, 'Initialising api client')
  return api.getClient({ config: configObj, logger, sns })
};

const client = getApiClient(options)
#spoiler

const stripTypePrefix = R.pipe(
  R.juxt([
    R.pipe(
      R.slice(1, 2),
      R.toLower
    ),
    R.slice(2, Infinity)
  ]),
  R.join('')
)
🤷‍♀️
 const stripTypePrefix = s => `${s.slice(1, 2).toLowerCase()}${s.slice(2)}`; 
#spoiler

const calcCacheTTL = (now, overhead) =>
  R.pipe(
    R.prop('expires_at'),
    R.of,
    R.append(R.negate(now)),
    R.append(overhead),
    R.reduce(R.add, 0)
  );
Take a minute, try to figure out what it does before looking at the spoiler
const calcCacheTTL = (now, extra) => ({ expires_at }) => expires_at - now + extra
#spoiler

My team went to the process of defining our coding principles. The second up – after Resiliance, which is key for the success of our platform – is Maintainability, so you can see why the code needs to evolve to enable it.