Monday, February 27, 2006

When to Automate

Generally speaking there are two main reasons to automate a process:
  • It's going to be done many times (so it'll save time), or
  • It needs to be done exactly the same each time
Doing a release build falls into both those categories, so from that perspective automated server builds (ala NAnt / CruiseControl.Net) start to look like a bit of a no brainer (especially if they can do the depoyment for you).

Interestingly, the Braidy Tester points out there's another important reason to automate, one that - as a developer - we invoke all the time: Morale. Even if I'm only going to do something once, if it doesn't take me much longer to automate it, then I will, for the sake of my own sanity. I'm a developer, not a computer.

It's worth factoring in the 'hidden cost' of not automating when making leadership calls, and err on the side of automation when it's a close call. Is not automating worth the morale cost of making people do really boring work?

Monday, February 20, 2006

Fluent Interfaces vs Currying

Martin Fowler's written recently about Fluent Interfaces, which are basically class API's designed from the perspective of creating highly-legible, flowing code. I've been dallying a bit with this over the last year, eg:
    TaskUtils.CopySettingsFrom(source).To(destination);
or
    Assert(someString, new Contains("some substring"));
... having been inspired by the NMock designers. There's even some examples in the .Net class library (eg: the SqlParameterCollection's Add method returns the parameter just added).

I'd only just got round to thinking of it as Currying (and prior to that, Syntactic Sugar). Terminology explosion! Martin's example is a bit more complicated than mine, and the more complicated schemes have their disadvantages, but it's always nice to see people going the extra mile to make their code usable. It adds polish, finesse.

