Tuesday, January 31, 2006

.norm insert usage

The DataGateway class is the facade to the .norm framework. Insert, Update, Delete, and Find are all completed by using the DataGateway class. The DataGateway class has only one requirement, an instance of type IConnectionInfo. The ConnectionInfo class is a simple data object that contains the data source, catalog, user, and password of the database you are attempting to use. All of the data elements of the ConnectionInfo class are required constructor arguments.

Using DataGateway to insert data can be accomplished by doing exactly what you would expect.
Foo user = new Foo();
user.FirstName = "Jay";
user.lastName = "Fields";
user.ID = 0;

ConnectionInfo info = new ConnectionInfo("data_source","my_catalog","user_name","password");
DataGateway gateway = new DataGateway(info);
gateway.Insert(user);
In this example you are inserting an instance of type Foo into the database. Foo is designed as follows.
namespace Example
{
public class Foo
{
public int ID;
private string firstName;
private string lastName;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
}
.norm uses reflection to persist the instance of the Foo class to a table named Example.Foo. By default .norm uses a type's FullName as the table name to persist an instance to. .norm also assumes that the columns of the Example.Foo table have the names ID, FirstName, and LastName. Again, reflection is used to map the values of public fields and properties to columns of the same name.

Additionally, if you need to customize the table and column names .norm uses attributes for object mapping.

Assume you want to put the same Foo object into a table named foo_user_data. Also, assume the columns in foo_user_data are f_name, l_name, and id. The insert code will remain exactly the same, but the definition of the Foo class will need to include attributes that specify the mapping names.
namespace Example
{
[RelationalMapped("foo_user_data")]
public class Foo
{
[Column("id")]
public int ID;
private string firstName;
private string lastName;

[Column("f_name")]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

[Column("l_name")]
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
}
After making these additions to the Foo class it will be persisted to foo_user_data table when Insert is executed. Note, despite the fact that the ID column did not need a different name specified, you must explicitly specify each member that needs to be persisted on a class decorated with the RelationalMapped attribute.

Monday, January 30, 2006

.norm version 0.1 released

.norm is a new .net object relational mapper.

.norm was designed with the following features in mind:
  • No additional code, such as default constructors, are necessary.
  • Object CRUD operations should be possible without any database mapping necessary.
  • Objects with dependencies should be in a valid state when they are returned from the database.
  • A single class will map to a single table in the database.
  • Database mapping will be done via reflection by default and attributes when specific names are necessary.
  • Mapping via attributes instead of XML.

No additional code. A default constructor is not necessary because .norm depends on a PicoContainer for object creation. If your class does not contain a default constructor you can register the dependencies with the DataGateway and it will use PicoContainer to construct your object using the greediest constructor it can satisfy.

CRUD for free.The .norm framework uses reflection for persisting to and retrieving objects from the database. By default the FullName of a type is used as a table name, and each public field name and public property name are used as columns of the table. Additionally, .norm provides a RelationalMappedAttribute that can be used to specify a table name. And, A ColumnAttribute can be used to specify a column name. By default all public fields and properties are persisted; however, if a class is decorated with a RelationalMappedAttribute, only the attribute decorated public fields and properties will be persisted.

Dependencies are injected before objects are returned. By default, DataGateway creates a PicoContainer instance at construction time. DataGateway exposes PicoContainer's registration methods allowing you to register dependencies without ever dealing with PicoContainer, if you desire. DataGateway also takes a PicoContainer as a constructor argument if you already have an initialized PicoConstructor.

.norm is simple. All insert, update, delete, and find actions can be completed through the DataGateway class. When you need specific data returned, the WhereBuilder class allows you to narrow your results. Those should be the only classes necessary to begin using .norm.

.norm can be downloaded here.

More information to follow in the next few days.

Thursday, January 26, 2006

Use stubs and mocks to convey intent

I've previously stated that only one concrete class should be used per test. I stand by this statement; however, this leads to the question "What should I use for the dependencies of the concrete class under test?"

To illustrate I will use a SqlStatementBuilder class that depends on an instance of IPersistable and an instance of IWhereBuilder. SqlStatementBuilder takes an IPersistable instance which is an object that exposes a name. SqlStatementBuilder uses IWhereBuilder to append a where clause.
class SqlStatementBuilder...
public SqlStatementBuilder(IPersistable instance, IWhereBuilder where)
{
this.instance = instance;
this.where = where;
}

public string CreateFindAllStatement()
{
string mask = "select * from {0} {1}";
return string.Format(mask,instance.Name,where.ToString());
}
Testing SqlStatementBuilder requires you to create instances of both IPersistable and IWhereBuilder. However, if concrete implementations are used any changes to Persistable or WhereBuilder would cascade and could potentially break SqlStatementBuilder tests.

After deciding to use stubs or mocks the decision becomes which of these two options is the best. Some feel that choosing mock or stub usage is exclusive; however, using both is the superior option. A mixture of both solutions can be used to clearly convey the intended usage of a dependency within the current test.

Using a mock to verify the class under test interacts in an expected manner with a dependency is natural. However, tests should verify behavior of a dependency independently of other dependencies. For all dependencies who's behavior is not currently under test a stub is preferred. By using stubs in this manner you convey the message that only the interaction of the class under test and the mocked dependency is important.

For example, if I were testing the CreateFindAllStatement method I would test both that IPersistable.Name was used as the table name and that IWhereBuilder.ToString() was appended to the end of the select statement.
[TestFixture]
class SqlStatementBuilderTests...
[Test]
public void IPersistableNameIsUsedAsTheTableNameInCreateFindAllStatement()
{
IMock mock = new DynamicMock(typeof(IPersistable));
mock.ExpectAndReturn("Name","Foo");
IPersistable persistable = (IPersistable)mock.MockInstance;

SqlStatementBuilder builder = new SqlStatementBuilder(persistable,new StubWhereBuilder());
Assert.AreEqual("select * from Foo ",builder.CreateFindAllStatement());
mock.Verify();
}

[Test]
public void WhereBuilderToStringIsAppendedToTheEndOfAFindAllStatement()
{
IMock mock = new DynamicMock(typeof(IWhereBuilder));
mock.ExpectAndReturn("ToString","where...");
IWhereBuilder where = (IWhereBuilder)mock.MockInstance;

SqlStatementBuilder builder = new SqlStatementBuilder(new StubPersistable(),where);
Assert.AreEqual("select * from where...",builder.CreateFindAllStatement());
mock.Verify();
}
Developing tests in this manner will increase the readability due to the conciseness and clear intent. Additionally, changing the interaction between a class under test and a dependency will only break the tests specific to that dependency. The tests become more durable because a stub's default behavior should be to return a default value or do nothing in the case of a void method. Therefore, stubs will not need to be updated based on a behavioral change.

Tuesday, January 24, 2006

Use delegates to replace repeated guard clauses

When working with Presentation Model a recurring source of pain is the isLoading guard clause. The isLoading guard is required on the Reload method. Despite not being required, I also prefer to have my setting methods guarded. If you choose not to guard setting methods the last changed value will be set in the Presentation Model twice (once where you set it and once when Reload raises the XChanged event).

For example:
class FooView...
FooView(FooPM pm)
{
this.pm=pm;
Reload();
}
...
private TextBox barTextBox;
private FooPM pm;
private bool isLoading=false;
...
public void Reload()
{
if (!isLoading)
{
isLoading=true;
barTextBox.Text=pm.BarText;
isLoading=false;
}
}

public void barTextBox_TextChanged(object sender, EventArgs e)
{
if (!isLoading)
{
pm.BarText=barTextBox.Text;
Reload();
}
}
}
As the number of data elements on the screen increases so does the annoyance with repeating the isLoading guard.

You can solve this issue by extracting the setting code into it's own method, creating a delegate to this method, and passing the delegate to the Reload method. The reload method can first set the value of isLoading and then execute the delegate.
class FooView...
...
public void Reload(SetDelegate setMethod)
{
if (!isLoading)
{
isLoading=true;
setMethod();
barTextBox.Text=pm.BarText;
isLoading=false;
}
}

public void SetBarText()
{
pm.BarText=barTextBox.Text;
}

public void barTextBox_TextChanged(object sender, EventArgs e)
{
Reload(new SetDelegate(SetBarText));
}
}
The resulting code is one method longer, but removes the isLoading repetition.

I prefer Rake to NAnt (#4)

I prefer Yaml for Ruby to the Configuration classes in the .net framework.
Configuration information is often stored in a text file. When using Rake the information can be put into a yaml file that is highly readable and maintainable without all the unnecessary noise.
--- !ruby/object:Configuration 
catalog: cat
data_source: source
password: password
user: jay
Next, you will need to create a Configuration class. Yaml.rb::load will automatically load your configuration information into an instance of the Configuration class.
class Configuration
attr_accessor :user, :password, :data_source, :catalog
end
At this point you are ready to access your configuration information via methods of the object. The following test verifies the expected behavior.
require 'yaml'
require 'test/unit'

class TestConfiguration < Test::Unit::TestCase
def testYmlLoaded
config = YAML::load(File.open('config.yaml'))
assert_equal("jay",config.user)
assert_equal("password",config.password)
assert_equal("source",config.data_source)
assert_equal("cat",config.catalog)
end
end
*SciTE formatting