Thursday, June 25, 2009

The ElementEnumerable Class

In our previous tutorial we showed how to use Methods like AllVariables and AllExpressions to extract information from some code in order to furnish the Code Metric subsystem of Coderush with additional Metric possibilities.

But what happens if you want to gather something that is not catered to explicitly? Perhaps you’d like to write an ExtremeMetric which counts Try..Catch information?

Let me introduce you to my good friend ‘ElementEnumerable’

ElementEnumerable

ElementEnumerable is exactly what it sounds like. It a class which is used for Enumerating Elements. It’s constructor takes a scope element, a Type filter and an option to recurs or not.

It implements IEnumerable and when used as an Enumerator, it will enumerate across the scope you handed it, stopping to pass out anything which matches what you asked it to filter.

We can create a MethodEnumerable for the current class thus…
e.Value = New ElementEnumerable(SomeClass, GetType(Method)).Cast(Of Method).Count

Our Variable Enumerator will be only slightly more complicated..

e.Value = New ElementEnumerable(SomeMethod, GetType(Variable), True).Cast(Of Variable).Count


The reason for the True param at the end is to allow The ElementEnumerable to recurse inside things like if statements in order to find variables declared deeper that the top level of the method in question.



In our previous example of a MethodEnumerable, we can safely assume that the methods we would like to find are all immediate children of the start point. If we had not made this specification, we could well have returned methods belonging to a nested class.


So if we wanted to count Try Statements, we could use….

e.Value = New ElementEnumerable(Method, GetType([Try]), True).Cast(Of [Try]).Count

…and of course you can do all kinds of calculations before you actually set this value.



So why don’t you go nuts and invent your own metric. Any questions? Just let me know :)


How To: Build your own CodeRush Metric

Well it’s been a long time, but I think I’ve finally found something I can turn into simple plugin.
-------------------------------------------------------------
Note: This tutorial assumes that you are familiar with LINQ, are coding your plugin in VS2008 and targeting a system with .Net 3.5 installed.
-------------------------------------------------------------

We’re going to provide a count of the number of variables declared in a given method.

This is an entirely contrived example. In the real world it might be used as an indicator of how complex a method is. However, you could also use the “Maintenance complexity” or “Cyclomatic Complexity” that comes with CodeRush :)

This theory this metric should involve:

  • Iterating through every node within the AST (Abstract syntax tree) looking for items representing variables.
  • Count these items and pass this count back to the DXCore for rendering by CodeRush

In practice this is a lot simpler than it sounds.

First you’ll need to create a new plugin. Once this is done, you’ll want to add a CodeMetricProvider to the design surface of the plugin. It can be found on the “DXCore: Extensions & Providers” tab of your toolbox and looks like this.CodeMetricProviderOnce dropped on the design surface, we should set a few properties.

ProviderName: ‘VariableCountMetric’
DisplayName: ‘Variable Count’
Description: Counts the variables declared within the member.
MetricGoal: Members
Warning: 10

Then handle the single event ‘GetMetricValue’.

The Theory

Your goal within the GetMetricValue, is to set e.Value based on some measureable quality of e.LanguageElement.

You could do anything here.. random numbers, length of member name, characters in method, characters in method if it were rendered in a different language :P All sorts.

In this case we will examine e.LanguageElement (the method) and calculate the number of variable declarations within it.

The “Warning” property is to give Coderush a value which is considered excessive for this metric.

Simples! :D

The Practice
Ok so how to count variables in a method?
Well the simplest way is…
-------------------------------------------------------------
SomeMethod.AllVariables.Cast(Of Variable).Count
-------------------------------------------------------------

So add this code to you handler and you’re done…
-------------------------------------------------------------
Dim Method As Method = TryCast(e.LanguageElement, Method)
If Method IsNot Nothing Then
      e.Value = Method.AllVariables.Cast(Of Variable).Count
End If
-------------------------------------------------------------

Ta Da…. Seriously go try it out…

If you get this to run successfully, then go have a look at some of the other “All” methods that hang off the method class..

Like AllExpressions, AllFlowBreaks, AllParameters or AllStatements. Similar methods exist on the ‘Type’ class.

Note: Remember to load your plugin via the “plugin manager” if you set it to “Load manually” when you created it (as you should have)


Friday, June 19, 2009

Coderush 9.2.0 Speed and Memory Improvements FTW!!

Recently Mr Mark miller posted on his blog about how much more efficient the next version of CodeRush was going to be.

In summary -> ZOMG This will be so cool".

So at the earliest opportunity, I requested access to the latest daily build of said product and was granted access

A few notes up front:

  • If you’re going to try this out, you need to uninstall 9.1
  • This version of 9.2 is a TRIAL version. It will expire eventually. Not sure when. I didn’t ask.
    • *YOU CANNOT* install this as a registered user… Nobody (Including me) has been given this level of access.
    • *Install as Evaluation* It works just as well :D
  • This is not the release version. It is a daily build. It did not go through the usual levels of testing.
  • There is a bug in this version which prevents some things from working unless you have installed everything (including the free bits)
  • The timings below were not done using a stopwatch but by me counting (1..1000..2..1000)

I have a solution I use every day at work so I thought I’d use that as the basis for my testing.

Some facts about this solution

  • It’s written in VB.net
  • It contains 13 projects (6 Class libraries, 7 Webapps/Webservices)
  • There are no project references in this solution
    • This is strange I know.
    • Instead we reference dlls built using nant as a part of our external build process.
  • According to this LOC program my solution has…
    • Number of lines = 61,358
    • Number of code files = 503
    • Number of code-generated lines = 6,563
    • Number of user-entered blank lines = 4,355
  • The .vb code files total some 3.5 MB(ish)

Some facts about the machine I use at work

WorkMachine
(click Image for large version)

WorkMachineDetail 
(click Image for large version)

So first I needed a baseline. I disabled all addins and re-loaded studio.

Studio at rest with nothing loaded, occupied [34,020 - 50,684]

(Note: Figures represent the values shown in Process Explorer for Private Bytes and Working set respectively)

I loaded my solution and timed how long it took to reach zero CPU usage within process manager.
It took approx 15 seconds to load my solution and afterward memory usage had risen to [150,740 - 193,556]
I built the solution and memory raised a little further to [170,640 - 209,184]

So this was the baseline.

What followed was several repetitions of this procedure inserting the loading of CodeRush 9.1 and 9.2 into the sequence.

In each case I restarted studio and reloaded CR where appropriate.

I will not detail everything here, but will present the summary figures.

CoderushFigures 
(click Image for large version)

So how does this break down?

Well basically it’s all in the bottom right hand corner.

So for my modest project… (after having built an on-disk cache during the first load of any given solution)

  • CodeRush has practically eliminated any previous overhead it added to the solution‘s load time. So it’s now as quick to use CodeRush as to not use it. :)
  • CodeRush saves between 45.2% and 58.5% memory depending on how you choose to judge it.

It is worth noting that these memory savings are likely to skyrocket as the complexity of your software increases.

Indeed, I have already seen a post on twitter from a user who has something more like 80% savings on memory.

I know I’m happy with my results … How about you ? … What results do you get ? :)


Wednesday, June 10, 2009

CR_ClearAllMarkers

I am something of an anomaly….

I’ve been using Coderush now for about 3 years and I *still* don't get ‘markers’. I'm an Idiot.. I have some kind of mental block. I just can't think that way for some reason.

I expect to remain ignorant/oblivious of their use in my day to day life, until I eventually meet up with Mark Miller some day and he has the opportunity to beat me until I come to my senses :D.

In the mean time however, I suffer from a particularly mild OCDesque affliction which cannot deal with their presence on my screen.

Because I don’t use them, they are noise. Small noise, but noise none the less. The fact that they are small and noisy is part of why I don’t like them… the other part is that they are everywhere.

I was explaining my psychosis to @Fredrikeriksson on twitter. I mentioned that whenever I see these little blue and red triangles in my code I have a compulsion to repeatedly hit Esc in order to clear my system of them.

Unfortunately for me, this has a side effect of causing my caret to lurch about inside my code like a demented puppy that just found a fresh roll of toilet paper. It was whilst explaining this little disadvantage, that I realized that I could probably knock up a plugin to deal with this problem in less than 2 minutes.

As it turns out, I was wrong.

It took a full 2 minutes and 15 seconds to develop and test. However the result of this short period of development is now available for all who feel the need to partake.

I give you CR_ClearAllMarkers.

In all honesty, it’s a sham of a plugin really. All I did was create a new action which called a pre-existing method within the DXCore. as usual all the hard work had already been done for me by the Coderush/DXCore team themselves.

In any case, I would like to take this opportunity to apologize to the Coderush Team. Sorry guys it's nothing personal :)