Adding unit tests to existing code is nowadays applauded for being progressive, almost borderline pedestrian, for most software development shops. This was not the case when I began writing automated unit tests several years ago. It now feels otherworldly to see greater acceptance of unit testing primarily because I'd greatly toned down my advocacy for it. This shift in attitude includes a (substantial) decrease practicing test driven development (TDD). Unit testing can not simply be applied on blind faith hoping to cure all of one's software ills.
Not long ago, I and other developers on a .NET software project were retroactively adding unit tests (no TDD) for recently produced C# code. Part of the process involved removing any cruft specifically code that was not being called by any other code. The motivation was to help increase code coverage by removing any untouched lines of code. We relied on the static analysis features of the Visual Studio plugin, ReSharper, to reveal these isolated areas of code. In ReSharper parlance, Find Usages handles the work of hunting down any dependencies for symbols and functions.
One of those areas ReSharper indicated that no usages found were for a few simple getter/setter properties of a class. This code was then confidently removed. However, it was later discovered that the removed code did indeed serve a purpose and was providing functionality to one of the GUI screens of the WinForms application. More specifically a few of the columns in a 'DataGridView' control that allowed editing no longer did so. They unexpectedly became read-only.
The GUI screens had no tests. The discovery was made via manual end-to-end testing. This 'DataGridView' control was bound to the properties of the class. It inferred from the properties whether they were getters, setters, or both. The 'Set' accessor of the properties were naively removed since the code we wrote did not seem to call it. The grid control however was binding to it and passing values to and from the properties. No setter accessors now meant the associated columns had become effectively non-editable.
Realizing our mistake we rolled back our original edits for that class and cautiously reviewed all other recent refactorings.
Joel Spolsky once stated that manual testing is all you need in developing quality software and that unit testing provides no notable value . Others taking the inevitable opposing view immediately went on the offensive denouncing his claims. Joel's view is more an over reaction to all the TDD zealots who, whether intentional or not, seem to be deemphasizing the value of old fashion manual testing. Meanwhile, the dissenting voices are manifesting as a fear that their do-no-wrong methodology (and possibly their identity) might possibly amount to nothing. Both views are too extreme and leaning one way or the other can cost you in other areas. You need to continually find and maintain a balance in testing and not become complacent with whatever approach you take.
Yes, integration-style tests might have helped in exercising and validating the correct behaviour in the UI but even that might give you a false sense of security. Manual testing does have its virtues. Without it, you might overlook the human elements of UI functionality, design, and usability. Just like it is an incorrect assumption that no compiler errors means your application is fully functional and ready for end-users.
Also, these were CRUD operations. In my experience they tend to be the least risky part of an application, least likely to be buggy, and the quickest to identify and fix. The cost of writing and maintaining these sorts of unit tests do not warrant their benefit. Is it really worth your time and effort chasing after an unrealistic 100% code coverage? You learn your lesson then you move on (part of continually defining the proper testing balance). Regardless, you should confirm that your seemingly harmless refactoring does not produce unwanted side effects. Unit tests help with that but not by themselves.
Putting the merits of unit testing aside for a moment, the inability to easily detect how the .NET framework is referencing and interacting with my code can be somewhat irritating. This datagrid binding issue is another one of those features in .NET where it does something behind the scenes on your behalf (automagically!) but it is not clear (at least not from a coding perspective) what and how it is doing it. I'd experienced this before when trying to implement paging using NHibernate in an ASP.NET GridView control and it was frustrating. Wait until the havoc WebMatrix, LightSwitch, and friends will unleash on the .NET community.
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts
Tuesday, August 31, 2010
Unit Testing Perils
Labels:
.NET,
C#,
datagridview,
resharper,
Test Driven Development,
UI,
Unit Testing,
winforms
Friday, April 30, 2010
Running Mono C# REPL on Windows
Being a big fan of programming language REPLs and command-line consoles, I have awaited one for C# that I can easily install and comfortably use for lightweight validation of C# syntax and for exploring its language features. Originally, Snippet Compiler had filled that role and then replaced with LINQPad but neither one is a REPL.
Fortunately, Mono, the open source project for .NET and C# that offers cross OS platform support especially for Linux and Mac, does have an interactive shell (CsharpRepl) for evaluating C# statements and expressions. Since Mono also runs on Windows, I downloaded and installed the latest Mono release 2.6 on my Windows development machine.
Once installed, to run the C# REPL simply:
The first step just adds Mono's bin directory to your environment PATH for the current shell session. (Alternatively, you can navigate via the command line to the Mono bin directory and directly run the file, csharp.bat.)
The C# REPL works if used within the Windows shell, cmd.exe (a.k.a. "command prompt") but with some caveats. The first immediate one is the command prompt text "csharp >" is not displayed making it a bit disorienting to use. It's difficult to distinguish between the input and the output of your expressions. [Update: This bug was subsequently fixed and it is now available with the version 2.6.7 release.]
Another is no autocomplete functionality but this feature is only available in Mono's GUI command console, 'gsharp'. GSharp requires an additional install of the mono-tools package available on the Windows platform download page under the link named "Gtk# for .NET". Once installed, to launch gsharp:
To activate autocomplete, type in part of a word and then hit <TAB>. Sometimes auto-completing words is slow in gsharp particularly if it has to search a large set of libraries. For example, typing the text "using Sys" and then <TAB> causes hanging since 'System' is the most top level .NET lib.
I decided to stick with using gsharp (a.k.a. the "C# InteractiveBase Shell"?) over csharp plus cmd.exe combo not only because of the autocomplete feature but because it also does display a "csharp >" prompt.
With those two issues resolved in gsharp, I continued to explore how the csharp REPL performed and behaved. The most striking deficiency I then encountered was when typing a statement containing invalid syntax, it did not show any output results. This was surprising since it goes against what I consider to be one of the hallmarks of a good REPL: immediate feedback not just on command/code that evaluated successfully but on things that failed to evaluate properly. Strange the lack of output...almost as if it was missing the 'Print' in REPL.
With continued use, I noticed in the examples found in the Mono REPL documentation that each expression or statement requires the ";" character at the end of it to produce any visible output. Otherwise, it gets ignored. I was expecting the same behavior found in the Visual Studio's Immediate Window where ";" is not always required. Not sure what the advantage of having to always type ";" (other than as a constant reminder that you are using a C based language in a REPL). Just seems like an extra unneeded keystroke.
However, reading more of the REPL docs, it implies multiple declarations can be made on a single line using ";" as a delimiter:
The docs also explicitly state the inverse: one declaration ending with ";" can be spread across multiple lines:
Although the docs states that multi-line input is supported, it does not seem to be true of my current install on Windows. On Linux, I can do this:
On Windows, however, the special indented continuation prompt " >" never appears when a new line is returned if the ";" character is not included. This is unfortunately a notable flaw in the REPL tool on the Windows platform.
In addition to the online documentation, another source describing the more common commands is available in the REPL itself. Just type "help;":
Perhaps to truly escape all of these OS specific limitations, I might be better off running Mono's REPL within a Linux VM on Windows. However, this approach negates the benefits of a cross-platform framework that Mono aspires to be.
Despite these minor difficulties, Mono's C# REPL has been a nice addition to my .NET development toolbox. It has proved useful when I needed a deeper understanding of how delegates and lexical closures behave in C# and when figuring out how to do list comprehensions in C# using List<T>.ConvertAll instead of LINQ. It provides a quick, frictionless way of observing and interacting with the functionalities of C# and the .NET libraries.
Fortunately, Mono, the open source project for .NET and C# that offers cross OS platform support especially for Linux and Mac, does have an interactive shell (CsharpRepl) for evaluating C# statements and expressions. Since Mono also runs on Windows, I downloaded and installed the latest Mono release 2.6 on my Windows development machine.
Once installed, to run the C# REPL simply:
- Select Start ->; All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
- At the command prompt, type "csharp"
The first step just adds Mono's bin directory to your environment PATH for the current shell session. (Alternatively, you can navigate via the command line to the Mono bin directory and directly run the file, csharp.bat.)
The C# REPL works if used within the Windows shell, cmd.exe (a.k.a. "command prompt") but with some caveats. The first immediate one is the command prompt text "csharp >" is not displayed making it a bit disorienting to use. It's difficult to distinguish between the input and the output of your expressions. [Update: This bug was subsequently fixed and it is now available with the version 2.6.7 release.]
Another is no autocomplete functionality but this feature is only available in Mono's GUI command console, 'gsharp'. GSharp requires an additional install of the mono-tools package available on the Windows platform download page under the link named "Gtk# for .NET". Once installed, to launch gsharp:
- Start -> All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
- c:\> gsharp
To activate autocomplete, type in part of a word and then hit <TAB>. Sometimes auto-completing words is slow in gsharp particularly if it has to search a large set of libraries. For example, typing the text "using Sys" and then <TAB> causes hanging since 'System' is the most top level .NET lib.
I decided to stick with using gsharp (a.k.a. the "C# InteractiveBase Shell"?) over csharp plus cmd.exe combo not only because of the autocomplete feature but because it also does display a "csharp >" prompt.
With those two issues resolved in gsharp, I continued to explore how the csharp REPL performed and behaved. The most striking deficiency I then encountered was when typing a statement containing invalid syntax, it did not show any output results. This was surprising since it goes against what I consider to be one of the hallmarks of a good REPL: immediate feedback not just on command/code that evaluated successfully but on things that failed to evaluate properly. Strange the lack of output...almost as if it was missing the 'Print' in REPL.
With continued use, I noticed in the examples found in the Mono REPL documentation that each expression or statement requires the ";" character at the end of it to produce any visible output. Otherwise, it gets ignored. I was expecting the same behavior found in the Visual Studio's Immediate Window where ";" is not always required. Not sure what the advantage of having to always type ";" (other than as a constant reminder that you are using a C based language in a REPL). Just seems like an extra unneeded keystroke.
However, reading more of the REPL docs, it implies multiple declarations can be made on a single line using ";" as a delimiter:
csharp> var a = "why so many semi-colons?"; 5; "more stuff!"; "more stuff!" csharp> a; "why so many semi-colons?" csharp>
All three statements get evaluated but only the last one ("more stuff!") is printed to the screen.
The docs also explicitly state the inverse: one declaration ending with ";" can be spread across multiple lines:
"...Statements and expression can take multiple lines, for example, consider this LINQ query that displays all the files modified in the /etc directory in the last week. The prompt changes from "csharp" to " >" to indicate that new input is expected..."and
"...Multi-line input...If your code does not fit in a single line, you can enter expressions in multiple lines. The shell will not execute the code until a valid expression has been entered or a syntax error is flagged. A special prompt is shown to indicate that ics is waiting for input..."
Although the docs states that multi-line input is supported, it does not seem to be true of my current install on Windows. On Linux, I can do this:
csharp> var list = new int [] {1,2,3};
csharp> var b = from x in list
> where x > 1
> select x;
csharp> b;
On Windows, however, the special indented continuation prompt " >" never appears when a new line is returned if the ";" character is not included. This is unfortunately a notable flaw in the REPL tool on the Windows platform.
In addition to the online documentation, another source describing the more common commands is available in the REPL itself. Just type "help;":
"Static methods:
Describe(obj) - Describes the object's type
LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)
LoadAssembly (ass) - Loads the given assembly (like -r:ASS)
ShowVars (); - Shows defined local variables.
ShowUsing (); - Show active using decltions.
Prompt - The prompt used by the C# shell
ContinuationPrompt - The prompt for partial input
Time(() -> { }) - Times the specified code
quit;
help;
TabAtStartCompletes - Whether tab will complete even on emtpy lines
"
Of course, a couple of these commands exhibit some quirks. If type 'ShowUsing();' it does not display anything in the console although it is expected to do so (it behaves like this on Linux). After trying the command several times, I looked at the original command prompt window from which gsharp launched and saw the results of the command showing in there. The same was true with 'ShowVars()'. Recommend keeping the command prompt console in view while using gsharp to see any output piped outside of it. (The issue appears to been logged at the mono project as a bug.)Perhaps to truly escape all of these OS specific limitations, I might be better off running Mono's REPL within a Linux VM on Windows. However, this approach negates the benefits of a cross-platform framework that Mono aspires to be.
Despite these minor difficulties, Mono's C# REPL has been a nice addition to my .NET development toolbox. It has proved useful when I needed a deeper understanding of how delegates and lexical closures behave in C# and when figuring out how to do list comprehensions in C# using List<T>.ConvertAll instead of LINQ. It provides a quick, frictionless way of observing and interacting with the functionalities of C# and the .NET libraries.
Friday, January 30, 2009
Paging in ASP.NET using NHiberate
NHibernate, the object-relational mapping (ORM) framework for .NET, supports custom pagination for collections. It provides a potential alternative to the built-in paging mechanism and native support found in ASP.NET GridView web controls. NHibernate exposes in the API for IQuery and ICriteria two methods, SetFirstResult and SetMaxResult, that can be used to enable paging:
Adding Paging to the Base DAO
The design and architecture of my project, where NHibernate style pagination shall be introduced, was deeply influenced by Billy McCafferty's NHibernate Best Practices with ASP.NET resulting in the proliferation of Data Access Objects (DAO) throughout the guts of the application. Each DAO maps one-to-one to a single matching table in the database.
For example, a 'Task' table would have a corresponding 'TaskDao' in the data access layer (DAL) of the application. All of these DAOs inherit from the same base class 'GenericNHibernateDao' responsible for containing commonly shared code including managing NHibernate sessions and providing generic methods for summoning a specific persisted instance by ID and for saving/deleting an existing instance.
The initial step to implement paging was adding the following members to the aforementioned base class 'GenericNHibernateDao':
The property 'PageSize' gets/sets the number of instances expected to be displayed on a web page for a specific strongly typed collection. Essentially, it handles how many rows to return for a embedded control (such as a GridView) on the page. This property is intended to be internally consumed by NHibernate's 'SetMaxResults' method belonging to IQuery or ICriteria. For example:
'PageNumber' specifies the set of multiple instances to be returned and displayed on a web page as identified and grouped by a page sequence numeric value (This is the equivalent of 'PageIndex' property for GridViews). For example, if you had a total of five pages worth of data rows then displaying the second page would require setting the page number value to '2' (e.g. _dao.PageNumber = 2). Just as with 'PageSize', this property is intended to be used by the method 'GetFirstResultPosition' as will be explained next.
The protected method 'GetFirstResultPosition' calculates the actual row at which to start paging based on the values provided by 'PageSize' and 'PageNumber'. This method's return value is expected to be passed to NHibernate's 'SetFirstResult' method, once again, part of IQuery or ICriteria. For example:
The overloaded method named 'SetPagingFor' performs the actual paging functionality via the 'SetFirstResult' and 'SetMaxResult' methods of IQuery and ICriteria. (As an aside, the use of IQuery to build and execute HQL is much more common on this project in comparison to the almost non-existent use of ICriteria).
The base class 'GenericNHibernateDao' was also modified to have one of its existing methods 'GetAll' call 'SetPagingFor'. (The 'GetAll' method simply returns a list of all strongly type objects in the database without any specified criteria or filtering):
As it shall be made clear later, this new line of code will optionally provide paging functionality when 'GetAll' is requested, if needed, but not required per se.
Applying Paging Functionality in the DAOs
Now that the base class 'GenericNHibernateDao' has been updated to manage paging, any of its derived DAO classes are instantly equipped to perform paging themselves. To actually invoke the paging functionality for any of the DAOs, simply set the appropriate values for page size and page number as shown in this example for the 'TaskDao' class:
Without paging, 'GetAll' would have returned something in the neighborhood of 100 or so rows. With paging, the returned list will instead be only 20 rows starting at row (i.e. position) # 80. While a hundred rows might not sound too substantial, larger sets of data can have a more noticeable effect on your application's day-to-day operations if your table contains tens or hundreds of thousands of rows. Your performance will be progressively impacted as your application scales with more data.
On the other hand, NHibernate's paging will significantly decrease the size of your result set. This is in stark contrast to the default behavior of the existing paging available in any GridView control. If this native functionality of the control is used, it will return all rows from the database and then page them in memory. As mentioned earlier, this can lead to slower performance as your data grows. More on this later.
If, for any reason, paging is not essential for a particular web page in possession of a control bound to a strongly typed list (for example,a very small static list of data) then setting the page size and number properties is not required at all. Simply call 'GetAll' by itself disregarding the 'PageSize' and 'PageNumber' properties and the DAO should return all rows found in the associated database table. What makes this possible is that the default values for those two paging properties are formally declared in the DAO base class to behave as expected for "non-pageable" collections:
Typically, a DAO might have other custom methods that return more narrowly focused (i.e. filtered) lists of typed objects than what 'GetAll' offers. For these other DAO methods, the same pattern can be followed by adding the one line of code calling 'SetPagingFor'. For example, the 'TaskDao' might have a method that returns tasks that were completed in 2006 excluding any other tasks not done within that same year:
It is generally good practice not to pass the values for page size and number directly via the parameter list for any of these custom filtered data access methods. A few reasons to avoid this: (a) it can quickly clutter the intent of the method, and (b) it would prevent the paging functionality from being optional and, as a result, become less flexible, less reusable, and more cumbersome to work with.
Consequently, while it would be tempting to write the method's signature as such:
It is preferable to do the following instead:
The Downside of NHibernate Paging with ASP.NET Controls
As indicated earlier, one weakness of NHibernate's paging when combined with ASP.NET's GridView control involves some loss of "out-of-the-box" functionality. Under more conventional circumstances, when a collection of objects are bound to a GridView control, one of the built-in paging features of that control is to automatically render on the web page the navigation hyperlinks for the pages. For example, you might see following below your control:
The GridView's default behavior assumes that all data bound directly to its DataSource can be paged as long as the number of items of that data is greater than its PageSize property value. Hence, if that condition is met, the control will slice up and present the data as appropriate.
Conversely, this is not true when using NHibernate style pagination. When binding to an NHibernate paged list method, the GridView's PageSize value will usually be set to the same size as the paged data list, a mere subset of the total data found in the database (or data source). Behind the scenes, the PageIndex property of the GridView will reset to zero because the number of items bound to its DataSource is less than or equal to the PageSize. Therefore, the GridView is under the impression that the data it receives is not pageable and, in turn, disables any paging features, unaware that more items do indeed exist but were just not provided at that moment. The paging features lost include not just immobilizing navigation links but also removing the availability of the event handlers linked with changing the page index.
Without the convenience of auto-generating navigation links, two options emerge that might help to produce the same desired behavior:
Initially, the easier path was taken by developing a very rudimentary and simple implementation of option # 2. This entailed providing in extremely basic custom controls functionality for navigating between pages using homemade "Previous" and "Next" buttons. Currently, it is not implemented as a shareable user control nor is it able to display the pages counts. I intend on exploring option # 1 a bit more in the event that option # 2 evolves into something more elaborate and unwieldy. Until then, it is a work in progress.
A third option does exist involving the possible use of the ObjectDataSource control. However, that strategy can lead down a less than desirable path for the following reasons:
All things considered, despite some trade offs and a little bit of work, leveraging NHibernate's ability to do paging can be an area that could contribute significantly in optimizing and improving the performance of a data-intensive web application.
Collections are pageable by using the IQuery interface with a filter:
IQuery q = s.CreateFilter( collection, "" ); // the trivial filter
q.setMaxResults(PageSize);
q.setFirstResult(PageSize * pageNumber);
IList page = q.List();
Adding Paging to the Base DAO
The design and architecture of my project, where NHibernate style pagination shall be introduced, was deeply influenced by Billy McCafferty's NHibernate Best Practices with ASP.NET resulting in the proliferation of Data Access Objects (DAO) throughout the guts of the application. Each DAO maps one-to-one to a single matching table in the database.
For example, a 'Task' table would have a corresponding 'TaskDao' in the data access layer (DAL) of the application. All of these DAOs inherit from the same base class 'GenericNHibernateDao' responsible for containing commonly shared code including managing NHibernate sessions and providing generic methods for summoning a specific persisted instance by ID and for saving/deleting an existing instance.
The initial step to implement paging was adding the following members to the aforementioned base class 'GenericNHibernateDao':
public abstract class GenericNHibernateDao: IGenericDao
{
public int PageSize
{
get { return _pageSize; } set { _pageSize = value; }
}
public int PageNumber
{
get { return _pageNumber; } set { _pageNumber = value ; }
}
protected int GetFirstResultPosition()
{
return _pageSize * (_pageNumber - 1);
}
protected void SetPagingFor(IQuery query)
{
query.SetFirstResult(GetFirstResultPosition());
query.SetMaxResults(_pageSize);
}
protected void SetPagingFor(ICriteria criteria)
{
criteria.SetFirstResult(GetFirstResultPosition());
criteria.SetMaxResults(_pageSize);
}
/*
other non-paging related members...
*/
}
The property 'PageSize' gets/sets the number of instances expected to be displayed on a web page for a specific strongly typed collection. Essentially, it handles how many rows to return for a embedded control (such as a GridView) on the page. This property is intended to be internally consumed by NHibernate's 'SetMaxResults' method belonging to IQuery or ICriteria. For example:
IQuery query = Session.CreateQuery();
query.SetMaxResults(_pageSize);
'PageNumber' specifies the set of multiple instances to be returned and displayed on a web page as identified and grouped by a page sequence numeric value (This is the equivalent of 'PageIndex' property for GridViews). For example, if you had a total of five pages worth of data rows then displaying the second page would require setting the page number value to '2' (e.g. _dao.PageNumber = 2). Just as with 'PageSize', this property is intended to be used by the method 'GetFirstResultPosition' as will be explained next.
The protected method 'GetFirstResultPosition' calculates the actual row at which to start paging based on the values provided by 'PageSize' and 'PageNumber'. This method's return value is expected to be passed to NHibernate's 'SetFirstResult' method, once again, part of IQuery or ICriteria. For example:
IQuery query = Session.CreateQuery();
query.SetFirstResult(GetFirstResultPosition());
The overloaded method named 'SetPagingFor' performs the actual paging functionality via the 'SetFirstResult' and 'SetMaxResult' methods of IQuery and ICriteria. (As an aside, the use of IQuery to build and execute HQL is much more common on this project in comparison to the almost non-existent use of ICriteria).
The base class 'GenericNHibernateDao' was also modified to have one of its existing methods 'GetAll' call 'SetPagingFor'. (The 'GetAll' method simply returns a list of all strongly type objects in the database without any specified criteria or filtering):
// GenericNHibernateDao class
public IList<T> GetAll()
{
ICriteria criteria = Session.CreateCriteria(persitentType);
SetPagingFor(criteria); // this is newly added!
return criteria.List();
}
As it shall be made clear later, this new line of code will optionally provide paging functionality when 'GetAll' is requested, if needed, but not required per se.
Applying Paging Functionality in the DAOs
Now that the base class 'GenericNHibernateDao' has been updated to manage paging, any of its derived DAO classes are instantly equipped to perform paging themselves. To actually invoke the paging functionality for any of the DAOs, simply set the appropriate values for page size and page number as shown in this example for the 'TaskDao' class:
// In context (such as a Presenter or Controller class
// part of an MVP/MVC applied framework)
TaskDao _taskDao = new TaskDao();
_taskDao.PageSize = 20;
_taskDao.PageNumber = 5;
IList<TaskDao>list = _taskDao.GetAll();
Without paging, 'GetAll' would have returned something in the neighborhood of 100 or so rows. With paging, the returned list will instead be only 20 rows starting at row (i.e. position) # 80. While a hundred rows might not sound too substantial, larger sets of data can have a more noticeable effect on your application's day-to-day operations if your table contains tens or hundreds of thousands of rows. Your performance will be progressively impacted as your application scales with more data.
On the other hand, NHibernate's paging will significantly decrease the size of your result set. This is in stark contrast to the default behavior of the existing paging available in any GridView control. If this native functionality of the control is used, it will return all rows from the database and then page them in memory. As mentioned earlier, this can lead to slower performance as your data grows. More on this later.
If, for any reason, paging is not essential for a particular web page in possession of a control bound to a strongly typed list (for example,a very small static list of data) then setting the page size and number properties is not required at all. Simply call 'GetAll' by itself disregarding the 'PageSize' and 'PageNumber' properties and the DAO should return all rows found in the associated database table. What makes this possible is that the default values for those two paging properties are formally declared in the DAO base class to behave as expected for "non-pageable" collections:
public abstract class GenericNHibernateDao: IGenericDao
{
protected int _pageSize = -1; // default for unlimited page size
protected int _pageNumber = 1; // default for first item in collection
// more members...
}
Typically, a DAO might have other custom methods that return more narrowly focused (i.e. filtered) lists of typed objects than what 'GetAll' offers. For these other DAO methods, the same pattern can be followed by adding the one line of code calling 'SetPagingFor'. For example, the 'TaskDao' might have a method that returns tasks that were completed in 2006 excluding any other tasks not done within that same year:
// TaskDao class
public IList<TaskDao>GetTasksCompletedIn2006()
{
IQuery query = Session.CreateQuery(
"some HQL statement that filters tasks by 2006...");
SetPagingFor(query); // newly added!
return query.List();
}
It is generally good practice not to pass the values for page size and number directly via the parameter list for any of these custom filtered data access methods. A few reasons to avoid this: (a) it can quickly clutter the intent of the method, and (b) it would prevent the paging functionality from being optional and, as a result, become less flexible, less reusable, and more cumbersome to work with.
Consequently, while it would be tempting to write the method's signature as such:
IList<TaskDao>list = _taskDao. GetAllTasksWithSubtasks( param1, param2, param3, ..., paramN, pageSize, pageNumber);
It is preferable to do the following instead:
_taskDao.PageSize = 20;
_taskDao.PageNumber = 5;
IList<TaskDao>list = _taskDao. GetAllTasksWithSubtasks(
param1, param2, param3, ..., paramN);
The Downside of NHibernate Paging with ASP.NET Controls
As indicated earlier, one weakness of NHibernate's paging when combined with ASP.NET's GridView control involves some loss of "out-of-the-box" functionality. Under more conventional circumstances, when a collection of objects are bound to a GridView control, one of the built-in paging features of that control is to automatically render on the web page the navigation hyperlinks for the pages. For example, you might see following below your control:
" 1 2 3 ... 10 "
The GridView's default behavior assumes that all data bound directly to its DataSource can be paged as long as the number of items of that data is greater than its PageSize property value. Hence, if that condition is met, the control will slice up and present the data as appropriate.
Conversely, this is not true when using NHibernate style pagination. When binding to an NHibernate paged list method, the GridView's PageSize value will usually be set to the same size as the paged data list, a mere subset of the total data found in the database (or data source). Behind the scenes, the PageIndex property of the GridView will reset to zero because the number of items bound to its DataSource is less than or equal to the PageSize. Therefore, the GridView is under the impression that the data it receives is not pageable and, in turn, disables any paging features, unaware that more items do indeed exist but were just not provided at that moment. The paging features lost include not just immobilizing navigation links but also removing the availability of the event handlers linked with changing the page index.
Without the convenience of auto-generating navigation links, two options emerge that might help to produce the same desired behavior:
- Inherit from the GridView control and attempt to confirm whether or not if any paging methods can be overridden some how or in some way
- Create a custom, reusable user control to implement the navigation features
Initially, the easier path was taken by developing a very rudimentary and simple implementation of option # 2. This entailed providing in extremely basic custom controls functionality for navigating between pages using homemade "Previous" and "Next" buttons. Currently, it is not implemented as a shareable user control nor is it able to display the pages counts. I intend on exploring option # 1 a bit more in the event that option # 2 evolves into something more elaborate and unwieldy. Until then, it is a work in progress.
A third option does exist involving the possible use of the ObjectDataSource control. However, that strategy can lead down a less than desirable path for the following reasons:
- loss of control of how the data access is managed
- ease of maintainability diminishes if any widespread changes were to emerge in the future within areas of the application relying on paging
- disrupts and conflicts with how the MCP/MVC methodology is currently applied on the project
- increased difficulties in writing and running reliable automated unit tests
All things considered, despite some trade offs and a little bit of work, leveraging NHibernate's ability to do paging can be an area that could contribute significantly in optimizing and improving the performance of a data-intensive web application.
Sunday, November 30, 2008
Speak to me...Interpreting C#
I came across A C# REPL (in Clojure) which discusses a means by which to interact with and run C# code via an interactive command-line by using Clojure and IKVM.NET . Now, Clojure I have heard of (a Lisp implementation that runs on the JVM) but this is my first time hearing about IKVM.NET (which I now know to be a .NET implementation for JVM). The post describes how combining these two technologies gives you the potential of working with a static language like C# in a way that is quite common in the world of dynamic languages such as Python, Ruby, Boo, etc.
Having an interactive code interpreter is a huge productivity boost. It allows you to easily run and test your code as you write and modify it while not needing to pay the dreaded compilation tax which can disrupt your development flow. This dramatically tightens and shortens the feedback loop on how well your code works ranging from whether it is behaving as intended for meeting spec requirements to much more quickly identifying any runtime bugs than you would using a development process common to traditionally compiled static languages. (As an aside, these are generally the same reasons that are given for creating and maintaining automated unit tests. Same goal but different methods.)
Not sure how well this C#/Clojure/IKVM.NET approach works or how well it realistically performs (typically, interpreted languages are slower). What is certain is that this unusual implementation requires the use of the very foreign-looking Lisp parentheses. I will openly admit as someone who does not program in Lisp it strikes me as kind of strange to use and see parentheses with C# but aside from this peculiar syntactical idiosyncrasy the general concept of REPL with C# overshadows even this oddity. This quote sums up its overall appeal in the world of C#:
This is precisely how I felt when I initially started to learn and use Python. Suddenly, coding in C# with Visual Studio certainly seems to now be relatively more restrictive. Similarly, whenever I have had to touch any VBA code (yes, that does happen from time to time) I customarily inhabit the VB Editor's Immediate Window (IW) pushing its limits by attempting to use it in a manner that is similar to how I code in Python.
For example, in the VB language, not only is it not required to declare the data type of a variable but it is even unnecessary to explicitly declare the variables themselves (usually this is done using the 'Dim' keyword but this can be avoided by quite simply not including the 'Option Explicit' statement). Subsequently, the first time a value is assigned to a variable, the variable will automatically and implicitly be defined on the stack just like it does in Python. As a result, you can somewhat attain that same level of interaction with code in VB (via IW) as you would in Python (via its standard interpreter) potentially gaining the productivity benefits of writing less code in contrast to strongly typed languages.
My increased reliance of the Immediate Window also extends to Visual Studio when coding in C# but it requires more work and syntax overhead versus IW in the old VB Editor. Overall, it is not quite the same experience as in Python. Regardless, as I have previously written, frequent use of the VB Editor's IW led me to lean heavily on the one in Visual Studio whenever coding in C#. Prior to that, I had somewhat forgotten it even existed. In fact, in VS 2005, the IW sometimes is missing and difficult to view when not in debug mode (this is allegedly also true for VS 2008). This is discouraging as it probably contributes to most .NET developers not favoring its use in more situations.
While I have seen other attempts at providing an interactive console for C# the following are ones I have noted to possibly try out in the very near future:
I am extremely curious if (and hopeful that) Microsoft will provide an improved implementation for VS's IW when the more dynamic C# 4.0 becomes mainstream. (How long before we have an official C#Script? It worked for VB and VBScript.)
Having an interactive code interpreter is a huge productivity boost. It allows you to easily run and test your code as you write and modify it while not needing to pay the dreaded compilation tax which can disrupt your development flow. This dramatically tightens and shortens the feedback loop on how well your code works ranging from whether it is behaving as intended for meeting spec requirements to much more quickly identifying any runtime bugs than you would using a development process common to traditionally compiled static languages. (As an aside, these are generally the same reasons that are given for creating and maintaining automated unit tests. Same goal but different methods.)
Not sure how well this C#/Clojure/IKVM.NET approach works or how well it realistically performs (typically, interpreted languages are slower). What is certain is that this unusual implementation requires the use of the very foreign-looking Lisp parentheses. I will openly admit as someone who does not program in Lisp it strikes me as kind of strange to use and see parentheses with C# but aside from this peculiar syntactical idiosyncrasy the general concept of REPL with C# overshadows even this oddity. This quote sums up its overall appeal in the world of C#:
A REPL is a Read-Eval-Print Loop, which is a fancy way of saying "an interactive programming command line". It's like the immediate window in the Visual Studio debugger on steroids, and its absence is one of the increasing number of things that makes C# painful to use as I gain proficiency in more advanced languages.
This is precisely how I felt when I initially started to learn and use Python. Suddenly, coding in C# with Visual Studio certainly seems to now be relatively more restrictive. Similarly, whenever I have had to touch any VBA code (yes, that does happen from time to time) I customarily inhabit the VB Editor's Immediate Window (IW) pushing its limits by attempting to use it in a manner that is similar to how I code in Python.
For example, in the VB language, not only is it not required to declare the data type of a variable but it is even unnecessary to explicitly declare the variables themselves (usually this is done using the 'Dim' keyword but this can be avoided by quite simply not including the 'Option Explicit' statement). Subsequently, the first time a value is assigned to a variable, the variable will automatically and implicitly be defined on the stack just like it does in Python. As a result, you can somewhat attain that same level of interaction with code in VB (via IW) as you would in Python (via its standard interpreter) potentially gaining the productivity benefits of writing less code in contrast to strongly typed languages.
My increased reliance of the Immediate Window also extends to Visual Studio when coding in C# but it requires more work and syntax overhead versus IW in the old VB Editor. Overall, it is not quite the same experience as in Python. Regardless, as I have previously written, frequent use of the VB Editor's IW led me to lean heavily on the one in Visual Studio whenever coding in C#. Prior to that, I had somewhat forgotten it even existed. In fact, in VS 2005, the IW sometimes is missing and difficult to view when not in debug mode (this is allegedly also true for VS 2008). This is discouraging as it probably contributes to most .NET developers not favoring its use in more situations.
While I have seen other attempts at providing an interactive console for C# the following are ones I have noted to possibly try out in the very near future:
I am extremely curious if (and hopeful that) Microsoft will provide an improved implementation for VS's IW when the more dynamic C# 4.0 becomes mainstream. (How long before we have an official C#Script? It worked for VB and VBScript.)
Labels:
.NET,
C#,
Programming Language,
Python,
REPL,
Software Development,
Tools,
VB,
Visual Studio
Tuesday, September 9, 2008
Cryptic Rhino Mock exception messages
Let me first start off by saying that Rhino Mocks is a great mock objects framework for unit testing in .NET and C#. As compared with NMock2, which was my first experience with testing using mock objects, it is far superior (the use of strongly typed method/property names instead of strings is one of its best features especially for TDD and refactoring.) However, there are some aspects of NMock2 that I do miss.
'Expect' Consistency
For starters, NMock2 was more consistent in how the 'Expect' calls are made versus the way Rhino Mocks does it. In NMock2, the use of 'Expects' are the same whether you use a void method or a method that returns a value:
Recently, a new way of expressing 'Expects' with void methods was added to the Rhino Mocks framework but it relies on 'delegates'. Not sure if I really like the solution. It trades off one form of weak readability for another albeit different one.
This could be yet another reason to turn off newbies from testing with a mock framework such as Rhinos. It can be confusing. It is already quite a difficult endeavor to encourage software developers the virtues of unit testing. It is even more difficult to promote mock object testing so anything to lower the barriers is important and critical.
Understandable Exception Messages
In addition, Rhino Mock exception messages sometimes can be vague and unclear. This can be frustrating for new (and even existing) users.
For example, I was recently working on an old test fixture for a project which uses NMock2 and not Rhinos as its testing framework. To some degree, I felt a bit more productive with and in control of it because the error messaging is a lot more user friendly. I could more quickly determine the cause of a problem.
For example, below is an actual exception I received from NMock2:
Now, here is what I might get from Rhinos:
Honestly, I like the first one better. It reads better to me. For one thing, Rhinos provides the raw (CLR?) object definition so that if the member is inherited from an interface or another class then it shows as it is defined for interface (i.e. "ICriteria") or the base class . Meanwhile, NMock2 shows the actual local variable name used in the code you are testing (i.e. "criteria"). Much faster to pinpoint the culprit.
In fact, where this really drives me crazy is for the domain objects (i.e. POCOs, business objects, etc.) for that same project. Every domain object inherits from IDomainObject so with Rhino Mocks I get this:
The following exception message is one I'm fairly certain I have gotten before but always forget because the message is so...well...CRYPTIC!!!!
Specifying the proper type should fix the problem as follows:
'Expect' Consistency
For starters, NMock2 was more consistent in how the 'Expect' calls are made versus the way Rhino Mocks does it. In NMock2, the use of 'Expects' are the same whether you use a void method or a method that returns a value:
Expect.Once.On(mockFoo).Method("SomeMethodThatReturnsAValue")That is not the case with Rhino Mocks. 'Expects' can only be used with methods that return values and not with void methods.
Expect.Once.On(mockFoo).Method("SomeVoidMethod")
Recently, a new way of expressing 'Expects' with void methods was added to the Rhino Mocks framework but it relies on 'delegates'. Not sure if I really like the solution. It trades off one form of weak readability for another albeit different one.
This could be yet another reason to turn off newbies from testing with a mock framework such as Rhinos. It can be confusing. It is already quite a difficult endeavor to encourage software developers the virtues of unit testing. It is even more difficult to promote mock object testing so anything to lower the barriers is important and critical.
Understandable Exception Messages
In addition, Rhino Mock exception messages sometimes can be vague and unclear. This can be frustrating for new (and even existing) users.
For example, I was recently working on an old test fixture for a project which uses NMock2 and not Rhinos as its testing framework. To some degree, I felt a bit more productive with and in control of it because the error messaging is a lot more user friendly. I could more quickly determine the cause of a problem.
For example, below is an actual exception I received from NMock2:
NMock2.Internal.ExpectationException: not all expected invocations
were performed
Expected:
1 time: criteria.SetFirstResult(equal to <50>) [called 0 times]
1 time: criteria.SetMaxResults(equal to <5>) [called 0 times]
1 time: criteria.List(any arguments), will return
<System.Collections.Generic.List`1[System.DateTime]> [called 0 times]
Now, here is what I might get from Rhinos:
Rhino.Mocks.Exceptions.ExpectationViolationException:
ICriteria.SetFirstResult(50); Expected #1, Actual #0.
ICriteria.SetMaxResults(5); Expected #1, Actual #0.
Honestly, I like the first one better. It reads better to me. For one thing, Rhinos provides the raw (CLR?) object definition so that if the member is inherited from an interface or another class then it shows as it is defined for interface (i.e. "ICriteria") or the base class . Meanwhile, NMock2 shows the actual local variable name used in the code you are testing (i.e. "criteria"). Much faster to pinpoint the culprit.
In fact, where this really drives me crazy is for the domain objects (i.e. POCOs, business objects, etc.) for that same project. Every domain object inherits from IDomainObject so with Rhino Mocks I get this:
IDomainObject.DescriptionOK....but, which domain object is it? If I happen to have two or more domain objects being mocked/stubbed in my test it can get really hard figuring out the one it's complaining about. Instead, it would be nice if Rhino provided the following as does NMock2 using the variable name (assuming my domain object is named 'Foo'):
foo.DescriptionAnother example of the disparity between the two frameworks is if a property related exception occurs then the Rhino message would contain this:
IFooView.set_PageSizewhile NMock2 would provide this:
_view.PageSize \\ instance variable nameSome would say, "What's the big deal?", "Can't you figure out what it is?", "It only takes a few seconds to know what it is", etc. Well, that is the problem. If my brain has to stop to process what it is, even if it takes a few seconds, then that is slowing me down during my software development process. Multiply those "few" seconds by how many times you get Rhino exceptions like that and it does eat away at your development time. It does add up over time. It is not unlike trying to read code that is not very readable or well factored. Sure, you'll eventually figure out what it does but at the cost of precious dev time.
System.If you specify the wrong data type in the 'Return' method of an Expect (or LastCall) then the above exception will be thrown. For example, if the method or property is suppose to return a 'string' type value but you instead specify a 'DateTime' type as shown below:InvalidOperationException: Previous method 'IView.get_ ReturnSomeStringValue();' require a return value or an exception to throw.
DateTime date = DateTime.Todaythen you will receive the error message mentioned earlier.
Expect.Call(_view.ReturnSomeStringValue).Return(date);
// this will throw an exception
Specifying the proper type should fix the problem as follows:
string someStringValue = "some string value";The exception message should really be about checking for strong typing and not the absence or lack of a return value.
Expect.Call(_view.ReturnSomeStringValue).Return(someStringValue);
// this is ok
Labels:
C#,
NMock2,
Rhino Mocks,
Unit Testing
Tuesday, August 26, 2008
Mocks vs Traditional Asserts
I encountered something extremely interesting regarding assertions versus mocks. Traditional assertions (e.g. the NUnit asserts) are typically for "state-based" type testing while mocks are for "interaction-based" type testing.
I find that I am using assertions less and less. I'm not sure if that is a good or bad thing. A few weeks ago, I was working on adding some functionality to one of the domain objects for the project at work which unlike for Controller classes in MVC tend to be more state based testing than interaction based. At least that's what I thought.
Below is a simple method that I needed to test:
Now here is another test whose intention is to test the exact same thing but using mocks instead:
Guess which one I wrote first? Of course the one with mocks even though I started with the complete intention of doing it with state-based assertions but it quickly morphed to using mocks.
It was really interesting to produce these two tests that are functionally different but accomplish the same goal. They both "fail" if you remove the line:
or if you place a different value:
So, which should I use? Truthfully, the test with mocks is less brittle because you do not need a real instance of the "Task" object. But am I taking it too far? One "problem" I seem to have is that since I have been using mocks for so long my mind is wired to use them for everything (once again, is that a good thing or an anti-pattern?) Basically, when I think about how to test something I immediately think in terms of expectations with dependencies.
Perhaps mocks win out in this situation and in most it is better because true unit testing means that the only real instance of an object is the one that you are trying to test and essentially everything else should be mocked and/or stubbed somehow. Perhaps assertions are best with objects that are not primarily defined by their dependencies and that simply perform complex algorithms that return value types results (for example, static classes and methods). Of course, I could be oversimplifying that but I find it really hard to know when to use plain vanilla assertions.
Well, shortly after stumbling upon this "dilemma" on my own, I then read Martin Fowler's article named Mocks Aren't Stubs and it became much clearer to me what I was doing and why (as it always seem to happen whenever I read any of Fowler's stuff). According to him, I would be classified as a "mockist TDD practitioner".
Honestly, some of the reasons he lists for choosing not to be one (as opposed to a "classical TDD practitioner") are things that I definitely felt on my own especially recently when I was struggling with writing a bunch of mock heavy tests that started to get unwieldy and far more complex than the thing I was actually testing (let's just say it was a weird, dark period in my recent dev efforts that I was really questioning the use of mocks).
The quote below from him is definitely something that I thought to myself off and on for as long as I have been doing "mock testing":
"...A mockist is constantly thinking about how the SUT ["system under test" a.k.a. the object under test] is going to be implemented in order to write the expectations. This feels really unnatural to me..."
I find that I am using assertions less and less. I'm not sure if that is a good or bad thing. A few weeks ago, I was working on adding some functionality to one of the domain objects for the project at work which unlike for Controller classes in MVC tend to be more state based testing than interaction based. At least that's what I thought.
Below is a simple method that I needed to test:
// domain object- TaskManagerThe following test uses traditional assertions:
public IList<Task> Reassign(IList<Task> tasks, string newTeam)
{
foreach (Task task in tasks)
{
task.Team = newTeam;
}
return tasks;
}
[Test]
public void CanReassignTasksToNewTeamWithAsserts()
{
TaskManager manager = new TaskManager();
const string oldTeam = "Old Team";
const string newTeam = "New Team";
// setup test data for tasks
Task task;
for (int idx = 0; idx < 3; idx++)
{
task = new Task();
task.Team = oldTeam;
tasks.Add(task);
}
// assert the re-assignment
IList<Task> updatedTasks = manager.Reassign(tasks, newTeam);
foreach (Task updatedTask in updatedTasks)
{
Assert.That(updatedTask.Team, Is.EqualTo(newTeam), "The task's team was not re-assigned.");
}
}
Now here is another test whose intention is to test the exact same thing but using mocks instead:
[Test]
public void CanReassignTasksToNewTeamWithMocks()
{
TaskManager manager = new TaskManager();
const string newTeam = "New Team";
// setup test data for tasks and set expectations
Task task ;
for (int idx = 0; idx < 3; idx++)
{
task = Mocks.CreateMock<Task>();
tasks.Add(task);
// set expectation to assign task to new team
task.Team = newTeam;
LastCall.Repeat.Once();
}
Mocks.ReplayAll();
manager.Reassign(tasks, newTeam);
Mocks.VerifyAll();
}
Guess which one I wrote first? Of course the one with mocks even though I started with the complete intention of doing it with state-based assertions but it quickly morphed to using mocks.
It was really interesting to produce these two tests that are functionally different but accomplish the same goal. They both "fail" if you remove the line:
task.Team = newTeam;
or if you place a different value:
task.Team = "Make this test fail.";Since they fail by doing either of the above that means both tests are good, valid tests, right?
So, which should I use? Truthfully, the test with mocks is less brittle because you do not need a real instance of the "Task" object. But am I taking it too far? One "problem" I seem to have is that since I have been using mocks for so long my mind is wired to use them for everything (once again, is that a good thing or an anti-pattern?) Basically, when I think about how to test something I immediately think in terms of expectations with dependencies.
Perhaps mocks win out in this situation and in most it is better because true unit testing means that the only real instance of an object is the one that you are trying to test and essentially everything else should be mocked and/or stubbed somehow. Perhaps assertions are best with objects that are not primarily defined by their dependencies and that simply perform complex algorithms that return value types results (for example, static classes and methods). Of course, I could be oversimplifying that but I find it really hard to know when to use plain vanilla assertions.
Well, shortly after stumbling upon this "dilemma" on my own, I then read Martin Fowler's article named Mocks Aren't Stubs and it became much clearer to me what I was doing and why (as it always seem to happen whenever I read any of Fowler's stuff). According to him, I would be classified as a "mockist TDD practitioner".
Honestly, some of the reasons he lists for choosing not to be one (as opposed to a "classical TDD practitioner") are things that I definitely felt on my own especially recently when I was struggling with writing a bunch of mock heavy tests that started to get unwieldy and far more complex than the thing I was actually testing (let's just say it was a weird, dark period in my recent dev efforts that I was really questioning the use of mocks).
The quote below from him is definitely something that I thought to myself off and on for as long as I have been doing "mock testing":
"...A mockist is constantly thinking about how the SUT ["system under test" a.k.a. the object under test] is going to be implemented in order to write the expectations. This feels really unnatural to me..."
Labels:
C#,
Mock Objects,
NUnit,
Rhino Mocks,
Unit Testing
Monday, July 21, 2008
Data Validation, Business Rules, and the Notification Pattern
On a previous project, I had encountered some unnecessarily long 'Save' methods in various ASP.NET web pages that contained numerous validations of each input value from the UI page. Within the body of those methods it would run through all of those vaildations before it would finally reach the decision as to whether to commit changes to the database or not. (for example, something like check the length of the first name of the user is less than 20, etc.) In general, the methods ended being a bit hard to follow especially if you needed to make a change to them.
Another developer who I used to work with had mentioned to me data validation shouldn't even be in the Presenter Class of a traditional MVP/MVC implementation. He also mentioned his approach at the time (which if I recall correctly was something like exception guards?) as well as Jimmy Nilsson's approach towards data validation as described in his book, Applying Domain-Driven Design and Patterns: With Examples in C# and .NET. In the meantime, I had been recently researching how to do MVP with the ASP.NET custom validators since we are using these on our project at work and was trying to find a "better" way to handle rudimentary validation.
After some "blood, sweat, and tears" I think I was able to successfully apply Fowler's Notification Pattern to solve this "issue". The notification pattern tries to manage the capturing of error messages as it relates to data validation that are specific to domain objects and are generally outputted to the end-user. (An example is if an email address is required on a submit form. If the user skips over that then on 'submit' a message is displayed such as "An email address is required...blah blah) It all started while re-reading one of Jeremy Miller's post on validation as part of his CAB series . His post lead to both Fowler's Notification Pattern and two posts from Jean-Paul S. Boodhoo's blog (Part I and Part II). Those served as my blueprints for my implementation.
Essentially, I went through each of their slightly differing approaches to see what I could use. The core of what I ended up with borrows heavily from Fowler with most of my changes just renaming things to suit my liking. Fowler always writes with such clarity and without the cruft and his code examples are so easy to follow that his version was the main driver for what I wanted to do. Miller's and JP took the pattern to another level but it was too much for what I wanted. My goal was to keep it simple of course and let it evolve on its own (BUFD bad!) I initially developed it on a separate test project. Once that worked I then implemented it in our project at work somewhat seamlessly.
I first created the initial base classes that are the foundation of this pattern and that can be re-used on any project. Below are their interfaces:
Another developer who I used to work with had mentioned to me data validation shouldn't even be in the Presenter Class of a traditional MVP/MVC implementation. He also mentioned his approach at the time (which if I recall correctly was something like exception guards?) as well as Jimmy Nilsson's approach towards data validation as described in his book, Applying Domain-Driven Design and Patterns: With Examples in C# and .NET. In the meantime, I had been recently researching how to do MVP with the ASP.NET custom validators since we are using these on our project at work and was trying to find a "better" way to handle rudimentary validation.
After some "blood, sweat, and tears" I think I was able to successfully apply Fowler's Notification Pattern to solve this "issue". The notification pattern tries to manage the capturing of error messages as it relates to data validation that are specific to domain objects and are generally outputted to the end-user. (An example is if an email address is required on a submit form. If the user skips over that then on 'submit' a message is displayed such as "An email address is required...blah blah) It all started while re-reading one of Jeremy Miller's post on validation as part of his CAB series . His post lead to both Fowler's Notification Pattern and two posts from Jean-Paul S. Boodhoo's blog (Part I and Part II). Those served as my blueprints for my implementation.
Essentially, I went through each of their slightly differing approaches to see what I could use. The core of what I ended up with borrows heavily from Fowler with most of my changes just renaming things to suit my liking. Fowler always writes with such clarity and without the cruft and his code examples are so easy to follow that his version was the main driver for what I wanted to do. Miller's and JP took the pattern to another level but it was too much for what I wanted. My goal was to keep it simple of course and let it evolve on its own (BUFD bad!) I initially developed it on a separate test project. Once that worked I then implemented it in our project at work somewhat seamlessly.
I first created the initial base classes that are the foundation of this pattern and that can be re-used on any project. Below are their interfaces:
/// Specific business rule error that provides a specific message about the broken business rules.
public interface IBusinessRuleError
{
/// Gets or sets the name of the property that causes the error.
string PropertyName { get; set; }
/// Gets or sets the specific error message.
string Message { get; set; }
}
/// Set of Business Rules used by Domain Objects that captures and stores errors.
public interface IBusinessRules
{
/// Gets or sets the business rule errors.
IListErrors { get; set; }
/// Gets a value indicating whether this instance has any business rule errors.
bool HasErrors { get;}
/// Determines whether the specified set of business rules contains error.
bool ContainsError(IBusinessRuleError ruleError);
}
Basically 'BusinessRules' manages a collection of individual 'BusinessRule'. The business rule contains the error message and it also contains the name of the specific property for the error that will be used later to when mapping it back to a specific UI control.
Now I added BusinessRules to the abstract DomainObject class and expose it as a property. Initially it was hard-coded into my domain object but at work I decided to pull it into its own class that could then be instantiated internally and, if need be, injected in as a dependency into the domain object base class (as you know ideal for mock testing it!) Here is what I call the "validator"
This interface has the RunValidation method whose purpose is to cycle through it each business rule that the derived class is responsible to implement for itself. In addition, the interface also has some basic, re-usable validation tests of these methods such as IsNullOrBlank, FailIf, etc. (courtesy of Fowler) (NOTE: What struck me very quickly was the similarities between these generic methods and with the Asserts of NUnit. It dawned on me when I started to implement a new one that checked the difference for dates such IsBetween(string startDate, string endDate). Mmm...looks a lot like NUnit's Is Constraint model. In fact, 'FailIf' looks like a special case of Assert.That. I'm wondering whether some framework exists out for me to use instead of trying to create and maintain my own.)
In turn, the validator's members are delegated and exposed as members of the domain class itself:
Once that was done then it was time to actually use it for a specific domain object. So I have a domain object named 'Question' that makes up a 'Quiz':
So in the actual Question class, I override and implement the 'RunValidation' method with "rules/errors" specific to 'Question':
So this is where it all happens. Basically, this is where all the business rules that require validation for 'Question' is kept and maintained. Not in the UI, not in the presenter, not in the database or not anywhere else. Right where it should be. What's great is how nice is it to itemize and view all of your business rules in one place. The best part is unit testing this (which you really can't do well at all if it's in the presenter). Here are one of the tests:
How cool is that? I especially like the clarity of this code line:
question.Rules.ContainsError(descriptionError)
Here are a few more tests:
By implementing this at work the app's Domain model is now slightly less anemic. However, the auto-gen of partial classes presented an issue that I was not too happy with. The MyGeneration template is currently set up to read from the database the constraints of the columns and then it's hard-coded directly into the property setters (which includes throwing exceptions). This forces the trapping of the validation error to occur OUTSIDE of the domain object which goes against this implementation of the pattern. So unless I modify the template to remove this from the setters (or at least move into some private method) I had to circumvent updating via the setters and use some methods as so:
question.Description = "My Description"; question.MaxPointValue = 101;
becomes using overloads
question.UpdateDescriptionUsingValidation("1234567891011") question.UpdateMaxPointValueUsingValidation (101)
and/or
question.UpdateUsingValidation("1234567891011", 101)
Not really what I wanted but it works for now until I can resolve that auto-gen issue (another reason why auto-gen can sometimes be an anti-pattern)
So let's see the entity 'Question' actually used in a Controller/Presenter context:
Now how does that compare with one of the original LONG save methods? The intent, readability, and therefore maintainability is light years better. (NOTE: As a side note, I had to use the NHibernate's ISession.Evict() to prevent the entity from being persisted to the db.)
OK, finally the UI/View/Code-Behind
The controls '_ctlDescriptionValidator' and '_ctlMaxPointValidator' are ASP.NET custom validators that are now really dumbed down. I also used the asp.net 'ValidationSummary' control on the web page without needing to do hardly any wiring up. Here is some of the related HTML:
All in all it does not matter if I use the asp.net validators, my own custom message controls, or whatever. The data validation is not tightly coupled with the UI by using the deadly combo of MVP and the notification pattern!!!
I'm certain that aspects of my implementation can be improved and/or extended in some fashion. There are some things I debated as to which is the best approach but I can go into more detail later (for example, I mulled over a couple of other ways on how to pass the messages to the View but settled on the one above. Another was possiblly using reflection to set the property names in the error messages...but like I said I wanted to keep it simple for now. )
Now I added BusinessRules to the abstract DomainObject class and expose it as a property. Initially it was hard-coded into my domain object but at work I decided to pull it into its own class that could then be instantiated internally and, if need be, injected in as a dependency into the domain object base class (as you know ideal for mock testing it!) Here is what I call the "validator"
public interface IDomainObjectValidator
{
/// Runs the validation of each business rule.
/// Each derived class can override this method to define its own
/// set of validation rules.
void RunValidation();
/// Gets the business rules.
IBusinessRules Rules { get;}
/// Gets a value indicating whether this instance is valid based on whether any business rules failed.
bool IsValid
/// Determines whether [is null or blank] [the specified item to test].
bool IsNullOrBlank(string itemToTest);
/// Fails if condition to test is true.
void FailIf(bool conditionToTest, IBusinessRuleError error);
/// Fails if is null or blank the condition to test is true.
void FailIfNullOrBlank(string itemToTest, IBusinessRuleError error);
This interface has the RunValidation method whose purpose is to cycle through it each business rule that the derived class is responsible to implement for itself. In addition, the interface also has some basic, re-usable validation tests of these methods such as IsNullOrBlank, FailIf, etc. (courtesy of Fowler) (NOTE: What struck me very quickly was the similarities between these generic methods and with the Asserts of NUnit. It dawned on me when I started to implement a new one that checked the difference for dates such IsBetween(string startDate, string endDate). Mmm...looks a lot like NUnit's Is Constraint model. In fact, 'FailIf' looks like a special case of Assert.That. I'm wondering whether some framework exists out for me to use instead of trying to create and maintain my own.)
In turn, the validator's members are delegated and exposed as members of the domain class itself:
// domain object abstract class
private readonly IDomainObjectValidator _validator;
public DomainObject()
{
_validator = new DomainObjectValidator();
}
public DomainObject(IDomainObjectValidator validator)
{
_validator = validator;
}
public bool IsValid
{
get { return _validator.IsValid; }
}
public IBusinessRules Rules
{
get { return _validator.Rules; }
}
public virtual void RunValidation()
{
_validator.RunValidation();
}
public bool IsNullOrBlank(string itemToTest)
{
return _validator.IsNullOrBlank(itemToTest);
}
public void FailIf(bool conditionToTest, IBusinessRuleError error)
{
_validator.FailIf(conditionToTest, error);
}
public void FailIfNullOrBlank(string itemToTest, IBusinessRuleError error)
{
_validator.FailIfNullOrBlank(itemToTest, error);
}
Once that was done then it was time to actually use it for a specific domain object. So I have a domain object named 'Question' that makes up a 'Quiz':
public interface IQuestion
{
/// The text of the question itself.
/// For example, "How old are you?"
string Description { get; set; }
/// Point value of the question if quiz taker gets it correct.
int MaxPointValue { get; set; }
/// Sequence # of the question within a quiz.
int SequenceNumber { get; set; }
// Bunch of other members...
}
So in the actual Question class, I override and implement the 'RunValidation' method with "rules/errors" specific to 'Question':
// Question class
public override void RunValidation()
{
// validation # 1
FailIfNullOrBlank(_description, new BusinessRuleError("Description", "Question description must contain a value."));
// validation # 2
if (_description != null)
{
FailIf(_description.Length > 10,
new BusinessRuleError("Description", "Question description can not be longer than 10 characters."));
}
// validation # 3
FailIf(_maxPointValue > 100, new BusinessRuleError("MaxPointValue", "Maximum Point Value can not exceed 100."));
// ....
// validation # 100...
}
So this is where it all happens. Basically, this is where all the business rules that require validation for 'Question' is kept and maintained. Not in the UI, not in the presenter, not in the database or not anywhere else. Right where it should be. What's great is how nice is it to itemize and view all of your business rules in one place. The best part is unit testing this (which you really can't do well at all if it's in the presenter). Here are one of the tests:
// Question test fixture
[Test][Category("Data Validation")]
public void DoesContainBrokenRuleWhenDescriptionIsNull()
{
Question question = new Question();
question.Description = null;
question.RunValidation();
IBusinessRuleError descriptionError = new BusinessRuleError("Description", "The description for this 'Question'
must contain a value.");
Assert.That(question.Rules.ContainsError(descriptionError), "Does not contain Description error.");
Assert.That(question.IsValid, Is.False, "Question is valid.");
}
How cool is that? I especially like the clarity of this code line:
question.Rules.ContainsError(
Here are a few more tests:
[Test][Category("Data Validation")]
public void DoesContainBrokenRuleWhenDescriptionLengthGreaterThan10()
{
Question question = new Question();
question.Description = "1234567891011";
question.RunValidation();
BusinessRuleError descriptionError = new BusinessRuleError("Description", "The description for this 'Question' can not be longer than 10 characters.");
Assert.That(question.Rules.ContainsError(descriptionError), "Does not contain Description error.");
Assert.That(question.IsValid, Is.False, "Question is valid.");
}
[Test][Category("Data Validation")]
public void DoesContainBrokenRuleWhenMaxPointValueExceeds100()
{
Question question = new Question();
question.MaxPointValue = 101;
question.RunValidation();
BusinessRuleError maxPointValueError = new BusinessRuleError("MaxPointValue", "Maximum Point Value for this 'Question' can not exceed 100.");
Assert.That(question.Rules.ContainsError(maxPointValueError), "Does not contain MaxPointValue error.");
Assert.That(question.IsValid, Is.False, "Question is valid.");
}
By implementing this at work the app's Domain model is now slightly less anemic. However, the auto-gen of partial classes presented an issue that I was not too happy with. The MyGeneration template is currently set up to read from the database the constraints of the columns and then it's hard-coded directly into the property setters (which includes throwing exceptions). This forces the trapping of the validation error to occur OUTSIDE of the domain object which goes against this implementation of the pattern. So unless I modify the template to remove this from the setters (or at least move into some private method) I had to circumvent updating via the setters and use some methods as so:
question.Description = "My Description"; question.MaxPointValue = 101;
becomes using overloads
question.
and/or
question.
Not really what I wanted but it works for now until I can resolve that auto-gen issue (another reason why auto-gen can sometimes be an anti-pattern)
So let's see the entity 'Question' actually used in a Controller/Presenter context:
// Presenter class
public void SaveChanges()
{
IQuestion question = new Question();
question.Description = _view.Description;
question.MaxPointValue = _view.MaxValuePoint;
question.SequenceNumber = _view.SequenceNumber;
question.RunValidation();
if (question.IsValid)
{
_dao.SaveOrUpdate(question);
_view.DisplaySuccess("The question has now been saved.");
}
else
{
_view.DisplayErrors(question.Rules.Errors);
}
}
Now how does that compare with one of the original LONG save methods? The intent, readability, and therefore maintainability is light years better. (NOTE: As a side note, I had to use the NHibernate's ISession.Evict() to prevent the entity from being persisted to the db.)
OK, finally the UI/View/Code-Behind
// View class
public void DisplayErrors(IListerrors)
{
foreach (IBusinessRuleError error in errors)
{
if (error.PropertyName.Equals("Description"))
{
_ctlDescriptionValidator.ErrorMessage = error.Message ;
_ctlDescriptionValidator.IsValid = false;
}
if (error.PropertyName.Equals("MaxPointValue"))
{
_ctlMaxPointValidator.ErrorMessage = error.Message;
_ctlMaxPointValidator.IsValid = false;
}
}
}
The controls '_ctlDescriptionValidator' and '_ctlMaxPointValidator' are ASP.NET custom validators that are now really dumbed down. I also used the asp.net 'ValidationSummary' control on the web page without needing to do hardly any wiring up. Here is some of the related HTML:
<form id="form1" runat="server">
<asp:ValidationSummary ID="_ctlValidationSummary" runat="server" />
<asp:Label ID="_lblSuccessMessage" runat="server"></asp:Label><div>
Description
<asp:TextBox ID="_txtDescription" runat="server" >
</asp:TextBox>
<asp:CustomValidator ID="_ctlDescriptionValidator" runat="server" ControlToValidate="_txtDescription"
ErrorMessage="" OnServerValidate="_ctlDescriptionValidator_ServerValidate">*</asp:CustomValidator><br />
Max Point Value
<asp:TextBox ID="_txtMaxPointValue" runat="server" >
</asp:TextBox>
<asp:CustomValidator ID="_ctlMaxPointValidator" runat="server" ControlToValidate="_txtMaxPointValue"
ErrorMessage="" >*</asp:CustomValidator>
All in all it does not matter if I use the asp.net validators, my own custom message controls, or whatever. The data validation is not tightly coupled with the UI by using the deadly combo of MVP and the notification pattern!!!
I'm certain that aspects of my implementation can be improved and/or extended in some fashion. There are some things I debated as to which is the best approach but I can go into more detail later (for example, I mulled over a couple of other ways on how to pass the messages to the View but settled on the one above. Another was possiblly using reflection to set the property names in the error messages...but like I said I wanted to keep it simple for now. )
Labels:
ASP.NET,
C#,
Design Patterns
Subscribe to:
Posts (Atom)