February 2004 - Posts

My first online article

In English, anyway: http://dotnetjunkies.net/Tutorial/77D4AFDC-585D-4539-A364-30028327FF14.dcik I'd love to have feedback!
Posted by Edgar Sánchez with 2 comment(s)

Are validation errors exceptions?

I was discussing with a customer about the best way to design, code and use business validation logic. First of all, there were a number of decisions already made:

  1. Business entities will be represented as typed datasets
  2. There will be one data access logic components (dalc) per each business entity. The dalc will do CRUD operations
  3. There will be (roughly) one business logic component per business entity
  4. The business validation logic will be implemented in one method, Validate(), member of the business logic component

So, in general terms, we'll have: VoucherDalc, DsVouchers and VoucherManager. Now let's focus on the validation issue. As many validation errors could be detected in the DsVouchers dataset, a reasonable signature for Validate() is:

public ValidationError[] Validate(DsVouchers ds)

Where a ValidationError object (structure?) has enough information to describe the problem to the final user. The method is public so as to allow the UI logic to call Validate() when necessary. Furthermore, the business logic component (VoucherManager) will also be responsible for passing update requests to the data layer, so it needs this method:

public void Update(DsVouchers ds)

But, so that no invalidated data is sent to the data layer, Update() should call Validate(), for this reason a better signature (and implementation) for Update() is:

public ValidationError[] Update(DsVouchers ds) {

ValidationError[] errors = this.Validate(ds);

if (errors.Length > 0)

return errors;

...

}

But I don't like this because:

  1. Is it natural (from a business design point of view) that Update() returns a ValidationError array? Not really
  2. Programmers calling Update() may easily ignore the returned value, so errors are ignored!

That's why a better implementation could be:

public void Update(DsVouchers ds) {

ValidationError[] errors = this.Validate(ds);

if (errors.Length > 0)

throw new ValidationException(errors); // now we use an exception

...

}

Performance suffers because of the use of exceptions but we win:

  1. No unnatural returns from Update()
  2. Errors are harder to ignore (a very lazy developer can still do a try { ... } catch {} though)
  3. If carefully written the ValidationException can travel thru physical layers

So, in spite of the general recommendation of using exceptions only for errors that happens outside the application control (e.g. printer not ready, server not available, disk full, ...) may be it's a good idea to use exceptions to report validation problems as part of the Update() method. Opinions?

Posted by Edgar Sánchez with 10 comment(s)

I don't have an Itanium :-(

HP is about to launch Itanium down here in Ecuador. The MS subsidiary would like to show Whidbey on it, I've got the Whidbey and Yukon PDC bits but I don't know whether they run on Itanium. I want an Itanium :-(

Your favorite WinForms library

I asked some friends what WinForms libraries they have used and which one they like the most. I didn't get that many answers but so far it seems like Developer Express is the favorite, followed closely by Janus (my personal pick). The key differentiator? With DevEx you can buy the source code. Infragistics, while mentioned, doesn't seem to have that many fans... Which one do you use?
Posted by Edgar Sánchez with no comments

Tiger Generics vs. Whidbey Generics

I know, I know, micro-benchmarks are questionable, besides we are talking about early betas, etc. But I just couldn't resist making some small testing. First of all, a generic list of integers in Whidbey C#:

using System;
using System.Collections.Generic;

namespace LogicStudio.Whidbey.Tests
{

  public class GenericValueArrayListTest {

    static void Main()
    {
      DateTime start = DateTime.Now;

      List<int> numbers = new List<int>();

      for (int i = 0; i < 1000000; i++)
      {
        numbers.Add(1962);
      }

      foreach (int i in numbers)
      {
        int number = i;
      }

      DateTime finish = DateTime.Now;

      System.Console.WriteLine(String.Format("Elapsed time: {0}", finish.Subtract(start)));
    }

  }

}

Now, it's equivalent in Tiger Java:

package net.logicstudio.tiger.tests;

import java.util.*;

public class GenericValueArrayListTest {

  public static void main(String[] args) {
    Date start = new Date();

    ArrayList<Integer> numbers = new ArrayList<Integer>();

    for (int i = 0; i < 1000000; i++) {
      numbers.add(1962);
    }

    for (int i : numbers) {
      int number = i;
    }

    Date finish = new Date();

    System.out.printf("Elapsed time: %d ms", finish.getTime() - start.getTime());

  }
}

As you can see, I am just creating a million integers list and then accessing every item. C# needed 70-80 milliseconds to complete the job, Java needed 1,430-1,450 milliseconds. Understandable, as Java generics always use reference types so the integers are being boxed/unboxed inside both loops. As I don't expect to see many value collections in real-life situations, the results are not that significative for me, but what about a collection of employees? First the Whidbey C# version:

namespace LogicStudio.Whidbey.Tests
{

  public class Employee
  {
    int id;
    string name;

    public Employee(int anId, string aName)
    {
      this.id = anId;
      this.name = aName;
    }

    public int Id
    {
      get { return this.id; }
    }

    public string Name
    {
      get { return this.name; }

      set { this.name = value; }
    }
  }

}

using System;
using System.Collections.Generic;

namespace LogicStudio.Whidbey.Tests
{

  public class GenericReferenceArrayListTest {

    static void Main()
    {
      DateTime start = DateTime.Now;

      List<Employee> employees = new List<Employee>();

      Employee emp = new Employee(101, "Smith, Joan");


      for (int i = 0; i < 1000000; i++)
      {
        employees.Add(emp);
      }

      foreach (Employee e in employees)
      {
        Employee currentEmployee = e;
      }

      DateTime finish = DateTime.Now;

      System.Console.WriteLine(String.Format("Elapsed time: {0}", finish.Subtract(start)));
    }

  }

}

Now the Tiger Java version:

package net.logicstudio.tiger.tests;

public class Employee {
  private int id;
  private String name;

  public Employee(int anId, String aName) {
    this.id = anId;
    this.name = aName;
  }

  public int getId() {
    return this.id;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String aName) {
    this.name = aName;
  }
}

package net.logicstudio.tiger.tests;

import java.util.*;

public class GenericReferenceArrayListTest {

  public static void main(String[] args) {
    Date start = new Date();

    ArrayList<Employee> employees = new ArrayList<Employee>();

    Employee emp = new Employee(101, "Smith, Joan");

    for (int i = 0; i < 1000000; i++) {
      employees.add(emp);
    }

    for (Employee e : employees) {
      Employee currentEmployee = e;
    }

    Date finish = new Date();

    System.out.printf("Elapsed time: %d ms", finish.getTime() - start.getTime());

  }
}

This time the C# version took 150 ms and the Java version took 630-650 ms. C# took twice the time with the employees list than with the integers list as a consequence of the compiler use of more efficient representations for value types. Java took less than half the time with the employees list than with the integers list because no boxing/unboxing was needed (Java uses objects in both cases). Anyway and so far, Whidbey is faster than Tiger by a wide margin. In compiling all the examples I used the default switches. Of course, these numbers are totally unscientific so there are no more than a personal divertimento and your results may vary widely.

Posted by Edgar Sánchez with 5 comment(s)
Filed under:
More Posts