New Feature Request: [Rotten] attribute

This is an inoffical new feature request – I am floating between sarkasm and really considering to implement this.

Here it is, I proudly present:

The [Rotten] attribute*

* Other candidate names are: [Smells], [CodeSmell], [Stinks]

The principle is simple:

  1. If you find a piece of code that is of very low quality, annotate it with the [Rotten] attribute.
  2. The tooling (e.g., Resharper, CI, any quality management tools such as SonarCube) does the rest for you:
    • The properties, methods, or classes (short: code unit) marked with the attribute are considered “rotten” and are marked as such – this could be anything ranging from a simple Resharper warning to a “rotten lines quotient” or the like, to gamification tools such as the Jenkins game plugin which would punish the introduction of and reward the removal of rotten code (though introduction of the attribute and the cascading markings should not count).
    • Any code unit that directly depends on a rotten code unit is itself considered rotten.
    • Any code unit that directly inherits from rotten code is itself considered rotten, too.
    • These rules are applied recursively such as to propagate the rot to the uttermost thing depending on the rotten cluster of code.

Help – my code is marked “rotten” – what can I do?

You can take the following measures to bring down your “rotten code quotient”:

1. Fix the rotten code.

Cover it with unit tests, refactor it, fix the bugs, remove the smell, make it readable. Once you are finished, remove the attribute – all of your dependent code will immediately get rid of its “rotten” status, too.

2. If 1. is not (yet) possible: Protect yourself against the rotten code

Remove direct dependencies on rotten units. For “has-a” dependencies: Invert your dependency. Put a well-defined interface between the two units. Then you can cover both sides with unit tests to document the behavior of the rotten unit, including correct and incorrect parts, and verify that your “clean” unit handles both correct and incorrect parts properly. It will also loosen the coupling of your not-in-itself-rotten code to the rotten part. It will improve odds that you will ever be able to simply exchange the rotten unit by a newly-written one.

In severe cases you could even consider to introduce a mediator class/adapter class between rotten and clean units. They could “even the bumps” and prevent the clean part from assimilating to the rotten part.

For “is-a” dependencies (i.e., subclasses) – Stop inheriting from that rotten base class. Introduce an interface for other code pieces so you can satisfy them without inheriting from a base class. Introduce a new clean baseclass, or stop subclassing at all – it might be part of the problem that led to the code rot.

3. Are you kidding?

Kind of. Only. If you take the measures above, you will manage to keep as much as possible of your code secure from being infected by the rot of the already-rotten parts. If you do not take these measures, and the code that you might consider clean depends on rotten code, your clean code will misbehave and become hard to maintain just as the rotten code does, because code rot is infectious. This is why this code is harshly considered “rotten”, too, thus providing an incentive to fix that.

Advertisements

Generic Types are prettier than Dictionaries

If you need to pass key-value-pairs to a method you can find many modern implementations prefer to take them as an “object” rather than a dictionary. This allows you to create a anonymous object which is prettier than a dictionary: It is a shorter notation, and it brings along some of the advantages of static typing:

var result = MyMethodThatTakesAnAnonymousObject(
    new { foo = "bar", baz = 1 };

 

The method then reflects on the object and uses the property names as keys and their values as the – values.

What you might not have been aware of: The same can be done for return objects. If the caller of the method knows what keys it expects, you can support it by taking this expectation as an anonymous object:

var result = PleaseReturnTheResultInAnObjectLikeThis(
    new { foo = "", bar = 0 });
Console.WriteLine(result.foo);

 

And this is how it works:

[TestClass]
public class LittleTest
{
    [TestMethod]
    public void Test_A_Little()
    {
        var t = PleaseReturnTheResultInAnObjectLikeThis(new { Foo = "" });
        Assert.AreEqual("hello", t.Foo);
    }
    private T PleaseReturnTheResultInAnObjectLikeThis<T>(T input)
    {
        // The following line simulates any logic that creates keys and
        // values in any form. You can use LINQ to transform them into
        // a dictionary as a pre-step to fill them into your T object.
        var values = new Dictionary<string, object> { { "Foo", "hello" } };

        // The next line brings us to the heart of the idea
        return MapToGenericType(input, values);
    }
    private static T MapToGenericType<T>(T input, IDictionary<string, object> values)
    {
        var constructorInfo = input.GetType().GetConstructors().Single();
        var parameterInfos = constructorInfo.GetParameters().ToArray();
        var parameters = new object[parameterInfos.Length];
        foreach (var parameterInfo in parameterInfos)
        {
            parameters[parameterInfo.Position] = values[parameterInfo.Name];
        }
        var output = (T) constructorInfo.Invoke(parameters);
        return output;
    }
}

The clue is that an anonymous object always brings along its anonymous type with a constructor whose parameters are 1:1 the properties that you defined for the anonymous object. You can use generics to transport knowledge of the type of any anonymous object beyond the scope where it was defined.

This way you kind of define an expectation to the results in a static-typed manner. Your compiler will not guarantee that the expectations hold true though, you will only find it by the time that MapToGenericType is executed.