Friday, October 23, 2009

First look at Visual Studio 2010 Beta 2

Visual studio 2010 Beta 2 is out, so lets take a look at some of the changes:

  1. The new WPF UI is a nice clean face lift.
  2. The new extension manager makes getting, updating, and managing plug-ins, templates, and controls(Telerik has almost their entire product line available) from the web easy, my only real issue with the extension manager is I can’t find a way to load plug-ins that aren’t in the gallery, and a lot of my favorite plug-ins(Ghost doc and R#) aren’t supported yet.
  3. The removal of the Team Studio versions, the Team Studio versions where confusing and over priced. The new SKUs are VS 2010 Professional, VS 2010 Premium, and VS 2010 Ultimate. For the full product descriptions see the Visual Studio Product page.

Some of the things that didn’t change:

  1. Adding a reference is still slow and painful.
  2. The testing frame work really hasn't changed much, although the test seem to run faster.

Things that are not quite there yet:

  1. Intellisense doesn’t work very well, but this may be a configuration setting.
  2. The number of supported plug-ins is limited, but that is understandable seeing that the plug-in model has completely changed

All in all I really like Visual Studio 2010 and I’m really excited for when it’s ready for prime time.

Saturday, October 17, 2009

Taking the pain out of code documentation

I have never known a developer that liked writing document let alone writing code document, well I take that back there was one guy but he had *Issues* and we’ll just leave it at that. I have heard all of the excuses, and in the end it still comes down to, we would rather write code then write about the code.

One common statement coming from the TDD/DDD methodologies is that the unit tests document the code; while this is great if we have the unit test, but even then a little documentation would still be useful so we don’t have to dig though unit test to figure out how to use a library. Another favorite excuse is the method names document themselves, granted having intelligently named methods and variables make understanding the code a lot easier(and we’ll get into that latter) but short of having the average method name be 40+ chars long this really isn’t practical either.

Luckily the are some tools to make writing code documentation much easier. For starters the .NET compiler can be configured to generate XML documentation files by setting an xml output file in the project build configuration. The xml content is created from specially formatted XML comments that looks like this

   1: /// <summary>
   2: /// Saves the contact.
   3: /// </summary>
   4: /// <param name="contact">The contact to be saved.</param>
   5: /// <returns>
   6: /// A true or false result of the successful saving this contact
   7: /// </returns>
   8: public bool SaveContact(Contact contact)

You can write this by hand or use a tool like the GhostDoc plug-in for Visual Studio. GhostDoc will auto generate documentation based on configurable rules for the different objects, classes, method, properties, etc. One of the very nice features about being able to configure the documentation rules is you can add additional item like remarks that say when it was documented and by who.

The second nice thing about using GhostDoc is the rules used to figure out what to put into the documentation can be used to make sure your using intelligent names, it’s not always right but it can be a good indicator for how good of names your using.

So why add this? This gives you two advantages, first it adds intelligence for your code, next it allows you to create MSDN like documentation using the .NET documentation generator Sandcastle.

Sandcastle can be downloaded from http://sandcastle.codeplex.com/ and provides a command-line interface for building your documentation from the .dll and .XML file generated by the .net compiler making it easy to add documentation generation to your automated build system. For the user it’s a little clunky and painful to use, if you want to build the documentation without scripting, there is an app for that, the Sandcastle Help File Builder located at http://www.codeplex.com/SHFB.

sandcastle_builder

Basically this lets you build a configuration that can include what is documented, the layout of the documentation, adding headers, footers, errors for missing items etc. and when you’re all said and done you get documentation that looks like this

sandcastle_documentation

it’s that easy.

Wednesday, October 14, 2009

Not ready for Inversion Of Control, just use a factory for now

There has been a lot of discussion latterly in the blog world about using inversion of control or IOC, some claiming it’s to hard to understand, it complicates development, and it’s unnecessary; the other side saying quit complaining it’s not that hard, it enforces good design and makes code more maintainable. To this I’m going to take the vary controversial position that they are both right.

Inversion of control can be intimidation the first time you use it, it adds a bit of complexity and you can write quality applications with out it. On the other side once you “get it” IOC really isn't that hard it encourages separation of responsibilities, and makes it much easier to test making regression testing and refactoring much easier.

So how do we get all of the advantages with out adding all of the complexities of an IOC container, simple just use a software factory class. For those who don’t know, basically a factory class is just away to abstract and consolidate the logic for getting your code dependencies.

Let’s say you have some code for accessing data from Amazon’s simpleDB

   1: public class ContactData : IContactData
   2: {
   3:     private Proxy simpleDBProxy;
   4:     public Proxy SimpleDBProxy
   5:     {
   6:         get
   7:         {
   8:             if (simpleDBProxy==null)
   9:             {
  10:                 simpleDBProxy = new Proxy();
  11:             }
  12:             return simpleDBProxy;
  13:         }
  14:         set
  15:         {
  16:             simpleDBProxy = value;
  17:         }
  18:     }
  19:     const string DomainName = "Contacts";
  20:  
  21:     public Contacts GetContacts()
  22:     {
  23:         Contacts myContacts = new Contacts();
  24:  
  25:         SelectRequest request = new SelectRequest
  26:         {
  27:             SelectExpression = string.Format("SELECT * FROM {0} ", DomainName)
  28:         };
  29:         SelectResponse response = SimpleDBProxy.Service.Select(request);
  30:  
  31:         var contacts = from item in response.SelectResult.Item
  32:                          select new Contact()
  33:                                     {
  34:                                         Email = item.Attribute.GetValueByName("Email"),
  35:                                         Name = item.Attribute.GetValueByName("Name"),
  36:                                         Phone = item.Attribute.GetValueByName("Phone"),
  37:                                         ID =  item.Name
  38:                                     };
  39:         myContacts.AddRange(contacts);
  40:         return myContacts;
  41:     }
  42:  
  43:     public Contacts GetContactsByName(string contactName)
  44:     {
  45:         Contacts myContacts = new Contacts();
  46:  
  47:         SelectRequest request = new SelectRequest
  48:         {
  49:             SelectExpression = string.Format("SELECT * FROM {0} where Name='{1}' ", DomainName, contactName)
  50:         };
  51:         SelectResponse response = SimpleDBProxy.Service.Select(request);
  52:  
  53:         var contacts = from item in response.SelectResult.Item
  54:                        select new Contact()
  55:                        {
  56:                            Email = item.Attribute.GetValueByName("Email"),
  57:                            Name = item.Attribute.GetValueByName("Name"),
  58:                            Phone = item.Attribute.GetValueByName("Phone"),
  59:                            ID = item.Name
  60:                        };
  61:         myContacts.AddRange(contacts);
  62:         return myContacts;
  63:     }
  64:    
  65:     public bool SaveContact(Contact contact)
  66:     {
  67:         List<ReplaceableAttribute> attributeList = new List<ReplaceableAttribute>
  68:            {
  69:                new ReplaceableAttribute().WithName("Email").WithValue(contact.Email),
  70:                new ReplaceableAttribute().WithName("Name").WithValue(contact.Name),
  71:                new ReplaceableAttribute().WithName("Phone").WithValue(contact.Phone)
  72:            };
  73:         contact.ID = Guid.NewGuid().ToString();
  74:         bool success = false;
  75:         try
  76:         {
  77:             if (!SimpleDBProxy.Domains.Contains(DomainName))
  78:             {
  79:                 SimpleDBProxy.AddDomain(DomainName);
  80:             }
  81:             PutAttributesRequest action = new PutAttributesRequest
  82:               {
  83:                   ItemName = contact.ID,
  84:                   Attribute = attributeList,
  85:                   DomainName = DomainName
  86:               };
  87:             PutAttributesResponse response = SimpleDBProxy.Service.PutAttributes(action);
  88:             success = true;
  89:         }
  90:         catch (Exception requestException)
  91:         {
  92:             success = false;
  93:         }
  94:  
  95:         return success;
  96:     }
  97: }

now because this implements the IContactData interface

   1: public interface IContactData
   2: {
   3:     Contacts GetContacts();
   4:     Contacts GetContactsByName(string contactName);
   5:     bool SaveContact(Contact contact);
   6: }

we can use it anywhere we would use IContactData, for example here we have an application that uses both local and remote contacts

   1: public class ContactsRequests
   2: {
   3:     private IContactData ContactData;
   4:     public bool UseLocalContacts { get;set; }
   5:  
   6:     public Contacts SearchContactsByName(string contactName)
   7:     {
   8:         if (UseLocalContacts)
   9:         {
  10:             ContactData = new LocalContactData();
  11:         }
  12:         else
  13:         {
  14:             ContactData = new ContactData();
  15:         }
  16:         return ContactData.GetContactsByName(contactName);
  17:     }
  18:  
  19:     public Contacts GetContacts()
  20:     {
  21:         if (UseLocalContacts)
  22:         {
  23:             ContactData = new LocalContactData();
  24:         }
  25:         else
  26:         {
  27:             ContactData = new ContactData();
  28:         }
  29:         return ContactData.GetContacts();
  30:     }
  31:  
  32:     public bool AddContact(Contact newContact)
  33:     {
  34:         return ContactData.SaveContact(newContact);
  35:     }
  36: }

now this works but there are a few problems, first there is no way to test it’s functionality without testing the functionality of LocalContactData and/or ContactData with a little simple refactoring

   1: public class ContactsRequests
   2: {
   3:     private IContactData contactData;
   4:     public IContactData ContactData
   5:     {
   6:         get
   7:         {
   8:             if (contactData==null)
   9:             {
  10:                 if (UseLocalContacts)
  11:                 {
  12:                     contactData = new LocalContactData();
  13:                 }
  14:                 else
  15:                 {
  16:                     contactData = new ContactData();
  17:                 }
  18:             }
  19:             return contactData;
  20:         }
  21:         set
  22:         {
  23:             contactData = value;
  24:         }
  25:     }
  26:     public bool UseLocalContacts { get;set; }
  27:  
  28:     public Contacts SearchContactsByName(string contactName)
  29:     {          
  30:         return ContactData.GetContactsByName(contactName);
  31:     }
  32:  
  33:     public Contacts GetContacts()
  34:     {
  35:        return ContactData.GetContacts();
  36:     }
  37:  
  38:     public bool AddContact(Contact newContact)
  39:     {
  40:         return ContactData.SaveContact(newContact);
  41:     }
  42: }
we remove the instantiation logic from the method and move it to a public property this way we can set the ContactData property to a mock object and test the specific logic of the methods in this class, now the only problem with this is everywhere we want to use IContactData we have to perform the same logic, and basically reproduce the same code over and over again. This is where factories come in, if we build a factory like this
   1: public static class DataFactories
   2: {
   3:     public static IContactData GetContactInterface(bool isLocal)
   4:     {
   5:         IContactData myContactData;
   6:         if (isLocal)
   7:         {
   8:             myContactData = new LocalContactData();
   9:         }
  10:         else
  11:         {
  12:             myContactData= new ContactData();
  13:         }
  14:         return myContactData;
  15:     }
  16: }

Then we just implement it like this

   1: public IContactData ContactData
   2: {
   3:     get
   4:     {
   5:         if (contactData==null)
   6:         {
   7:             contactData = DataFactories.GetContactInterface(UseLocalContacts);
   8:         }
   9:         return contactData;
  10:     }
  11:     set
  12:     {
  13:         contactData = value;
  14:     }
  15: }

your applications don’t know or care how they got there class for getting contact all they know is they did, where this really comes in handy is if you have to change out how you handle your local contacts from let’s say an xml file to a database, the only place you have to change your code is in the factory.

Congratulations you are now 90% of the way there for using a IOC container, you have a single place for handling all of your instantiation so once you decide to use IOC you just change how the factory works from having logic that decides what class to insatiate to pulling it from the IOC container, it’s that simple.

Truth be told I always start with a factory and then later “IF” I need the functionality of an IOC I’ll add it. In the end an IOC container really isn’t nearly as scary as it seems to be, and in the same token it isn’t nearly a vital as some people would like to claim, it’s a tool that can be used to solve specific problems, but 90% of the same problems can be solved using a factory.


Tuesday, October 6, 2009

A walk in the clouds with SimpleDB

For starters I’m a cloud skeptic, I think it’s too new and untested to make any real long term predictions about where it’s going to go, but having said that it looks very interesting, and if you don’t have the hardware it can be a very inexpensive way to have a very scalable application.

Signing up with Amazon

For starters go to http://aws.amazon.com/simpledb/ and click on the signup and create an account which requires a credit card, just so you know.

As far as the cost, it really is very reasonable to free, based on your monthly usage with the first 25 Machine Hours free and each additional hour costing $0.140, your first GB of storage is free with each additional GB costing $0.25 per GB Per month. For bandwidth your 1st GB of data upload is free with each additional GB costing $0.10; your first GB of download is free with the following price structure for additional download badwith

  • $0.170 per GB - first 10 TB / month data transfer out
  • $0.130 per GB - next 40 TB / month data transfer out
  • $0.110 per GB - next 100 TB / month data transfer out
  • $0.100 per GB - data transfer out / month over 150 TB

While setting up the account was easy, there site is confusing, hard to navigate, and frustrating, my biggest complaint is I have to resign in constantly.

Getting the Amazon Tools

Finding the C# Library for Amazon SimpleDB is a pain, so I’m kindly providing you a link, now this is just source code, which is kind of irritating, why can’t they just give me the DLLs, but on the other side I can look at what they are doing, and how they do it.

Using the Amazon Tools

The first thing to do is build a proxy for interfacing with the simpleDB web service, something like this

   1: public class Proxy
   2: {
   3:     private string PublicKey = String.Empty;
   4:     private string SecretKey = String.Empty;
   5:     public AmazonSimpleDBClient Service{ get; set;}
   6:     private List<string> domains;
   7:     public List<string> Domains
   8:     {
   9:         get
  10:         {
  11:             if (domains==null)
  12:             {
  13:                 domains = GetDomains();
  14:             }
  15:             return domains;
  16:         }
  17:     }
  18:  
  19:     public Proxy()
  20:     {
  21:         PublicKey = ConfigurationManager.AppSettings["PublicKey"];
  22:         SecretKey = ConfigurationManager.AppSettings["SecretKey"];
  23:         Service = new AmazonSimpleDBClient(PublicKey, SecretKey);
  24:     }
  25:  
  26:     public List<string> GetDomains()
  27:     {
  28:         ListDomainsRequest ListDomainsAction = new ListDomainsRequest();
  29:         ListDomainsResponse response = Service.ListDomains(ListDomainsAction);
  30:         return response.ListDomainsResult.DomainName;
  31:     }
  32:  
  33:     public void AddDomain(string domainName)
  34:     {
  35:         CreateDomainRequest myCreateDomainRequest = new CreateDomainRequest {DomainName = domainName};
  36:         CreateDomainResponse response = Service.CreateDomain(myCreateDomainRequest);
  37:     }
  38:  
  39:     public void DeleteDomain(string domainName)
  40:     {
  41:         DeleteDomainRequest request = new DeleteDomainRequest {DomainName = domainName};
  42:         DeleteDomainResponse response = Service.DeleteDomain(request);
  43:     }
  44: }

This class provides several things, first it sets the public and secret keys for simpleDB, this is basically your authentication to simpleDB, as you can see I’m using an app setting to store this. The next important thing is the AmazonSimpleDBClient property called service, this is how you interact with simpleDB. Last you have the Domain methods, these are used to get what domains you have, add new domains, and finally delete unused domains.

Now we have our proxy lets build something that uses it

   1: public class ContactData
   2: {
   3:     private Proxy simpleDBProxy;
   4:     public Proxy SimpleDBProxy
   5:     {
   6:         get
   7:         {
   8:             if (simpleDBProxy==null)
   9:             {
  10:                 simpleDBProxy = new Proxy();
  11:             }
  12:             return simpleDBProxy;
  13:         }
  14:         set
  15:         {
  16:             simpleDBProxy = value;
  17:         }
  18:     }
  19:     const string DomainName = "Contacts";
  20:  
  21:     public Contacts GetContacts()
  22:     {
  23:         Contacts myContacts = new Contacts();
  24:  
  25:         SelectRequest request = new SelectRequest
  26:         {
  27:             SelectExpression = string.Format("SELECT * FROM {0} ", DomainName)
  28:         };
  29:         SelectResponse response = SimpleDBProxy.Service.Select(request);
  30:  
  31:         var contacts = from item in response.SelectResult.Item
  32:                          select new Contact()
  33:                                     {
  34:                                         Email = item.Attribute.GetValueByName("Email"),
  35:                                         Name = item.Attribute.GetValueByName("Name"),
  36:                                         Phone = item.Attribute.GetValueByName("Phone"),
  37:                                         ID =  item.Name
  38:                                     };
  39:         myContacts.AddRange(contacts);
  40:         return myContacts;
  41:     }
  42:  
  43:     public Contacts GetContactsByName(string contactName)
  44:     {
  45:         Contacts myContacts = new Contacts();
  46:  
  47:         SelectRequest request = new SelectRequest
  48:         {
  49:             SelectExpression = string.Format("SELECT * FROM {0} where Name='{1}' ", DomainName, contactName)
  50:         };
  51:         SelectResponse response = SimpleDBProxy.Service.Select(request);
  52:  
  53:         var contacts = from item in response.SelectResult.Item
  54:                        select new Contact()
  55:                        {
  56:                            Email = item.Attribute.GetValueByName("Email"),
  57:                            Name = item.Attribute.GetValueByName("Name"),
  58:                            Phone = item.Attribute.GetValueByName("Phone"),
  59:                            ID = item.Name
  60:                        };
  61:         myContacts.AddRange(contacts);
  62:         return myContacts;
  63:     }
  64:    
  65:     public bool SaveContact(Contact contact)
  66:     {
  67:         List<ReplaceableAttribute> attributeList = new List<ReplaceableAttribute>
  68:            {
  69:                new ReplaceableAttribute().WithName("Email").WithValue(contact.Email),
  70:                new ReplaceableAttribute().WithName("Name").WithValue(contact.Name),
  71:                new ReplaceableAttribute().WithName("Phone").WithValue(contact.Phone)
  72:            };
  73:         contact.ID = Guid.NewGuid().ToString();
  74:         bool success = false;
  75:         try
  76:         {
  77:             if (!SimpleDBProxy.Domains.Contains(DomainName))
  78:             {
  79:                 SimpleDBProxy.AddDomain(DomainName);
  80:             }
  81:             PutAttributesRequest action = new PutAttributesRequest
  82:               {
  83:                   ItemName = contact.ID,
  84:                   Attribute = attributeList,
  85:                   DomainName = DomainName
  86:               };
  87:             PutAttributesResponse response = SimpleDBProxy.Service.PutAttributes(action);
  88:             success = true;
  89:         }
  90:         catch (Exception requestException)
  91:         {
  92:             success = false;
  93:         }
  94:  
  95:         return success;
  96:     }
  97: }

Here we have a simple example of how to add/get items from simpleDB, one important thing to note is the IDs are GUIDs, this is because the objects don’t get and incrementing index ID you need to get a unique identifier and the easiest way to do that is to just used a GUID.

One thing you will notice is I have added some extension method helpers for getting the data out, this is just a way to simplify getting your data back out.

   1: public static class SimpleDBExtedors
   2: {
   3:    public static string GetValueByName(this IList<Attribute> myAttributes, string name)
   4:    {
   5:        string myValue = (from attribute in myAttributes where attribute.Name == name select attribute.Value).FirstOrDefault();
   6:        string value = string.Empty;
   7:        if (!string.IsNullOrEmpty(myValue))
   8:        {
   9:            value = myValue; 
  10:        }
  11:  
  12:        return value;
  13:    }
  14: }

Final thoughts

SimpleDB has some very interesting abilities, primarily the ability to not have to manage your DB structure, worry about indexes, and all of the other DB stuff most devs don’t want to deal with, you simply take whatever objects you have and put them into the DB, and pull them back out. The cloud has some unknowns(security, reliability, etc.) but i think this is definitely a technology to keep your eye on, and last here is the source for the sample application (source), just keep in mind this sample application isn't done and the source is subject to change.