Friday, May 25, 2012

Object Design Principles - Part 1

Singular Focus and Coupling


This will be the first installment of a multiple part posting on object design principles.  These are vital to keep in mind as we go through creation of large product platforms with many interaction services and objects that must be maintained and enhanced over time.

Object Responsibility

In my mind, the most vital question you can ask yourself at the outset of an object design is, "What is this object's core responsibility?"  Your entire design should flow from that very basic question. You should consistently look for the most granular object definition possible and work back from that.  It's really easy to get blinded by the vastness of the entire project and the complete set of user stories and completely misjudge where to segregate your logic.  Once you have defined the core responsibility and focus of an object, you can immediately start creating an inheritance path as well as supplemental interfaces to bring your object into full functionality.  This is the most vital step in ensuring a scalable and easily maintainable system long term.  Consider the following basic user requirement:  "I need to be able to view images and apply enhancements to them."  The first thing that comes to my mind is that although the user requirement is to always view images, every image view session will not ultimately result in an image enhancement session.  So, I immediately break into two objects, a viewer and an editor : viewer.  At its core, the viewer object should do nothing more than accept image data and render in a viewable state. The viewer should have no concept of any data or state outside of the image itself.  It should interact via an interface with a standardized image format so that it doesn't need to have any system context. 

The system also should have no specific knowledge of the viewer (more on that when we talk about coupling).  Then, the editor class should start by extending the known viewer class.  It should not extend any operation that pertains to the loading and displaying of the base image.  That aspect of responsibility should be a black box to the editor.  The editor should contain an interface for advertising its list of manipulations as well as a standardized message based interface for executing them.  This object is not responsible for a menu or toolbar system, it is simply an image manipulator requiring system input to launch an execution of its internally known action.  It also would not have any context for displaying an image history listing.  It would maintain a list of events, based on its internally known list of manipulations and allow an outside source to interact with that list via a standardized message or interface.

Loosely Coupled Objects

The main point of the granularity of the design listed above is to ensure a loosely coupled framework.  These controls and objects should all be interacted with via their interface over standardized messages.  If each object is singularly purposed and has a black box for its implementation, the only exposure and ultimate point for breakdown is the interface itself.  The loosely coupled system (or systems) interacts with itself based on standard messages or interfaces. The granularity, once released to production, allows for a dynamically upgradeable system with hot swap components.  In this scenario, we could easily swap out our image viewer or image editor in any given system with a very limited impact on the system as a whole. The change would be contained in a singularly purposed object that is loosely coupled with its housing system.  We would be able to quickly respond to a requirement for viewing a new image format without having to make changes to our image editor control.  Additionally, this transforms every control, service or object in every system into a plausible enterprise level base class by never assuming product knowledge or any aspect of external state.

By thoroughly investigating singular focus and coupling as part of every design, we can work toward a much more stable and dynamic system in the future.

Wednesday, May 23, 2012

Dynamic WCF Throttling Behavior


WCF provides some advanced configuration opportunities to allow for performance tuning of services.  The throttling behavior allows you to configure the throughput of the service so it can be scaled to the resident processor.  The configurable attributes are:

maxConcurrentCalls: The total number of calls that can currently be in progress across all service instances. The default is 16.  Sometimes it is better to wait a couple of ticks than to allow another large process to start.

maxConcurrentInstances:  The number of InstanceContext objects that execute at one time across a ServiceHost. The default is Int32.MaxValue.

maxConcurrentSessions:  A positive integer that limits the number of sessions a ServiceHost object can accept. The default is 10.

From what I have read, the default configuration is not really wired up for a high demand environment.  It seems that the best way to target these settings is to target them at the server hardware on which you have deployed the services.  Most of the experts on the subject seem to agree that you should base these settings on the number of processors on the target machine.  The recommended settings for .NET 4.0 WCF services are maxConcurrentSessions = 100 * ProcessorCount, maxConcurrentCalls=16* ProcessorCount, maxConcurrentinstances=116 * ProcessorCount.  This is obviously problematic for a commercial software vendor since we have no knowledge of our customer machines.  Since these are so varied and fact dependent upon production environment, I thought a more dynamic approach would be a useful exercise.

I have created a class that will take the service interface name and return to you a behavior class.  The idea here is that it will dynamically find the number of processors on the machine, use your default settings for multipliers and then look in the config file for a service specific modifier for the multiplier override in case you want to configure a specific service to act independently.

First, create a static class to dynamically build a throttling behavior:

public static class ThrottleBuilder
{
   public static ServiceThrottlingBehavior BuildThrottler(String serviceName)
   {
      // check config for service specific multipliers
      Int32 maxConcurrentCalls = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxCallsMultiplier"] ?? "16");
      Int32 maxConcurrentSessions = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxSessionssMultiplier"] ?? "100");
      Int32 maxConcurrentInstances = 
            Convert.ToInt32(ConfigurationManager.AppSettings[serviceName + "maxInstancessMultiplier"] ?? "116");
 
       // build new throlttling behavior
       ServiceThrottlingBehavior throttle = new ServiceThrottlingBehavior();
       throttle.MaxConcurrentCalls = (maxConcurrentCalls * Environment.ProcessorCount);
       throttle.MaxConcurrentSessions = (maxConcurrentSessions * Environment.ProcessorCount);
       throttle.MaxConcurrentInstances = (maxConcurrentInstances * Environment.ProcessorCount); 
 
       return throttle;
 
   }
}
>
Then, leverage it as you attach the service to the host.
// crete service host
ServiceHost host = new ServiceHost(typeof(TestService));
 
// if host has behaviors, remove them.
if (host.Description.Behaviors.Count != 0)
{
    host.Description.Behaviors.Clear();
}
// add dynamically created throttle behavior
host.Description.Behaviors.Add(ThrottleBuilder.BuildThrottler("TestService"));
            
//open host
host.Open();

With this class and creation approach, you will be able to dynamically configure your throttle behavior at runtime based on the current environment.  This also gives you the benefit of additional configuration opportunities to troubleshoot or tweak the behavior for a specific customer installation.  Hopefully, you will find this useful and set yourself up to scale to any customer server configuration.

Tuesday, May 22, 2012

Microsoft Certifications

The certification marathon is complete.  The process was long and extremely difficult.  The exams themselves are very detailed and require some fairly in-depth knowledge of the specific environment / technology being covered.  I received the following six certifications:
  • MCTS - Accessing Data with .Net Framework 4.0
  • MCTS - .Net Framework 4 - Web Application Development
  • MCTS - WCF Development with .Net Framework 4.0
  • MCTS - .Net Framework 4 - Windows Application Development
  • MCPD - Designing and Developing Windows Applications using .Net Framework 4.0
  • MCPD - Designing and Developing Web Applications using .Net Framework 4.0
I learned many new things in regard to each of these items.  Had a bunch of 'light-bulb moments' for possible directions or possible fixes to existing items.  I want to set the proper expectations as well; these certifications were hard to achieve.  In my group, only two of these tests had the entire class pass the first time.  Our failure rate was around 25% on the first take and some as high as 50%.  These are not exams that you go into with a working knowledge of the platforms and pass.  They are much more in-depth than just a working knowledge.  The WCF exam is probably the most difficult test of all the TS level exams.  The MCPD exams are even tougher that the TS exams.  You are presented test scenarios that are the equivalent of business requirements and then must answer a set of questions on technical implementation.  The trick on those is that very few of the answers are absolutely wrong, so you have to choose the one that is 'best', based on wording of the questions.  For instance, there are a couple of questions where you are presented with four 'correct' answers, meaning they all fix the scenario, but the question asks for the single answer that would limit the regression testing the most.

For those of you keeping score, or just wondering, I passed all of my exams the first time (passing grade was 700/1000) .  My average score was just above 870/1000 with a high of 978/1000 (MCPD Windows).  I hope to leverage the new knowledge and intense training on some new platforms very soon.