Just trying to make sense of things...

I Still Work With Software

Thursday, 16 April 2009 10:51 by jordan.terrell

I wanted to take a moment to assure my handful of readers that I am still very much involved/interested in software development on the .NET platform.  I’m actively learning jQuery, ASP.NET MVC, and I’m looking forward to spending some serious time in Visual Studio 2010 (and related releases) when they make Beta 1 available (I’m not dealing with the VPCs).  I’m just a little more inclined to write about my hardware escapades because such things seem to get less coverage in the blogosphere.  However, if I do come across something novel or interesting in the software-only space, I’ll be sure to write about it.

A New Testing Framework

Friday, 7 November 2008 10:23 by jordan.terrell

A new friend of mine wants to collaborate on building a new .NET based testing framework.  I know, I know, there are plenty of testing frameworks out there.  Just to name a few: NUnit, MbUnit, xUnit.NET, nSpec, etc.  Each of these has their own strengths, weaknesses, and implicit/explicit testing methodologies associated with them.  So why would I bother saturating the market further with another testing framework?

I think I have a semi-unique idea.  I say “semi”, because the underlying design idea is applied in other technology areas, but it would be unique in its application to testing.  I think it’s has enough of a fundamental difference from all of the existing testing frameworks to justify building it.  A by-product of the design would mean that it would be mostly compatible with existing testing frameworks (and in fact I would try hard to maintain that quality, but not in all scenarios), but would also open up avenues for experimenting with new ways to represent tests.

So, the reason for this post (besides encouraging a barrage of people telling me not to put yet-another-testing-framework out there) – what do you think is missing from testing frameworks today that you would like to see in the future?

Disturbing On So Many Levels

Friday, 3 October 2008 13:57 by jordan.terrell

That’s all that needs to be said:

Categories:   Programming | .NET
Actions:   E-mail | | Permalink | Comments (0) | Comment RSSRSS comment feed

LINQ: Distinct() does not work as expected

Thursday, 2 October 2008 10:20 by jordan.terrell

A few days ago I was using LINQ to filter a distinct (only unique items) list of custom objects.  I needed the distinction to be based on a property of type System.String.  Prior to this, I have never used or looked at the Distinct query operator - thus I expected it to have overloads that let me pass in a selector (Func<T, TRet>) to select the property to make the distinction on.

Unfortunately, it has no such overload.

However, what it did have was an overload that took an IEqualityComparer<T>.  As much as that felt like a cop-out (not a very LINQ-ish approach), I figured it would have to do the job.  There was one other overload that basically defaulted to EqualityComparer<T>.Default - this goes through a series of type checks to determine the best comparer for the type T being compared.  If the type T implements the IEquatable<T> interface, it will use that for the comparison.  Great!  I'll just implement that interface on my custom type, and be on my way!

Not so fast! It didn't work - for some reason it never invoked the IEquatable<T>.Equals method implemented on my custom type.  My next step was to implement as custom IEqualityComparer<T> to make the comparison based on the the property value.

That didn't work either! At this point I was quite confused, and then out of sheer desperation I put a breakpoint on the other method defined on IEqualityComparer<T>: GetHashCode.

"You've got to be kidding me!" - I believe those were the words going through my mind.  The Distinct query operator uses hash codes provided by an IEqualityComparer<T> to determine the distinct set of items.  Upon further inspection, the Distinct operator doesn't really use GetHashCode, it defers to another Set class to filter the items - that class uses the GetHashCode method.

Not what I expected.  Needless to say I was a bit disappointed.  Not only was there not an standard overload for me to pass in a selection lambda, but now I couldn't even use the Equals method on IEquatable<T> OR IEqualityComparer<T>!

I wasn't about to implement a custom GetHashCode method - I believe the annotations in the book Framework Design Guidelines basically says that the current implementation of GetHashCode is flawed.  Plus, for it to work in my case I would have to return the hash code for the property I wanted compared, not the hash code for the custom type.  All of this left a very sour taste in my mouth.

I did find an alternative though - using a combination of the GroupBy, First, and Select query operators, I was able to get what I wanted:

   1: var distinctItems = items
   2:     .GroupBy(x => x.PropertyToCompare)
   3:     .Select(x => x.First());


It looses quite a bit in meaning, but it accomplishes the end goal.  At some point I think I'm going to create an Extension Method that adds another Distinct() overload that takes a selection lambda - something that should have been there to being with!

Tags:   ,
Categories:   .NET | Programming
Actions:   E-mail | | Permalink | Comments (7) | Comment RSSRSS comment feed

Room 2531 Building 41

Friday, 11 July 2008 11:06 by jordan.terrell

The room where C# was born.

Categories:   .NET | Programming
Actions:   E-mail | | Permalink | Comments (0) | Comment RSSRSS comment feed

iSynaptic Commons - Release On Hold

Friday, 11 July 2008 09:23 by jordan.terrell

Back in April I mentioned that I was close to releasing my iSynaptic Commons framework - I've changed my mind on how soon I'm going to release it.  I've noticed a trend in short-changing my personal projects from certain quality practices that I am very strict about in my professional projects - practices such as unit tests with high code coverage, using a build server, well factored build scripts that compile, package, and publish builds, an active versioning policy,  code generation support (more on this later), etcetera.

The iSynaptic Commons framework represents my first public open source project envisioned and implemented by me.  As a result, I've become quite conscious of the missing quality practices mentioned above.  This in part of the reason why I chose to upgrade some software I've been using - I'm going to try to get strict about following all the best known practices with all of my iSynaptic projects, starting with the Commons framework.  I intend to get a build server up and running, and implementing all of these practices.

