Friday, February 27, 2009

How does collaboration context work?

One of the most typical examples of a context object is a logger. There are two very different approaches that are available in .NET; System.Diagnostics.Trace class and the Page.Trace object (System.Web.TraceContext class). The Trace class provides static methods that you can use anywhere in your code. The TraceContext on the other hand, is only available in an ASP.NET application. But TraceContext ensures all logged messages are kept without being effected from other logging operations that are simultaneously done in other threads. Unfortunately, Trace class doesn’t care about the current threads context. It just logs whatever is passed to it, and whenever it’s passed to it. So you usually see your messages in an interwoven pattern in the log file rather than a contiguous one. In other words, the TraceContext knows about the current page context and behaves in such a way to support page related logging, while the Trace class knows only about the global app context. So how do we get TraceContext behavior like ASP.NET without having to use a global Trace object? Unfortunately, there’s no such thing in .NET.

Good news is there’s such a thing in SOCF. You just create a logging context as follows, and all the code that is called within the enclosing using() block is able to use this context. And this is done without effecting or being effected by other threads. More importantly, this is not just available in ASP.NET page, it is available wherever you need it.

            using (var log = new LoggingContext())
            {
                try
                {
                    MyMethod();
                }
                finally
                {
                    log.Dump();
                }
            }

When you want to log something to the current logging context specific to the current thread, you just use it as if it is a static class:

          LoggingContext.Add("Processing order");

Or just access it as if it’s a singleton:

          LoggingContext.Current;

This method just writes a message to the enclosing LoggingContext object. Then you can write it to Trace, or Debug output.

Now let’s look into what’s actually going on behind the scenes.

When an instance of LoggingContext is created it puts a reference of itself into the HttpContext or CallContext. These two context objects are available in .NET class library and provide a shared storage attached to a thread. HttpContext actually uses CallContext behind the scenes, but also makes sure that the context is migrated when the ASP.NET switches thread that is running the current request. In other words, CallContext is thread specific, whereas HttpContext is request specific.

          CallContext.SetData(key, data);

A string key specific to the collaboration context is generated and the collaboration context object is set to the CallContext.

The .NET call context makes sure that the context is available to all code in the execution code path. The CallContext is used as if it’s a singleton, but it’s really like a virtual singleton that knows about your current thread and won’t cause concurrency issues in a multithreaded environment. When you access the logging context for adding a message, it’ll first check if there’s a context available, and if so it’ll get it and add the message.

        public static void Add(string message)
        {
            if (Current != null)
                Current.AddMessage(message);
        }

The Current property eventually uses the previously used key to get the previously cached collaboration context object from CallContext and uses it:

        CallContext.GetData(key);

The collaboration context objects all derive from a base NamedCollaborationContext.

It is possible to nest such collaboration context objects like the LoggingContext. The nesting provides three important features: Overriding, limited scope and lifetime, reuse of parent(s).

Overriding is the simplest. When a new using() block is encountered while executing, the new object will just put itself to the current context just like the previous one, and become the new current context. So all code within the new using() block will see the new context object.

Also, the new context object will keep a reference back to the parent (or super) context object so it can refer back to it when it needs data or functionality. Here’s a pseudo code that shows how it does this:

        this.SuperConext = CallContext.GetData(key);
        CallContext.SetData(key, this);

The collaboration context object also raises some events when such context switches occur so you can do more stuff if needed.

Finally, when the using() block is exited, it’ll automatically call Dispose() method of the collaboration context object. And Dispose() method just makes sure that the super context is activated back again. Here’s a pseudo code that shows this:

        this.SuperConext = CallContext.GetData(key);
        CallContext.SetData(key, this.SuperConext);

Because of the construction and disposal behaviors, the collaboration context objects should be treated specially. Preferably they should be used only in a using() block as shown. But there’s nothing to prevent them from being just created directly. If you have to do that, you must also make sure the object is disposed of at a proper point of time when they aren’t needed.

If you don’t use using blocks, you may end up calling dispose methods in the wrong order. In that case, you’ll get an exception.

You can nest such context blocks inside the same method, or even in different methods. There’s no difference because it relies on the CallContext which is always available for the current thread. Here’s an exaggerated example for demonstration purposes:

            using (new LoggingContext())
            {
                LoggingContext.Add("Message 1");
                using (new LoggingContext())
                {
                    LoggingContext.Add("Message 2");
                    using (new LoggingContext())
                    {
                        LoggingContext.Add("Message 3");
                        MyMethod();
                        LoggingContext.Add("Message 4");
                    }
                    LoggingContext.Add("Message 5");
                }
                LoggingContext.Add("Message 6");
            }


            private void MyMethod()
            {
                using (new LoggingContext())
                {
                    LoggingContext.Add("Message 8");
                }
            }

It turns out, using those context objects, we can do pretty interesting things. For instance, we can merge the current context data or behavior with the super context or contexts. Multiple nested blocks of IdentityMap contexts can provide data from the local context, or super contexts if allowed. Or a notification context can notify only local context handlers, or super context or contexts. We can use it to provide an object creation context to do inversion of control.

In the next post, I’ll explain other types of collaboration objects that I've implemented so far.

Tuesday, February 24, 2009

Background

I just want to give some background before I go into details. The SOCF is was born with a hobby project that I'm currently working on. There is a single basic idea that everything else is based on, but it elevated my OO development experience significantly.

Object Oriented developers tend to think of everything, not surprisingly, in terms of objects. You may be thinking this statement is very totological. But think about this; what if you were allowed to write a single class for the whole app? Or you were allowed to instantiate single object or a class? Wouldn't that still be considered OO? I think, that's called procedural programming. If you have a single class that's responsible for everything, then you'll end up writing many methods (or more appropriately 'procedures') that operate on data. That's what procedural programming is all about. (The modern version of this is called 'SOA' :) OK, OK, it's a bit more than that.)

So OO is about managing many objects. And you know the difference between 1 and N. It should be quite obvious, but let me make an analogy. If you're talking about a single bit on a computer chip, that's just an electrical representation of a boolean value, an answer to some logical question you might ask. But when you put enough bits together that becomes computer engineering. The whole point is to manage the emergent complexity arising from the multiplicity of things. It's the same with OO. OO is about managing parts and pieces of your code that are usually more than 1 in number. More generally, the challenge of SW engineering, in some sense, is to manage complexity. If it wasn't so, we'd just give people CPUs and they'd do whatever they wanted to with them without needing SW engineers.

Anyway, what I'm trying to point out is the fact that, in order to talk about OO, you have to talk about it in a plural sense. And as soon as you start talking about a multiplicity of objects, you have some fundamental problems that you need to solve; The problem of creating these objects, getting them to find each other and talk to each other and letting them die. OO developers solve these problems every single day. So there's a considerable amount of code that's scattered all throughout an OO app that just sits there to do this kind of plumbing and wiring of objects together and managing their lifetimes (when they should be instantiated and when they should die), whether each object is visible to others and so on.

These are partially solved by the languages. For instance .NET provides ways of creating objects (new MyObject() or Activator.CreateInstance), and it also provides garbage collector to do the dirty work for you. Languages provide ways of passing objects around (using parameters), or providing objects (instance and static properties) etc. And then there are of course, 'Creational Patterns' like 'Singletons', 'Factories', 'Prototypes'. Languages also provide visibility; local variables, class scope, namespace, assembly, etc.

What about object lifetime? Well, it's kind of entangled with the scope because in a managed environment what you see is what you give life to. So if you have a local reference to an object, that also controls that object's minimum lifetime as long as it remains local. Or if you have a member variable that refers to an object, then the referred object's lifetime is kind of controlled by the referrer. So if it's the only reference to an object, then releasing the parent object will also release the child. On the other hand in COM, you give life to objects by incrementing their reference counts. It's like a cat that has 7 lives, and will only really die after 7 fatal accidents. It's a common scenario to keep a reference to an object that already died and use it, which is one of the causes of an instance management bug in COM. It's the same with C, C++ except it doesn't even do ref counting. So you just new() .. or malloc(), and also have to explicitly kill it by using delete, or free(). This means, the whole lifetime management has to be done manually within your code. Now if you haven't used COM or C++, you may just think how lucky you are that you didn't have to write all that lifetime management code. Well, that has some truth to it, but actually is an overstatement. You definetely still have to do some lifetime management. All the decisions about when an object should be created, whether it should be a local variable, an instance variable or a static one, or if it should be put to session, page, or viewstate all imply lifetime management decisions. Back in the day, you'd have to think about when to create an object and when to kill it. Nowadays, you think about its scope and how it's shared with other objects so it'll determine its lifetime. If you don't have a lifetime management policy embedded into your architecture, you will definetely get into some serious trouble. Here are some examples;

