# Wednesday, July 19, 2006

After being poetic on my TDD preface post my good friend Moran, a geek with no shame, gave me a few poetic titles for future(?) posts:

"web.config - friend or foe?" (this one kills me, honestly ;-))

"yellow screen - a blessing in disguise."


Can you beat him down ? Have some issues you want me to talk about ?
Have some geeky titles to share with the rest of the geeks that follow my posts ?


Bring it!

   

Posted by Oren Ellenbogen 
19/07/2006 01:01, Israel time UTC-07:00,     Comments [0]  | 

If you didn't read the preface yet, I strongly recommend you to invest good 5 minutes for it now; I'll wait...

Code:

OrenTDDWorkShop.zip (37.09 KB)


the NameResolver:

This class should have a method named GetFamilyName that gets a string as parameter and return the last name of a person.

The client defines these requirements:

  • If the sent string is empty (""), the method should return "None".
  • The string can contain only one word - in this case, return that word.
  • The string can contain first name and last name separated by space between them. The method should return the last name (obviously).

Simple enough right ?

Let's TDD this thing. We start with a "Create" test:

[TestFixture]
public class NameResolverTests
{
   [Test]
   public void Create()
   {
      NameResolver c = new NameResolver();
      Assert.IsNotNull(c);
   }
}

This code doesn't compile as we don't have NameResolver class yet. This test will check that we have an empty constructor for NameResolver and that we can actually initialize it. So let's write the required code:

public class NameResolver
{

}

Run the test. It works. It's time to test our GetFamilyName method. Let's see if the first requirement works:

[Test]
public void GetFamilyName_EmptyString_ReturnTheWordNone()
{
   NameResolver c = new NameResolver();

   string actualResult = c.GetFamilyName(string.Empty);
   Assert.AreEqual("None", actualResult);
}

Notice the structure of the method:

MethodName_State_ExpectedResult

This will not compile as we don't have the method GetFamilyName, so we'll make the minimum effort to make it compile.

public class NameResolver
{
   public string GetFamilyName(string fullName)
   {
      throw new NotImplementedException("");
   }
}

Now it compiles. Nice. Let's run the test. 1 passed, 1 failed(our last test).

Let's refactor the method so it will pass, remember, minimum effort.

public string GetFamilyName(string fullName)
{
   return "None";
}

I know, it doesn't make sense at first. The trick here is "baby-steps". You will add new code or refactor existing one only if you have a test that prove you *need* to do so. Our tests pass without problems so we don't have to modify our GetFamilyName. It works as expected so far!

Before we are running along and writing another test that will fail let's make some refactoring. We can do it with peace as we have tests to run after we change our code. In my tests you can see a line that repeat itself which is "NameResolver c = new NameResolver();". We don't like initializing new objects in the tests method as this initialization can get complex later on and we don't want to change X test methods. Refactoring:

[Test]
public void Create()
{
   NameResolver c = GetNewNameResolver();
   Assert.IsNotNull(c);
}

[Test]
public void GetFamilyName_EmptyString_ReturnTheWordNone()
{
   NameResolver c = GetNewNameResolver();

   string actualResult = c.GetFamilyName(string.Empty);
   Assert.AreEqual("None", actualResult);
}

private NameResolver GetNewNameResolver()
{
   return new NameResolver();
}

Compile - Good. Run tests - Good. That was simple.

Let's carry on and prove ourself that GetFamilyName is not good:

[Test]
public void GetFamilyName_OneWordOnly_ReturnThatWord()
{
   NameResolver c = GetNewNameResolver();

   string actualResult = c.GetFamilyName("test");
   Assert.AreEqual("test", actualResult);
}

Perfect, run the test - 2 passed, 1 failed (our last one)

expected: <"test">
but was: <"None">

This is quite obvious, we return None no matter what. Let's fix it. remember, minimum effort.

public string GetFamilyName(string fullName)
{
   if (fullName == string.Empty)
      return "None";

   return fullName;
}

