Normally I wouldn’t post anything (as simple) as this but since I’ve got this question numerous times I decided to post it here anyway. Let’s say you require mapping an enumeration to both the database and a user interface representation. Although I would normally recommend a Mapper pattern to set up communication between two independent objects, I now choose to use an attribute based solution. In the code listing below the ‘Description’ attribute maps against the user interface representation and the ‘Code’ attribute maps against string based values stored in the database (a legacy database).
I borrowed the idea from this blog.
[TestFixture]
public class EnumTests
{
[Test]
public void GetDescription()
{
string description = EnumConvert.GetDescription(TrafficLight.Green);
Assert.AreEqual("Procede", description);
}
[Test]
public void GetCode()
{
string code = EnumConvert.GetCode(TrafficLight.Green);
Assert.AreEqual("G", code);
}
[Test]
public void EnumValueForCode()
{
TrafficLight t = (TrafficLight) EnumConvert.GetValue(typeof (TrafficLight), "G");
Assert.AreEqual(TrafficLight.Green, t);
}
#region Helpers
private enum TrafficLight : byte
{
[Description("Procede"), Code("G")]
Green = 0,
[Description("Caution"), Code("R")]
Red = 1
}
#endregion
}
public class CodeAttribute : Attribute
{
private string code;
public CodeAttribute(string text)
{
this.code = text;
}
public string Code
{
get { return code; }
}
}
public class EnumConvert
{
public static string GetDescription(Enum enumeration)
{
Type type = enumeration.GetType();
MemberInfo[] memInfo = type.GetMember(enumeration.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attributes = memInfo[0].GetCustomAttributes(typeof (DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return ((DescriptionAttribute) attributes[0]).Description;
}
return enumeration.ToString();
}
public static string GetCode(Enum enumeration)
{
Type type = enumeration.GetType();
MemberInfo[] memInfo = type.GetMember(enumeration.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attributes = memInfo[0].GetCustomAttributes(typeof (CodeAttribute), false);
if (attributes != null && attributes.Length > 0)
return ((CodeAttribute) attributes[0]).Code;
}
return enumeration.ToString();
}
public static object GetValue(Type type, string code)
{
string[] names = Enum.GetNames(type);
foreach (string name in names)
{
object o = Enum.Parse(type, name);
if (GetCode((Enum) o) == code)
return o;
}
return null;
}
}
<newbish>
Take your pick… ERD -> physical database. What are the rules for table names or better; when to use singular or plural names? To keep my team from smashing each others heads in, please settle this argument.
</newbish>
I just felt all emotional (how geeky can it get) reading Dennis’s follw up post on Martin Fowler’s Five Pound Bag post.
There are also managers that try to get 20 pounds in the 5 pound bag. Although to me totally illogical, they seem to think that, when you place four developers on the project, they can divide the 20 pounds by four, resulting in 5 pounds. That's exactly what fits in the bag.
To my experience managers tend to add an extra pair of hands when the going gets tough. Although there are managers, though rare, with a recent background in programming who know the consequences of such an extra pair of hands. This is one of the answers to Dennis’s question: how come project managers don't follow that simple rule? Because they’re standing to far away from the actual process even while sitting in the same (team) room to notice. It’s to simple to blame only our managers for badly done planning, it’s our job to create awareness.
Instead of pulling an enormous object graph in-memory and bring the contained data on the users screen we decided to use so called Views on our Domain Model. Roger Johansson is developing a UI mapper (he calls NView) which generates such view models on the fly. Paul Wilson invested his time on a similar concept named UIMapper. Mats Helander wrote a series of articles on this very same subject. Interesting?
So now we use a resultmap in iBATIS to map directly against a CustomersOrdersView. By using raw T-SQL/Views it is pretty easy to optimize a view displaying aggregated data.
Your take?
*update
Fabrice Marguerie mentioned Martin Fowler's page about the PresentationModel [1] and John Gossman's weblog [2] on Avalon's ViewModel.
Both James Shore and Sam Gentile have had it with people accusing XP’s lack of design. This week I’ve seen very competent people struggling with an authorization design (small, fits on A3 format). This design of our new authorisation module was crafted by a team member who is currently on leave. Although the design is conceptually rock solid it still needs things to be ironed out. IMHO stuff that would have been touched upon early and probably had changed insights when using TDD. It depends whether the implementation-model meets the design-model. It’s only matter of luck I guess.
XP == DATT (Design All The Time) and what I just described is simply Design As Sketch utilizing UML As Sketch.
What about application/enterprise architecture in XP, thoughts? I want to collect my thoughts in a follow-up since to my current believe XP is lacking on these parts.
Good architecture discussions (online that is) are scarce these days. A couple of weeks ago Peter Veentjer pointed me to the Spring Framework Architecture forum which contains interesting discussions. See for yourself!