Removing Otherwise method from CuttingEdge.Conditions
In this post I’ll describe another breaking change I’m making to my open source project, CuttingEdge.Conditions.
You might noticed I'm working on CuttingEdge.Conditions again; my open source library on Microsoft's CodePlex. Two days ago I described a controversial breaking change in CuttingEdge.Conditions.
Today I want to write about another breaking change that I'll be making in the coming stable release of CuttingEdge.Conditions: I'm removing the Otherwise<TException> methods from the library.
The Otherwise<T> method overloads let users define the exception type that has to be thrown. Normally the library throws an ArgumentException (using Requires) or PostconditionException (using Ensures). Sometimes however, it's useful to throw another exception type and with the beta releases, CuttingEdge.Conditions lets you do this.
The name of the Otherwise method is based on Spec# (SpecSharp). I looked closely at the Spec# language, while designing CuttingEdge.Conditions. Besides requires and ensures, Spec# defines an otherwise keyword. One of the requirements I had in the initial design of Conditions was to use the same terminology as Spec#.
There are however, two problems with Otherwise:
1. The name of the method doesn't properly describe its intend.
While Otherwise follows Spec#, I noticed developers find the name confusing. While documentation helps, I think it’s name can be improved. This means that I break with the initial requirement of staying close to Spec#, but I think this is okay. It could take years before Spec# (or its syntax) becomes mainstream I think it’s better to make a library that’s usable right now.
2. The use isn't intuitive, which leads to programming mistakes.
Perhaps it's the lack of proper documentation, lack of proper code samples, or simply a quirk in the design, but I recently experienced developers writing code like this:
Condition.Requires(x)
.IsNotNull()
.Otherwise<InvalidOperationException>();
The developers who wrote this code, expected an InvalidOperationException to be thrown when x was null. This is not the case however. This code throws an ArgumentNullException. The Requires(), Ensures(), and Otherwise() methods return an object that will be passed to validation methods such as the IsNotNull() method in the snippet above. That object determines the exception type to be thrown. When the Otherwise is specified last, the object it returns will never get used. The right way to write this is:
Condition.Requires(x)
.Otherwise<InvalidOperationException>()
.IsNotNull();
The problem however is that this is perhaps not as intuitive as I had expected.
For these two reasons I'm not sure the current implementation is the right one. However, it's not clear to me what the correct design is. I'm finalizing the first stable release of the library at the moment. Leaving the current implementation in, means I can never change or remove it, without introducing a breaking change in a stable product. This would possibly lead to many angry users, which is something I like to prevent.
While I know I might frustrate users of the current beta release, for most of them, Otherwise is a rarely used feature. Therefore I think it's better to remove it before the stable release and let the user community participate in an improved design of the otherwise feature.
The consequence of this change is that users will have to revert to using old fashion ‘if (...) throw ex’ statements in these situations. Although I published some code that could be added to your code base that fixed the breaking change I discussed two days ago, this isn’t possible in this case. It’s not possible to supply code that will prevent you from making changes throughout your code base.
But if you’re so hooked on this way of validating that you don’t want to go back to old fashion throw statements, please participate and let us together get a better implementation. Also if you’re really interested, I have an implementation with a slightly different syntax, that you actually can use in your own code base. If you’re interested, let me know.
Cheers
- .NET General, C#, CuttingEdge.Conditions, LINQ - No comments / No trackbacks - § ¶