Generate Dependency Graph – Analyzers … what are they?

When we chatted about Visual Studio architecture tooling in Ranger chalk talk sessions today and especially when I was watching Suhail demonstrate the use of the architecture tooling, I started think about what circular references really mean. Looking at the enormous diagrams generated when analyzing the PetShop or Tailspin sample applications the actual code and the analysis results seem to get lost in all the noise.

I decided to write some simple code, defining classes in four namespaces and creating instances where a class method calls another class method, which in turn calls the original class method. Take note of ClassA2.Test() and ClassB3.Test() …

    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Text;
    5:  
    6: namespace ClassLibraryDemoA
    7: {
    8:     public class ClassA1
    9:     {
   10:         public void Test(int iValue)
   11:         {
   12:             ClassA2 classTwo = new ClassA2();
   13:             classTwo.Test(iValue);
   14:             System.Console.WriteLine(iValue);
   15:         }
   16:     }
   17:     
   18:     public class ClassA2
   19:     {
   20:         public void Test(int iValue)
   21:         {
   22:             ClassA1 classOne = new ClassA1();
   23:             classOne.Test(iValue); 
   24:             ClassA3 classThree = new ClassA3();
   25:             classThree.Test(iValue);
   26:             ClassLibraryDemoD.ClassD1 classFour = new ClassLibraryDemoD.ClassD1();
   27:             classFour.Test(iValue); 
   28:             System.Console.WriteLine(iValue);
   29:         }
   30:     }
   31:  
   32:     public class ClassA3
   33:     {
   34:         public void Test(int iValue)
   35:         {
   36:             ClassLibraryDemoB.ClassB3 classThree = new ClassLibraryDemoB.ClassB3();
   37:             classThree.Test(iValue);
   38:             System.Console.WriteLine(iValue);
   39:         }
   40:     }
   41: }
   42:  
   43: namespace ClassLibraryDemoB
   44: {
   45:     public class ClassB1
   46:     {
   47:         public void Test(int iValue)
   48:         {
   49:             ClassLibraryDemoA.ClassA2 classTwo = new ClassLibraryDemoA.ClassA2();
   50:             classTwo.Test(iValue);
   51:             System.Console.WriteLine(iValue);
   52:         }
   53:     }
   54:  
   55:     public class ClassB2
   56:     {
   57:         public void Test(int iValue)
   58:         {
   59:             ClassLibraryDemoA.ClassA1 classOne = new ClassLibraryDemoA.ClassA1();
   60:             classOne.Test(iValue);
   61:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
   62:             classThree.Test(iValue);
   63:             System.Console.WriteLine(iValue);
   64:         }
   65:     }
   66:  
   67:     public class ClassB3
   68:     {
   69:         public void Test(int iValue)
   70:         {
   71:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
   72:             classThree.Test(iValue);
   73:             System.Console.WriteLine(iValue);
   74:         }
   75:     }
   76: }
   77:  
   78: namespace ClassLibraryDemoC
   79: {
   80:     public class ClassC1
   81:     {
   82:         public void Test(int iValue)
   83:         {
   84:             System.Console.WriteLine(iValue);
   85:         }
   86:     }
   87: }
   88:  
   89: namespace ClassLibraryDemoD
   90: {
   91:     public class ClassD1
   92:     {
   93:         public void Test(int iValue)
   94:         {
   95:             System.Console.WriteLine(iValue);
   96:         }
   97:     }
   98: }

We then generate a Dependency Graph by Namespace, enabling all three currently available analyzers as shown below.

So what happens?

  1. Namespaces and associated classes that are acting as a hub … get called and call … are shown in blue.
  2. Namespaces and associated classes that not called by anyone … are unreferenced … are shown in violet.
  3. Namespaces and associated classes that calls others, which in turn call the classes again and thereby creating a circular reference, are highlighed in red.

When we create a sequence diagram off the ClassA2.Test() method, to get a clearer view, we suddenly realize that the circular reference is a bad one, which will result in the system eating itself up … like a recursive call that recursively calls itself. At some point the system will throw a no memory exception and implode.

Changing the code as follows, maintains a circular reference between classes, nut not a recursive call that would sooner than later result in a system blow-up. … still showing a circular reference, but not one that will implode ourselves.

    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Text;
    5:  
    6: namespace ClassLibraryDemoA
    7: {
    8:     public class ClassA1
    9:     {
   10:         public void Test(int iValue)
   11:         {
   12:             ClassA2 classTwo = new ClassA2();
   13:             classTwo.TestIn(iValue);
   14:             System.Console.WriteLine(iValue);
   15:         }
   16:     }
   17:     
   18:     public class ClassA2
   19:     {
   20:         public void TestOut(int iValue)
   21:         {
   22:             ClassA1 classOne = new ClassA1();
   23:             classOne.Test(iValue); 
   24:             ClassA3 classThree = new ClassA3();
   25:             classThree.Test(iValue);
   26:             ClassLibraryDemoD.ClassD1 classFour = new ClassLibraryDemoD.ClassD1();
   27:             classFour.Test(iValue); 
   28:             System.Console.WriteLine(iValue);
   29:         }
   30:  
   31:         public void TestIn(int iValue)
   32:         {
   33:             classFour.Test(iValue);
   34:             System.Console.WriteLine(iValue);
   35:         }
   36:     }
   37:  
   38:     public class ClassA3
   39:     {
   40:         public void Test(int iValue)
   41:         {
   42:             ClassLibraryDemoB.ClassB3 classThree = new ClassLibraryDemoB.ClassB3();
   43:             classThree.Test(iValue);
   44:             System.Console.WriteLine(iValue);
   45:         }
   46:     }
   47: }
   48:  
   49: namespace ClassLibraryDemoB
   50: {
   51:     public class ClassB1
   52:     {
   53:         public void Test(int iValue)
   54:         {
   55:             ClassLibraryDemoA.ClassA2 classTwo = new ClassLibraryDemoA.ClassA2();
   56:             classTwo.Test(iValue);
   57:             System.Console.WriteLine(iValue);
   58:         }
   59:     }
   60:  
   61:     public class ClassB2
   62:     {
   63:         public void TestOut(int iValue)
   64:         {
   65:             ClassLibraryDemoA.ClassA1 classOne = new ClassLibraryDemoA.ClassA1();
   66:             classOne.TestIn(iValue);
   67:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
   68:             classThree.Test(iValue);
   69:             System.Console.WriteLine(iValue);
   70:         }
   71:         public void TestIn(int iValue)
   72:         {
   73:             System.Console.WriteLine(iValue);
   74:         }
   75:     }
   76:  
   77:     public class ClassB3
   78:     {
   79:         public void Test(int iValue)
   80:         {
   81:             ClassLibraryDemoA.ClassA3 classThree = new ClassLibraryDemoA.ClassA3();
   82:             classThree.Test(iValue);
   83:             System.Console.WriteLine(iValue);
   84:         }
   85:     }
   86: }
   87:  
   88: namespace ClassLibraryDemoC
   89: {
   90:     public class ClassC1
   91:     {
   92:         public void Test(int iValue)
   93:         {
   94:             System.Console.WriteLine(iValue);
   95:         }
   96:     }
   97: }
   98:  
   99: namespace ClassLibraryDemoD
  100: {
  101:     public class ClassD1
  102:     {
  103:         public void Test(int iValue)
  104:         {
  105:             System.Console.WriteLine(iValue);
  106:         }
  107:     }
  108: }

… changes the view as follows:

 

 

 

Cool stuff …