- Load a collection of objects from db using Linq-to-sql, take one of the objects and put it into session or static variable. You're not only keeping that single object around, but also all the objects that it's referring to. Namely, the entire collection and any loaded associated objects.

- Put an object into session or a static varialbe in ASP.NET. Then in your page start handling its event. You just created a 'memory leak' like behaviour wihout knowing about it. You'll be able to track this down only by using a memory profiler like ANTS. The reason is because whenever you handle an event of an object in .NET, you are effectively adding a strong reference from the target object back to the handler object which is the Page in this case. That means, with every post back, a new page object will get created and add itself to the list of handlers on the target object's multicast delegate.

- Just create a bidirectionally navigable object graph. And try to send it thru remoting. That will serialize the entire object graph and send over to the target service. Perhaps it's not a problem with some scenarios, but what if one of your references actually point to a large cached object?

So even if .NET provides better memory management, it can't do it without your help. So the life time management that I'm talking about here specifically emphasizes the necessary responsibility assignment for objects to control the lifetime of other objects.

What about instance discovery? Although language and runtime features are quite powerful, people found ways of improving the OO programming experience beyond fields, properties, parameters. 'Dependency Injection' frameworks are a monumental example of this pursuit. Here's Scott Hanselman's list of Dependency Injection Frameworks: http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx

Also, I recommend reading Martin Fowler's article on 'Inversion of Control and Dependency Injection Frameworks' (DI vs Service Locator).

So yes, there's quite some effort and mind power that's put into these issues. I've used 'Object Builder' and some 'Spring.NET'. I don't like messing up wiht XML files that you have to keep in sync with code. So I prefer the attribute based approaches better. However, I'd prefer the XML approach in scenarios where plug-in style extensibility is of concern.

And of course, there's this whole discussion around using DI to improve TDD. Well, DI + XML is kind of reducing maintainability by introducing new failure points, and making the code much less traceable. I mean you can't just look into code and read it. Now you also have to look into all those XML files. You have to keep all those files in sync with your code. And don't forget, the runtime will also have to do the same. There is almost no design time support for doing this kind of development as of now. So perhaps, you get to run some isolated tests, with the cost of maintainability. I'm not sure how many people can really do the tradeoff and find the sweet spot. And I'm almost sure that the sweetspot that they find is actually a sliding one. Anyway, this is a long discussion that I don't want to go into now.

OK, back to the main idea. SOCF provides some simple but practical answers to the issues discussed above. Creation, lifetime, sharing, scope, and messaging are all design considerations for object collaborations. SOCF uses .NET CallContext or HTTPContext to do instance discovery without cluttering up class contracts, because you don't really need to pass collaborating objects to all the collaborators thru their constructors, method parameters, or by setting properties on them. Instead, you start a collaboration scope within a using() block and all the collaborating objects can find the provided objects as if they are singletons provided on static properties. Of course it's more of a 'virtual singleton' than a 'singleton' that is globally available. The context object is only accessible by the currently executing thread. So you can safely use it knowing that only your thread can access this object and only within an enclosing using() block. Here's a typical usage of a collaboration context entity:

            using (var validation = new ValidationContext())
            {
                try
                {
                    TestOrderConfirmation();
                }
                finally
                {
                    // Dump the validation context in any case
                    validation.Dump();
                }
            }
Then inside any method call withing the using() block, we can access the validation context as if it's a singleton:
                if (order.Order_Details.Count == 0)
                    ValidationContext.AddError(order, "No order details!");
Although the idea is very simple, its implications on design and development considerations are huge. It really changes OO programming experience. Here are some of the interesting things that we can do with such context objects:

- Create a local singleton scope for context sharing.

- Manage scope and lifetime of collaborating objects.

- Nest such collaboration context blocks.

- Override existing context, or let the current scope use its parent or parents data and behavior.

- Implement patterns with less plumbing code with syntactic sugar.