Run tests - Good! Now that the tests were OK, we can refactor (we have the tests as our backup - to see that we didn't introduce new bugs). You can see that the lines of GetFamlyName("...") and the Assert repeat itself. Let's extract this into a private helper method and use it:

[TestFixture]
public class NameResolverTests
{
   [Test]
   public void Create()
   {
      NameResolver c = GetNewNameResolver();
      Assert.IsNotNull(c);
   }

   [Test]
   public void GetFamilyName_EmptyString_ReturnTheWordNone()
   {
      NameResolver c = GetNewNameResolver();
      VerifyGetFamilyName(c, string.Empty, "None");
   }

   [Test]
   public void GetFamilyName_OneWordOnly_ReturnThatWord()
   {
      NameResolver c = GetNewNameResolver();
      VerifyGetFamilyName(c, "test", "test");
   }
   
   private
void VerifyGetFamilyName(
      NameResolver nameResolver, 
      string fullNameToCheck, 
      string expectedResult)
   {
      string actualResult = nameResolver.GetFamilyName(fullNameToCheck);
      Assert.AreEqual(expectedResult, actualResult);
   }

   private NameResolver GetNewNameResolver()
   {
      return new NameResolver();
   }
}

VerifyGetFamilyName will help us to write smaller test. We want the option to write a new test with only a couple of lines. Adding new tests should be fun.

Let's move on.

Now we don't have bugs anymore right? we do ?
prove it!

Here you go:

[Test]
public void GetFamilyName_TwoWords_ReturnLastWord()
{
   NameResolver c = GetNewNameResolver();
   VerifyGetFamilyName(c, "one two", "two");
}

Run test - 3 passed, 1 failed (our last one).
It makes sense, we don't check for space character yet so Let's fix it with minimum effort (remember?).

public string GetFamilyName(string fullName)
{
   if (fullName == string.Empty)
      return "None";
   else if (fullName.IndexOf(" ") == -1) // no spaces
      return fullName;
   else
   {
      string[] words = fullName.Split(' ');
      return words[1];
   }
}

Run tests - Good !

Hold on, you think you're done but you're not. The client adds another requirement (things change, you know):

  • the string can contain 3 words - first name, middle name and last name; Separated by space, of course. Return the last name (obvious).

We have a bug! How do I know? Here you go:

[Test]
public void GetFamilyName_ThreeWords_ReturnLastWord()
{
   NameResolver c = GetNewNameResolver();
   VerifyGetFamilyName(c, "one two three", "three");
}

Run tests -  4 passed, 1 failed(our last one). Let's fix the method so our last test will work. minimum effort.

public string GetFamilyName(string fullName)
{
   if (fullName == string.Empty)
      return "None";
   else if (fullName.IndexOf(" ") == -1) // no spaces
      return fullName;
   else
   {
      string[] words = fullName.Split(' ');
      return words[2];
   }
}

Run tests - 4 passed, 1 failed (GetFamilyName_TwoWords_ReturnLastWord()). Oops! our last test passed but I screwed up our previous test (to two words scenario - "one two"). This is a great thing with TDD, you cover your ass with tests! Let's refactor:

public string GetFamilyName(string fullName)
{
   if (fullName == string.Empty)
      return "None";
   else if (fullName.IndexOf(" ") == -1) // no spaces
      return fullName;
   else
   {
      string[] words = fullName.Split(' ');
      return words[words.Length-1];
   }
}

Run tests - 5 passed, 0 failed! Good!


Conclusions:

We want to work with ~100% code coverage. That means that every piece of code in GetFamilyName method is accounted for. I don't add new features to this method until I have a test that shows it is required. In addition, look at our GetFamilyName method, the code is so simple you want to cry with joy. Instead of thinking about all the possibilities to screw this method up at the beginning, write your "bugs" and see if the method can handle it. In addition, let's say that the client request another feature ("I want to allow sending names in Hebrew and names in English. The GetFamilyName should be able to handle them both". You can change whatever you need (but with minimum effort) and you've got the tests to see that everything is still ticking as expected. Refactoring is something you can do here with a smile on your face. You don't have to be afraid changing the code. The well known sentence "But what if I'll create 5 other bugs?!" is no longer valid. You've got the tests to tell you "You're OK!".

Good tests = peace of mind.

TDD
   

Posted by Oren Ellenbogen 
19/07/2006 12:33, Israel time UTC-07:00,     Comments [5]  | 
# Tuesday, July 18, 2006

I sat down for about 15 minutes before I could even write this sentence.

You see, as human beings, we (usually) tend to think too much before we speak.
As programmers, we (usually) tend to think too much before we write our first line of code.
"But what if the programmer will send null?"
"What if the programmer will send string when I expect int? should I throw an exception?"
"Should I return int or maybe void will do?"
"Should I implement the feature in this class? maybe I should use some external object and implement it there?"
"Should I inherit from this class or encapsulate it?"

We tend to over-think stuff. That's the way we are wired.

Tell me if you can relate to this monologue:
" I'm putting a lot of effort in finding solutions to many problems before they appear. These effort makes me tired so a few "end-cases" still slips me by; This, of course, only makes me think more before I write my code. Little, not-more-than-1-day-max missions turn into "Projects". The frustration when something breaks for unknown reason is sky-high as I spent 1-2 days just to think about how to avoid these bugs! I simply don't have enough time. I'm working like hell but the day is just too short and I've got too many tasks to complete. "

I remember sitting with my last team leader, Pasha, in the office one evening(~3 years ago), after spending 12 hours in refactoring something that never actually worked; His words were: " Oren, you fell in love with your code. You're spending way too much time on things that... are not really important at the moment.... If you keep it up this way, you'll never finish your task. "
I remember my response, his words were like a knife in my heart: " Hey! I put my guts in this code, I've stayed the all week for more than 14 hours per day! I even sat at home during the weekend and worked on this task just to keep up with the deadline! you can't tell me that this is not important! Someone can use this some day! And the design is so extendable! "Not really important..." (bad, bad, dirty thoughts) ".

He was right. I couldn't make the deadline. It was a battle I couldn't win; I had to much work and almost no time at this point.

I remember that day like it was a few hours ago. I couldn't sleep the all night. I kept running scenarios in my head and analyzing his words. I thought about the way I worked until that point, about the times I managed to complete my tasks in time and those times I worked extra hours and still miss my deadlines. I could really see what he meant. I wasn't able to think in small tasks. I connected every little piece of code with 1000 other usages "that could be used someday". I thought that I could make it all work at once. I thought that I can prevent bugs from happening. The reality proved me otherwise.

I knew that I can get better, so I set my mind on "think less, do more". I needed some basic rules to contain my need to over-think, so I use these simple rules to make my life easier:

  • I refactor only when I see a tangible reason (2 places with the same code).
  • I think in small "Contexts" (=tasks). No context should be bigger than 1-1.5 days of work.
  • I'm trying to WIN *small* battles.
  • I write some API usages, test that API with my programmers (to see if it's comfortable enough) and only than starting to code it.
  • I participate others when things get a little more complicated than they should be.
  • I write my milestones on my white-board so I could look at them during the day.


This is the mantra behind TDD.
TDD is about letting things go. To Work in small tasks and most importantly:

Let the *code* prove you wrong, not your thoughts or fears.


I don't have a bug until I can write a test that proves me otheriwse.
With this said, we can now start practicing TDD. Let's write NameResolver class.

* As this post turned to be quite long, you can see the example here.


clarification
: if it wasn't obvious, the simpleminded is yours truly.

TDD
   

Posted by Oren Ellenbogen 
18/07/2006 09:19, Israel time UTC-07:00,     Comments [0]  | 
# Sunday, July 16, 2006

This is another brilliant idea from Juval Lowy. I got to see him speak about unify ASP.NET and WinForms security models last week and during the session (which was really great by the way, but that's for another day), I've notice this genius row:

public event EventHandler<EventArgs> Click = delegate {};

Isn't it a beauty ?!

I know, it doesn't ring a bell yet, so I'll make the picture a bit clearer. But before we move forward, let's take a few steps backward.

Starting from scratch, a reminder:

We want to raise our Click event.
I'm sure you are familiar with these lines:

private void OnClick(EventArgs e)
{
   if (this.Click != null) // check if the invocation list is empty
      this.Click(this, e);
}

The reason we do it is we we don't want to raise an event with an empty invocation list; This will raise an exception, which is a big no-no if we can avoid it. simple ah ?

This implementation is problematic as between the check (if statement) and the activation the listener can be removed. A quick fix will look like this:

private void OnClick(EventArgs e)
{
   EventHandler<EventArgs> handler = this.Click;
   if (handler != null) // check if the invocation list is empty
      handler(this, e);
}


Ok, so it's a little safer invocation now (I remember a version with locking, but the above will do for now).

Rewind:

Now let's get back to Juval's genius line I've showed before:

public event EventHandler<EventArgs> Click = delegate {};

attaching delegate{} to the invocation list will create (behind the scene) a class, with a random name, with an empty method (matching EventHandler<EventArgs> signature), with a random name.

Why is this so brilliant ? Because now we verified that the the event invocation list is
always filled with *at least* one (empty)listener.

We can't clear the empty listener as we don't have it's instance (it was generated for us) nor it's name.

The checks for not-empty invocation list can be thrown to the garbage. We now have a safe event, guaranteed.

This is certainly a best practice for working with events (following Framework Design Guidelines structure):

   Do   Consider attaching an empty delegate to your event.


Recap

public class MyClass
{
    public event EventHandler Click = delegate {};
    
    private void OnClick(EventArgs e)
    {
        // no need to check if (this.Click!=null)
        this.Click(this, e);
    }
}

nice and easy.


Extra: one more step for safe events:

If we're talking about safe events, there is an advanced scenario in which you want the "eat" exception raised by one of the listeners, so the the other listeners will still be triggered. In the above, any exception in one of our listeners will stop the triggering of our invocation list.

The solution is quite simple also:

private void OnClick(EventArgs e)
{
   EventHandler<EventArgs> handler = this.Click;
   if(handler != null)
   {
      Delegate[] list = handler.GetInvocationList();

      foreach (Delegate del in list)
      {
         try
         {
            EventHandler<EventArgs> listener = (EventHandler<EventArgs>)del;

            listener(this, e);
         }
         catch { }
      }
   }
}

Juval even wrote a cool generic utility class named EventsHelper which you can get here.

Brilliant.

.NET | Design
   

Posted by Oren Ellenbogen 
16/07/2006 10:13, Israel time UTC-07:00,     Comments [6]  | 
# Saturday, July 15, 2006

I'm having 1-on-1 coaching with Roy Osherove on TDD coming up in the following 2-3 weeks. My goal is to practice real TDD work process to determine if our department can benefit from this developing methodology (or as a design tool).

I've read a big bunch of articles and blogs (Jeremy D. Miller, Sam Gentile, Scott Bellware, Roy Osherove and others) about TDD and even practiced it for a bit during the last two years, but to be sincere, it wasn't a real Test Driven Development. I stopped TDD-ing in the middle and moved back to write-with-haste, switched to TDD and so forth. I was lazy and I had no one to guide me through. I had to "guess" the right process and to read a big set of articles to see if I'm on the right track. I was lacking of some good feedback.

This 1-on-1 with Roy should give me a clear insight about the process and immediate feedback. If the process will prove itself, we'll arrange a 3 days course for my department and try to fit TDD to our development process (where and how I'm still not sure, but I've got the feeling that I'll be smarter in a few weeks).

What is SEE Infrastructure all about ?

SEE stand for: Simple Expression Engine which I've wrote about before.

I came up with SEE as I wanted to SEE what sort of filter the GUI requests from our Data Services.

I'll give you an example for a client's request and a solution based on our old infrastructure and how SEE changed the picture.

Example:

Let's imagine we have a screen with one GridView. Our goal is to show all the (1) active orders (2) from today with (3) price bigger than 1000 NIS. It should be easy as counting 1,2,3 right ?

-- OLD --

With our old infrastructure the code will look something like this:

(1) Orders.aspx:

OrdersFilter filter = new OrdersFilter();
filter.IsActive = true;
filter.Date = DateTime.Today;
filter.Price = 1000;

EntityCollection<Order> orders = OrdersService.Instance.Get(filter);
// ... bind orders to our GridView ...

(2) OrdersDal.cs:

in our Data Access Object for the Orders entity, we're required to override a method which builds the dynamic SQL based on the given filter:

if (this.Filter.IsActive != null)
{
   query.Append(" AND Orders.IsActive = @IsActive");
   paramaters.Add(DbServices.CreateParameter("IsActive", SqlDbType.Bit, this.Filter.IsActive));
}

if (this.Filter.Date != null)
{
   query.Append(" AND Orders.OrderDate = @Date");
   paramaters.Add(DbServices.CreateParameter("Date", SqlDbType.DateTime, this.Filter.Date));
}

if (this.Filter.Price != null)
{
   query.Append(" AND Orders.Price > @Price");
   paramaters.Add(DbServices.CreateParameter("Price", SqlDbType.Double, this.Filter.Price));
}

Now, look at the 2 lines marked in red. The filter at the GUI sent Price = 1000 while the DAL object looks for Price > 1000 (remember, this is the client's request).

Not only we've got a mismatch, the coding wasn't trivial nor "easy". We had to know(=remember) what method to override at our OrdersDal.

-- New --

Orders.aspx:

FilterExpression filter = new FilterExpression();
filter.Where(
   Where.EqualTo(Order.Field.IsActive, true),
   Operator.And(),
   Where.EqualTo(Order.Field.Date, DateTime.Today),
   Operator.And(),
   Where.GreaterThan(Order.Field.Price, 1000)
);

EntityCollection<Order> orders = OrdersService.Instance.GetByExpression(filter);
// ... bind orders to our GridView ...


That's it. No mismatch - the GUI programmer can now see exactly what results the Orders Service will return and no need to look at OrdersDal.
Coding was short and fun.


I thought that this small but important infrastructure will be a nice platform to practice a "Real-World" work with TDD. The infrastructure at its current form is working quite well so I know how to API should look in general and what are my "big" problems (Mapping, Resolving db function names and a few more).

Is SEE revolutionary ?

Hardly!
Expressions like languages are all over the place lately:

  1. LINQ - to be honest, this is a really great query language but it ruined my Visual Studio .Net 2005!! The product requires some installation that simply is a disaster for a developer station.
  2. HQL - Nhibernate. This is actually very nice but I get no errors during writing.
  3. eSql - Looks great. is it safe for production? I'm not so sure... anyway, it's all with C# 3.0 and suffers from symptom (1).

I can add additional 2-3 infrastructures to the list but you get the picture.  

So why do I\you still need SEE for ?

SEE is an home-made infrastructure which was developed by the KISS (keep it simple, stupid) principle. I know that there are many folks out there who still write\generate custom Data Access Objects. Integrating SEE in your custom DAO objects will be very simple as the infrastructure gives a solution to a very narrow problem domain. There is no need to learn a new "quotation marks prisoner" language. The developer can enjoy the VS.NET IntelliSense and as you could see in my previous example, the API is very easy to understand.

Moving toward one of the other languages\technologies can take some time as the learning curve can be quite high.

You could SEE with a very small time investment by your side.


Where do you come along ?

I will upload any code I'll write during this coaching lessons so you can see our progress, bit after bit. In addition, I'm going to write a prolonged post after each lesson, to share with you my insights. This is the interesting part though - my infrastructure will change according to your requests (well, some of them anyway, and only the "good" and "simple" ones ;)). Feel free to suggest new features or to change method\classes names\relations. This will able me to practice changes to our SEE infrastructure as part of the TDD practice.

I hope that we'll enjoy the process and learn new things on the way,
Oren.

Design | TDD
   

Posted by Oren Ellenbogen 
15/07/2006 04:44, Israel time UTC-07:00,     Comments [5]  | 
# Thursday, July 13, 2006

ORM conversations flood the web during the last months.

Microsoft new players (DLinq, ADO.NET entity framework) cause a lot of drama and "oh-ha" statements in our industry. Microsoft is playing around; They are throwing names all over the place (DLinq, LINQ for Sql, LINQ for simple scenarios, ADO.NET vNext, ADO.NET Entities, ADO.NET 3.0). I guess that the picture will become clearer in a few months as the minds behind this infrastructures will assemble and a new, solid infrastructure will take place. Just look at Remoting, WebSercies, Enterprise Services which assembled together into WCF.

This causes some old, damn good, questions to arise as well:

"Should I use Business Entities (Entity Info+ BL + DAL in the same class) or should I create a separate classes ?"

"Should I write my queries or ORM is good enough? I heard it's somewhat slow, but I'm not sure..."

"Should I use ORM and map my entities with attributes or with xml? What is better ?"

"Which infrastructure to use? Is DLinq or ADO.Net solid ? Should I use NHibernate? "

etc...

I'm not going to answer these questions at the moment, but I'm certainly going to address them in the following months as my BL->DAL agenda started to shift from separate classes to Business Entities. I'm still doing a lot of prototypes to see the pros & cons.

In case you are interested to know the difference between DLinq and ADO.NET Entities (or ADO.NET vNext, you name it), here is a nice post to set your mind.


Oh, before I forget - It is time to make some good names to Microsoft products !
Why not calling ADO.NET vNext something like DARVIN (Data Access Revolutionary INfrastructure) ?
That's cool !


Any thoughts ? names ?

   

Posted by Oren Ellenbogen 
13/07/2006 12:04, Israel time UTC-07:00,     Comments [0]  | 
# Wednesday, June 28, 2006

I don't know, maybe I'm missing something or maybe I'm just stupid (you can pick, just let me know):

class User
{
   public static readonly int ID; // class property

   public int ID; // instance property
}


Compiling this little cutie returns the error:
" The type 'ConsoleApplication1.User' already contains a definition for 'ID' "

What's going on here ? This properties are completely different, one is *instance* property and the other is *class* property. What is the conflict here? Am I missing some Microsoft spec on this one? Am I missing some OOP lesson? Is it C# restriction? Is it CLI restriction ?

I'm confused...

   

Posted by Oren Ellenbogen 
28/06/2006 10:02, Israel time UTC-07:00,     Comments [4]  | 
# Tuesday, June 27, 2006

I've just created an interface named:

/// <summary>
/// Defines an object which support xml representation in the system.
/// </summary>
public interface ISupportXmlFormat
{
   /// <summary>
   /// Return the object representation as xml string.
   /// </summary>
   /// <returns>Xml string</returns>
   string ToXml();
}

I know, this is a silly name but it made me laugh quite a bit so I thought to share with you my geeky sense of humor ;-)

It is hard sometimes to think about a good name for an interface. I general, I follow Roy Osherove's Interface naming guidelines and name my interfaces by their purpose or "what can be done to them".

Do you have a better name to suggest ?

   

Posted by Oren Ellenbogen 
27/06/2006 09:27, Israel time UTC-07:00,     Comments [8]  | 
# Sunday, June 25, 2006

Restoring Smart Tags in the C# IDE after installing the C# Language Service (LINQ Preview May 2006):

After installing C# Language Service, you'll notice that Visual Studio .Net starts to misbehave. The IntelliSense and the Refactoring(Resolve, Rename, etc) engine disappears from the menu and do not work even if you try to activate them manually. It turns out that this is a known issue and there is a fix available here.

TIP: Take a good, long, coffee break(or use the time to read C# 3.0 Specification) after running the command devenv /setup /resetuserdata /resetsettings . You'll have a second break when you'll try to run the Visual Studio .Net 2005 again (for the first time). I guess that Microsoft are kind enough to decide when I should(== I must) take a break from code.

[ via Ken Egozi ]

   

Posted by Oren Ellenbogen 
25/06/2006 01:57, Israel time UTC-07:00,     Comments [0]  | 
# Thursday, June 22, 2006

Prologue:

I'm a big fan of Interface with a Base Class which implement that interface with base behavior. Providing this two together allows the programmer to decide if he wants to inherit from the Base Class and override only the things he really wants or to implement the Interface from scratch.

Here is an example from our code:

1). The Interface:

public interface IPersistentEntity
{
   string ToXml();
   string GetKey();
   // ... snippet ...
}

2). The Base Class that implements the interface:

/// <summary>
/// Base class for a Business Entity.
/// </summary>
public abstract class EntityBase : IPersistentEntity
{
   public string GetKey()
   {
      return GetKeyCore();   
   }

   protected abstract string GetKeyCore();

   public virtual string ToXml()
   {
      // Build the xml via Reflection over the current type.
   }

   // ... snippet ...
}


I constraint my EntityCollection object to EntityBase:

/// <summary>
/// Represents a strongly typed list of Business Entities.
/// </summary>
/// <typeparam name="ENT">Entity type which inherits from EntityBase class.</typeparam>
[Serializable]
public class EntityCollection<ENT> : List<ENT>, ISerializable
   where ENT : EntityBase
{
   // ... snippet ...
}

As you can tell, I'm constraining the ENT generic type to be any object that inherit from EntityBase.


The Story:


My teammate, Moran (Yes, him again, goshh... he really challenges me to think deeply about our infrastructure), wanted to create a new EntityCollection of ISpecificEntity (i.e: EntityCollection<ISpecificEntity>). That means that he wanted to extend the IPersistantEntity I showed above.

The problem was that my EntityCollection made a constraint on the generic type to inherit from EntityBase.

That means that the interface should inherit from EntityBase class which is obviously not possible. so his interface should have been some sort of another SpecificEntity class that inherit from EntityBase. Well, that's no good as some of our existing entities already inherit from the EntityBase and Moran wanted to use them in the collection. That means that Moran should have change the signature of this class (among others):

public class Zone : SpecificEntity //EntityBase
{
   // ... snippet ...
}

The problem was that Zone was inherited also by another class and we couldn't change that. To make a long story short, our  headaches were a result of one simple fact:
One of the biggest drawback of inheriting from a Base Class is [your answer here].
You right, the biggest drawback is that you can do it only *once*.

Using abstract classes with interfaces behind is a very good practice, in my book anyway, but using it(abstract class) as a constraint in a Generic Type can cause you some problems later on. The only thing we did was to change the signature of EntityCollection to:

public class EntityCollection<ENT> : List<ENT>, ISerializable
   where ENT : IPersistentEntity
{
   // ...
}

That made our life easier as we can always implement additional interface(s) in our class.

Epilogue:

The drawback of single inheritance from class is a dangerous pitfall you should avoid while working with Generics constraints, so my tip for you is:

Constraint your generic type(s) by Interface and not by Base Class.

.NET | Design
   

Posted by Oren Ellenbogen 
22/06/2006 10:57, Israel time UTC-07:00,     Comments [3]  | 
# Wednesday, June 21, 2006

I'm reading one of our client's characterization in order to determine the amount of time it will be required from us to develop the project. While reading the paper I've encountered this hilarious sentence:

"Architecture: Smart-Client application in DNA methodology(3 tiers) with .Net"

(global) Tip: If you don't understand the meaning of a (buzz)word, don't use it. It is that simple.

btw - I think that this phrase will win the "How-Many-Buzzwords-Can-You-Put-In-A-Sentence-Without-Knocking-Yourself-Out" contest. I'll vote for it anyway.

   

Posted by Oren Ellenbogen 
21/06/2006 05:21, Israel time UTC-07:00,     Comments [3]  | 

I'm reading a fantastic management book: "First, Break All The Rules" by Marcus Buckingham and Curt Coffman. There were few paragraphs which really made me think about the way I'm interviewing people when our company look for candidates.

" Managers look at "lower-level" roles like housekeeping or out-bound telemarketing and wonder, "How could anyone want to do that job ? That job must be so demoralizing." "

" Let's take hotel housekeepers as an example. Most of us haven't spent much time mulling over the details of house-keeping. But consider, for a moment, what hotel housekeepers do and how often they have to do it. Put yourself in their shoes. Okay. Two things might have occurred to you: first, that this is an easy job anyone with a modicum of responsibility can do; and second, that this is a terrible job that everyone, including housekeepers, must hate to do. If this thought crossed your mind, then you would be wrong on both counts.We shouldn't devalue housekeepers. Anyone can probable clean a hotel room once in a while, but great housekeepers are special. "

" "How do you know if a room is clean?" we asked them (the housekeepers). They said that the last thing they did before leaving a room was to lie on the guest's bed and turn on the ceiling fan.
"Why?"
"Because", they explained, "that is the first thing that a guest will do after a long day out. They will walk into the room, flop down on the bed, and turn on the fan. If dust comes off the top of the fan, then no matter how sparkling clean the rest of the room was, the guest might think it was as dirty as the top of the fan. "


Does it ring a bell? how many times we think that maintaining code is a job that any mediocre programmer can do but developing infrastructures requires a superstar programmer. I guess that we all do in some point of our lives. The truth is that those tasks will be performed in a productive manner according to the person's talents. If the person is passionate about understanding how current things work just so he could fix a leaking class in the system he'll probably be very good in maintaining applications (this is the same talent that will make a superstar plummer). If the person passion is to know how the entire framework works, he love to read about the small details and he loves to develop everything from scratch (at least at first), he'll probably be a great infrastructures developer but poor at maintenance.

As an interviewer, how many times are you interviewing people just to see if they're good programmers in general. Let's assume that you're looking for a programmer for your existing team. "On the one hand, her analytic thinking is excellent, she's familiar with the technology, she can handle problems by herself and she can find her path in a pile of documents. On the other hand, she looks kind of a "cold" person, which can be problematic in our very bound-together team; But hack, I can teach her how to be "wormer" so she could fit it. what are we waiting for?! she's an excellent programmer, let's hire her !!"

Do you really think you can change a person that much ? would she be able to express her full potential in your team ? I guess it's possible, but not likely. What about your other teammates ? Will they be more productive with her in the team ? I guess that probably not.

My point is that you should consider the talents the candidate should posses before considering the skills and experience you're looking for. Skills can be taught and upgraded, knowledge can be transfered, experience is only a matter of time. Talent is what we born with and what makes us unique. You can't teach someone to be a positive guy or a code-passionate person (or any other talent, for that matter), but you can certainly place him in the right spot so he could make the most of his *existing* talents.

   

Posted by Oren Ellenbogen 
21/06/2006 10:14, Israel time UTC-07:00,     Comments [0]  | 
# Monday, June 19, 2006

Today I sat with Moran after he "paged" me. He reviewed some code of one of our applications and he saw some things he thought he could make better. It was one of those classic "Hey! it should be a single service which every one of our applications will use!". Step after step he made the required refactoring and some elegant API took shape. The improvement was in magnitude but I still thought that the API should be quite different before making it "public" and placing it in our infrastructure. But, and that's a big but, the guys that develop the specific application needed the class and Moran was required to help in another project.

Should Moran take the opportunity to invest some time in this API? Should I help him through? We can talk about services, about providers, about extendability. We can play with code just to see how the API will look like. We can play with ideas, learn from each other, share our experience. We can share with others, we can send some quick "API tests" to get some feedbacks.

The process of developing the basics for our applications should be *long*. It should allow space for errors. The margins should be wide enough to let us experience, to learn from our mistakes, to discuss, to make Design Reviews, To Prototyping and throwing it all to the garbage 2 days later. It's all OK.

But maybe this is not the right time for games. Maybe Moran should make it work somehow and carry on to the next project ? After all, the next project's deadline is near(like always) and we need to join forces just to keep it up. Hey! we get paid to reach deadlines, to make it happen while keeping the quality at high level. The deadline is sacred. I truly believe that a good team will deliver on time even on the expense of features or well-known but low prioritized bugs.

On the one hand, I know that developing small to medium applications (0.5-2 human years) almost never allow you to invest the required amount of time in the basics. On the other hand, I also know that developing applications at work and infrastructures at home is not the answer for long terms. The process is short. No errors are allowed. There is almost no Design Reviews. Does it mean that the results of "home infrastructures" will be poor ? of course not, but the experience, the ability to break our requirements to programmer stories, to exchange ideas, to grow - is lost. The funniest part is that developing small application without a solid infrastructure turns into medium-large application. I guess it's the egg-chicken paradox.

The best I can do is to tell the reality from my perspective. My reality is that there is never time(well, that depends on the urgency and the magnitude of the application), and keeping with my expectations makes me perform the global thinking and implementation at home. This is the only time that I actually "have the time". Investing my time in developing some required infrastructure can save my guys at work a significant amount of work. Still, putting the effort on developing infrastructure during work hours will come on the expense of developing user stories, mentoring, guiding, consulting, talking with our customers. I guess that I still don't know my place. I'm a good developer, I would like to think, and coding some really interesting delegates-based infrastructure or some neat OOP solution are those treats I can't live without. Still, leading projects, make sure everything ticks and the quality is high is a challenge I love to face in my every-day work; Above all - seeing my guys getting to the next step and helping them in this journey is the main reason I'm doing what I'm doing. I want to be the best I can be for my team and yet make an influence in the way we work via developing some solid infrastructures. My gut feeling is that I need to get better. I feel that I can and should be a lot better as a manager and a programmer but It is still very hard for me to decide how and where to invest my time.

This issue keeps me awake at nights "lately"(last 6 months or so).


Where do you put the line ? How do you decide to invest your time in programming on the expense of managing and vice versa ? When do you think it'ss appropriate to invest additional hour\day\month to something you believe in ? Do you have some rules of thumb ?

   

Posted by Oren Ellenbogen 
19/06/2006 10:53, Israel time UTC-07:00,     Comments [4]  | 
# Thursday, June 15, 2006

linq.png

:-)

   

