Monday 26 November 2012

IDisposable and object initialisers

Background...

The "using" statement is just syntax trick. The resulting compiled code from a "using" statement is actually a try-catch statement.

This...


    public class MyClass
    {
        public void MyMethod()
        {
            using (MyDisposableClass myDisposableClass = new MyDisposableClass())
            {
                myDisposableClass.DoSomething();
            }
        }
    }


...is converted by the compiler to this...


    public class MyClass
    {
        public void MyMethod2()
        {
            MyDisposableClass myDisposableClass = null;
            try
            {
                myDisposableClass = new MyDisposableClass();
            }
            catch
            {
                myDisposableClass.Dispose();
            }
        }
    }


Problem...

Consider the following code:

    public class MyClass
    {
        public void MyMethod()
        {
            using (MyDisposableClass myDisposableClass = new MyDisposableClass
                {
                    MyProperty = string.Empty
                })
            {
                myDisposableClass.DoSomething();
            }
        }
    }


This can cause a problem.

The problem is caused by the object initialiser. Remember, the object initialiser is just syntactic sugar. "Under the covers" (the actual compiled code), the object will be created as normal with its constructor and then the properties would be assigned afterwards.

So the use of the object initialiser means the object will be created outside the scope of the using statement. This in turn means the scope of the try-catch statement generated by the compiler would be incorrect. If the object is not created inside the scope of the using statement (and therefore the try-catch statement), should there be an error during the creation and initialisation, then "Dispose" will never be called. If Dispose is never called, the object will not be disposed in a timely manner. This means you may leak resources.

FxCop will advise you of the problem with an error like the following:

CA2000 : Microsoft.Reliability : In method 'MyClass.MyMethod()', object '<>g__initLocal0' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g__initLocal0' before all references to it are out of scope.

The correct code is as follows:


    public class MyClass
    {
        public void MyMethod()
        {
            using (MyDisposableClass myDisposableClass = new MyDisposableClass())
            {
                myDisposableClass.MyProperty = string.Empty;
                myDisposableClass.DoSomething();
            }
        }
    }


The lesson is not to use object initialisers in combination with "using" statements.

Monday 19 November 2012

Enterprise debt

Following on from the earlier post on Technical Debt, there exists a similar concept for the enterprise - "Enterprise Debt".

Enterprise debt follows the exact same parallels with financial debt. You may have inefficient business processes, duplicated business processes, manual processes or a myriad of problems with your Enterprise Architecture. These problems constitute a tax on your business but this costs may be justified. Duplicated business processes might allow different business units to start or move in parallel. Inefficient or manual business process might be justified because you have not had time to improve them or automated them, yet they perform a critical function. You might be happy, in the short or medium term, to pay the interest on these debts to keep your enterprise functioning.

Of course, as before, you must take care not to go bankrupt. Should your enterprise debt exceed your capacity to pay down the interest, your business is finished.

One of the goals of an Enterprise Architecture initiative should be to identify your enterprise debt and seek to reduce it. An ongoing Enterprise Architecture program should also identify new enterprise debt and ensure that it is justified i.e. the "tax" that it incurs brings a larger long term benefit.

Monday 12 November 2012

Technical debt

Technical debt is a way of describing some of the costs you can incur when building software. For example, when implementing a feature in a system you generally have two options.

  1. Implement the feature quickly, knowing that it will make future changes to the system harder.
  2. Implement the feature with more care (using time/effort) resulting in a better design and more robust implementation. This makes subsequent changes to the system easier.
There is a clear trade off here. You can liken technical debt to financial debt.

When incurring technical debt, as with financial debt, you will have to pay "interest". In the example above, the interest you pay on quickly implementing the feature is the additional cost required to implement subsequent features. You can continue to pay the interest each time you add a feature or you can repay the principal by going back and implementing the original feature properly.

Note that technical debt, like financial debt, is sometimes useful. In the same way that you likely couldn't buy a house without going into debt, sometimes you might struggle to deliver an application or system without taking on some technical debt first. Examples of useful technical debt are as follows...
  • Quickly building features so that users or business sponsors can see functionality.
  • Quickly building features to attract more customers or satisfy existing ones.
  • Quickly building features (or a whole product!) so that you get first mover advantage over competitors.
In most circumstances the driver for taking on technical debt is time, for example, you have to deliver the software on a certain date.

However, like with financial debt, you must take care not to go bankrupt. Should the interest payments exceed your capacity to repay them, you are finished.

Should you be spending all your effort on simply paying down the interest on your debts, you will be unable to move your project or business forward. At this point your your project or business will fail.

There are many examples of technical debt. Not having an automated deployment mechanism is common. Not having such a thing saves you the time it takes to implement one. The trade off being that this costs you time/effort for each occasion you deploy your application, because you have to do the deployment manually. You can either invest the time to implement an automated deployment and then experience very low cost for subsequent deployments or continue with a fixed cost for each release. Note that if the application has a short lifespan, and you will only deploy the application a few times, then it's simply not worth investing in the automated deployment mechanism. Continuing the financial debt parallel, this is similar to renting a car versus buying a car. The automated deployment is like buying the car - large up front cost giving a low cost for subsequent uses. Where as manual deployments are like renting a car - zero up front costs but a fixed cost for each use.

Like most things in software, its a matter of weighing up the costs and benefits. Taking on technical debt can be justified but should be clearly acknowledged if it is. In the vast majority of times there should be a plan to pay off the debt.

Tuesday 6 November 2012

SignalR included in ASP.NET Fall 2012 Update

Just what it says on the tin, the SignalR framework is included in ASP.NET Fall 2012 Update.


It's really great to see Microsoft really embracing open source components, giving them first class support (SignalR Hub Classes have their own Visual Studio templates) and delivering them via NuGet.

And if you've not yet heard of SignalR, you really need to check it out.

Monday 5 November 2012

Base 64 encoding strings

Encoding strings to base 64 is super trivial...

The code.


    using System;
    using System.Text;
 
    public static class StringExtensions
    {
        public static string Base64Encode(this string text)
        {
            byte[] bytes = new UTF8Encoding().GetBytes(text);
            string base64EncodedText = Convert.ToBase64String(bytes);
            return base64EncodedText;
        }
 
        public static string Base64Decode(this string base64EncodedText)
        {
            byte[] bytes = Convert.FromBase64String(base64EncodedText);
            string text = new UTF8Encoding().GetString(bytes);
            return text;
        }
    }


The test.


    using Microsoft.VisualStudio.TestTools.UnitTesting;
 
    [TestClass]
    public class StringExtensionsTests
    {
        [TestMethod]
        public void TestEncodeAndDecode()
        {
            const string OrginalText = "originalText";
            string encodedText = OrginalText.Base64Encode();
            Assert.AreNotEqual(OrginalText, encodedText, "The encoded text was the same as the original plain text.");
            string decodedText = encodedText.Base64Decode();
            Assert.AreEqual(OrginalText, decodedText, "The decoded text was not the same as the original plain text.");
        }
    }


And that is it.

Not sure why there aren't such methods in the Base Class Libraries (BCL).

Friday 2 November 2012

Interrogating NServiceBus Saga data stored in RavenDB

These days, NServiceBus stores its data in RavenDB, including any saga data. Sometimes it is useful to interrogate the saga data to report on running processes.

Querying the saga data stored in NServiceBus is not as simple as plain RavenDB Document Store client, you need to supply conventions to be able to pick up the saga data.

An example is as follows:

    using System;
    using System.Linq;
 
    using NServiceBus.Persistence.Raven;
 
    using Raven.Client;
    using Raven.Client.Document;
 
    public class Example
    {
        public void GetSagaDataFromRavenDB()
        {
            using (IDocumentStore documentStore = new DocumentStore
                {
                    ConnectionStringName = "MyConnectionString",
                    ResourceManagerId = Guid.Parse("C6687DB2-764C-46A4-A3C5-15A3BA22A01A"),
                    Conventions = new DocumentConvention
                        {
                            FindTypeTagName = new RavenConventions().FindTypeTagName
                        }
                })
            {
                documentStore.Initialize();
                using (IDocumentSession documentSession = documentStore.OpenSession())
                {
                    MySagaData[] mySagaDatas =
                        (from mySagaData in documentSession.Query<MySagaData>()
                         select mySagaData).ToArray();
                    foreach (MySagaData mySagaData in mySagaDatas)
                    {
                        Console.WriteLine(mySagaData.SomeProperty);
                    }
                }
            }
        }
    }

The GUID is specific (you need to supply that one) and the "RavenConventions" come from the NServiceBus persistence API.

And that is it.

About Me