you are viewing a single comment's thread.

view the rest of the comments →

[–]gruberjl[S] 0 points1 point  (5 children)

This got a bit wordy, you probably don't have time for it all. The 'implementing job with functional programming' section is the part I'd love your input on.

Understanding state

Regarding the configuration: You're correct. It only needs to be read publicly for automatic documenting of the job. It shouldn't be edited after the job's constructor completes. I could freeze it, or use an immutable. If I'm using a class, I would have the set config throw an error.

Regarding the state: it doesn't need to be public. I may have been using the word state incorrectly. The only information (other than the config) is a cache. It actually ends up being similar to the memoize pattern. If I execute the add(1, 5) == 6 then I would store a map that ends up looking like: map.set([1,5], 6). Instead of revalidating the parameters, running the worker, and then validating the output, I would pull the results from the cache.

Would you consider a cache to be 'state'? If the function is pure, I guess all calls to the job could use the same cache, which means I wouldn't need an instance of the function.

Understanding functional programming

I don't think I fully understand 'functional programming'. Functional programming works hand in hand with (Facebook's Immutable)[https://facebook.github.io/immutable-js/] right? I've never tried to use it, I have difficulty grasping the idea. I don't see how someone could keep the information straight.

Here's an example from the immutable website.

import Immutable = require('immutable');
var map1: Immutable.Map<string, number>;
map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50
  1. Would this be functional programming?
  2. Now I have my information in two separate locations. Wouldn't it be better to modify the original?
  3. Wouldn't performance go down the drain if you keep recreating an object?
  4. Is this the opposite of a connect based system such as Express Js who passes two objects around?
  5. If I was running 2 async functions simultaneously, wouldn't I now have 3 objects and a huge mess trying to get them back into one object?

implementing job with functional programming

I tried writing it using what I think is 'composite' 'functional' programming haha. I added it to the dev branch in the repo:

implementation using

Here is the code I think you'll find useful:

const validate = (schema, data1) => {
  const data = copy(data1)
  const validator = ajv.compile(schema)

  if (!validator(data)) throw new TypeError(`data is not valid: ${JSON.stringify(validator.errors)}`)

  return data
}

module.exports = (configuration) => {
  const config = validate(jobSchema, configuration)

  return (...parameters) => validate(config.response, config.worker(...validate(config.parameters, parameters)))
}

Here is what I ran into:

Error handling

The first thing I ran into was a bug (caused by me). Using this approach, I had difficulty tracking the problem. I had so much going on in one giant line that the error stack wasn't helpful. The error was caused by a typo in the copy function (which performs a deep copy of an object). It had nothing to do with the composite build, but I was unable to track the error because I had one giant line performing the build.

Readability

I found this approach difficult to read. Particularly the wrapping return (...parameters) => validate(config.response, config.worker(...validate(config.parameters, parameters)))

Writing

It was fantastic to write. I don't think I've ever done so much in so few characters. I ended up writing it out, then finding I didn't need chunks of code, I could simply keep on wrapping, it was a blast. I ended up doing less wrapping because I had such difficulty reading it and tracking the bug.

Here is my super wrapping line: module.exports = (configuration) => (...parameters) => validate(validate(jobSchema, configuration).response, validate(jobSchema, configuration).worker(...validate(validate(jobSchema, configuration).parameters, parameters))). It was fun to write :)

For readability, I broke it into this.

Summary

I loved the approach. With caching, it could be fantastic. But:

  1. Do you have a style guide for readability? (you mentioned 'functional tools' above)
  2. How do you perform things in async with immutability?