Managed Dependencies vs. Dependency Injection In RequireJS

Posted January 25, 2012 at 10:37 AM by Ben Nadel

Tags: Javascript / DHTML

In my journey towards understanding modular JavaScript application architecture, I've been using a lot of RequireJS. The RequireJS framework facilitates the organization and then the subsequent loading of individual JavaScript classes. When it comes to defining classes, RequireJS provides us with two opportunities for dependency loading: managed dependencies - those loaded by the RequireJS framework; and injected dependencies - those loaded by the application. When I first started using RequireJS, I found myself getting hung-up on when to use which approach. While some use-cases are quite clear, others are much less black-and-white.

To set the context of this discussion, take a look at the following JavaScript class defined using the RequireJS framework:

my-class.js - Our JavaScript Class Being Managed By RequireJS

  • // Define our class within the dependency management system.
  • define(
  • [
  • "dependency-1",
  • "dependency-2"
  • ],
  • function( Dependency1, Dependency2 ){
  •  
  •  
  • // Define the actual class constructor and methods.
  • function MyClass( argument1, argument2 ){
  •  
  • // ... more code ...
  •  
  • }
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Return the class constructor to define the class
  • // representation within the dependency management system.
  • return( MyClass );
  •  
  •  
  • }
  • );

I've omitted most of the code in order to draw attention to point of the conversation. This JavaScript class has four dependencies:

  • Dependency1
  • Dependency2
  • Argument1
  • Argument2

The first two dependencies are managed and loaded by the RequireJS framework itself. This means that when another part of the application requests the MyClass() module, RequireJS will handle the loading of Dependency1 and Dependency2. When the MyClass() JavaScript class is later instantiated, however, the last two dependencies - Argument1 and Argument2 - have to be managed and loaded by the application itself.

So, when you're building your modular JavaScript application, which type of dependency loading should you use?

After some trial and error, my rule of thumb has become this: If a given dependency is an "instance," it should always be loaded using dependency injection (ie. a constructor argument). The RequireJS framework exists outside of your business domain; as such, it shouldn't be charged with having to instantiate anything - instantiation requires business logic, which is the sole purview of the application.

As I started to form this opinion, the one use-case that really tripped me up was the use of the "text!" plugin to load remote HTML templates. Should RequireJS load the template? Or should my application load the template (using RequireJS) and then inject the template dependency during subsequent class instantiation?

Eventually, I embraced the idea that a remote HTML template was a "definition," not an "instance." As such, the RequireJS framework should be used to load HTML template dependencies as part of a class definition.

The other use-case that felt confusing, at first, was that of Singleton objects. This would include classes that could only be instantiated once as well as objects that did not require any explicit instantiation (ex. a hash of key-value pairs). Single-instantiation objects were relatively easy to classify - they still had to be explicitly instantiated by the application; as such, they should be injected into dependent classes during the invocation of the constructor.

But what about a static collection of key-value pairs? Such an object does not truly need to be instantiated. But, does this mean that it should be loaded by the RequireJS framework?

This one has me a bit stumped! My gut is telling me that the Application, itself, should be responsible for injecting static hashes during class instantiation. But, seeing as I have yet to define a module that consists of a static hash, I can't reason from any experience.

To use my rule-of-thumb as a guide - to fight my strictly emotional reaction - I would say that static hashes should be loaded directly by the RequireJS framework. They are not instantiated and therefore fall outside the domain of business logic.

The more I use RequireJS as a modular JavaScript dependency management system, the more I love it! And, now that I've thought more deeply and effectively about how objects should be loaded within the RequireJS framework, I think my passion for it will only continue to grow.




Reader Comments

Jan 25, 2012 at 1:53 PM // reply »
5 Comments

You have a good approach here: anything that is "static" or a singleton is a great candidate as a module. Instances of something should be created in application space, but the constructor functions can be modules.


Jan 25, 2012 at 3:30 PM // reply »
11,238 Comments

@James,

Thanks! I'm really loving this RequireJS stuff you created! I think it's completely reinvigorated my interest in JavaScript - helping me take my vision, understanding, and deep-thinking to the next level! You rock :)

There's something that I love about dealing with Constructors (as module definitions). I think it was just how I was first taught JavaScript way back in the day. It feels like it offers a level of control that is not necessarily as elegant when done with object literals.

Of course, to each their own. I'm just trying to be consistent with how I think about this stuff.


Jan 26, 2012 at 3:04 AM // reply »
2 Comments

I wouldn't call it "Dependency Injection", as that is something drastically different. (http://en.wikipedia.org/wiki/Dependency_injection)

How about "Dynamically Loaded Modules"?


Jan 26, 2012 at 8:55 AM // reply »
11,238 Comments

@Dusty,

Unless I'm reading it wrong, the Wikipedia page appears to support what I am saying:

"In its simplest implementation, code that creates a dependent object supplies dependencies to that object via constructor arguments or by setting properties on the object."

In what I am talking about, the Application is supplying the dependencies via the constructor.

If you're talking about what RequireJS is doing when it loads a module, I wouldn't know how to classify that. That's what I was referring to when I said "managed dependencies." I don't think that can be classified as dependency injection because it's not acting on an object - it's just using an asynchronous callback.


Jan 26, 2012 at 10:33 AM // reply »
11,238 Comments

@All,

I've slightly extended this conversation to the context of sub-classing in a RequireJS context:

http://www.bennadel.com/blog/2320-Extending-Classes-In-A-Modular-JavaScript-Application-Architecture-Using-RequireJS.htm

No real additional insights - just talking about how modules that provide both class definitions and "static functionality" can start to blur the lines between what *I* consider a definition vs. an instance.


Jan 26, 2012 at 11:42 AM // reply »
2 Comments

I suppose it almost fits the definition of Dependency Injection... but I still don't think I'd call it that. It's definitely not the intention of the RequireJS lib.

I think you're missing the 'injector' part, which should be able to instantiate objects based on some criteria.

RequireJS is a class definition importer, not an object instance injector. The items you call out as things that can't be injected are the only things that DI injects in other language domains (Java, C#, AS). These languages don't have an analog to RequireJS, because it's done by the compiler.

On a side note, I'm told that AngularJS has Dependency Injection... I'm just starting up a project with it, so I hope to find out soon.


Jan 26, 2012 at 11:45 AM // reply »
11,238 Comments

@Dusty,

Ah, I think I see our disconnect. I'm *not* calling RequireJS a dependency injector. Just the opposite. I'm saying that the Application (which instantiates classes and provides them to subsequent class _constructors_) is the dependency injector.

RequireJS, I'm saying is just a dependency manager - not dealing with instantiation at all. Just loading file definitions.


Jan 26, 2012 at 11:45 AM // reply »
11,238 Comments

@Dusty,

I've heard good things about AngularJS, but have not tried it yet. Sounds very interesting, though.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools