A Portion of Buff

Everybody else had one, so...
Visual Studio.Net 2001

On the last project I was on, there were a lot of ex-Java guys who were used to working with IntelliJ and Eclipse, and who derived endless pleasure from ridiculing Visual Studio's comparative shortcomings.  They renamed it 'Visual Retardio' ('Visual Subbuteo' came a close second).  When Jetbrains started the ReSharper EAP earlier this year we all jumped on board in a flash, and stuck through months of pain and suffering (it was nicknamed 'ReBlunter' for a time) until finally the finished product was released.

Then Visual Studio 2005 went beta, and I was hoping that Microsoft would now have an IDE that was competetive with the best Java IDEs, and that would give us all the things we had become used to with ReSharper.

After using VS.Net 2005 for a few weeks, and having used VS.Net 2003 with ReSharper for the last six months or so, I have come to realise the following:

I much prefer VS.Net 2003 + ReSharper over VS.Net 2005, for the following reasons:

1) Refactoring

  • ReSharper's refactoring menu is context sensitive, and will only present those which are relevant to the current cursor location.  2005 just gives you all of them, then throws an error when you try and use one in the wrong place.
  • ReSharper has Introduce variable.  I use this all the time.
  • ReSharper has a sweet inline rename for local variables and parameters, and will even suggest names for you based on the type.

2) Highlighting

  • ReSharper will colour fields, local variables and methods.
  • It will colour unused or unreachable code.
  • It will highlight all usages of a field/variable/method within a file.
  • Type this into any method in 2005:

      Console.WroteLine();

What happens?  Very little.  Try it with ReSharper and it will colour 'WroteLine' in red, and present you with a drop-down list of all the valid Console methods (it will even narrow the list to the best matches).

4) Code Navigation

  • 2005 now has a usable Goto Definition, but you can't navigate to sub or parent types.
  • 2005 now has Find References, but it doesn't find references.  It finds symbols matching the currently selected element, which is a very different thing.  If I'm looking for references of a method, I don't want to be presented with a list of similar-looking methods on other classes, and I don't want the method I just selected to be present in that list.  It's just broken.
  • Guess what?  Both these features really work in ReSharper.  And it has decent 'Find Type' and 'Find Method' feature, which narrows the list as you type.

5) Quick Fixes / Smart Tags

  • I'm no big-city usability expert <gasp!>, but to me, Smart Tags have a big failing: they require three steps to select an option via the keyboard.  First, you use a hot-key to get the menu up.  Then, you move the cursor down to the option you want, and then you hit return.  This wouldn't be so bad, but if there's only one option in the list, you still have to navigate to it!  ReSharper's Quick Fixes automatically select the first or only option in the list, and in some cases (if you use a type without importing it with a 'using' statement, for example) it will bring up a tooltip with the relevant option, requiring only one key press to activate it.

6) Intellisense

  • ReSharper will give you a list of types which haven't yet been imported.  When you select one, it will complete your code and add the 'using' statement for you.  It will also auto-complete variable assignments, including brackets and a semi-colon if required.

7) 'Miscellaneous'

  • ReSharper's 'Extend Selection' feature is quite hard to explain, but very useful.  Essentially it's like ctrl-click, but it selects outwards from the current cursor position, and is scope-aware (eg it will select the name of a method call, then the call + its parameters, then anything enclosing that, then anything enclosing that, right up to the file level).
  • Duplicate Line - like [ctrl-c, cursor down, ctrl-v], but all in one go.

I really could go on, but this sounds too much like an advertisement already.  Suffice to say that I am disappointed by the first beta of 2005, and I hope that Microsoft can improve things a little by the time they release.  I am looking forward to the day when Visual Studio really understands code, rather than being a glorified text editor.

Double whammy

Anyone who has passed a managed delegate as a parameter to an unmanaged function will be familiar with the oh-dear-the-GC-just-pulled-the-rug-from-under-me NullReferenceException you get if you don't keep save a reference to that delegate.  It's hard to debug, but once you are aware of the problem you tend not to make the same mistake again.  Or. So. I. Thought.

So I'm merrily hacking away with .Net 2.0, trying out the new flashy bits like generics and anonymous methods, when I tried out the new type-inference features in C#.  Essentially this means that C# creates the delegate for you, and code like this:

button.Click += new ClickEventHandler(OnClick);

can be simplified like this:

button.Click += OnClick;

