5 ms·
Refraction – JS library to make modules independent, testable and re-usable
- NathanKP 10y agoVery nice. This technique of code organization will bring some of the benefits of microservices even though the code is actually all running in one monolithic process. And as a bonus its not hard to imagine adding RPC capabilities to this library if one of the modules has performance characteristics that require a different type of scaling, so you want to move that module out to its own process running on a different machine.
- Noseshine 10y agoI don't quite understand it, so just to be sure: Instead of fixed calls to other modules all modules use this library to call other modules' functions? I think everyone has that idea at some point. I started writing my own but ended up going back to rigid coupling because unless I really decouple the system, for example to place modules in different processes or even machines, or letting different versions of certain modules "plug in" simply by loading them (run-time configurable) instead of having to change module names all over the code (needs to be done before deployment), it didn't really give me any benefit (at that early stage). I still use it for logging: I don't have to call a specific method, instead it's all just "messages", and when I have a "logger" listening for certain messages it logs them on the console, in production I'd leave the calls in but send them to a server, simply by loading another logger module, without code changes. My statement is only for my own specific project, I found that whether to use such a method or not is highly specific. So my only point is that trying to use such an approach "because it sounds cool" turned out not to be sufficient reason. IMHO the provided "Motivation" document is not sufficient (https://mbasso.github.io/refraction/docs/introduction/Motivation.html https://mbasso.github.io/refraction/docs/introduction/Motiva...). I think more could (should?) be said and explained.
- ubertaco 10y agoSo...it's an event bus?
- JohnDotAwesome 10y agoYep. Who needs explicit coupling when you can silently couple interfaces?
- scotty79 10y agoCould you still have explicit coupling? For example by keeping definition of given message in the same module where the sender is?
- spriggan3 10y ago> A guard that represent central point of control in your application. Yeah, it looks like a pubsub system. The use of the word "module" here is misleading. It's not about ecmascript modules.
- h8liu 10y agoNo dependency is often not the right dependency. For example, http depends on tcp, because an http stack cannot work or be reasonably tested without a working tcp stack. Yes, the tcp stack can be provided as an injection. Yes, the tcp stack can be defined as an interface and faked or mocked with a minimal implementation that barely supports the required execution, but still, without providing the depended tcp module, the http module does not work "independently". Sure that the http stack semantically only depends on the tcp "interface" to "compile" (if that was a thing in javascript), but as an http module that ideally should just work out of the box, it should always be shipped with a default tcp "implementation" that just works fine, rather than having the user of the module to "register" a tcp module. Using centralized message passing/routing/registering is just being lazy on handling dependency, it is like abandoning structure programming and starts using "goto" for every branch, which makes the logic flow eventually untraceable. For a system of N modules, it ideally should have around O(N) dependency edges, but a centralized hub is essentially modeling a possibly O(N^2). It only makes sense to introduce a hub when everyone potentially wants to talk to everyone. And worst of all, every module using the framework now depends on the "hub" now. While the actual logic-related dependencies are all converted to "dynamically" instantiated ones, this "static" dependency on the hub becomes extremely hard to remove in the long term. It's like a cancer. It is not a good "pattern".
- romaniv 10y agoOne interesting way of avoiding direct dependencies is to let modules interact with one another via reading/modifying DOM. It probably sounds strange, but the approach works well when you want to create reusable code that also follows the progressive enhancement principle.
- stanislavb 10y agoI've added Refraction under the "Package Managers" category; however, I'm not sure this is the right categorization https://js.libhunt.com/categories/1-package-managers https://js.libhunt.com/categories/1-package-managers Suggestions?
- spriggan3 10y agoNo it's a pubsub/event listener/subscriber library, backed by Rx js, it has nothing to do with package management. The use of "modules" here is misleading. It has nothing to do with ecmascript modules or even js modules.
- JohnDotAwesome 10y agoI don't want to rail on the author here - lord knows I've written some JavaScript that I regret now - However, putting things on an event bus does not make modules independent, testable, or re-usable. You get those things from careful planning. You are still going to introduce conceptual dependencies between modules. I'd personally rather have explicit control over those dependencies and their interfaces rather than passing it through a bus. But anyway, y'all, if class A depends on class B, formalize the interface between the two (throw an error when expectations aren't met) and then inject the instance!
- wesleytodd 10y agoHey John!! Couldn't agree more. We had an event bus in an early implementation of our application and it was a huge pain later when we didn't know every place that was using and relying on a given event. We switched to a much more explicit structure with defined dependencies and more boilerplate to reduce the "magic". It is much easier to debug and maintain over the long haul. The boilerplate stuff sucks to write, but when you are going to maintain the application for more than a few months, it takes MUCH less time to go back and understand than the alternatives.
- pheeney 10y agoWould it be possible to write some pseudocode on how you converted some of your code? I am trying to avoid some "magic" as well but not certain how to handle some of these dependencies.
- pheeney 10y ago> But anyway, y'all, if class A depends on class B, formalize the interface between the two (throw an error when expectations aren't met) and then inject the instance! Do you have a simple example of this for something like https://mbasso.github.io/refraction/docs/basics/Publishing.html https://mbasso.github.io/refraction/docs/basics/Publishing.h... in react? Would you hard code in the dependencies if you have "multiple" modules that respond to "onUserLogin" "event".
- throwanem 10y agoThis appears to be an inspired and clever attempt to solve a problem which, unfortunately, is already much better addressed by means of dependency injection.
- exception_e 10y agoMy thoughts exactly with things like this. If a new pattern is introduced, it should be superior to the old one and (hopefully) translate across languages.
- deleted 10y ago[deleted]
- shove 10y agothis is a great example of a good idea being turned into rubbish by dogmatic worship of The Idea (tm) rather than understanding the reasoning behind that idea.
- gnestor 10y agoRedux (among many others) uses an immutable log of messages (actions) to manage state and uses pub/sub to communicate between UI components and the state "store." This is significant because it allows the developer to debug the application by replaying messages/actions. Refraction appears to to take a similar approach with "history" and "replay" and "publish"/"subscribe". Both Redux and Refraction have a concept of middleware (such as a logger) that will log every messages that dispatched/published. One notable feature of Redux is the single reducer that centralizes all state update logic. It appears that with Refraction, subscriptions are scattered about the project and there is no way to inspect the dependencies between modules at a given point in time. So my question is: Why use Refraction in lieu of Redux or a Elm architecture-like pattern?