July 2004 - Posts
Recently I've spoken with a couple individuals about openings they were looking to fill. Don't ask why but I didn't consider them official interviews, more of an opportunity to speak with some people about other opportunities that are out there. During my "interviews" I started realizing that I kinda suck at it. The fact that nobody sent me an offer for an obscene amount of money seems to back that up. Bummer.
A couple days go I wrote about the UI Mapper'ish code I wrote recently to help alleviate the repetitive code necessary for editing domain objects. In the post I described how I used reflection to analyze my domain objects and automatically load and retrieve values to and from controls within my edit forms. What I didn't discuss in the previous post was how the information within my O/R Mapper can be used along with the UI Mapper code to automagically add validation to the form.
Before moving on, let me point you to a couple posts with my thoughts and opinions on validation:
As specified in "More Fun with Attributes" my validation rules are "applied" to the properties of my domain objects via attributes.
public class Customer : EntityObject {
string _firstName = String.Empty;
string _lastName = String.Empty;
string _company = String.Empty;
[Persist, Required, MaxLength(100)]
public string FirstName {
get { return _firstName; }
set { _firstName = value; }
}
[Persist, Required, MaxLength(100)]
public string LastName {
get { return _lastName; }
set { _lastName = value; }
}
[Persist]
public string Company {
get { return _company; }
set { _company = value; }
}
}
In the Customer object above we specify what properties are persisted, what fields are required, as well as the max length of the first and last name properties. Although not presented in the above example we could have applied attributes for the minimum length, format via a regular expression, a comparison validation (property minimumPrice is less then maximumPrice), and etc.
In addition to the validation attributes, we can also use the type of the property to validate our business objects. The CompareValidator allows you to validate that the value entered into a form field matches is valid for a particular data type (integer, boolean, currency, and dates). By combining the data type validation with the validation information provided by the set of custom attributes mentioned above we can create a validation framework that can automatically add a whole suite of validation controls to the edit forms in the application. Now our UI Mapper is providing us not only with auto mapping between our objects and UI but its also providing extensive data validation.
Although I'm not going to go into too much detail in this post (since its getting a little long already) let me briefly describe how this is accomplished.
The first step in the process involves determining if a property of the domain object has an associated control.
Control controlForProperty = control.FindControl(property.Name);
if(controlForProperty != null) {
// add validation
}If the property doesn't have an associated form we don't want to add any validation to our UI. If a control is found, we loop over all the validation attributes assigned to the property and add the appropriate validation control to the form. After adding the necessary controls for the validation attributes a final evaluation is done on the type of property.
object
[] attributes = property.GetCustomAttributes(typeof(ValidatorAttribute), true);
for(int i = 0; i < attributes.Length; i++) {
ValidatorAttribute validationAttribute = (ValidatorAttribute) attributes[i];
BaseValidator validator = validationAttribute.GetValidator(property);
if(validator is RequiredFieldValidator) {
Label label = control.FindControl(property.Name + "Label") as Label;
if(label != null) {
label.CssClass += " required";
}
}
control.Page.Validators.Add(validator);
control.Page.Controls[1].Controls.AddAt(control.Page.Controls[1].Controls.IndexOf(controlForProperty) + 1, validator);
}If the type of the property is one of the data types that the CompareValidator supports (Currency, Integer, Date, Double, String) then we also add a CompareValidator to the form ensuring that the user enters a valid value into the control.
if(property.PropertyType == typeof(DateTime)) {
CompareValidator compareValidator = new CompareValidator();
compareValidator.Operator = ValidationCompareOperator.DataTypeCheck;
compareValidator.ControlToValidate = controlForProperty.ID;
compareValidator.Type = ValidationDataType.Date;
compareValidator.Text = "*";
compareValidator.ErrorMessage = "The " + property.Name + " entered is not valid.";
control.Page.Validators.Add(compareValidator);
control.Page.Controls[1].Controls.AddAt(control.Page.Controls[1].Controls.IndexOf(controlForProperty) + 1, compareValidator);
}
At the end of the day we end up with a form that can load and retrieve values from a domain object, as well as add all the validation necessary to the UI of the form.
Pretty cool?
Well I just finished my first night of coding using Subversion as my source control repository and I have to say I'm not sure I'll go back to Vault, or VSS anytime soon. I've been using the VS.NET plug-in with good success. The one issue I did run into was when I tried to replace a project folder. When I removed the folder I wiped out the .svn folder and when I created the new project I tried committing without luck. I was getting a svn: working copy not locked error. I did a svn update, deleted the project file (note the .svn was not deleted) and then added the project via "Create project in existing directory". A new svn commit -m "some message" and I was back in business. I also installed TortoiseSVN tonight which seems to work quite well.
Related Links:
I've recently come across a couple of articles that identify the problem of mapping domain objects to the UI layer. Paul Wilson suggests that we might be able to solve the problem by implementing a UI Mapper. A UI Mapper would serve a similar purpose as the OR Mapper. However, rather then mapping our object to our relational database as we do with our OR Mappers, we use the UI Mapper to map our objects to our user interfaces. To continue on with some thoughts from the blogosphere we travel over to Jimmy Nilsson blog, where he wonders if the recent buzz surrounding the topic is a sign of things to come.
I haven't put a ton of thought into the topic, however, I think we can gain efficiencies from a UI Mapper as we can with OR Mappers. On a recent project I didn't exactly flesh out a complete UI Mapper, however, I did do some UI Mapper'ish things to help speed the development of the UI of the application.
On many project in the past I've gotten a little bored writing a bunch of repetitive code to load data within my domain objects into my UI, as well as pulling information out of the UI and placing it into my objects. The process went something like this...
protected void Page_Load(object sender, EventArgs e) {
if(!Page.IsPostBack) {
Customer customer = new CustomerRepository().FindById(99);
LoadFormFormCustomer(customer);
}
}
protected void saveButton_Click(object sender, EventArgs e) {
if(Page.IsValid) {
Customer customer = new Customer();
LoadCustomerFromForm(customer);
}
}
private Customer LoadCustomerFromForm(Customer customer) {
customer.FirstName = firstName.Text;
customer.LastName = lastName.Text;
// and on and on and on....
}
private void LoadFormFormCustomer(Customer customer) {
firstName.Text = customer.FirstName;
lastName.Text = customer.LastName;
// and on and on and on....
}
Rather then continuing on the same basic path outlined above I set out to automate the process and reduce the amount of code required for creating "edit pages" within my application. The solution I developed uses reflection to automatically load forms from domain objects, and domains objects from forms. I created a controller class that takes a domain object and control as parameters. The controller then loops over the properties of the domain object (via reflection) and finds controls on the form with a matching ID.
Control foundControl = control.FindControl(property.Name);
If a control is found for the property the controller loads the control with the value within the associated properties of the domain object. With this infrastructure in place the edit page for the Customer becomes much simpler:
public class CustomerEdit : Steve.Eichert.Sample.Web.UI.EditPage {
protected override Type DomainType() {
return typeof(Customer);
}
}Could UI Mappers be the next big thing? Maybe, maybe not, all I know is my simple UI Mapper saved me from writing a bunch of boring repetative code and allowed me to concentrate on developing the domain logic within the application which in my opinion is a very good thing.
One of the primary focuses of DDD is ensuring that a Ubiquitous Language is used. What this essentially means is that everyone, and yes I really mean everyone, involved in the project uses the same terms to describe the system. Typically as software developers we create our own language in which we speak to describe the various aspects of our software design. When we then talk to business users we use a different language. We usually justify these two languages by saying that the business users simply "wouldn't understand" what we were talking about if we tried speaking "our" language to them.
By speaking in two different languages we create a gap between the developers on the project and the business users who are defining how the application should work. We miss the opportunity to give proper names and meaning to the objects within our domain. Although we often think we understand the business of the clients we work for, we often times don't know nearly as much as we think. The analysts have expertise in the domain, we're just trying to gain some of the knowledge that they've accumulated over the course of their career. Rather then finding our own names for "components" within the system we should take the business users lead.
Before I get to far, let me ensure you that I don't think we can simply take everything the business users says and apply it directly to our domain. We will certainly have to train them to understand parts of our terminology as well. There has to be collaboration, we need each other to develop the best domain model possible for the systems we develop.
It's not enough to simply use the same language among our internal development teams as well as with the business users. We need to listen carefully to how we describe the system with the ubiquitous language and look for areas that aren't clear. We need to refine the language constantly to ensure it keeps up with all the new information we gather from our business users. When we describe the system the ubiquitous language MUST be used. By forcing ourselves to use the ubiquitous language at all times we provide ourselves with that much more opportunity for improving the domain. As we hear ourselves talk about the domain with the ubiquitous language we will identify areas that are confusing, unclear, and desperately need "refactoring." As the ubiquitous language is updated so to should the domain be updated.
After reading DDD I've begun to notice how much of a divide we create in order to speak the language of different groups of people. We describe systems one way for fellow developers, another way for user experience and design folks, a third way for project managers, and yet another way for the business users (our client). I'm still far from knowing how to really apply this in all circumstances, however, I believe having a ubiquitous language and forcing ourselves to use it at all times can certainly help improve our domain. I am still skeptical that it can really be used with every individual on every project. What do you think?
I've been using Vault for a while as my source control provider, however, I've decided to give subversion a try. Today I started placing some of my projects into subversion. I've heard the VS.NET integration can be a little flaky, but so can Vault's, so I'll have to see how it goes.
Over the past month or two I've been trying to wrap my head around the ideas and principles of Domain Driven Design, and how it affects how I develop software. A lot of the concepts and principles are things that I've been following for a long time, I just didn't call them by the "proper" names. In an effort to flesh out some of my thoughts on DDD I'm going to be posting a few entries about some of the core principles that have stuck in my head after reading DDD. As a disclaimer all the information that I write regarding DDD is my interpretation of what I read and not necessarily what Eric and friends have laid out.
To start if you haven't already read Domain Driven Design please go buy it now, so that I can get a bunch of feedback and reaction from you all as I write about my interpretation and thoughts surrounding it. Ok, all done? Really, go now 
Ok, now that we have that out of the way lets lay out a temporary list of things to write about:
Stay tuned for the first installment.....aren't you sooooo excited!?!?!
[Side Note: I finally bucked up for BlogJet, you gotta love the simplicity of its design/ui]
Clemens writes an interesting post stating that objects aren't any good on the business logic abstraction level. Several other have weighed in with their opinions.
Clemens
Maybe I am too much of a data (read: XML, Messages, SQL) guy by now, but I just lost faith that objects are any good on the "business logic" abstraction level. The whole inheritance story is usually refactored away for very pragmatic reasons and the encapsulation story isn't all that useful either. You simply can't pragmatically regard data validation of data on a property get/set level as a useful general design pattern, because a type like Address is one type with interdependency between its elements and not simply a container for types.
Michael Earls
Instead, I think the pipeline approach (controlled workflow) using self-contained functional units is the way to go. I think too many developers are focusing on how to create classes. I don't think classes are a first-class citizen in the world of business implementations. I think you need to start thinking (or go back to thinking) of things just as Clemens suggested - Rows and Columns + Elements and Attributes.
Jimmy Nilsson
I'm currently quite strongly influenced by Domain-Driven Design [Evans DDD] which is why I use, for instance, Repositories, Factories and Services quite a lot in my Domain Models. In a way you could think of those patterns as different kinds of services, just carefully classified. So that is probably pretty close to what Clemens said.
My current design philosophy is similar to Jimmy's. Although I didn't have the correct names for the different objects within my architecture I was very much applying a Aggregate, Repository, and Factory pattern within my application and underlying architectures. With that said, I've also thought a lot about moving more towards a message and service oriented architecture for my applications. Most of my current experience lies with richer domain models which is why I haven't jumped on the services bandwagon (yet). The fact that so many extremely smart people are preaching on the benefits of adopting a more message oriented architecture definitely has me thinking a lot about what is the best route to take for developing applications going forward. The hardest part is having that light switch on where you see the benefits of a given architecture. I've already had that light switch on the domain driven design side of the architectural world, now I just need to find my way over to the other side of the room so I can get a more balanced view and make the most informed decision going forward. Does anyone have a flashlight?
This morning I was working on a form that required some of the validators to be enabled/disabled via client side script. I quick look through the WebUIValidation.js script and I uncovered the ValidatorEnable function. The ValidatorEnable function takes the validator as the first parameter and an enabled flag as the second parameter. So to disable a validator using client side script you can use the following code:
// javascript
ValidatorEnable(document.getElementById('<%=myRequiredFieldValidator.ClientID<%=streetAddressValidator.ClientID%>'), false);
Arvindra Sehmi, the co-lead on FABRIQ, has started talking all things FABRIQ over on his blog. Arvindra posted several comments to my post on FABRIQ that really cleared up some misconceptions I had surrounding what its purpose was as well as how it compares to Shadowfax. Check out Positioning FABRIQ - What? Why? Apple or Orange? to get a background on where FABRIQ is positioned and how it compares to Shadowfax. I'm looking forward to additional posts on the how's and why's of FABRIQ!
Last week I posted about how, rather unexpectedly, I've been craving a Mac lately. Yesterday I received Software Development magazine which included an article speaking directly to some of the thoughts and concerns I was having regarding how good of a software development platform the Mac OS is. The article makes it sounds like its a pretty solid software development machine as long as your not doing Windows dev, hrm, well thats pretty much all I do as of right now. Good thing we have Mono ;-) I've been further rationalizing my desires by telling myself I need a machine to do more photo editing, management, as well as a machine to work on movie editing with.
Any Mac owners out there care to offer advice regarding what I should look at (iBook, G4, etc.), and where is the best place to order one from. Apple.com seems to be the only place that lets you customize, which I guess makes sense.
So now that I have a gmail account I need a way of knowing when I get
mail. I have all kinds of notifications pop up for my varios email
accounts so that I know when to go check it. Currently, as far as I know,
there isn't any utilities out there to notify me when I recieve mail at my brand
spanking new gmail account. Has anybody figured out a creative way to find
out when they have new mail at their gmail accounts? I'm sure google will
come out with something, possibly integrated into the Google toolbar that lets
users know when they have new mail, I just hope it comes soon!