Ayende @ Rahien

Hi!
My name is Ayende Rahien
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,949 | Comments: 44,548

filter by tags archive

Handling nullable datetime in NHibernate : The Interceptor


System.DateTime is a value type, and as such, cannot be null. The default value for DateTime in .Net is DateTime.MinValue, which equals to 01/01/001 00:00. The problem is that SQL Server's dates start at 1753, or there about.

This is usualy solved in .Net 2.0 using Nullable<DateTime> (or DateTime? in C#), but my "entities" are messages to web services, and are generated from WSDL, so they lacked this nice feature. I also didn't realize that some of the DateTime values were nullable until pretty late into the game.

After a lot of head scratching, I came up with this solution, which utilizes NHibernate's IInterceptor capabilities. The interceptor allows to get the raw data before it is loaded and after it is saved, and interfer with it. Using that, I got this DefaultDateToNullInterceptor:

public bool OnFlushDirty(

    object entity, object id, object[] currentState, object[] previousState, string[] propertyNames,

    IType[] types)

{

    MinValueToNull(currentState, types);

    return true;

}

 

public bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)

{

    MinValueToNull(state, types);

    return true;

}

The OnSave() and OnFlushDirty() methods are called before the values are saved or updated (respectively). The MinValueToNull() method is very simple, it replace all instances of DateTime.MinValue with null, like this:

private static void MinValueToNull(object[] state, IType[] types)

{

    int index = 0;

    foreach (IType type in types)

    {

        if(type.ReturnedClass == typeof(DateTime) &&

           DateTime.MinValue .Equals(state[index] ))

        {

            state[index] = null;

        }

          

        index+=1 ;

    }

}

All that was left was openning the session with the interceptor, and I was set.

Distributed Applications Failure Points