Posted by Oren Ellenbogen 
15/06/2006 03:05, Israel time UTC-07:00,     Comments [1]  | 
# Monday, June 12, 2006

I'm proud to introduce "Filter By Expressions". As I mentioned in my previous post about LINQ and IQueryable<T>, I got several ideas about implementing some sort of data(base) filter mechanism just until LINQ will be stable enough. I have  3 alternatives: (1) Implementing some sort of HQL language (like NHibernate) or query parser, (2) use an existing infrastructure and (3) Implement my own mechanism. Considering the options with my managers' hat on, options (1) and (2) are irrelevant at this stage as the learning curve and the adjustments I'll have to make is simply too much for me at the moment. In addition, LINQ will be here shortly so I don't want to invest more than 2 days of work. This leaves me with option (3).

After some good thinking(nothing more) during the weekend and 15 minutes of exchanging ideas with Moran, the [1]API took form. Here is a quick example (from one of our .aspx files):

IFilterObject filter = new Filter();
filter.PageResults = true;
filter.CurrentPage = 1;
filter.PageSize = 10;

// Here is the gold !
filter.Where(
   Expression.EqualTo(Order.Field.PurchaseDate, DateTime.Today),
   Expression.Operator(OperatorType.And),
   Expression.EqualTo(Order.Field.IsValid, true)
);

ordersGrid.DataSource = OrdersGateway.Instance.Get(filter);


Any idea what kind of "Where clause" it will generate behind the scenes ?
I bet you do so here it goes(SqlServer syntax):

WHERE Orders.PurchaseDate = @p0 AND Orders.IsValid = @p1

@p0 and @p1 will be filled with DateTime.Today and true respectively.


Here is another example, this time with "Inner condition":

filter.Where(
   Expression.Block(
      Expression.GreaterThan(User.Field.Age, 18),
      Expression.Operator(OperatorType.And),
      Expression.NotEqualTo(User.Field.Email, "")
   )

   Expression.Operator(OperatorType.Or),
   Expression.EqualTo(User.Field.IsGoldMember, true)
);

This will generate the following query(SqlServer syntax):

WHERE (Users.Age>@p0 AND Users.Email != @p1) Or Users.IsGoldMember = @p2

@p0, @p1 and @p2 will be 18, "" and true respectively.

But what about complex scenarios ? My answer is "keep it simple". With this in mind I think that we covered about 98% of every-day queries, which is good enough for me at the moment.

At the moment, our Query Generator Engine only filter the Where clause so you can't do some sort of magic like LINQ or other infrastructures out there allow you to do. Still, this infrastructure is small enough to be easily integrated with almost any existing infrastructure and yet powerful enough to be extremely useful.

Oh, by the way - at current stage, our engine support queries for SqlServer & Oracle databases.

Enough about high-level API. I'll try to explain the Architecture before I'll start showing you the way I decided to sew this engine. Our first (static)class is Expression, which is kind of Factory for expressions:

Expression.gif

Factory of expression ah ? what kind of concrete objects I've got there ?
Well, here are few samples: EqualExpression, NotEqualExpression and OperatorExpression

Expressions.gif

IDataExpression inherit from IExpression and overload GenerateQuery method with two additional parameters: DatabaseMapper and IDataParameterCollection.

IDataExpression.gif

The former one(DatabaseMapper) will simply "tell" the Query Engine how to convert User.Field.Age enum into "Users.Age" string and the latter(IDataParameterCollection) will be an empty collection of parameters which every expression can fill according to its' needs.

Eventually, we've got an Engine that receives the IExpression(s) and generates code from them:

ExpressionEngine.gif

Here is the implementation of IQueryCreatorEngine.GenerateWhereClause():

string IQueryCreatorEngine.GenerateWhereClause(IExpression[] expressions, IDataParameterCollection parameters)
{
   IDataExpression wrapper = (IDataExpression)Expression.Block(expressions);
   return wrapper.GenerateQuery(this.Mapper, parameters);
}

Pretty straight forward: wrap the expressions with DataBlockExpression and let him take care of our business. Let's look at our DataBlockExpression.GenerateQuery method:

