haskellcamargo / js-real-world-functional-programming

Tips and guidelines for real world functional code-bases in JS
MIT License
356 stars 14 forks source link

Doubt about external reference #3

Open arojunior opened 7 years ago

arojunior commented 7 years ago

In user.js example:

const listUsers = () => User.find().asArray()

The listUsers method is using an external reference. Where User come from?

Is it not a good practice to pass what the method gonna need as argument?

Considering that User is something like:

const User = {
  find: () => ({
    asArray: () => {
      return ['User1', 'User2']
    }
  })
}

Then you can inject to listUsers

const listUsers = User => User.find().asArray()

And then you can call listUsers(User)

What if you expect an id to filter the users list? (i'm not going to implement another Users) but you can do something like:

const listUsers = id => User => User.find(id)
listUsers(id)(User)

You got everything you need inside the method.

Thank you for this repo, I learned a lot.

haskellcamargo commented 7 years ago

Hi! Thanks for your feedback! You're right!

User is an external reference and, in this case, the right way to deal with it would be isolating everything in an isolate module and using partial application. The dependency injection methodology, however, can still be replaced by partial application:

// Remember the nice way to deal with null values is with monads and // not undefined' nornull'. I'm using the classic way here just for the sake // of clarity of the original purpose of the issue export const find = curry((collection, query) => collection.find.bind(collection, query))


- `db/find-user.js`
```js
import { find } from '../lib/db'
import User from '../model/user'

export default find(User)

const logUserWithId10 = IO(() => { findUser({ id: 10 }).tap(console.log) })

logUser.runIO()


Of course, this is a model to only find the user. In a CRUD application, the generated model probably will already do that for you. Mongoose does something similar, but is full of failures. This would be a good abstraction to, for example, Mongo driver directly.

Thus, a function to list users could be easily written as:

```js
import findUser from '../db/find-user'

export const listUsers = findUser.bind({}) // {} is the query

These patterns, in general, work great together, but may present issues individually. For example, if you try to use monads individually in Java without even dealing with the rest of the effects and avoiding mutability, you'll have problems. Functional programming is all about composition :heart: