Ramblings of a .NET Developer

22 February 2015

Sunday, February 22, 2015 | by Paul | Categories: , , , | No comments
So, Nathan introduced me to his TypeScript Tiny-IOC implementation last week. As a .NET dev, using IoC/DI is standard practice and nothing new and was immediately comfortable with the concept.

This library has good intentions, but I think it goes against what TypeScript is all about, which is to have type checking and provide more OO like functionality.
In this type of implementation as each Interface has to be doubled up I feel it will cause unnecessary code. Also, you will need to keep each of the IInterfaceChecker implementations up to date whenever it's referring class changes, resulting in a maintenance nightmare.

The problem is that TypeScript does not generate objects for Interfaces. And that is fair enough, as TypeScript in my view is a developer aid for those who prefer the OO world. At the end of the day, it still generates JavaScript.

My main problem with it is the existence of IInterfaceChecker. This "interface" requires the implementing object to provide the methods they implement and the type name. This to me is an immediate "code smell", so I set about seeing how it could be done without magic strings. Also, I'm still fairly new to the web world, so I thought it would be a good excuse to have a play. :)

So, in JavaScript world there is no such thing as an interface, so my first point is to not use it in TypeScript, instead create a Class named with I as the prefix for anything we want to act like an interface. Specifying I as a prefix is a convention that has been used quite widely so I hope it would not be too much of a problem.

So, to the code...

Models

So, lets create an IPerson class that has some basic details. Remember, this is a Class and not an Interface so we get the generated JavaScript.
 class IPerson {  
      firstName: string;  
      lastName: string;  
      salary: number;  
        
      constructor(){  
           this.firstName = '';  
           this.lastName = '';  
           this.salary = 1;  
      }  
   
      fullName() {  
         return this.firstName + ' ' + this.lastName;       
      }  
 }  

Next, I created some example implementations. One correct implementation, and another 3 that are in some way invalid.

Our Person class is a true implementation of IPerson
 class Person {  
      firstName: string;  
      lastName: string;  
      salary: number;  
        
      constructor(){  
           this.firstName = '';  
           this.lastName = '';  
           this.salary = 1;  
      }  
   
      fullName() {  
         return this.firstName + ' ' + this.lastName;       
      }  
 }  

Below are 3 other objects. The first does not implement salary. In the second, salary is a string and not a number and the third, the fullname function takes two arguments, whilst the interface does not specify any.
 class PersonWithNoSalary {  
      firstName: string;  
      lastName: string;  
        
      constructor(){  
           this.firstName = '';  
           this.lastName = '';  
      }  
   
      fullName() {  
         return this.firstName + ' ' + this.lastName;       
      }  
 }

class PersonWithInvalidSalary {  
      firstName: string;  
      lastName: string;  
      salary: string;  
        
      constructor(){  
           this.firstName = '';  
           this.lastName = '';  
      }  
   
      fullName() {  
         return this.firstName + ' ' + this.lastName;       
      }  
 }

class PersonWithInvalidFullName {  
      firstName: string;  
      lastName: string;  
      salary: number;  
        
      constructor(){  
           this.firstName = '';  
           this.lastName = '';  
      }  
   
      fullName(firstname: string, lastname: string) {  
         return firstname + ' ' + lastname;       
      }  
 }

JavaScript

For those that don't have TypeScript, below is the equivalent JavaScript for the models.
 var IPerson = (function() {  
   function IPerson() {  
     this.firstName = '';  
     this.lastName = ''  
     this.salary = 1;  
     this.fullName = function(){  
       return this.firstName + ' ' + this.lastName;  
     }  
   }  
   
   return IPerson;  
 })();  
   
 var Person = (function() {  
   function Person() {  
     this.firstName = 'Paul';  
     this.lastName = 'Sanders';  
     this.salary = 100000;  
     this.fullName = function(){  
       return this.firstName + ' ' + this.lastName;  
     }  
   }  
     
   return Person;  
 })();       
   
 var PersonWithNoSalary = (function() {  
   function PersonWithNoSalary() {  
     this.firstName = 'Paul';  
     this.lastName = 'Sanders';  
     this.fullName = function(){  
       return this.firstName + ' ' + this.lastName;  
     }  
   }  
     
   return PersonWithNoSalary;  
 })();       
   
 var PersonWithInvalidSalary = (function() {  
   function PersonWithInvalidSalary() {  
     this.firstName = 'Paul';  
     this.lastName = 'Sanders';  
     this.salary = 'My Salary';  
     this.fullName = function(){  
       return this.firstName + ' ' + this.lastName;  
     }  
   }  
     
   return PersonWithInvalidSalary;  
 })();       
   
 var PersonWithInvalidFullName = (function() {  
   function PersonWithInvalidFullName() {  
     this.firstName = 'Paul';  
     this.lastName = 'Sanders';  
     this.salary = 100000;  
     this.fullName = function(firstname, lastname){  
       return firstname + ' ' + lastname;  
     }  
   }  
     
   return PersonWithInvalidFullName;  
 })();  

Reflection