protected override string GenerateQueryCore(DatabaseMapper mapper, System.Data.IDataParameterCollection parameters)
{
   StringBuilder whereClause = new StringBuilder(this.Expressions.Length * 150);

   whereClause.Append("( ");

   foreach (IExpression exp in this.Expressions)
   {
      IDataExpression dataExpression = exp as IDataExpression;

      if (dataExpression != null)
         whereClause.Append(dataExpression.GenerateQuery(mapper, parameters));
      else
         whereClause.Append(exp.GenerateQuery());
   }

   whereClause.Append(" )");

   return whereClause.ToString();
}


The only thing we have to do now is to supply some sort of method which implement DatabaseMapper (delegate) signature when we initialize the QueryCreatorEngine. Here is a quick example:

QueryCreatorEngine engine = new QueryCreatorEngine(
   delegate(object field)
   {
       User.Field typedObj = field as User.Field;
       if (typedObj != null)
       {
          switch(typedObj)
          {
              case User.Field.Age: return "Users.Age";
              case User.Field.IsGoldMember: return "Users.IsGoldMember";
              case User.Field.Email: return "Users.Email";
              default
               throw new ArgumentException("field not supprted"); //whatever
          }
       }
       else
           throw new 
               ArgumentException("field != User.Field type"); //whatever
   });

That's it.

Our mapper is generated by tool (our lovely Code-Agent) and our Filter By Expressions infrastructure is ready to go !

If you are still here, leave me a comment and I'll send you a T-Shirt of "Code don't make me sleepy!".

I'll upload our Data Access infrastructure in a few days so be patient and let me know if this post made you happy.


[1] We did a quick API exam in our department and the results were good.

   

Posted by Oren Ellenbogen 
12/06/2006 01:22, Israel time UTC-07:00,     Comments [4]  |