Dependency Injection with Javascript – An Illustrated Guide (in 10 minutes or less) – by Mike Geyser



Dependency Injection with Javascript – An Illustrated Guide (in 10 minutes or less) – by Mike Geyser

0 0


dependency-injection-with-javascript

A lightning presentation for the developer user group

On Github mikegeyser / dependency-injection-with-javascript

Dependency Injection with Javascript

An Illustrated Guide (in 10 minutes or less)

by Mike Geyser

Developer User Group

08 July 2014

Overview

  • Introduction
  • Components of a hand rolled injection
  • What makes it tick?
  • How angular does it

Dependency Injection

  • Easier to test/mock Easier to test/mocklame..
  • Isolate behaviour
  • Configure at runtime
  • Object creation responsibility

The rest are awesome!

In Javascript? Why?

  • It's become a 'real' language
  • Patterns solve problems
  • Rapidly growing adoption - Angular + RequireJs

Disclaimer:

The content of this talk is shamelessly ripped off of Angular.

No original thought was harmed in the making of this presentation.

Angular style injection


    var Controller = function(Greeter) {

        /*Greeter is 'constructor' injected*/
        Greeter.greet()
    };

					    

Container has three responsibilities

    var Dependency = {

        register: function(name, dependency){

		},

        resolve: function(name) {
	        
        },

        inject: function(target){

        }
    };
					    

Registration

    var Greeter = {
        greet: function(){
            Alert("Hello Developer User Group!");
        }
    };
                            
    Dependency.register("Greeter", Greeter);
					    

Inject by key, because JS has no 'interfaces'

Registration

    var Dependency = {
        dependencies: {}, // Simple object hash
        register: function(name, dependency){
            this.dependencies[name] = dependency;
        }
    };
					    

Resolution

    var greeter = Dependency.resolve("Greeter");
    greeter.Greet();
					    

Resolution

    var Dependency = {
        resolve: function(name){
            return this.dependencies[name];
		}
    };
					    

Easy. But not what we're after..

Constructor Injection

(Where the real money is)

                                     
    var Controller = function(Greeter) {
        Greeter.greet()
    };
                                
    Dependency.inject(Controller);

					    

Magic strings

  • We want to deal in objects, but resolution is by key.
  • Simple string representation of the object.
    Controller.toString();

    /*
         "function (Greeter){
            Greeter.greet();
		 }"
    */					    

Magic strings

Relax. Embrace it. The feeling of discomfort will pass.

Magic strings

The incantation:

    var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;

    var arguments = Controller.toString()
                              .match(regex)[1]
                              .split(',');

                        

Injection

    var Dependency = {
        inject: function(target){

            var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
            var arguments = target.toString()
                                  .match(regex)[1]
                                  .split(',');
            var self = this;
            var dependencies = arguments.map(function(key){
                return self.resolve(key);
            });

            target.apply(target, dependencies);
        }
    };
                        

The whole picture

    var Dependency = {
        dependencies: {},
        register: function(name, dependency){
            this.dependencies[name] = dependency;
        },
        resolve: function(name){
            return this.dependencies[name];
		},
        inject: function(target){
            var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
            var arguments = target.toString()
                                  .match(regex)[1]
                                  .split(',');
            var self = this;
            var dependencies = arguments.map(function(key){
                return self.resolve(key);
            });
            target.apply(target, dependencies);
        }
    };
                        

How Angular wires it up

    <script>
        function Controller(Greeter) {
            Greeter.greet();
        }
    </script>

    <div ng-app="" ng-controller="Controller">
        <!-- -->
    </div>
                        

Ng hides the injection behind Controller injection.

(Much like ASP.NET MVC)

Summary

  • Simple registration / resolution
  • Reflection and 'magic strings'
  • Spirit of the law (or pattern) vs. letter of the law

Questions?

@mikegeyser