which is much nicer.  It also means you can pass delegates to, you guessed it, unmanaged code without explicitly declaring a new delegate instance, and then spend a happy few hours debugging a stack-less NullReferenceException, safe in the knowledge that the problem can't be related to the delegate being garbage collected, because you'd never make that mistake again.  In my defence, I was clearly drunk on syntactic sugar.

Which leads me to the second whammy: in 2.0, you don't always get a NullReferenceException in this situation.  Sometimes, you get an AccessViolationException, which is a new type meant to help distinguish between null references and other types of AVs.  Unfortunately, the CLR seems to be inconsistent about which one it chooses to throw (I was getting NRE on some runs and AVE on others) and led me to investigate the wrong flavour of bug.

Oh yes, we're fully XML enabled

I missed one off the Programming by Superstition list:

Myth:

DataSets store their data internally as XML.

Rationale:

Microsoft said so!

When ADO.Net was announced, there was a lot of marketing guff about how it was "based around" XML, and how XML was a "first-class citizen".  After all, it was the year 2000, and no CxO worth their salt was going to buy into a solution that wasn't "fully XML enabled".  In fact, there is at least one article on MSDN which refers to DataSets being "natively an XML structure", so perhaps Microsoft believed their own hype.

Truth:

DataSets aren't really the key structure here - they don't do much more than group DataTables together.  In turn, DataTables group DataColumns together, and DataRows act as a "horizontal slice" into a group of DataColumns.  Going one level further, a DataColumn is just a wrapper around one of a number of classes inheriting from DataStorage (BooleanStorage, ByteStorage, CharStorage and so on), and those are just strongly-typed arrays with a bit of collection-management logic thrown on top of them.  So, no XML.  Sorry.

(And just for the record, they would have been feckin stupid to have used XML anyway).

Programming by superstition

Myths and half-truths around .Net and C# best-practices crop up frequently in discussion forums, with rationales ranging from utterly believable to indefensible.  I thought I would catalogue the ones I see most frequently.  I realise I am leaving myself open to ridicule by prefixing my 'corrections' with 'Truth', but someone has to make a stand :-)  Feel free to correct me.

Myth:

Always set your objects to null (or Nothing) when you're done with them.

Rationale:

The garbage collector won't be able to free an object if any another object is referencing it. 

Truth:

The garbage collector can free any object that is unreachable from any of the various heap roots.  If object A references object B, and object A is unreachable, object B can be released if it has no other references from reachable objects.

Myth:

StringBuilder.Append() is always faster than String.Concat().

Rationale:

String operations always create new string objects, whereas StringBuilder uses internal magic to avoid expensive allocations.

Truth:

Using a StringBuilder is sometimes (even usually) faster than using simple string concatenation, but there is a performance cutover point.  Various people have found this to be around the 5 - 10 concatenations mark.  The bottom line being that replacing this:

string fullName = firstName + " " + lastName;

with this:

StringBuilder builder = new StringBuilder();

builder.Append(firstName);

builder.Append(" ");

builder.Append(lastName);

string fullName = builder.ToString();

is rather pointless.  Remember that StringBuilder is itself reference type, and has the associated allocation/deallocation costs.

Myth:

Strings are passed to, and returned from, methods by-value.

Rationale:

Strings are immutable, therefore they must have value type semantics, therefore must be copied by value.

Truth:

Strings have certain value-type semantics (namely, immutability), but are otherwise heap-based reference types, and references to them can indeed be passed or copied.  Passing a string reference to or from a method does not copy the underlying string.

Myth:

Dispose() releases an object's memory.

Rationale:

Well, it's called 'Dispose' isn't it?

Truth:

Dispose() is merely a convenient place for a class' developer to place any resource clean-up code, in the hope that clients will call it.  Dispose does not free the managed memory allocated for an object.  The only thing that can do that is the garbage collector; there is no way to deterministically (or manually) release memory.

Myth:

Keeping ADO.Net connection objects open for the duration of a [Page/Control/1000-line method]'s lifetime is more efficient than repeatedly opening and closing it around each operation.

Rationale:

Connecting to a database is expensive, so try to avoid doing it too much.

Truth:

If your managed provider allows connection pooling, and if pooling is enabled (it is, by default, for the managed SQL Server provider at least), calling Close() on the connection object does not simply close the underlying connection.  It merely releases that connection back to the pool where it can be associated with another managed connection object at some time in the future.  This is a Good Thing, especially in multi-threaded environments such as ASP.Net, because physical connections are rare resources and should not be coveted.  (By the same token, calling Open() on a managed connection when a pooled physical connection is available will simply associate the former with the latter).