Towards that end, I want to communicate the inception of two other frameworks (extensions to the Commons framework):

    • iSynaptic.SolutionBuild - This will be a suite of reusable MSBuild scripts and tasks, aimed towards having a componentized build system where you can pick and choose build functionality

    • iSynaptic.Modeling - A set of class models, a XAML-like parser, and code generation templates for common infrastructure layers (e.g. db schema/data access, domain modeling, etcetera

    The Commons framework will be dependent on the SolutionBuild framework.  This will not unduly postpone the Commons framework, but should present a higher quality release.

    Thanks for your patience, and hopefully I can get a first release out soon...

    Rhino Mock 3.5 Release Candidate - I Got To Help!

    Monday, 30 June 2008 02:22 by jordan.terrell

    Rhino Mocks 3.5 just went to release candidate.  Probably the biggest change is the new Arrange-Act-Assert (or AAA) syntax.  This now allows you to use a nearly identical approach to Moq's API.  What I like about Rhino Mocks is the fact that it uses extension methods, so you don't have to access an "Object" property to get the real mocked object.

    But what is even cooler about this release, at least for me, is that I got to help with it!  I was migrating a project over to Rhino Mocks 3.5 beta, specifically because I wanted to make use of the new AAA syntax to simplify our tests, and during that process I found a pretty big bug - ordered expectations did not work with the new syntax.

    To make the problem summary short, when you used the Expect() extension method, it put your mock object in Record mode, recorded the expectation, and then immediately put the mock object back in Replay mode.  Two problems with this: First, it assumed you were in Replay mode to begin with (Ayende noticed/fixed that); Second, switching back to Replay mode originally would ensure that you could not do so within the context of an Ordered() scope.  This was, I assume more to encourage proper use of the API than a real design/implementation constraint.  With the fix that I made in place, IF you were in Replay mode when you call the Expect() extension method, it now skips the check to see if you are in an Ordered() scope.  However, using the previously existing MockRepository.Replay() method still behaves the way it did before - it will throw an exception if you try to call it within an Ordered() scope.  The reason we can make an exception for the extension method is because it is an atomic action: if you were in Replay mode already, you will just be adding an expectation; you'll still end up in Replay mode.  If you were not in Replay mode, it will not try to place you in replay mode.  The API with the fix in place still protects the invariant disallowing you to enter an Ordered() scope in Record mode and switching into Replay mode before exiting the Ordered() scope.

    If you want to look at my fix, it's revision 1482 in the Rhino Mocks Subversion repository.  Not a rocket science-like fix, but it's still cool that I got to contribute, and that Ayende choose to recognize my contribution when announcing the Release Candidate (thanks Ayende!).

    You can bet I will be updating my project to use the Release Candidate later today...

    Categories:   .NET | Programming
    Actions:   E-mail | | Permalink | Comments (1) | Comment RSSRSS comment feed

    Apress Books 45+% Off!!!

    Tuesday, 24 June 2008 14:26 by jordan.terrell

    Anyone who knows me well knows that I'm a huge book reader (mostly technical in content).  I love to learn new things, and books present, at least to me, and ideal package.  Having said that, you can imagine I get pretty excited when there is a book sale; especially when the discount exceeds 30%.

    I'm normally a Borders fan, however Bookpool is having a sale on many new Apress books, all discounted at 45% or more.

    I personally recommend the book entitled "Pro C# 2008 and the .NET 3.5 Platform (4th Edition)" by Andrew Troelsen.  The very first edition (based on .NET 1.0 beta) introduced me to .NET.  Since then, this book has grown to include new framework and language features all the way up to .NET 3.5 and C# 3.0 (2008).


    Tags:   ,
    Categories:   .NET | Programming
    Actions:   E-mail | | Permalink | Comments (1) | Comment RSSRSS comment feed

    IEnlistmentNotification: Implementation Nuances

    Friday, 20 June 2008 11:15 by jordan.terrell

    I am a big fan of System.Transactions.  It is by far one of the coolest additions to the .NET framework.  It was what introduced me to the power of ThreadStatic variables (use with caution).

    Since being introduced to System.Transactions, I've been using it to create transactional business objects (volatile resources in System.Transactions lingo).  This has worked very well for me, however, I recently (read: in the past two weeks) discovered some nuances in implementing IEnlistmentNotification that might not be readily obvious or documented (as far as I could tell).

    Nuance 1: Do not throw exceptions from the Prepare(PreparingEnlistment pe) method

    If you need to indicate that your resource cannot prepare for the transaction to complete, you must call the ForceRollback(...) method on the PreparingEnlistment object passed into your implementation of Prepare().  If you want to include additional information on why your resource was unable to prepare for the transaction to complete, there is an overload of ForceRollback() that accepts an object that derives from System.Exception.  Once all resources have rolled back, the System.Transactions infrastructure will throw a TransactionAbortedException.  Any custom exception that you've provided to the ForceRollback() method will surface as the InnerException on the TransactionAbortedException thrown by the System.Transactions infrastructure.

    You should NOT throw an exception from Prepare(), and you should wrap all code within the Prepare() method with a try/catch block - the catch block should catch all exceptions and pass them on via the ForceRollback() method.  Throwing an exception from Prepare() (or allowing one to bubble up thru Prepare()) will short-circuit the System.Transactions infrastructure from calling Rollback() on enlisted resources - not something you want to happen.

    Nuance 2: Rollback() is not called on your resource if Prepare() votes to rollback

    If you call ForceRollback() within your implementation of the Prepare() method, the Rollback() method will not be called on your resource.  Any clean up that typically occurs in Rollback() will need to occur within Prepare() IF your Prepare() method votes to rollback.  For example, if your Prepare() method acquired any locks (e.g. "row locks", "table locks", etcetera) you will likely want to release them in the Prepare() method right before you vote to rollback.

    Moving Forward

    I hope that this is useful to you - I haven't seen this behavior documented anywhere, but that could be my own fault.

    I have no doubt that I will find additional implementation nuances when it comes to System.Transactions.  When I do, I'll be sure to document them here.


    I'm Going To The PDC!!!

    Monday, 16 June 2008 09:27 by jordan.terrell

    I can't wait to see what Microsoft has cooking now!  The 2005 PDC was great because of all the LINQ-related language enhancements and WinFX content.  I'll keep you posted.



    Categories:   .NET | Programming
    Actions:   E-mail | | Permalink | Comments (0) | Comment RSSRSS comment feed