Now that I have these, I set about creating a Reflection class to help me validate the implementation or one object, against another. After a bit of playing, googling and borrowing a little code from StackOverflow I came up with the following.
 var Reflection = (function () {  
   function Reflection () {  
     this.getArgs = function(fn) {  
       var args = fn.toString ().match (/^\s*function\s+(?:\w*\s*)?\((.*?)\)/);  
       args = args ? (args[1] ? args[1].trim ().split (/\s*,\s*/) : []) : null;  
       return args;  
     };  
     this.implements = function(obj,interface) {       
       var self = this;  
       for(var item in interface)  
       {  
         if(typeof interface[item] == 'function' && typeof obj[item] != 'function')  
         {  
           return false;  
         }  
         else if(typeof interface[item] == 'function' && typeof obj[item] == 'function')  
         {  
           var interfaceArgs = self.getArgs(interface[item]);  
           var objArgs = self.getArgs(obj[item]);  
           //check arguments  
           if(interfaceArgs.length != objArgs.length)  
           {  
             return false;  
           }  
           //as js has no types, can only check names  
           for(i=0;i < interfaceArgs.length;i++)  
           {  
             if(interfaceArgs[i] != objArgs[i])  
             {  
               return false;  
             }  
           }  
         }  
         else if(!obj.hasOwnProperty(item))  
         {  
           return false;  
         }  
         else if(typeof interface[item] != typeof obj[item])  
         {  
           return false;  
         }  
       }  
       return true;  
     }  
     this.dump = function(obj, elementId) {  
       var d = document.getElementById(elementId);  
       var properties = '';  
       var methods = '';  
       var classType = obj.constructor.name;  
       for(var item in obj)  
       {  
         if(typeof obj[item] == 'function')  
           methods += (item + '(' + this.getArgs(obj[item]) + '), ');  
         else  
           properties += (item + ' : ' + typeof obj[item] + ', ');  
       }  
       d.innerHTML=d.innerHTML + "<p>Type: " + classType + "<br>Properties: " + properties.substr(0,properties.length-2) + '<br>Methods: ' + methods.substr(0,methods.length-2) + '</p>';  
     };
   }  
   return Reflection;  
 })();  

The getArgs function was used from a thread on StackOverflow, which is a nice and simple method to obtain arguments of a function.

The implements function is the main routine. It finds each property and function on the interface and checks the implementing object to see if has the same property/function and that their types match.

The dump function is a helper function for me quickly visualize an object properties into an element.

IoC

As I'm still learning JavaScript etc, it is only natural that I wrote my own IoC container. :)
This is a pretty simple one, and does not implement DI.
After a bit more playing, this is what I came up with.
 var IoC = (function () {  
   function IoC () {  
     this.__keys__ = new Array();  
     this.__values__ = new Array();  
   
     this.isRegistered = function (interface) {  
       var t = typeof this.__keys__[interface];  
       var index = this.__keys__.indexOf(interface.__proto__);  
         
       if (index == -1) {  
         return false;  
       }  
   
       return true;      
     }  
       
     this.register = function(obj,interface) {  
       if(!this.isRegistered(interface))  
       {  
         var r = new Reflection();  
         if(r.implements(obj, interface))  
         {  
           this.__keys__.push(interface.__proto__);  
           this.__values__.push(obj);  
         }  
         else  
         {  
           throw "Object '" + obj.constructor.name + "' must implement '" + interface.constructor.name + "'";  
         }  
       }  
     }  
   
     this.resolve = function(interface) {  
       if(this.isRegistered(interface)) {  
         var index = this.__keys__.indexOf(interface.__proto__);  
         var template = this.__values__[index];  
         var obj = Object.create(template);  
           
         return obj;  
       }  
       else  
       {  
         throw "No registration found for '" + interface.constructor.name + "'";  
       }  
     }  
       
     this.unRegister = function(interface) {  
       if(this.isRegistered(interface))  
       {  
         var index = this.__keys__.indexOf(interface.__proto__);  
         this.__keys__.splice(index,1);  
         this.__values__.splice(index,1);  
       }  
     }  
   }  
   return IoC;  
 })();  

The functions are pretty self explanatory, but the main thing to note is that I'm storing the prototype of the "interface" object as my key. In the register function I'm using the Reflection object to valid the implementation. If the object does not implement the interface, then I throw an exception.

So, to test all this I could use some testing framework like Jasmine. But, I've not used this yet, and didn't want to get bogged down in figuring it out. So, I've created a regular html page to do this for me. Maybe a Jasmine implementation should be the next item on my long TODO list...

Again, here is the page to test the functionality.
 <!DOCTYPE html>  
 <html>  
 <head>  
   <script src="models.js"></script>  
   <script src="reflector.js"></script>  
   <script src="ioc.js"></script>  
 </head>  
 <script language="javascript">  
   
   function validateImplementations() {  
     var i = new IPerson();  
     var validPerson = new Person();  
     var invalid1 = new PersonWithInvalidFullName();  
     var invalid2 = new PersonWithInvalidSalary();  
     var invalid3 = new PersonWithNoSalary();  
       
     var r = new Reflection();  
   
     var result1 = r.implements(validPerson, i);  
     var result2 = r.implements(invalid1, i);  
     var result3 = r.implements(invalid2, i);  
     var result4 = r.implements(invalid3, i);  
   
     r.dump(i,"data");  
     var e = document.getElementById("data");  
     e.innerHTML += "<hr />";  
       
     r.dump(validManager,"data");  
     printResult('data', 'Does Person implement MyInterface?', result1);  
   
     r.dump(invalid1,"data");  
     printResult('data', 'Does PersonWithInvalidFullName implement MyInterface?', result2);  
       
     r.dump(invalid2,"data");  
     printResult('data', 'Does PersonWithInvalidSalary implement MyInterface?', result3);  
   
     r.dump(invalid3,"data");  
     printResult('data', 'Does PersonWithNoSalary implement MyInterface?', result4);  
   }  
   
   function printResult(id,question, result) {  
     var e = document.getElementById(id);  
     var text = '<p style="font-style: italic"><b>' + question + '&nbsp;' + (result ? '<span style="color: green">Yes</span>':'<span style="color: red">No</span>');  
     text += '</b></p><hr />';  
       
     e.innerHTML+=text;  
   }  
     
   function testIoc() {  
     var ioc = new IoC();  
       
     var i = new IPerson();  
     var personTemplate = new Person();  
       
     ioc.register(personTemplate, i);  
     var text = "";  
       
     if(ioc.isRegistered(i))  
       text += ("Registered '" + personTemplate.constructor.name + "' as implementation for " + i.constructor.name);  
     else  
       text += ('Could not register ' + personTemplate.constructor.name + ' as implementation for ' + i.constructor.name);  
       
     var person1 = ioc.resolve(i);  
     text += ("<br>Resolved Person 1 (" + person1.constructor.name + ")");  
     manager1.firstName = 'Fred';  
     manager1.lastName = 'Flintstone';      
     text += ("<br>Person 1 Name: " + person1.fullName());  
       
     var person2 = ioc.resolve(i);  
     text += ("<br><br>Resolved Person 2 (" + person2.constructor.name + ")");  
     manager2.firstName = 'Wilma';  
     manager2.lastName = 'Flintstone';  
     text += ("<br>Person 2 Name: " + person2.fullName() + "<br>");  
   
     ioc.unRegister(new IPerson());  
     if(ioc.isRegistered(i))  
       text += ("<br>Attempt to unregister " + i.constructor.name + " failed");  
     else  
       text += ("<br>Unregistered " + i.constructor.name);  
             
     try  
     {  
       var person3 = ioc.resolve(i);  
     }  
     catch(err)  
     {  
       text += ("<br>Attempt to resolve failed: " + err);  
     }  
       
     var e = document.getElementById("iocdata");  
       
     try  
     {  
       var otherPerson = new PersonWithInvalidSalary();  
       ioc.register(otherPerson, i);  
       text += "<br><br>Invalid person correctly registered! :(";  
     }  
     catch(err)  
     {  
       text += ("<br><br>Attempt to register invalid person failed:<br><div style='color: red'>ERROR : " + err + "</div>");  
     }  
   
     e.innerHTML = text;  
   }  
 </script>  
 <body>  
   <button onClick="testIoc()">Test Ioc</button>  
   <div id="iocdata"></div>  
   <hr />  
   <button onClick="validateImplementations()">Validate Implementations</button>  
   <div id="data"></div>  
 </body>  
 </html>  
   

As you can see, I've saved the models, reflection and ioc in separate JavaScript files. And yes, the IoC would probably benefit from require.js, again something I've not used yet.

An example of everything is here.


12 February 2015

Thursday, February 12, 2015 | by Paul | Categories: , | No comments
I've been maintaining a few intranet sites at work which has been good to get up to speed with some of the web stuff.
A good portion of this is legacy C#/ASP.NET code with only a hint of a pattern here and there. But as the only maintainer, it has been a necessary evil to get into.

Some other project have been a lot more current, using BackboneJS, JQuery etc. Not sure I'm a fan of Backbone - there seems a lot of boiler plate code to get it working.
I find I'm a lot happier using KnockoutJS as I'm more familiar with MVVM patterns and binding paradigms - shame no one has used it on any of the projects I'm on.

But, this week I'm going to start inheriting another web application written using Ext.JS 4. All I can say is..holy crap! This is not just some nice set of components you can fit in where you want. This is a complete framework that is seems to be either all or nothing. And you build the UI by describing it through a proprietary API, and not HTML. Awesome.

Working through an example was painful, as it didn't work as described and it ended up taking me a day to get it working. It relies on magic strings everywhere which just rings alarm bells straight away and doesn't work on mobile. But, working in health means we need to have sites and software that can run on old machines and IE8. Gulp.

The one thing I've noticed moving more into web dev as there are simply too many ways to do something and quite often the optimal choice is not obvious. On the other hand, writing a Windows application, service or even web service is much easier as there are only a few ways to do things optimally. And you don't get bogged down in stuff I don't care about. But maybe that's because I've developed my own libraries/re-usable code/patterns over the years and I don't need to think about it...