In fact, this idea is not new and has been all around since COM+ times as far as I'm aware. In COM+, the transaction context is provided by the runtime and you don't have to pass transaction objects within your own code. It's still available on .NET if you use EnterpriseServices. If you're a ASP.NET developer, you're already doing this kind of programming because ASP.NET makes sure objects like Request and Response are always accessible. You don't need to be passed a reference to acess these objects within your code. You just use them as if they are singletons accessible thru a static property:

HttpContext.Current.Request
However, the concept is not generalized. You can use those 'contextual' objects provided to you, but you can't provide your own for the block of code you want to manage a set of collaborating objects.

So the whole idea behind SOCF was born by generalizing the idea of providing a contextualized instance discovery mechanism. It is based on the existing CallContext and HttpContext technology. But I have just elaborated on the idea and created a simple framework that implements some patterns. Then I realized, really what it leads to, is a new style of programming. Of course, like anything else it has its adventages and disadventages, but I think there's a lot of opportunity to elevate OO development experience based on this idea. So I have developed this initial version and published on CodeProject. I will be publishing another article soon with the new developments. But until then, I will keep posting the improvements as I find new ideas, and as I write the code.

The version on CodeProject implements the three base types of collaborations, a simple Identity Map, and two other sample custom collaboration context implementations for logging and validation. It also uses a simple provider model to replace the CallContext access behavior.

Currently, I'm working on collaboration contexts entities some of which are based on well known patterns: Service Locator based IoC container, A collaboration context for Spring.NET DI container, Operation Trace Context, Notification Context (weak event pattern), A sequence context (producer-consumer pattern).

I have some other ideas, but I'll first focus on those to settle the main idea and the codebase. If you download and want to use the source code, please be aware that this code is not tested under heavy load. So it's kind of at 'it works on my machine' stage at this point. But I'll do better tests and let you know about the results. Please share your ideas and comments for improving or critisism. If you do testing and find bugs, that's also welcome. If you're interested, this blog is the only place for this kind of sharing on SOCF, but should be good enough for now.

Saturday, February 21, 2009

The first simple implementation of SOCF published on CodeProject

I'm a senior software engineer focusing mostly on .NET technologies, specifically c#. I've worked on C, C++, assembly languages, pascal, delphi in my early days. My OO experience is mostly based on my Pascal and Delphi background. I also gained a lot of Component Oriented development experience in the COM, COM+ days up until 2000s. I developed the first speech synthesis software for Turkish back in '97 (SpeakTurkish). While working on OCR/ICR technology in 97, I developed a contextual dictionary based ICR postprocessing engine which was used in multimillion dollar projects. I learnt OpenGL for hobby, did some neural network + genetic algorithms stuff just for curiosity. I developed a 3d rendering engine which used a self devised version of portal based games. The engine could render geometrically impossible environments defined by logically interconnected spatial information which I called 'Hyperspatium'. During this project, I developed a scripting engine that helped developing spatium and skeletal animation definitions. Other countless hobby projects that I worked on helped me gain quite some OO design and development experience.

For the last 5 years I've been working as a consultant for a startup in Manhattan, New York. I love this job because it gave me the opportunity to realize some of my ideas in SW engineering in a friendly environment. For my current company, I have developed the Netsoft-USA Framework that improves the development lifecyle based on SW Factory approach. The framework provides tools and libraries for developing ORM based data access, hierarchical containment based domain object model, remoting/WCF based business services as well as ASP.NET, Windows Forms bindings. The ORM component provides a strongly typed query model (EQL-Entity Query Language) based on call chaining pattern. Contrary to Linq, it specifically targets SQL language within C# and almost provides all syntactical details of TSQL (insert, select, update, delete, union, join, subqueries, functions, aggregates, validation, conditional building, caching etc). The data is populated into entities directly by on-the-fly generated IL code. The latest version of the framework also contains unit testing library for highly data dependent applications, something not yet addressed by other unit testing frameworks as of today. In the last year, I have focused on the DSL approaches with VS 2008 Extensibility Framework and developed new tools for the existing framework.

I have some interesting ideas that I've been accumulating for some time. So I decided to create an open source project and share it.

The SOCF started as part of a weekend project that I'm currently developing. As I implement new features I'll be discussing those in this blog with periodic posts. I also published an article on CodeProject.

If you're interested please send me your comments. Since this is my weekend hobby project, it may take a while for me to respond, but I'll be as responsive as possible at least in the beginning.