The Dark Ages

Any Architect that deals with Business Domain OO Applications faces, sooner or later, the need to design a Person class.
 
A common problem in a Person class is the Age property. It is clear that it should be a derived (calculated, read-only) property, in which case
the class should have a DateOfBirth field (DoB) to solve such calculation.
 
Under such conditions, we have to find ways to "compare" the Date Of Birth of the person with today’s date that will allow us
to determine the person’s age.
The business rules to determine the age of a person are, more or less, like this:
If the person’s birthday is already due, then the age of the person is today’s year minus the year of her birth.
If the person’s birthday is not yet due, then the age of the person is today’s year minus the year of her birth minus one (1).
 
These business rules seem to be Ok, but then we realize that we need to add another business rule, to define or determine
the following:
How do we know if the birthday of person is already due or not?
 
To make sure that we have the "right" business rule, we must check that it works fine for whatever the Date Of Birth of the person may
be, even if it falls on a 29th of February (funny thing the leap year!)
 
We may use the services of a helper (private) method for this additional business rule. This helper method could be called:
isBirthDayAlreadyDue(), which returns a boolean.
 
A literal implementation for the business rules that we have discussed so far is available in Sample Code 1 (see below)
For those that really appreciate simplicity and elegant solutions, my favorite implementation for this problem is available in
Sample Code 2 (see below).
 
Cualquier Arquitecto que trabaja con aplicaciones OO de dominios de negocios debe enfrentarse, tarde o temprano, con la necesidad de diseñar una clase Persona.
 
Un problema común en una clase Persona es la propiedad Edad. Está claro que la misma debería ser una propiedad derivada (calculada, read-only),
en cuyo caso esta clase debería tener un campo FechaDeNacimiento (DoB) a fin de resolver tal cálculo.
 
Bajo estas condiciones, debemos contar con formas de "comparar" la Fecha de Nacimiento de la persona con la fecha de hoy que nos permitan
determinar la edad de dicha persona.
 
Las reglas de negocios para determinar la edad de la persona son, mas o menos, así:
Si el cumpleaños de la persona ya ha pasado, entonces la edad de la persona es el año de la fecha de hoy menos el año de su nacimiento.
Si el cumpleaños de la persona no ha pasado todavía, entonces la edad de la persona es el año de la fecha de hoy menos el año de su nacimiento menos uno (1).
Estas reglas de negocios parecen estar Ok, pero luego nos percatamos que necesitamos agregar otra regla de negocios, para definir o determinar
lo siguiente:
Cómo sabemos si el cumpleaños de la persona ha pasado ya o no?
 
A fin de asegurarnos que tenemos la regla de negocios "correcta", debemos verificar que funciona bien para cualquier Fecha de Nacimiento de la persona,
inclusive si dicha fecha cae un 29 de Febrero (cosa simpática esto del año bisiesto!).
 
Podemos usar los servicios de un método helper (private) para esta regla de negocios adicional. Este método helper podría llamarse:
isBirthDayAlreadyDue(), el cual retorna un boolean.
 
Una implementación literal para las reglas de negocios que hemos discutido hasta ahora esta disponible en Sample Code 1 (ver mas abajo).
Para aquellos que realmente aprecian la simplicidad y las soluciones elegantes, mi implementación favorita para este problema esta
disponible en Sample Code 2 (ver mas abajo).
Sample code 1
 
using System;
namespace PersonAge
{
 /// <summary>
 /// Description of Person.
 /// </summary>
 public class Person
 {
  private DateTime DoB;
  private DateTime today;
  
  public Person(DateTime aDateOfBirth)
  {
   DoB = aDateOfBirth;
   today = new DateTime();
   
  }
  
  private bool isBirthDayAlreadyDue()
  {
   // We use today in two methods. To make sure that the comparisons
   // are consistent, we must maintain the same state for today
   // in all methods.
   //
   // Usamos today en dos metodos. Para asegurarnos que las comparaciones
   // son consistentes, debemos mantener el mismo estado para today
   // en todos los metodos.
   
   today =  DateTime.Now;
   
   return (((today.Month*100 + today.Day) / (DoB.Month*100 + DoB.Day)) != 0);
    
  }
  
  public int Age
  {
   get
   {
    
    if (isBirthDayAlreadyDue())
     return ( today.Year – DoB.Year);
    else
     return (today.Year – DoB.Year – 1);
   
   }
  
  }
 }
 
 
 
 
 
}
 
Sample code 2
using System;
namespace PersonAge
{
 /// <summary>
 /// Description of Person.
 /// </summary>
 public class Person
 {
  private DateTime DoB;
  
  public Person(DateTime aDateOfBirth)
  {
   DoB = aDateOfBirth;
   
  }
  
 
  public int Age
  {
   get
   {
    DateTime today =  new DateTime();
    
    today =  DateTime.Now;
    
    return ( today.Year – DoB.Year + ( -1 + Math.Sign((today.Month*100 + today.Day) – (DoB.Month*100 + DoB.Day)))/2   );
   
   }
  
  }
 }
 
 
 
 
 
}
 
 
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s