Skip to main content

Micro Fluency

I’ve been having a lot of conversations at work lately about how comments are a code smell, and if you’re not writing self-documenting code, ur doin it rong.
Then I found myself in a position I’ve been in quite a few times… The general description is this: I have a method that takes two parameters. The action the method performs is best written in English in the form “{SomethingTheObjectDoesWith} {parameter1} {On/With/For/SomeOtherPreposition} {parameter2}”. The only way to name the method is “SomethingTheObjectDoesOn/With/For(parameter1, parameter2)”. It seems like I run into this situation too often. The API for all of the concerned code doesn’t necessitate building out a huge fluent interface for readability, but it would be nice to have things read just a little better in this case.
An example is certainly in order. I have an ASP.NET server control that activates a certain index on an associated MultiView. In order to let client code know whether or not it activates an index, I have this method:
public bool ActivatesViewOn(int viewIndex, string multiViewId)
{
    // Some logic that determines if the control activates the specified view
}
Here is the method in use:
filterPanel.Visible = itemClicked.ActivatesViewOn(0, contentMultiView.ID);
This is *kinda* self-documenting, but it doesn’t really read as nicely as it could. So I did this fairly minor refactoring in the control:
public IActivateViewOn ActivatesView(int viewIndex)
{
    return new ActivateViewOn(viewIndex);
}

public interface IActivateViewOn
{
    bool On(string multiViewId);
}

private class ActivateViewOn : IActivateViewOn
{
    private readonly int viewIndex;

    public ActivateViewOn(int viewIndex)
    {
        this.viewIndex = viewIndex;
    }

    public bool On(string multiViewId)
    {
        // Some logic that determines if the control activates the specified view 
    }
}
And now the calling code looks like:
filterPanel.Visible = itemClicked.ActivatesView(0).On(contentMultiView.ID);
So here I’ve created a miniature fluent interface that is specific to this method. But at what cost? Have I added needless complexity to the control? Arguably, I’ve made the client code more readable but the control code harder to maintain. Here’s how I see it:

  • PRO: Consuming code is easier to read.
  • PRO: Adding nested types (the IActivateViewOn interface and ActivateViewOn class) is no more complicated that adding methods. Basically, I get a nice fluent syntax by breaking my uglier method into a few smaller ones.
  • PRO: The added private class isn’t exposed to the client, so that piece doesn’t complicate the external API. The added interface is only exposed as a nested class on the control, so it doesn’t pollute the controls namespace.
  • PRO: I can modify this further pretty easily to keep my client code very readable as dictated by usage. Though it would probably be overkill to have itemClicked.Activates.FirstView.On(someMultiView), the option is there and the syntax could be easily produced.
  • PRO: I could rename the nested types for even more clarity in the control’s code.
  • CON: The IActivateViewOn interface might not aid discovery as a return value as much as bool might. I’m reaching here… I personally think the fluent interface is more discoverable. But how do I know I can eventually get the data that I want?
  • CON: A developer maintaining the control will think “what the hell is this?!?”.

Comments

Sam Nissim said…
I like the fluency and definitely agree with your policy on trading comments for more readable code in general. Another possible approach would be to create a MultiViewExtender control (similar to the extender controls in the Ajax Toolkit). The extender would take the MultiView, the view index, and the target control as properties. In this approach you would have to have many extenders if you have many views. Alternatively, you could have one extender as a composite control with many child bindings.

Popular posts from this blog

Migrating Hg Repos with hg-fast-export and Windows Subsystem for Linux

Introduction I prefer Mercurial (hg) to git . I don’t really have any reason for this preference - they both do the same thing, and the user experience for 90% of the use cases is the same. It probably comes from the conditions of the DVCS landscape when I started using these systems. Some of this may have been perception only, but it looked like this: GitHub didn’t have free private repos BitBucket did have free private repos BitBucket was very hg-friendly Joel Spolsky had an amazing tutorial that served as both a how-to for hg as well as a general intro to DVCS hg was much more Windows-friendly than git Since hg was written in python, I felt like extending it would be easier than doing so for git if I ever needed to (admittedly, this is a pretty ridiculous reason) hg felt like a more unified, “coherent” system than the very linux-y feeling git and its extensions (also pretty ridiculous) Where they differed, I liked the verbs hg used better than git’s counterparts ...

Enabling Globalization Invariant Mode for .NET Core App on Raspberry Pi Running LibreElec

I had an app I wanted to run on my Raspberry Pi 3 running LibreElec . In LibreElec you can install the dotnet core 2.2 runtime as an addon, and in Visual Studio you can compile for ARM processors with ‘Target Runtime’ set to ‘linux-arm’ in the publish profile. So, I published to a folder from VS using that profile, and I copied the output over to my RPi which had the dotnet runtime installed. I did a simple dotnet Whatever.dll to run the app (actually in this case, it was /storage/.kodi/addons/tools.dotnet-runtime/bin/dotnet Whatever.dll because of the way the addon is installed) and was met with this error: FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support. at System.Environment.FailFast(System.String) at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode() at System.Globalization.GlobalizationMode..cctor() at Syste...

Stubbing Static Methods with PostSharp

TypeMock uses the Profiler API to allow mocking, stubbing, etc. of classes used by code under test. It has the ability to handle sealed classes, static classes, non-virtual methods, and other troublesome-yet-oft-encountered scenarios in the world of unit testing. Other frameworks rely on proxies to intercept method calls, limiting them to be able to only fake virtual, abstract, and interface members. They also rely on dependecy injection to place the proxies as the concrete implementation of calls to the abstracted interface members. Anyone working with a legacy codebase is bound to run into static method calls (especially in the data access layer), dependencies on concrete types with non-virtual methods, and sealed class dependencies (HttpContext anyone?). The only way to unit test this without refactoring is with TypeMock. I've never used TypeMock, and I'm sure it's a great product, but it's not free. I decided to spike some code to see if I could solve the prob...