You're still changing code as evidenced by your original email. - With dependency injection, you're changing the call sites (name -> method call) and argument count or state size (to hold the injection). - With your idea, you're changing the call sites (name+args to `yield`) and return value (value -> `yield` result).
To give you an idea what I mean by dependency injection, take a look at this: - `util` uses here: https://github.com/isiahmeadows/thallium/blob/master/lib/cli/run.js - `state.util` uses here: https://github.com/isiahmeadows/thallium/blob/master/lib/cli/loader.js - Main `state.util` definition: https://github.com/isiahmeadows/thallium/blob/master/lib/cli/util.js - Testing `state.util` definition (`Mock` class): https://github.com/isiahmeadows/thallium/blob/master/test-util/cli/cli.js I mean small functional dependency injection, not the boilerplatey Java-style one. Mine is a bit more complex, because I also am passing shared state with it (like parsed args and config), but it's just an extra object property on that state, as defined in the `State` constructor in `lib/cli/run.js`. On Sat, Dec 16, 2017, 11:51 Pranay Prakash <[email protected]> wrote: > I don't understand what you mean by "record actions done by iterables". > Could you please expand on that :) > > My main reason for being weary of dependency injection is that I don't > want to change how I write application code just to make it more testable. > That's a pretty well shared concern about dependency injection whereby it > affects the entire structure of your codebase, or adds additional arguments > to simple functions for the sole purpose of testing it. > > With the method I'm proposing, you wouldn't have to change how you code at > all, and I think that's really nice > > On Sat, 16 Dec 2017, 10:32 Isiah Meadows, <[email protected]> wrote: > >> I think what you're looking for is dependency injection, which is simply >> the functions you care about passed as an argument rather than sent from >> `yield`. In your case, the injections would be recording what method is >> called when and with what, but that's what I typically do. As an added >> bonus, I don't need to rely on how the functions are structured - I can >> even record actions done from iterables. (That's one area yours won't work.) >> >> The only catch is that you can't asynchronously block, but that's far >> more rare in practice (automated testing doesn't need it, and you can set >> breakpoints when debugging, removing the need to asynchronously hook into >> it). >> >> On Sat, Dec 16, 2017, 00:19 Pranay Prakash <[email protected]> wrote: >> >>> Hmm, I suppose the stack traces drawback doesn't matter as long you're >>> only using this within the context of testing. The emphasis here is that >>> the actual application code that you run in production is what you wrote >>> (the imperative function calls), but when you 'require' the function into >>> your testing code, it gets transformed into this pure generator function >>> that's easier to test. >>> >>> I don't see how the state/future of async functions affects this. In >>> fact, in my example, I use an async function to try and show that this >>> transform can even work for async functions (and will convert them to a >>> synchronous generator function rather easily) >>> >>> On Fri, 15 Dec 2017 at 23:14 Isiah Meadows <[email protected]> >>> wrote: >>> >>>> You're describing a variant of the interpreter pattern. I've used >>>> similar in task scheduling contexts, and the key drawback is you no longer >>>> have useful stack traces. >>>> >>>> I haven't done any formal research on the approach, though. I will >>>> caution you that async functions are already widely used enough >>>> (particularly in Node) they're unlikely to go anywhere beyond something >>>> drastic. >>>> >>>> On Sat, Dec 16, 2017, 00:07 Pranay Prakash <[email protected]> wrote: >>>> >>>>> Hey all, >>>>> >>>>> I was just reading the docs for `redux-saga` where I encountered a >>>>> nice design pattern for a saga which is (correct me if I'm wrong) a >>>>> regular javascript generator function that yields the intent to call a >>>>> function (instead of actually calling a function) until it goes through >>>>> all >>>>> the steps. If that doesn't make sense, consider this simple function: >>>>> >>>>> ``` >>>>> async function findFriends() { >>>>> const myId = getMyID(); >>>>> const myUser = await fetchUser(myId); >>>>> return myUser.friends; >>>>> } >>>>> ``` >>>>> >>>>> instead of actually making the function calls needed, we can instead >>>>> have a function that does something like this: >>>>> >>>>> >>>>> ``` >>>>> function* findFriends() { >>>>> const myId = yield { fn: getMyID }; >>>>> const myUser = yield { fn: fetchUser, args: [myId] }; >>>>> return myUser.friends; >>>>> } >>>>> ``` >>>>> >>>>> This is a pure generator function that doesn't actually do anything, >>>>> but has all the necessary information to recreate the original function[1] >>>>> (or have a library "trampoline" through the function and make all the >>>>> necessary calls for you) >>>>> >>>>> A HUGE plus of the second version of the function is that it's >>>>> *easily* testable (unlike the first one). Pure functions are easier to >>>>> test. Testing this is simply a matter of calling `.next()`, getting the >>>>> "intent", making sure the right intent was yielded (good enough for unit >>>>> testing) and calling `.next()` again with the "mock" value, you want to >>>>> return and continue to test. >>>>> >>>>> An observation to make here is that you can transform the original >>>>> version of this code (easy, normal code to write) to the latter (easy code >>>>> to test). So, what about having some sort of babel transform perhaps that >>>>> can convert the first to the second but only in the context of unit tests. >>>>> You write code the normal way as you would for your application and don't >>>>> worry about test suite implementation details (mocking/dependency >>>>> injection/etc.), and when you want to test, simply import your function >>>>> (which gets converted to a generator) and step through it to test >>>>> different >>>>> scenarios. >>>>> >>>>> I personally think this is a super clean way to do testing since >>>>> the tests never interfere with how you actually write the code AND you >>>>> don't have to explicitly mock. >>>>> >>>>> Does anyone have thoughts on this / prior research (or knows about an >>>>> existing implementation of this)? >>>>> >>>>> Cheers, >>>>> Pranay >>>>> >>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> [email protected] >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

