Caps Lock Me Up
0 comments so far

When is the last time you voluntarily pressed Caps Lock for its intended purpose? When was the last time that last time wasn’t meant as an ironic mocking of the key’s intended function? And yet, the key is so easy to reach, nestled in the loving embrace of the fan favorites Shift and Tab. It seems quite unfortunate that such a useless key has such a prime piece of keyboard real-estate.

Replacing the Caps Lock key is definitely not groundbreaking – indeed, many archeologists believe that the Caps Lock key is itself an usurper. Harkening back to the days of yore, many modern developers opt to replace the function of the caps lock key with Control, hearkening back to the ways of their ancestors, who in the early 1640’s apparently manufactured keyboards with the Controlle Ceye in that position. For a period in the early 18th century, it was popular to place an additional Backſpace there instead. The Caps Lock key was only seated in its modern-day position beginning in the 1830’s, where it has remained a thorn in the side of many coders ever since.

But what can be done to right the wrongs that history has wrought? Many traditionalists revert the key to its historical mappings. Randall Monroe did something awesome, as usual. Both of these are more useful than the Caps Lock key in its native state. Another useful technique is to turn the Billy Mays key into an additional modifier key, allowing you to have even more useful shortcut keys to barely remember.

I use a buckling-spring Customer 104 Keyboard, and love it, but I occasionally miss having modern conveniences such as easily keyboard-accessible volume controls. The idea of repurposing Ctrl, Shift, and Alt for global shortcuts makes me nervous, because real programs use these keys. But real programs generally don’t use Caps Lock in their shortcut keys, so there’s essentially no chance of a collision, and you are likely to be able to select better mnemonics because you have no competition.

The tool I use for my Caps Lock adventure is AutoHotkey. Install the program, then edit your global script. Disabling Caps Lock in the conventional sense is as easy as SetCapsLockState AlwaysOff, but CapsLock will still function in your own aliases. Simply remapping keys is trivial, and fairly complex things are easily possible in the script as well – an excellent place to start looking is Lifehacker’s extensive AutoHotkey directory.

Among other changes, I’ve mapped CapsLock+Up/Down to volume controls, CapsLock+PageUp/PageDn to the media next/previous, and CapsLock+Home is Pause/Play. These combinations are both extremely easy to reach and extremely unlikely to be used by other programs. You are more likely to have the media keys already, but you get the drift – there is a large number of unused key combinations available that you can repurpose for whatever actions would be most beneficial in your daily life. If you’re feeling ambitious, script them up to do something smart. You have dozens and dozens of potential shortcut keys waiting to serve, and you don’t have to involve six modifier keys or Scroll Lock to avoid trampling over that obscure shortcut that launches HyperTerminal.

In this article, I give a brief tutorial on how to use PartCover, a free, open-source code coverage analysis tool for .NET developers. Code coverage can help you to determine whether or not your software has been adequately unit tested, and is particularly useful in highlighting edge cases that may have been overlooked.

As far as free code coverage tools for .NET developers are concerned, neither the NCover Community Edition nor PartCover are 64-bit compatible out of the box yet, which is quite a shame, since I think most developers have moved on to 64-bit boxen by now. Luckily, the solution was readily available on the venerable StackOverflow. Note that if you’re running Windows 7, there is a a minor additional step: you will have to launch PowerShell or cmd as an administrator, because otherwise Program Files is read-only. Alternatively, you can download this version of PartCover.exe that has already been converted and place it in your installation directory.

Running the Analysis from the GUI

Before you can view the results of your analysis, you’ll have to run it. It’s not exactly immediately clear how to set up the analysis from within the PartCover Browser, so here’s a quick rundown of the dialog you’ll see when you do a File –> Run Target…

imageThe Executable File should be set to the 32-bit version of your unit testing framework’s runner – in my case, that’s nunit-console-x86.exe. It should not be the path to your project’s binary.

Set the Working Directory to your unit test project’s bin folder. Working Arguments is where you’ll finally specify the path to your unit test project’s binary – in my case, this is Debug\SuffixArrayTests.dll.

Last, you need to specify the rules for what to run. Each rule takes the form of +filter or filter, where +filter causes a class to be included in the coverage report, and filter causes it to be excluded even if a previous rule would have included it. Filters, in turn, take the form [Namespace]Class, with support for wildcards. In the case depicted here, coverage analysis will be provided for all classes in the SuffixArray namespace, and all classes in the SuffixArrayTests namespace.

You can save these settings for later, but remember that the Save / Load buttons here are not the same as the Save/Open report buttons in the main window, which are for the results of the coverage analysis, not for these settings. That is to say, if you want to load your target settings again later, you’ll need to do so within this window.

 

Running the Analysis from the Console

You can also run the coverage analysis from the command line or with a batch file like this one. This is useful if you’d like to run the same coverage report frequently, or if you’d like the analysis to be performed as part of your continuous integration.

set partcover="C:\Program Files (x86)\Gubka Bob\PartCover .NET 2.3\partcover.exe"
set nunit="C:\Program Files (x86)\NUnit 2.5.3\bin\net-2.0\nunit-console-x86.exe"
set tests="Debug\YourTests.dll"
%partcover% --target %nunit% --target-args %tests% --include [*]* --output PartCoverResults.xml

Once your coverage report has been generated, you can open it in the PartCover Browser exactly as if it had been created from within the GUI.

 

 

What Your Coverage Is Telling You

Before you do anything else, enable “View Coverage Details.” Frankly, I’m not sure why this isn’t enabled by default, because it’s what reveals most of the information you’re interested in.

image

The pane to the left shows you the structure of your code, as well as how much of the code was reached during execution. Code that is reached is green, while code that is never reached is red. If code is not reached, a unit test is probably missing.

image 

Essentially, unreached code means that there is a path of execution that is not hit by any of your unit tests. This doesn’t necessarily mean that you’re missing a unit test – there is some grey area – but it is definitely a warning light. Even if you’re confident that the code works, it’s worth remembering that unit tests are one of the few kinds of documentation capable of yelling at you when they’ve become outdated or inaccurate.

What Your Coverage Is Not Telling You

Remember that a code coverage analysis tool can only analyze the coverage of your unit tests in terms of how many paths through your code get exercised. It can’t tell you if you’re exercising these paths properly, or whether you are checking for meaningful conditions.

Another case where your coverage tool cannot help you is when your unit tests are conflated. In my example, there is a SuffixArray class and a SuffixComparer class. In this example, I did not even load the unit tests for the latter class, but it’s still considered to have 100% coverage. This is because the SuffixComparer’s sole method has only one execution path, and it is used by SuffixArray methods which are tested, despite not having been tested itself. That’s not to say that code coverage analysis is useless in this case, though – if you’re like me, unexpectedly covered code can also help you realize when you’ve forgotten a unit test. I’ll be honest with you: although I’ve fixed it now, when I first started writing this article, I didn’t forget to load the tests for SuffixComparer -- I forgot to write them. As I looked at the results, it jumped out at me that SuffixComparer was “covered” even though I had failed to write tests – and having noticed this, I went back and created the missing tests. Even when code coverage does notice your failures, it may help you to notice them yourself.

