Subscribe
Sign In
|
 Tuesday, September 09, 2008
Just a quick post to highlight the recent release of the F# compiler for Visual Studio. This release shows some real improvement upon the IDE integration featuring true F# project files and an improved language service which benefits both intellisense and background compilation. I didn't realise how much I liked Visual Studio projects until I was deprived of their functionality. Just simply having a project file that operates like C# or VB projects is a real boon to F# newbies and experts alike. My previous experiences with intellisense in F# were such that I would often ignore it as it was easily confused. This appears to be less of a problem now and is much more of a help than a hindrance. So if you haven't already, download and install the F# September CTP from the MS download centre and have a look.
 Sunday, July 13, 2008
So after a great day yesterday of presentations and, ultimately pizza, I'm sitting here in a Lecture Theatre at the University of South Australia in Adelaide enjoying presentations for Code Camp SA, day 2.
Personally, I've been very impressed with the quality of presentations, and some highlights for me thus far have been:
I'm also keenly awaiting a presentation by Corneliu I. Tusnea on CLR Production Debugging. This particular topic should be dear to all our hearts as developers, and Corneliu really knows his stuff.
Hopefully in the next day or two I'll have some information regarding a presentation that Jason Stangroome and I gave, we decided to give a bit of a feature comparison of Subversion and TFS SCCMs smackdown style. I'm grateful to Paul Stovell for helping Jason and I polish our ideas and giving us plenty of inspiration and motivation.
So another big thankyou should go to Peter Griffith and ADNUG for making CCSA a reality, and yeah the pizza last night was awesome. I must say its nice to sit back today and not worry about my own material, and I look forward to the rest of the day. And if your at CCSA08 today, collar me at lunch and say hi!
 Wednesday, June 11, 2008
Today Resharper 4.0 goes RTM, if you haven't been following the EAP, you might be interested to know that we now have full C# 3.0 language and LINQ support. That's not all we get, there are a swag of cool new refactorings, solution wide code analysis, extra framework annotations, camel humps in code completion....the list just goes on. There are some improvements to the VB experience like new refactorings only previously supported in C# 2.0: Convert Method to Property Convert Property to Method Pull Members Up Push Members Down Extract Interface Extract Superclass Convert Interface to Abstract Class Convert Abstract Class to Interface Extract Class from Parameters Use Base Type Where Possible Replace Constructor with Factory Method The ASP.NET guys don't miss out either, amongst other things - a performance increase to page analysis, which has been a real problem for large ASP.NET pages in the past. Personally, I find Resharper to be the best C# productivity tool out there for the money, and they are paying more and more attention to VB.NET. Combined with Viemu its my productivity suite of choice and I encourage you to give them both a try.
 Wednesday, May 14, 2008
Recently I discovered the xUnit.NET framework for unit testing, and it is a very nice minimalist framework for TDD. I especially like writing tests for F# code using it. It allows me to write very short test suites against any CLR library, in most .NET languages. For example:
#light
open Xunit open NT.Model
let sut = new Person("Jim")
[<Fact>] let jim_is_a_geek() = Assert.True(sut.IsAGeek)
The Person class could be written in C# or VB and used here. Also note that the ultimate class name of this test is inferred by the filename. I could add explicit module and namespace information if necessary.
In something like MbUnit / NUnit / Gallio I have to use the following OO style syntax...
#light
namespace NT.Model.Specs
module PersonSpecs
open MbUnit
open NT.Model
[<TestFixture>]
type jims_behaviours() =
let sut = new Person("Jim")
[<Test>]
member j.is_a_geek() = Assert.True(sut.IsAGeek)
Note that the namespace and module must be declared in order for the gallio runner to discover the tests. I think this might be a bug...
However, regardless of the framework you use, F# also lends itself well to setting up for customized approaches to testing. I feel this has some potential for BDD testing in F#. Take the following example:
#light
open Xunit
let MustEqual expected actual = Assert.Equal(expected, actual)
[<Fact>]let a_fluent_assertion() = 0 |> MustEqual 0
Taking this one step further we can take advantage of operator overloading to provide extremely terse tests. Note that I don't actually advocate doing this, only pointing out that its possible:
#light
open Xunit
let (&=) expected actual = Assert.Equal(expected, actual)
let (&!=) notExpected actual = Assert.NotEqual(notExpected, actual)
[<Fact>]
let an_obscure_assertion() = 0 &!= 1
Based on these samples, I think it is clear that without much effort, a fluent specification interface could be arrived at, perhaps even a domain specific one at that.
F# record types are readily testable also:
#light
open Xunit
type Person = { name : string; age : int; }
let Jim = { name="Jim"; age=28 } let Fred = { name="Fred"; age=52 }
let IsNot expected actual = Assert.NotEqual(expected, actual)
[<Fact>] let jim_is_not_fred() = Jim |> IsNot Fred
Sometimes, the assertion framework isn't needed, but having a test runner is still obviously handy. For the next example I setup a discriminated union and then use pattern matching to determine the outcome of the test simply using the built in failwith keyword:
#light
open Xunit
type Animal =
| Dog
| Cat
type Person =
{ name : string;
age : int;
pet : Animal; }
let Jim = { name="Jim"; age=28; pet=Cat; }
[<Fact>]
let Jim_cannot_own_cats() =
match Jim.pet with
| Cat -> failwith("Jim owns a cat!")
| _ -> ()
A snippet from the xUnit console runner output for this failing test: Tests failed:
1) Jims_specifications.jim_cannot_own_cats : Microsoft.FSharp.Core.FailureException : Jim owns a cat!
On that...hopefully soon tools like Gallio will provide us with some F# support in Visual Studio for the Resharper test runner or even MSTest. At current support for xUnit testing with Gallio in F# projects appears to be a non starter. Alternatively, latest SharpDevelop betas have inbuilt F# and NUnit support which I find to be quite good.
In the meantime we can go all 'old school' on VS 2008 to provide some ease of use.
In the following screen shot I've added the xUnit.NET console runner to external tools by selecting from the menu, Tools, External Tools...
Next I like to map this to a keyboard chord, say Ctrl+R,Ctrl+X:
So that now after building, I can run my entire test suite using my keyboard shortcut to yield a testing experience that is 'good enough' for TDD/BDD development in F#, well, that's my opinion of course :)

 Monday, April 28, 2008
...Other Project Euler posts...
Today, my mission is to solve Project Euler Question #2:
Find the sum of all the even-valued terms in the fibonacci sequence which do not exceed four million.
The obvious solution is to use a brute force approach:
public static int Problem2() { var fib = 0; var sum = 0;
for (var n = 0; fib < 4000000; n++) { fib = Fibonacci(n); if (fib % 2 == 0) sum += fib; }
return sum; }
private static int Fibonacci(int n) { return n < 2 ? 1 : Fibonacci(n - 2) + Fibonacci(n - 1); }
Lazy evaluation
Slightly more elegant solutions do exist. For starters, F# allows us to use lazy evaluation to create sequences of values. This has the advantage of sequence values only being evaluated when necessary. Robert Pickering's "Foundations of F#" gives us the following example for generating fibonacci numbers using lazy evaluation. In fact, the example here is one of an infinite list.
#light let fibs = (1, 1) |> Seq.unfold(fun (n0, n1) -> Some(n0, (n1, n0 + n1)))
Initially, a pair of values (named a tuple) 1 and 1 is piped through to the Seq.unfold function. The unfold function allows us to define how we want our list to be generated. It returns a disciminated union type called Option which in this case is called with a tuple, the first value in the tuple being the value applied to the list, the second value is the accumulator. The accumulator basically allows you to pass some state into next round of calculations. Option types are there own blog post, as they are a totally awesome example of applied discriminated unions.
To put the fibs function into english: fibs takes a tuple of integers (n0, n1), and always returns the first member in the tuple, however when we evaluate the next item in the sequence, the first member of the tuple will be n1 and the second will be n0 + n1. This will go on and on even once we hit the 32bit limit and starting looking at negative integers.
Pattern matching
So how does this help us to solve question two? Using a similar approach as the C# version we could alter the way the list is generated before we summate:
#light
let summate x = x |> Seq.sumByInt (fun n -> n) let Question2 = (1, 1) |> Seq.unfold(fun (n0, n1) -> match n0 with | n0 when n0 % 2 = 0 -> Some(n0, (n1, n0 + n1)) | n0 when n0 > 4000000 -> None | _ -> Some(0, (n1, n0 + n1))) |> summate
Here, I'm using simple pattern matching to do two things, make sure any numbers that arent even are mapped to 0, and also to ensure that once n0 exceeeds 4 million, we stop generating values in the list. This is the power of the unfold function at play: the ability to lazily evaluate the members of the list and also to define the condition to terminate the list.
A Mathematical approach
However, this is still a brute force approach, although dressed up a little. Since the fibonacci set is full of patterns and properties surely we can take advantage of one or three? Of course, each 3rd term in the fibonacci set happens to be even. We also have an approximate ratio between two consequetive terms: Phi. Therefore, the ratio between even terms is approximately Phi to the power of 3. Using these properties we should be able to come up with the same answer as our brute force approach:
#light let summate x = x |> Seq.sumByFloat (fun n -> n) let PhiCubed = ((sqrt(5.0) + 1.0) / 2.0) ** 3.0 let Question2 = 2.0 |> Seq.unfold (fun x -> match x with | x when x < 4000000.0 -> Some(x, Math.Round(x * PhiCubed)) | _ -> None) |> summate
So with a starting point of 2.0 I simply round the result of x * (Phi ^ 3) to yield each value in my list which is then summed. The C# interpretation as follows:
public static double Problem2() { return EvenFibsBelowFourMillion().Sum(); } private static IEnumerable<double> EvenFibsBelowFourMillion() { var phiCubed = Math.Pow(((Math.Sqrt(5D) + 1D) / 2D), 3); var fib = 2D; do { yield return fib; fib = Math.Round(fib * phiCubed); } while (fib < 4000000); }
In Summary
C# still outperforms F# ever so slightly on my machine, C# taking an average 0.002 milliseconds, F# taking an average 0.003 milliseconds. So far I feel that F# lives up to the promise of a 'similar performance profile as C#'. I'm starting to appreciate the 'point and shoot' nature of F# syntax. Having said that, the C# solution is equally nice and easy to read. I cant wait to get into some of the meatier questions.
 Sunday, April 06, 2008
One of the languages I have decided to learn this year is F Sharp. F# is a multi paradigm programming language; it is capable of expressing ideas in an imperative, functional and object oriented fashion. It is the result of some very hard work by Microsoft Research and integrates into VS2005 and 2008. F# rounds out the MS language ecosystem quite nicely i think, as it provides a solid platform for mathematical solutions, as well as maintaining the ability to be used to create windows applications of all types.
I decided to get my head around using it by reading Foundations in F# and by undertaking Project Euler, a series of mathematical puzzles. I'm certainly not alone, and to set myself apart from those who have trod before me, I've decided to compare the solutions in F# to possible solutions in to my favourite language: C# 3.0. Since I am no maths expert, this could be a real trainwreck...
Question 1: Find the sum of all the multiples of 3 or 5 below 1000.
Sounds simple enough. We can use mod 3 and mod 5 to filter a list of positive numbers below 1000 and sum the result. One approach might be:
static int Problem1() { return MultiplesOfThreeAndFiveBelow(1000).Sum(); }
static IEnumerable<int> MultiplesOfThreeAndFiveBelow(int n) { for (var i = 0; i < n; i++) { if (i % 3 == 0 || i % 5 == 0) yield return i; } }
OK, so thats a little expensive, I've used a generic list instead of an array, but hey it works. Its main strength is that its readable. So how about a functional approach?
let solution = Array.init 1000 (fun x -> if x % 3 = 0 || x % 5 = 0 then x else 0 ) |> Array.fold_left (+) 0
Array.fold_left is a higher order function, since it accepts a function as a parameter. I am passing it the addition operator (a function in its own right) and an accumulator initialized to 0. The first iteration of the fold function will take the value of first element of the sequence and add it to zero. The result is then added to the value of the next element in the sequence to produce a new result and so on. Essentially, it provides the summation required to complete this problem. The downside with this approach is that it naively overestimates the size of the array required, and folding left doesnt immediately lead the reader to think of summation.
I can do better though, F# provides us some constructs for more efficient array initialisations; a comprehension syntax:
let solution = Array.fold1_left (+) [| for x in 1 .. 999 when x % 3 = 0 || x % 5 = 0 -> x |]
While this is readable, some might complain that Array.fold1_left is a cryptic way to summate, and is therefore hard to maintain, so without much effort we can curry it to look like this:
let summate a = Array.fold1_left (+) a let solution = summate [| for x in 1 .. 999 when x % 3 = 0 || x % 5 = 0 -> x |]
I've split the array initialization over 4 lines for extra readability but in essence its only 1-2 lines of readable code to solve Project Euler Problem 1 using F#.
So, for those of you interested in speed, using the time honored technique of taking the average execution time over 1 million executions, the C# implementation came in at around 10 times faster than the final F# one. The first F# implementation was faster but was still two times slower than C#. The main bottleneck seemed to be the array initialization; using the comprehension syntax is a little pricey. But, who cares about optimization anyway? It was only the difference between fractions of a millisecond anyhow :)
 Friday, March 14, 2008
Hey y'all, long time no see. Life has thrown me a few curve balls which impeded my blogability, but rather than boring you with details lets just get into straight into it.
Recently I've had a few queries regarding a check in policy I eluded to in this post. Today I hope to clarify how one might go about implementing a check in policy which ensures that Option Strict is turned on for VB projects.
Rather than rehashing a perfectly good walk through, I suggest you read this article from MSDN to get the basics of Check In Policy creation.
Once we have our check in policy project and have derived a class from Microsoft.TeamFoundation.VersionControl.Client.PolicyBase it is time to start overriding the behaviour of the base rule. Imports Microsoft.TeamFoundation.VersionControl.Client
<Serializable()> _
Public Class OptionStrictPolicy
Inherits PolicyBase
Once we are over that little hurdle we want to:
* Get the set of pending changes that have been selected by the user to check in
* For each pending change determine the project file that the change belongs to
* For each VB project determine if Option Strict has been turned on
* For each project that hasn't got option strict turned on, create a policy warning.
For extra fun I'll do this all with VS2008 & VB9. I love my C# but to be honest VB9 kicks its ass when dealing with XML.
1: Get the set of pending changes that have been selected by the user to check in
Everything from here on out extends the Evaluate method of PolicyBase. Getting the set pending changes selected by the user is a cinch. I've filtered by vb code files, but you could just as easily go for more file types. Public Overrides Function Evaluate() As PolicyFailure()
Dim pendingChanges = PendingCheckin.PendingChanges.CheckedPendingChanges
Dim vbCodeFiles = _
From c In pendingChanges _
Let extension = Path.GetExtension(c.FileName) _
Where extension = _VBFileExtension OrElse extension = _VBProjectFileExtension _
Select c.LocalOrServerFolder, c.FileName
2: For each pending change determine the project file that the change belongs to
This step is a little trickier and basically involves drilling up the folder structure until we find a project file, and then checking the project file for a compilation reference to the pending change. This seems like a good place to refactor into a recursive function...
*SIDE NOTE* Am thinking of starting a petition to all relevant Dictionary makers to make the word "Refactor" a real word. Whose with me?
I'm sure we are all capable of looking for .vbproj files recursively up the folder chain. However we do need to allow for the possibility that there may be two vbproj files in a folder and if so, is our pending change referenced by either of them? To do this I need to go through the project file looking for <Compile> tags that include my pending change. For example in C# we might do it like this var doc = XDocument.Load(XmlReader.Create(projectFilename));
var compileItems = from e in doc.Descendants()
where e.Name.LocalName == "Compile"
select e;
return (from c in compileItems
where c.Attribute("Include") != null && c.Attribute("Include").Value.Contains(filename)
select c).Any();
But since Im using VB today I can do it like this...
Dim doc = XDocument.Load(XmlReader.Create(projectFilename))
Return doc...<Compile>.@Include.Contains(filename)
Not bad...but for this to work I do need to import the namespace of the project file schema, since the syntax that allows for <Compile> is checking qualified names, not local names. Imports <xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3: For each VB project determine if Option Strict has been turned on
Once I have a list of projects that are loosely associated with a check in, I can easily check for the existence of OptionStrict tags in the vbproj file. OptionStrict still defaults to off, so a lack of OptionStrict tags implies the setting is OFF. However it is perfectly valid to have an OptionStrict tag that is set to OFF so I need to account for those. Private Shared Function IsOptionStrictOn(ByVal project As XDocument) As Boolean
Return project...<OptionStrict>.Value = "On"
End Function
4. For each project that hasn't got option strict turned on, create a policy warning.
Creating policy warnings is a breeze and you can return as many as you want, in this scenario I want to ensure that one is created for each project that is in violation of my rule. The final Evaluate function looks like this... Public Overrides Function Evaluate() As Microsoft.TeamFoundation.VersionControl.Client.PolicyFailure()
Dim pendingChanges = PendingCheckin.PendingChanges.CheckedPendingChanges
Dim vbCodeFiles = From c In pendingChanges _
Let extension = Path.GetExtension(c.FileName) _
Where extension = _VBFileExtension OrElse extension = _VBProjectFileExtension _
Select c.LocalOrServerFolder, c.FileName
Dim vbProjects = From c In vbCodeFiles _
Select GetProjectFile(c.LocalOrServerFolder, c.FileName)
Dim strictOffprojects = From p In vbProjects _
Where Not IsOptionStrictOn(p)
Dim policyFailures = New List(Of PolicyFailure)
Dim messageFormat = "Please turn option strict on in the project file: {0}"
For Each s In strictOffprojects.Distinct
policyFailures.Add(New PolicyFailure(String.Format(CultureInfo.InvariantCulture, messageFormat, s), Me))
Next
Return policyFailures.ToArray()
End Function
So there you have it, VB9 to make coding an Option Strict ON policy nice and easy. Seems appropriate doesn't it?
 Wednesday, December 19, 2007
Yes, I still use XSLT, hopefully in another post soon I'll elaborate as to what the hell for. For those of you in a similar boat to me, here is a short primer on using extension objects.
Some things, like interacting with the system environment, are hard to achieve using XSLT/XPATH 1.0. On the other hand its fantastic at declaratively transforming XML documents.
The .NET framework, even with the introduction of XLINQ, is fantastic at interacting with the environment, but its relatively poor for transforming XML.
The solution might be to marry the two together, but how?
Enter the extension object
Microsoft has saw fit to bestow upon us the power of the CLR inside the MSXSL Parser.
This approach obviously couples the usage of our XSLT to being executed via the MSXSL Parser, so for some people is not an option, however I am under the impression that Saxon for .NET allows a very similar approach if you need.
Another downside is that the Visual Studio XSLT debugger will not run your extended transforms, so you have to find alternative means to assess your output. However, for the seasoned XSLT hand coder, this should not be a problem.
So, to begin, this is how we inject our custom extensions object into a compiled transform.
Note that the URN provided is arbitrary, as long as you reference it correctly in your XSLT. It should look a little like this:
The extension object itself can be an instance of any class you wish to use. By declaring a function in your extension class you can use that function like any other XPath function from your XSLT.
This should open up a world of possibilities for XSL transformations. Oh, and extra points are awarded to those who figure out what I am trying to do from the examples ;)
 Thursday, November 01, 2007
Perhaps I've lost my mind... perhaps I'm a little too open minded... but why is there so much press out there on Resharper vs Refactor?
After investigating both CodeRush and Resharper I finally decided to purchase Resharper 3.0. I have been happily using Refactor Pro! 2.x for the past year or so, but I recently stretched it's capabilities.
I like Refactor; the simplicity of using Ctrl+~ is intoxicating. However, since embracing test driven development along with using a model view presenter pattern for my UI design I've found it lacking.
The main things that tipped me over the edge happened to fall into the refactoring and navigation categories:
Create a new class/interface declaration from an unknown initialization.
This is perhaps the single most productive feature anybody doing TDD could desire, just declare willy nilly and fix up the red bits as you go with Alt+Enter. Intellisense works with types you haven't implemented yet.
Create a new field/local/property/method from an unknown word.
Once again allowing you to code with the knowledge of what does and doesn't exist (yet) using red highlighting, and to instantiate as late as possible into the design of your test.
Force a type to implement the interface of the variable type it is being assigned to.
I don't have to worry about switching over to the class code file to slot in the interface - all taken care of inline.
Walking thru usages via Ctrl+Shift+F12.
When programming behind interfaces, getting around can get a little tedious with the standard VS2005 UI. F12 doesn't cut it, especially in mixed language solutions. The advanced usage tools make it easy to hop around implementations.
But perhaps the one feature that wins it, that sets up a whole lot of other cool features for Resharper, is background compilation for C#. As far as I'm concerned, the compilation tax for C# is a major productivity drain when in comparison to VB.
Perhaps I'm weird in that I can't stand CodeRush, but I love Refactor Pro for its insanely creative refactorings. There are plenty of refactorings that Resharper doesn't do. However, when it comes to a fully fledged productivity suite - I seem to fly with Resharper without thinking. CodeRush, despite its name, seems to slow me down more than anything.
Whats even weirder is that it feels like Resharper begins where Refactor finishes - they seem to co-exist in near perfect harmony. And yes it still feels like fitting Ford parts to my Holden.
I think I've just exploded in a fit of non-conformity.
 Monday, October 22, 2007
I hate strings. I like strong typing. Its that simple. I guess that is why I have a slight aversion to web development. Too many string literals make me nervous. It's not paranoia if every string literal *is* out to get you, right?
Thankfully, the .NET framework comes to the rescue more often than not and I have often found myself using the System.Net.Mime namespace to alleviate my paranoia about string like "text/xml".
Or is it "text\xml"? XD
In particular the MediaTypeNames class has a lovely declarative series of classes and string constants that define some of the most common mime types used today. Whilst not comprehensive by any stretch, it covers the standard cases. For example if you intend to use the "text/xml" type, then the syntax is as follows:
using System.Net.Mime; . . . string textXml = MediaTypeNames.Text.Xml; //look Mum, no strings!
Of course this is just a bit of a buck pass to the framework; it all boils down to a string literal eventually, but it lets me sleep better at night nonetheless.
 Friday, August 03, 2007
I'm not sure what to make of this. Deftflux has created a library to aid brave C# developers in their dark quests to use duck typing.
Given that C# 3.0 is around the corner with anonymous types I feel the duck typing library is a bold move towards Rubyesque abilities. While anonymous typing only gets you some of the niceties of duck typing, I think the greatest advantage of anonymous types is compiler checking goodness.
There is no doubt duck typing can save a lot of time coding. I admire languages like Ruby for their declarative, artistic form of expression. The .NET framework makes use of it too; duck typing has very real use cases.
The TDD crowd has a distinct advantage over the rest, in that one could happily duck type all day long, trusting in the safety of ones unit tests to provide alerts to type mismatches.
Sure, if you write a thorough test suite you can theoretically avoid most of the dangers of duck typing. Though all it takes is one hole in the tests and the time saved coding is spent debugging. I would rather my compiler tell me about a type mismatch, than the beta testers complaining of unhandled InvalidCastExceptions. In the spirit of using the right tool for the job, surely the compiler is the right tool to inform us of type mismatch problems? It does a fantastic job of it. Cedric Otaku puts it in a way that's hard to ignore:
In a way that's typical for dynamically typed languages, the error will therefore only appear at runtime and only if such code gets run.
If you are duck typing in copious amounts and not writing tests, then you are walking on shaky ground.
I guess I like to be explicit in general; say what you mean and mean what you say. Life is simpler that way. I like suspense & innuendo in movies, not code. I can't wait for anonymous typing in C#, but perhaps even more so, I look forward to the day work lets me use languages like Spec# to enable me to be even more explicit to the compiler as to my intentions.
 Wednesday, August 01, 2007
I often see superfluous use of Me.This and this.That lying around in code and it always bugged me, but tonight I found a reason it might be more than just my anal nature. Typing 'Me.' or 'this.' is not a clever way to fire up Visual Studio's Intellisense drop down. The Ctrl+<Space> keystroke is a much tidier, and quicker way of getting there.
Sure, there are circumstances where you need to use these keywords, for instance when you need to differentiate between your class and your base class. Me and MyBase, or this and base are valid ways to get around in that case.
The benefit of refraining from using these keywords until its necessary is that you could reduce the cognitive load on someone who has to understand your code. Every time you avoid the use of the Me keyword you will decrease your maintenance complexity score by 2 points every time you do so. In functions that address members heavily, this could represent a significant increase in the readability of your code.
So what is this metric, Maintenance Complexity? Its an idea coined by Mark Miller from Developer Express. Its been a feature in CodeRush and Refactor! Pro for some time now. The 2008 release of Visual Studio, codename Orcas will also provide code metrics visualisation. Simply, it recognizes the fact that the more code you write to achieve a goal, the harder that code is to maintain. That is to say, if you can achieve the same goal in less code, you have written it in a more maintainable fashion. It has been said before, the best developers code smaller.
Each type of construct attracts a score, much like letters do in the board game, Scrabble. At the end of a function you are scored by adding the values of each construct up. For a complete description of the metric, please visit Mark Millers blog entry on his creation.
There are some valid criticisms to this metric, and simply refactoring in aid of reducing MC scores is only cheating yourself. As such I suggest the reader use code metrics in general as an indicator rather than a developers divining rod.
 Thursday, July 26, 2007
In my last post, I outlined why I felt that tab order is an easy way to measure your GUI's complexity, and in this post I intend to show you how. Bad tab order is on my top 5 pet peeve list, so it's one of the first things I look for in an application. As you can see, even the simplest of UI's can be over engineered, and layout metrics that are purely concerned with user interaction wont pick it up. Turning on the View > Tab Order will show that the devil truly lies in the detail.  Nested panels adjacent to more nested panels will make for some mind exploding tab ordering, as shown in the example above. This is definitely panel overkill, or panelcake as I have affectionately dubbed it, and the main culprits include the ToolStripContainer, the SplitContainer, the TableLayoutPanels, and finally the GroupBoxes. The depth is so great, the tab order obscures the design! YAGNI applies to GUI's too, so lets rescue this poor innocent interface... In Visual Studio 2005, I press the Ctrl + W, U key chord to bring up the document outline viewer. This tool is absolute gold for rearranging hairy container hierarchies. Step 2, set the window style to Fixed Window. Unless there is a compelling reason to be able to resize then there is no point in offering it. If it is needed, then careful use of Anchor and Dock properties will suffice for the most part. TableLayoutPanels should be used sparingly. YAGNI all the way. Next, I lose the ToolStripContainer. Its function is to provide a drop target for ToolStrips and MenuStrips on the outer extremities of your Form. Does the user need to move the menu or tool strips from the top position? Nice idea, but probably not. I continue to carve into the UI, removing all of the table layout panels and the split container until I am left with the fewest amount of controls to represent the data I need the user to edit. Careful choices for anchoring replicate much of the TableLayoutPanels functionality. Some grouping is beneficial to the user, and doesn't hurt when you need to alter the visibility state of groups of controls. What I am left with is a form that achieves the same end as the original, trimmed of unneeded function. The acid test is that I can set the tab order in roughly 10 clicks of the mouse button. Not to mention the fact that you can see what you are doing. 
Graphical user interface design is a subject dear to my heart, as it should be to most GUI developers. However, creating a useful, efficient and ergonomic user interface is easier said than done. All too often I see (and in the past have written) applications that just clearly get it wrong. There is nothing more frustrating to me, as a programmer, than using a poorly planned UI. Some UI's make you feel as though it would be quicker to write the program yourself.![]() |