Programming Tip #2: In JavaScript, Python, and Lua, avoid globals for dependencies; instead inject them as function arguments.
Learn More from Justin Searls and Dave Farley below.
For further actions, you may consider blocking this person and/or reporting abuse
Fadi Khadra -
Gabriel Rowan -
PRANTA Dutta -
Mahmud R. Farhan -
Top comments (6)
What about this so you can use
getName(id)
normally outside tests?That is a WONDERFUL technique for AWS Lambdas or other places where you cannot modify the function's first parameters, but you want to extend it and have it be testable.
It's also very nice for data-last style programming such as ReScript/OCAML.
... however, once you start doing FP, most of the literature and tutorials I follow all do data last style where you put all your dependencies first, and data last.
Sorry, 1 thing I forgot.
So... when I started learning Functional Programming, I wasn't really familiar or good at currying and partial applications. I knew about pure functions, but not about how FP does dependency injection. I used to use the default parameter style a lot, and data last. However, as learned more, I started learning about function arity, and how most FP languages don't do default parameters because you typically just use partial applications for functions that have defaults built in. This means you always pass arguments to a function, and don't leave things out.
If you do, you use something called
unit
. It's like annull
; it means "nothing", but unlikeundefined
, you can test for it, and has a distinct value that's different fromundefined
; it means "intentionally putting nothing here" whereasundefined
is usually by accident unless you're mutating something. Other languages like ReScript handle it similiar to how Python handles kwargs; you have parameters that have names, but you don't have to use them. Whether you do or don't, the function needs something to know you're done, and typically that's with unit.As I got better at FP in JavaScript, I started using curried functions and partial applications more heavily for years. For example, back then, I'd never write:
but instead:
Once I learned about data last, I'd change the above to:
I started learning for unit tests, I needed a fake one so I'd expose it like that:
... but for integration tests, and for other modules to use the function without having "include your own batters", I'd have those modules expose partial applications with the defaults they needed. This is important because sometimes it's not just a simple thing like fetch, but a multitude of other modules, and sometimes that one module knows what should be private, what is public, vs shared, etc.
Using default parameters like you have it works, and I'd still mix that in specifically with functions I didn't control. I found, even in customizable JavaScript, mucking around with things I don't control, like using Lodash' curryRight to make things like AWS Lambda more comfortable to use wrecked strange havoc on non-FP users of my modules. Calling a function with 2 paramerters when it needs 3 leads to strange exceptions, not normally the same you'd get with
undefined is not a function
. You start doing operations on functions you didn't mean to and it's quite different runtime error messages compared toObject
. Lodash is nice in that it supported the(a)(b)(c)
as well as the regular(a, b, c)
function calling format, so many only found out by accident, but I realized, your defaultParameter last example is the safest option on things you don't own, or things that are going to be used in public from your module.However, the rest of your code is hopefully pure functions, with as little side effects as possible, so you end up with a lot of data first style coding. That allows you to JavaScript pipeline operator (or Promises for now if you don't want to brave using unfinished standards) using partial applications. When you start doing that style of coding, you start appreciating more partial applications and data first programming (my brain is currently being rewired as I learn data last in ReScript....). So all of your code ends up with the "stuff" first, and the data last.
I hope that gives more context. It was a long journey for me to learn all that, and my JavaScript changed many times as I learned more, eventually leading me to typed functional languages, but when I return to JavaScript, I try to write is close to FP as possible.
Sure, that’s why I’m using Elm for all my front end dev.
Still I’m embracing the standard JS way when writing JS (actually TS) functions.
Nice little set of posts by the way.
Thanks! I can't wait till Roc Lang is near beta. Switching my mind from Elm on the front-end to ReScript on the back-end is ROUUUUGH. No types, data last, deprecated
|>
use->
instead, and discouraged type annotations. I like it, but I like how Roc Lang is "basically Elm on the server" more.I’m all serverless now, but yes in a perfect word I could write my serverless functions in ROC 🙏