Since Nitriq is a new tool, I thought that it might be useful to share a few simple, real-world-style queries that demonstrate what you can expect Nitriq queries to look like.

  • This will filter out automatically generated names and generic type parameters from the lists. You can replace Types with Methods as well.

    var results = Types.Where(t => !t.Name.Like("<.*>.__.*") && t.FullName[0] != '.');

    Nitriq’s simplified regular expression queries make it very easy to find identifier names – ordinarily, you’d have to use a RegEx object, or roll your own extension method to hide those details.

  • We can find all recursive methods:

    var results = Methods.Where(method => method.Calls.Contains(method));

    Normally, you’d have to examine individual methods to see whether or not they were recursive, but because Nitriq gives you access to all of the methods that a method calls, we only need to find methods that call themselves and we’re done. In one line, we’ve found every recursive method. Nitriq also gives access to all of the methods that call a given method via the CalledBy property, and makes it easy to find out where instance variables are set and where their values are used.

  • As another example of using the method call information provided by Nitriq, we can find all public methods that are only called within the class in which they are defined:

    var results = Methods
        .Where(m => m.IsPublic && m.CalledBy.All(m2 => m.Type.TypeId == m2.Type.TypeId));
  • Sometimes even the name of a type can provide us with information about what might be wrong with it. Oftentimes, a method name with a conjunction indicates that the method could be violating the single responsibility principle. This query will find all methods that contain some such conjunctions in PascalCase:

    var results = Methods
        .Where(method => method.Name.Like(".*And.*|.*Then.*|.*Or.*", false));

    The ‘false’ we’ve passed in makes the query case-sensitive so that methods like HideHeadInSand() don’t trigger the rule.

  • Find all methods that return or take in System.Object:

    var objectType = Types.Where(t => t.FullName == "System.Object").Single();
    var results = Methods
        .Where(m => m.ParameterTypes.Contains(objectType) || m.ReturnType == objectType);

    C# has excellent type-safety, but inappropriate use of object negates many of these benefits. It often indicates a place where another approach, such as generics, should be preferred.

  • Find excessively commented methods:

    var results = Methods.Where(m => m.PercentComment > 10);

    Depending on how your religion treats comments, you may want to tweak this value, but methods with more than a few lines of comments tend to indicate either a case where an old implementation has been commented out as a poor substitute for version control, or an futile attempt to shoehorn clarity into a muddled method.

  • As Scott recently discussed in his amazingly alliterative post, Copious Cyclomatic Complexity Creates Confusing Code, excessive cyclomatic complexity can be strongly indicative of potential faults. This little snippet gives you the average cyclomatic complexity of all of the methods in each type.

    Func<BfType, System.Collections.Generic.IEnumerable<BfMethod>>
        cyclomaticMethods = t => t.Methods.Where(m => m.Cyclomatic > 0);
    
    var results = Types.Select(
        t => new {
            TypeId = t.TypeId,
            TypeName = t.Name,
            AverageCyclomatic = 
                cyclomaticMethods(t).Any() ? 
                cyclomaticMethods(t).Average(m => m.Cyclomatic) : 0
        }
    );
  • For today’s final example, we can see a few other neat features while we find circular dependencies:

    var inTypePairs = Types
        .SelectMany(t => t.InTypes.Select(
            u => new { TypeId = t.TypeId, TypeName = t.FullName, DependentOn = u.FullName })
        )
        .Where(t => t.TypeName != t.DependentOn);
    var reverseTypePairs = Types
        .SelectMany(t => t.InTypes.Select(
            u => new { TypeId = u.TypeId, TypeName = u.FullName, DependentOn = t.FullName })
        );
    var results = inTypePairs.Intersect(reverseTypePairs);

    Nitriq exposes the types that a type depends on as InTypes, and the types that depend on a type as OutTypes. This allows us to see a list of all types such that have circular dependencies, which, although allowed within a namespace, might not be ideal, especially if the two types really belong in different modules. This query selects a list of pairs (Type, InType) for each of a Type’s InTypes. It also selects the reverse pairs (InType, Type), and performs an intersection between the two list.

    Dependencies This query is also doing something different than all of the previous queries: here, we’re selecting an anonymous type, instead of one of the Bf- types ‘native’ to Nitriq. Nitriq is smart enough to show the fields of an anonymous type with the appropriate column headings, as you can see to the right.

 

I haven’t really delved deeply into what you can do with Nitriq here, but I hope that I’ve at least demonstrated how easy it is to accomplish many real-world queries.

Here at NimblePros, we’ve recently begun working to release a new code analysis tool called Nitriq. Because I wasn’t personally involved in its development, my goal was to attempt to break it, as I am wont to do with any new tool. I was pleased to find that it was actually very difficult to throw an impossible query at it -- at the risk of sounding clichéd, “simple queries were easy, and difficult queries were possible.” There are many different code analysis tools, but what we believe differentiates Nitriq is how customizable it is. You aren’t limited to customizing existing rules, and you don’t need to learn any kind of “special” language to create new rules – they’re all written in C#, just like your project.

Nitriq allows you to perform queries on the properties of types, methods, and more, and to issue warnings based on your findings. It’s easy to find methods that require too many parameters, or types that have an inordinate number of dependencies. These queries are normally written as LINQ, because it’s simple to read and write, and idiomatic to a C# developer. Most of the time, you’ll find that LINQ alone can express your rules quite elegantly, but when you start to need more complex queries, you won’t find yourself out on the street.

Nitriq holds its own as your queries get more complicated. Because you’re almost always writing LINQ, it’s easy to forget that you aren’t limited to it when the task at hand requires bigger guns -- you’re really writing an honest-to-goodness C# method, and anything that is valid within method scope in a ‘real’ project can be done in Nitriq as well, because Nitriq rules are methods. This means that you can split your queries into multiple steps to improve readability, or extract methods to simplify queries.

You can’t define a method within a method in C#, but you can define a delegate, and quite easily – really, the only ‘trick’ is that we need to specify the types that are accepted and returned. Types that you’re likely to care about in Nitriq begin with Bf – BfMethod, BfType, and BfNamespace, for example. As a quick first example, let’s extract a simple delegate. We want to get all public methods that are in the core assembly and which are not constructors, operators, or properties.

Func<BfMethod, bool> isRegularMethod =
    method => !(method.IsConstructor || method.IsStaticConstructor ||
    method.IsPropertyGetter || method.IsPropertySetter || method.IsOperator);

var results = Methods.Where(m => m.Type.IsInCoreAssembly)
    .Where(m => m.IsPublic)
    .Where(isRegularMethod);

It would also be easy to embed the last part of the query, but extracting parts of a query can be convenient and improve readability if they occur in multiple locations in your query, or, like in this case, the expression is very long. There are also cases where using this method will allow you to express rules that would be difficult or impossible to express if you were limited to a single LINQ expression.

For a slightly more complex example: let’s say that you’ve inherited the source of a large, egg-related library with an base class called, appropriately, Egg. There is a naming convention that the names of all of Egg’s overly-specific derived types must be suffixed with “Egg.” Not all eggs directly inherit from Egg, though: you have many types of BirdEgg, many types of LizardEgg, and even a couple of MammalEggs, thanks to our friends the monotremes. Furthermore, we can’t assume anything about the depth of our inheritance hierarchy – a ChickenEgg inherits from BirdEgg directly, but an AracaunaEgg is a kind of ChickenEgg. To make matters more difficult, Eggs do not currently implement an interface, so we can’t do a type.Interfaces.Any(t => t.Name == "IEgg"), and the Egg namespace is polluted with a variety of Nests, so we can’t apply our rule to every type within the namespace. You need to find a list of all descendants of Egg – no matter how indirect – that do not end with “Egg.”

A type’s DerivedTypes field includes only its directly derived types, but because we can break the query down, it doesn’t have to be difficult to find further derived classes. Using a delegate, we can use recursion, which will make it much easier to express this query.

Func<BfType, System.Collections.Generic.IEnumerable<BfType>> allDerivedTypes = null;
allDerivedTypes = delegate(BfType type)
{
    if (type.DerivedTypes == null || !type.DerivedTypes.Any())
        return new BfType[]{};
    
    var furtherDerivedTypes = type.DerivedTypes.SelectMany(t => allDerivedTypes(t));
    return type.DerivedTypes.Union(furtherDerivedTypes);
};

var results = Types
    .Where(t => t.Name == "Egg")
    .SelectMany(t => allDerivedTypes(t))
    .Where(t => !t.Name.Like("Egg$"));

WarnGreaterThan(results, 0);

Our rule can now help us easily find that somebody forgot to put Egg at the end of several classes, causing the humble Ostrich and many other excellent birds to have rather unexpected methods and properties such as BreakShell() and ShellStrength.

Ostrich

Nitriq has allowed us to save time by automating a search that would normally be cumbersome and error-prone, even with excellent tools like ReSharper. Chances are, your application doesn’t have any eggs in it – but if I can write a rule specifically about eggs, of all things, you can write rules to handle whatever your specific requirements happen to be.

There are many other things you can do with a code analysis tool like Nitriq, which I plan to blog about occasionally, as do my alphabetically-by-surname-ordered coworkers, Scott and Ben. Nitriq isn’t quite ready for mass-consumption, but if you’re feeling adventurous, and don’t mind the occasional hiccup, there’s a free beta available.

 After no small amount of prodding, poking, and piddling about, and with only eleven months to spare*, I have now joined the current decade with a blog of my very own, where I can post my thoughts and musings about software development without bringing harm to the internet community at large. Although it may be too much to hope that my posts will be insightful, I certainly hope that they will at least be informative. Except for this one. This one is a lost cause, as are all introductory posts.

As for who this Chris Wagner is, I work as a part-time developer at Nimble Software Professionals, a software consultancy in perennially sunny Hudson, OH, while also working toward an M.S. in Computer Science at the nearby Kent State University. I genuinely enjoy my work and my work environment -- I consider myself very fortunate to be in this position.

At any rate, I aspire to make my first real post at some point in the near future. I also aspire to be be more coherent at that time, but I do not want to set the bar so high so soon.

* Or a few negative months, if you are such a real coder that you feel that the common era should zero-indexed, just like an array.