A sharp tool[1] like ReSharper, or VS2005 (C# only) can really make this kind of stuff a breeze - you just type
    someobject.Add(thing).Substract(thing)
...and ReSharper will prompt you to create the appropriate Add and Subtract methods, with it's best guess as to the parameters you want. The result - clearer, more usable API's - is one of the reasons why the TDD guys have been advocating this approach all the time....


[1] As in Chapter 12, 'The Mythical Man Month', Frederick P. Brookes

Wednesday, February 15, 2006

VSS 2005 doesn't allow 'Leave this file' for writable files during Get Latest

Which is a bit of a pain really:

Unable to keep writable version of file in VSS 2005?

I tried the hack / workaround and it didn't work for me, so I've 'worked around' the problem by uninstalling VSS 2005 and going back to v6 (NB: need to re-run SourceSafe\Win32\SSInt.exe to re-register VSS6 for integrated source-control with VS / VB).

VSS 2005 was only mildly useful in that it allowed me to use an external diff tool (BeyondCompare, WinMerge) to view my changes, rather than the built-in one, but even then that meant I could only diff against the latest version (no dialog to allow you to put the previous numbered version syntax: eg File.cs;16), so I won't miss it much.

Saturday, February 11, 2006

Non transitive equality in VB.Net

One of the good bits of advice that floats around is to avoid overriding Equals() unless you know what you're doing[1]. The requirements for equality (reflexive, symmetric and transitive) are easily broken if you're not concentrating.

It's a pity no-one told the VB team[2]...
Public Sub TestStringEquality()
Dim someString As String
Assert.IsTrue(someString Is Nothing, "Of course someString is Nothing")
Assert.IsTrue(someString = String.Empty, "But it's also empty...")
Assert.IsTrue(String.Empty Is Nothing, "...so doesn't that mean that String.Empty = Nothing ?")
' last test fails
End Sub


[1] And that's without getting into the whole GetHashCode() trauma: When (not) to override Equals?, The Rules for GetHashCode
[2] This is tongue-in-cheek - the Is operator isn't really equality, I know. It's 'samey'.

Thursday, February 09, 2006

Doh! VB.Net and C# have different order-of-execution for field initializers...

He stared at the code for some time. The field was Nothing, when there was clearly a field initializer present. What the ...?

It turns out that C# and VB.Net differ in the order in which field initializers and constructors fire in an inheritance tree, whereas me being somewhat C# orientated had assumed the C# way was the .Net / CLR way (those kind of assumptions always get you in the end).

So in C# (as you know) all fields are initialized before any instance constructors run, working from most derived to base class, then the constructors fire from the base out:
Out: Initializing static field initializer in BaseClass
Out: Initializing static field initializer in DerivedClass
Out: Initializing field initializer in DerivedClass
Out: Initializing field initializer in BaseClass
Out: Initializing field in constructor in BaseClass
Out: Initializing field in constructor in DerivedClass
However in VB.Net all the base class field initializers and constructors run before the derived class gets a look in:
Out: Initializing shared field initializer in BaseClass
Out: Initializing shared field initializer in DerivedClass
Out: Initializing field initializer in BaseClass
Out: Initializing field in constructor in BaseClass
Out: Initializing field initializer in DerivedClass
Out: Initializing field in constructor in DerivedClass
This is probably due to the slightly looser rules VB has about what can go in a field initializer (eg dates). I'm guessing they probably fudge the IL so all those field initializers end up rolled into the constructor), but aaaaaaaaaarrrggghh... .

(I wonder what happens with cross-language inheritance....)

Of course none of this would be a problem if people[*] avoided the 'calling virtual methods from a constructor' trap, but at least in C# you can use the field initializers to (partly) ameliorate the problem. In VB, no.

ConstructorsShouldNotCallBaseClassVirtualMethods
Brad Abrams : New Design Guideline: Virtual Members

* by people, obviously I mean whomever originally wrote the class I was struggling with

Wednesday, February 08, 2006

Wierd stuff about VB.Net (from a C# perspective)

I knew that VB.Net was different, but it's funny how many extra things you find when you have to work on it day in day out:

Language
  • Wierd syntax (of course :-)
  • No documentation comments, or support for tool-tip documentation at break time (hover over String: C# "System.String represents text etc..." VB: "String" :-(
  • Can have dates as constants
  • WithEvents
  • Exposes static methods on instance members, but only by casted type (so no real advantage from a polymorphic perspective)
  • Shadow by name, not by signature
  • With keyword (kinda handy at times)

Syntax hording / Legacy syntax

The VB.Net team seem to be dragging a lot of compatability cruft with them.
eg. 7 different ways of declaring arrays, depending on where you feel like placing the brackets and the array length (watch out for the UBound / out-by-one syntax):

Dim someArray1() As String ' -> Nothing
Dim someArray2(1) As String ' -> Array[2] of Nothing
Dim someArray3() As String = New String(1) {} ' -> Array[2] of Nothing
Dim someArray4() As String = New String() {"One"} ' -> Array[1] as specified

Dim someArray5 As String() ' -> Nothing
' Dim someArray6 As String(1) ' -> Actually not allowed
Dim someArray7 As String() = New String(1) {} ' -> Array[2] of Nothing
Dim someArray8 As String() = New String() {"One"} ' -> Array[1] as specified

Also...
  • Assigning return values to the property / method name rather than using Return, which as a consiquence requires...
  • Default return value of 'Nothing'
And they seem to be making more as they go along:
  • Me.New() vs MyClass.New()

IDE
  • Funny (slightly disfunctional) pulldowns
  • No pre/post build events
  • No 'close all windows but this' (how wierd is that?)
  • Simplistic flat namespace model (everything in a namespace named by the assembly, hard to change this model)
  • Debugger 'rolls up' class heirachy if not dealing with most derived type - can make it impossible to see some fields / properties on base class that are later shadowed
  • 'This' debugger window actually is a 'Me' window. However what's displayed in all the debugger windows does change from language to language (see above), so what's with not changing the window name...

Runtime
  • Different order of field initialization (base first)
  • Strange non-transitive equality with empty strings


Good article from McConnel 'Stuck in a VB.Net ghetto'

Using Log4Net's FileAppender in a web garden

Whilst you might not think you're running a web garden (that is: running your website in two or more processes simultaneously on the same machine), it's worth checking in case your server SOE catches you by surprise (hint: this happened to me):



Obviously in this scenario it's not just log4net you've got to watch out for, but anything you're saving on the local filesystem is a candidate for cross-process resource contention. In log4net's case, the RollingFileAppender can block itself (in the other process).

There's a couple of ways round this. You can configure the FileAppender to minimize the amount of time it locks the file (the MinimalLock attribute), but for diagnostic simplicity I prefer to configure each web application instance to log to a different file. Something like this:


<appender name="File" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\temp\MyApp_[%processid].log" />
<datePattern value="yyyyMMdd"/><!--roll the file daily-->
<rollingStyle value="Date"/>
<appendToFile value="true"/>

<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{ABSOLUTE} [%thread] %-5level %logger.%method() - %message [%identity]%newline" />
</layout>
</appender>


This way if anything screwy happens in one of the instances (it didn't start alltogether?) it's easier to isolate.

PS: Blogger is so not the right engine to be doing this XML stuff in...

Monday, February 06, 2006

The VS forms designer sucks

When you drag a control onto a form, what's the first thing you do?

You rename it (to something sensible rather than TextBox1), and clear or set the .Text property from the default. Both of which involve fiddling about in the property grid finding the right entries, which is slow and tedious. Why?

Presumably Microsoft think I spend all my time resizing and repositioning the controls, rather than tweaking their properties. Well, sorry... but no, most of the time it's just drag and drop, possibly adjusting the width to fit after I set the text.

There must be a better way... (thinks: probably some kind of VS add-in that prompts for the control's caption, and bases it's name on that with some kind of standard prefix...)

Popular Posts