By keeping a managed connection in an open state, you are preventing objects in other threads from getting hold of them, leading to potential bottlenecks.

Myth:

Int32 and int are not the same thing (ditto float/Short, long/Int64, string/String, etc.).

Rationale:

They're spelled differently.

Truth:

The C# simple type keywords are interchangeable with the equivalent BCL types; they are aliases.

The remarkable staying-power of of System.Assembly

There was an interesting bug in NMock until recently (it's been fixed) which saw memory usage during unit test runs increase in relation to the total number of mock objects created during the run.  The culprit was .Net's inability to unload assemblies from a running AppDomain: each mock was being hosted in a brand new dynamic assembly - which never gets garbage collected - so you could easily end up with a few hundred assemblies languishing in the root domain, eating memory.  We fixed it by creating one assembly for all mock types, and by caching identical types for the duration of the test run.

Today, another bug was raised against NMock, which involved calling GetManifestResourceNames() on all loaded assemblies.  Dynamic assembliles will throw NotSupportedException for this method (and for a couple of others), so if any code which relies on this call is used alongside NMock (in this case it was NVelocity), we break it.

I looked at a couple of workarounds, including saving our mock assembly to disk and reloading it as a static assembly so it could play nicely, but noticed that AssemblyBuilder, which we use to generate the mock assembly, is never garbage collected either!  So, kids, be aware that if you generate assemblies at runtime, even just to save them to disk, your AssemblyBuilders will hang around for ever, holding you memory hostage and calling you "poo-breath" behind your back.  The solution, of course, is to do your code-gen in a separate AppDomain, which is pretty weak but at least you can throw it away when you're done.

Does anyone have a good reason why assemblies cannot be garbage collected?

Build, old woman! Build like the wind!

What's your build speed?  How long does it take between you clicking on the check-in button and the green (or red!) light appearing on the task bar telling you your build succeeded (or failed!).  In our case a finished build is announced by Homer shouting "woohoo!" or "D'oh!", and it takes around three minutes for the "express" build - just compilation and unit tests- and twenty minutes for the full build, which includes acceptance tests, MSI compilation and deployment.  That's for a 200,000 line application, which I suppose is medium-sized.

Colleagues on different projects have remarked on this as being pretty quick, and have noted build speeds of 1 - 2 hours for similar sized applications.  The biggest overhead for them seems to be database activity, which we try to minimise by using mock objects and abstraction layers like Neo.  We also try to keep compile times as short as possible by aggresively deleting dead code, useless comments and using statements etc., and to keep unit tests small and well-targeted.

So, it would be interesting to get a sense of how long other people sit around for waiting for a build, and what the biggest contributing factors to slow build speeds are.  Does your build take so long you only run it at night?  Do you find it unnecessary to build more than once a day (or even less frequently?).  Let me know.

Jetbrains 'ReSharper'

Jetbrains briefly posted a feature list for the first beta of their VS.Net plugin (hopefully out this week), and then pulled it. Watch me get in trouble for posting it here (excuse the lack of formatting):

ReSharper is a Visual Studio .NET add-in which facilitates everyday code development tasks. Currently it mainly targets code navigation, search and insight. In the near future it will support refactorings and more outstanding code modification and insight features.

Navigation

Navigation is one of the most frequently used groups of features, so we discuss it first.In ReSharper one can go to a declaration, base or inherited element, variable type, etc. using a single keyboard shortcut which is much simpler than to dig to drop-down menus.

Action Shortcut Description

Go to Declaration Ctrl+B Position the caret at usage of any symbol and use this action to jump to its declaration

Go to Inheritor(s) Ctrl+Alt+B Position the caret at usage or on the declaration of any type (class, interface, etc) and use this action to navigate to its inheritors.

- or -

Position the caret at usage or on the declaration of any method (as well as property, indexer, etc) and use this action to navigate to methods overriding (implementing) this one.

Go to Base Ctrl+U Position the caret within declaration of any method (as well as property, indexer, etc) and use this action to navigate to method(s) this one overrides(implements).

- or -

Position the caret on declaration of any type and use this action to navigate to its super types.

Go to Type Declaration Ctrl+Shift+T Position the caret at usage of any variable and use this action to jump to the declaration of its type

 

You can also use the following shortcuts to quickly open any classes or files for editing:

Action Shortcut Description

Go to Type Ctrl+N Invoke this action and type in a few first characters of some class (interface, etc) name. It will bring you list of all types whose names match entered prefix and you'll be able to quickly navigate to the desired type. You can also use wildcard ('*') characters (e.g. enter "*Test" for all types which have "Test" in their names).

Go to File Ctr+Shift+N Same to Ctrl+N, but displays list of files in the solution

 

Finally, we have the following in-class navigation shortcuts:

Action Shortcut Description

Go to Previous Method Alt+Up Go to previous method (property, operator, etc)

Go to Next Method Alt+Down Go to next method (property, operator, etc)

 

Search

To search for usages (inheritors, implementing classes, etc.) of any symbol position the caret at its usage or on its declaration and press Alt+F7. Found results are displayed in Find Results View. They are organized there in tree where you can change grouping, merge occurences, filter out reads/writes, etc.

Another useful action is Highlight Usages. By pressing Ctrl+Shift+F7 you can highlight usages of the symbol you're standing at in the current file. It is mostly useful for local variables but can also be used for any other symbol. It highlights reads and writes with different colors, so you can easily see where you assign or read a variable or property.

You can use Ctrl+Alt+Up/Ctrl+Alt+Down to navigate between occurences found by either Alt+F7 or Ctrl+Shift+F7. Note that these shortcuts work for selected find results view even when focus is in the editor pane.

File Structure

You can easily view structure of the file you're currently in by pressing Ctrl+F12. You can navigate in this list by typing first letters of the member you're looking for.

Refactorings

The first EAP version has only one refactoring - rename refactoring (more refactorings come soon!). Rename refactoring is called with Shift+F6 shortcut. You can invoke it from the editor when caret is at the declaration or on usage of the symbol to be renamed. You can also use it from VS views like Class View or Object Browser.

Parameter Info

Position the caret within argument list of some method call (or new operator, indexer etc) and press Ctrl+P. A small popup window with list of available signatures is displayed.

Code Completion

Code completion tries to predict which code is appropriate in the current context making code writing faster. There are three kinds of code completion:

Action Shortcut Description

Basic Completion Ctrl+Space Diplays list of symbols available in the current context.

A special case of this completion works for completion of variable name when you declare it. For example, you may type in "ArrayList color", press Ctrl+Space and get "colorList" and "colorArrayList".

SmartType Completion Ctrl+Shift+Space It detects the type which is expected in the context and suggests only choices that match the expected type. It works on the right hand of assignments, in argument lists of method invocations, in return statements and other places where expected type is known.

Special variants of this completion work after "new" keyword allowing to instantiate the expected type and for type casts (after '(' or "as" keyword) casting to the expected type.

Type Name Completion Ctrl+Alt+Space This type of completion displays the list of all types matching the entered prefix independently from using directives in the current file and when you select an item it inserts the necessary using directive if needed.

 

IMPORTANT: If you want the completed item to replace the existing code, use Tab key to complete item instead of Enter. For example, if you have the following code:

 

e.{Caret here} foo();

and want to replace foo with bar, press Ctrl+Space, choose "bar" from the list and press Tab.

Live Templates

Live Templates are pieces of code which can be inserted into the code and are automatically customized to match the context they're called in. A live template can be called by typing its "abbreviation" (a short mnemonic sequence of letters associated with template) and then pressing the Tab key to insert the template. Another way is to use Ctrl+J shortcut which lists available templates with abbreviations matching the entered prefix. To see all available templates just press Ctrl+J on a blank line. Currently the set of available templates is fixed but soon users will be able to define their own templates.

Surround With

This feature allows you to quickly put the selected code fragment into if-statment, loop or code block. To try it select a few lines of code and press Ctrl+Alt+J.

Error Highlighting

As you type code ReSharper analyses the code "on-the-fly" and automatically highlights syntax errors such as unresolved symbols, mismatched types or uninitialized variables. Soon all errors detected by the compiler will be highlighted and you will not need to run the compiler to test correctness of your code.

Syntax Highlighting

For better understanding of the code ReSharper provides highlighting of different kinds of symbols in code (fields, locals, classes etc) in different manner. You can configure highlighting settings in the standard VS.NET highlighting setup page ( Tools > Options > Environment > Fonts and Colors ).

Brackets Matching

Brackets matching is another intuitive feature. Put the caret right after '}', ')' or ']' in the code and see the matching bracket. The same for the caret right before the openning bracket.

Brackets and Quotes Auto-insertion

Another cool feature: when you type '(', '[', double quote or single quote character a pair character is inserted automatically (when makes sense). It can be disabled but don't hurry going to the options to turn it off if you're afraid that you will be frustrated by extra brackets you'll have to skip. It moves you over the matched bracket if you try to type an extra one.

Options

At last, all ReSharper options are available in the standard VS.NET options area: Tools > Options > ReSharper.

Do you know what your constructor is doing?

Earlier, Peter Torr posted about the differences between language-enforced rules and framework-enforced rules (calling class constructors, specifically).  An interesting and related thing I discovered a couple of weeks ago was that constructors are not guaranteed to be called at all by the framework, let alone twice.  Again, it involves emitting MSIL (or not, as we shall see), rather than C#, but it's still a useful/dangerous/so-what feature.

Here's the MSIL that CSC emits by default for an empty constructor:

ldarg.0
call       instance void [mscorlib]System.Object::.ctor()
ret

As you can see, the base constructor is automatically called.  This call, as CSC would have it, happens before anything else in the current constructor is executed.  The trick - you guessed it - is simply to omit this call.  A constructor then becomes:

ret

Marvellous.  And what's the big deal?  Well, it turns out to be a solution to a limitation I keep running into with NMock, namely that it cannot mock a class without a parameterless constructor (NMock creates testable sub-classes on the fly using Reflection.Emit).  I got so fed up of creating single-implementation interfaces or empty constructors just to mock a class that I decided to investigate, and that's what I came up with.  If constructing the base class is a chore (because of the parameters it takes), then don't call it.  If it doesn't have an empty constructor, so what?  I don't have to call it.

You do have to be a bit careful calling unmocked methods who rely on state that should have been initialised by the constructor, but in certain situations it makes life much much easier.

The code should make it into NMock in the next couple of weeks, if I can get my arse in gear.

Fowler on Inversion of Control
My esteemed colleague has a new article up on his site: "Inversion of Control Containers and the Dependency Injection pattern".  Don't let the title put you off, it's actually not that dull, and describes a useful pattern that we've been employing to great effect recently.
Like falling off a blog

I've been busy working on a good-sized project for Thoughtworks over the last 9 months, which is one reason for the lack of posts.  The other is that it's taken me about 9 months to think of something to write about.  Here's something I thought worthy of note:

Neo is an open-source object/relational mapping tool (I'll probably get in trouble about calling it an O/R mapper by its author - he calls it an "object facade") developed by my colleague Erik Doernenburg then tweaked, debugged, used and abused on the aforementioned project.  At least a couple of other teams are using it now, and it's very close to a 1.0 release.

Neo works by generating both .Net classes and database tables from an XML schema. It then creates a one-to-one mapping between the two (which is why I should really call it a facade) using ADO.Net and provides typed collections, factories and query mechanisms for working with the generated classes.  The resulting object model is remarkably simple to use and has saved us from much of the hell of manual persistance.  Let's take a look at an example:

IDataStore store = new SqlDataStore(connectionString);
ObjectContext context = new ObjectContext(store);
Title title = new TitleFactory(context).CreateObject("TC1234");
title.Price = 12.99M;
title.Publisher = new PublisherFactory(context).FindSingle("Name = 'New Moon Books'");
context.SaveChages();

In order of appearance:

  • IDataStore - Provides a means for an ObjectContext to store and load DataTables.
  • ObjectContext - Provides a scope for objects to exist within, performs bulk load/save operations and helps manages the lifecycle of loaded objects.  It is backed by a DataSet which hooks all the entity tables together.
  • TitleFactory - Used for creation and location of objects.  Each entity class has its own strongly typed factory.
  • Title - An example of a Neo-generated entity class.  It is backed by a single DataTable (each instance represents one row in that table).
  • Price/Publisher - Two properties representing both a column entry and another Neo object.

Neo, like ADO.Net, doesn't care where its data originates - we use SQL Server, local XML files and web services (using DataSets makes it easy to hook it up to a web service).  Working in-memory also makes testing much easier and quicker.  Our app was in development for about 4 months before it even saw a real database (which was probably too long in hindsight, but that's a different story).

There are limitations, of course:

  • There is a one-to-one relationship between classes and datatables, which can make complex systems hard to model correctly. 
  • The only supported database at the moment is SQL Server, although it would be trivial to implement IDataStore for others.
  • Currently, Neo is really only suited to projects which have full control over their database schema.

Anyway, go and check it out, and let us know what you think.  I can post more information and samples if requested.

More Posts « Previous page - Next page »