The worst part of building a distributed application is that you get different state in different parts of the system. Let us take a look at a simple message passing application, and the issues there. At the end of the day, each and every message should arrive once, and exactly once. I am assuming that it is not possible for the message to be corrupted in transmissions (The TCP/IP stack in general makes sure that you won't see those messages).

The simplest model is where everything works out great:

(Image from clipboard).png

A common scenario is that the sender failed to send the message:

(Image from clipboard).png

A simple resolution is sending the message again, and again, until you get an OK reply back. But then there is the dropped reply scenario, the reciever got the message, but the reply was dropped. As far as the sender knows, the reciever never got the message:

(Image from clipboard).png

A naive implementation on the reciever side will lead to the duplicate message scenario, but a slightly less naive implementation, which detects and errors on duplicate messages may result in a lot more headaches in the end, consider this scenario:

(Image from clipboard).png

The sender never recieves an OK reply for his message, so it will send it to the end of the days. The reciever got the message the first time and replied just fine, but the sender persist trying to give it duplicate data, which means that it keeps returning error messages back.

A good way to prevent that is to check before sending, like this:

(Image from clipboard).png

Assuming that we always keep this semantics, a failure at any points of the road never leads to losing messages or duplicating them. I tried, but I can't think of a way the sender will think that the reciever got a message when the reciever didn't get it.

Just to point out, the scenario above happens all the way up from TCP. This is a relatively simple scenario. More interesting ones include ordered messages, and two ways communications.

Hope you liked the pretty pictures.

Clarifying interaction based testing


One of the big advantages to state based testing is the clearer error messages, like this:

Assert.AreEqual(5, collection.Count, "Expected to have 5 broken rules as a result of XYZ");

Using interaction based testing, you usually can specify much less information:

validationResult.AddBrokenRule(null);
LastCall.IgnoreArguements().Repeat.Times(5);

Is this a setup code? Is this the expected result of the test?

Who knows? Certianly not me in tree weeks (or months) times, when this test is broken and I need to figure out why.

I am thinking about adding a Message construct to Rhino Mocks, which wil allow to specify messages that clarify the intent of the developer. Something like this:

validationResult.AddBrokenRule(null);
LastCall.IgnoreArguements().Repeat.Times(5)
   .Message("Expected to get 5 broken rules");

There are some implementation issues (what happen when you get called too much, for instnace), but they should be workable. But before I try to add this, I would like some thoughts about the value of this feature.

Book ReviewApplying Domain-Driven Design and Patterns



Applying Domain-Driven Design and Patterns: With Examples in C# and .NET

Couple of disclaimers before I continue:

  • I got a free copy of this book to review.
  • I am probably not in the intended audiance of the book.

Nearly a month and a half ago, I posted my initial impressions from this book, which were good (even if it didn't come out like that). It took me quite a bit more to read it than the usual, mainly because I was swamped with work.

Anyway, the book declares itself as a guide to develop sofware using DDD. In fact, it covers much more ground than that, including patterns, inversion of control, testing, high and low level design, and more.

The overall tone of the book is very... relaxed. It felt at times like I was reading a long blog post, which meant that I had no problem with reading it on/off for a long time. The material is presented in a very approachable way, including a lot of details and explanations about what is going on.

I particularly liked the side notes where there are critiques on the code, some from Jimmy and some from other reviewers (This approach had this and that disadvantages, but I am using it because of the following reasons..., etc).

The first part of the book is an introduction to the concepts that are used throughout the rest of the book, patterns, TDD, domain concepts, etc. This was mostly repeating stuff that I knew, but it is a point to Jimmy's point that he managed to present the material in a way that was interesting even when I already knew what he was talking about.

The second part is where I consider the meet and bone of this book, covering how to apply DDD. The general architecture that is presented is similar to what I consider as ideal at the moment, and close to what I am trying to build in several applications at the moment. This part also straighten out some concepts that I didn't quite manage to understand from Evan's DDD book. Specifically, the relationships between the domain model and services and how to use them. I got several good ideas from this part, and it is responsible for my NHibernate Query Generator.

What I didn't quite like is the 7th chapter, about business rules. Partly this is because I'm currently invovled in an effort to implement fairly complex business rules implementation, and I don't think that the approach presented can hold in the face of the more complex scenarios. (Think of a case where you got heirarchical rules that are time dependant executing over a domain model that is timing sensitive. If you said Yuck!, I agree ;-)).

The forth part is talks about persistance, how to prepare to it, and how to implment it using NHibernate. I mostly agree with what was preseneted, and I was very surprised to learn new (and exciting) stuff about NHibernate (did you know that the mapping can declare Assembly and Namespace attribute seperatedly?).

The last part talks about moving the design forward, and how to take the domain design into the UI layer, and give the users a chance to take advantage of that as well.

What I didn't like:

Jimmy tries hard not to fall into the trap of using a specific product to show the concepts he is talking about. While it is a good approach in general, I felt at times that he is attempting it too hard. It might have been preferable to show the concepts using a certain tool, and mentioning how other products are solving similar problems.

There isn't any real refinement of the domain model as a result of new requirements or better understand of the client's model. The changes presented were changes mostly driven by technical decisions, not different way to understand the model.

Evans' DDD book made use of the shipping industry, with the difference being changing from focus on moving the cargo around, to moving the legal responsability for the cargo. I didn't see any such example in the book, and this is a core part of DDD.

Conclution:

I would like to work on applications developed using the principals shown in this book.

I don't think that the title is doing the book justice. It is not nearly about DDD as about the whole approach to develop applications.

I tried to pinpoint who exactly will not benefit from this book, and I couldn't quite put my finger on it. If you are currently busy building application based on Evans' DDD, with full usage of TDD and are familiar with Fowler's Patterns of Enterprise Applications, you will probably not get much out of this book.

If you are a "standard" .Net developer, and by that I mean that you mainly used Microsoft's prescribed tools and practices*, you will get quite a bit of insight from reading the book. I intentionally do not limit this to intermediate (whatever that means) developers, since it is more about a shift in thinking than about the level of code required.

I am certainly going to circulate this book to other developers in my team.

Great job, Jimmy.

* And I don't need to tell you what I think about most of them, do I?

IRepository(Of Customer) vs. CustomerRepository


Using IRepository(Of Customer):

Customer[] customersWithUnpaidOrders = repository.FindAll(@"select c from Customer c, Order o 
where o.Customer = c and o.Status = OrderStatus.Unpaid"
); 

Using CustomerRepository:

Customer[] customersWithUnpaidOrders = repository.GetCustomersWithUnpaidOrders();

The difference is the level of abstraction that is used. In the first case, the code define the question explicitly, using the generic repository to pose the question. In the second, it is the CustomerRepository responsability to get the data.

The first is much more flexible, but it is harder to test. The second is much easier to test (but require better integration testing to check that it the repository is actaully doing its job), and is more intention revealing.

Don't get greedy with online ads


I just spent four minutes configuring AdBlock to remove annoying ads from this page, I don't have an issue with normal advertising, but naything that blinks, jumps, etc is annoying.

I am not going to pay positive attention to stuff that annoys me. The end result that I don't know what the ad was about (it was big and black and green, that is all), but just about any ad server from this page is forever blocked on my browser.

C# Riddle #5


Following Alex's post about traps in interviews, I thought about posting bits of code that I won't use in interviews. Mostly because I don't think that it is fair to the interviewee. I can think about crazy usages to langauge features, and not in a good way.

Consider the following peice of code (which is valid C# 2.0):

public IEnumerable<Predicate<Customer>> ValidationPipeline()
{
 yield return delegate(Customer c)
 {
  return c.Name != "";
 };
 
 yield return delegate(Customer c)
 {
  return EmailService.IsValid(c.Email);
 };
}

How would you use this method, and what is wrong with it?

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats