Tuesday, January 31, 2006
.norm insert usage
Using DataGateway to insert data can be accomplished by doing exactly what you would expect.
Foo user = new Foo();In this example you are inserting an instance of type Foo into the database. Foo is designed as follows.
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);
namespace Example.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.
{
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; }
}
}
}
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 ExampleAfter 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.
{
[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; }
}
}
}
Monday, January 30, 2006
.norm version 0.1 released
.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
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...Testing
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());
}
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]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.
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();
}
Tuesday, January 24, 2006
Use delegates to replace repeated guard clauses
For example:
class FooView...As the number of data elements on the screen increases so does the annoyance with repeating the isLoading guard.
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();
}
}
}
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...The resulting code is one method longer, but removes the isLoading repetition.
...
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));
}
}
I prefer Rake to NAnt (#4)
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:ConfigurationNext, you will need to create a Configuration class.
catalog: cat
data_source: source
password: password
user: jay
Yaml.rb::load will automatically load your configuration information into an instance of the Configuration class.class ConfigurationAt this point you are ready to access your configuration information via methods of the object. The following test verifies the expected behavior.
attr_accessor :user, :password, :data_source, :catalog
end
require 'yaml'*SciTE formatting
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
Monday, January 23, 2006
Rake NUnit Task
I have word from a good source that Jim Weirich is working on a plug-in architecture for Rake that will allow for easy rake task creatioin. With more tasks available the adoption rate will increase.
This is great news; however, you don't have to wait for this architecture to create your own rake tasks. On my current project I wanted to make the rakefile more readable for the developers who were less familiar with rake. One way to accomplish this is to abstract a few variables and a shell execute into a task.
I chose to use NUnit as the example; however, the idea can be applied to any task that is completed by a commandline application (Simian, Devenv.com, etc). The NUnit task requires only the Library value; however, it does allow you to specify optional xml and config information. Adding other commandline switches could be accomplished very easily by following the same model. To use this task all you need to do is save the code to nunittask.rb in the lib folder.
#!/usr/bin/env rubyNow that you have NUnitTask saved it can be used in your rakefile simply by adding an NUnitTask.
require 'rake'
require 'rake/tasklib'
module Rake
class NUnitTask < TaskLib
# Name of the main, top level task. (default is :nunit)
attr_accessor :name, :library, :xml, :path_to_console, :config
# Create an NUnit task named nunit. Default task name is +nunit+.
def initialize(name=:nunit) # :yield: self
@name = name
@path_to_console = "lib/nunit-console.exe"
yield self if block_given?
define
end
# Create the tasks defined by this task lib.
def define
task name do
sh "#{@path_to_console} #{xml} #{config} #{library}"
end
self
end
def xml
"/xml=#{@xml}" if @xml
end
def config
"/config=#{@config}" if @config
end
end
end
require 'lib/nunittask'You can wrap any commandline task in the exact same way. If you create enough of them, your rakefile reads much more like a specification than a ruby program.
...
Rake::NUnit.new do |nunit|
nunit.library = "foo.dll"
end
Thursday, January 19, 2006
I prefer Rake to NAnt (#3)
The current application I'm working on has lots of data. With every build we drop, create, and reload the objects in the database. The drop and create sql must be executed first, but the loading scripts can be run in parallel. Ruby makes this easy with the Thread class in the Core API.
task "setup_db" do*DbTasks is simple class that contains common information (login info). The DbTasks.execute_osql method is just a wrapper for executing osql as a system command with DbTasks' static information.
tasker = DbTasks.new
tasker.execute_osql("object_drop_and_creation.sql")
#execute in parallel
threads = []
threads << Thread.new { tasker.execute_osql("dummy_data1.sql") }
threads << Thread.new { tasker.execute_osql("dummy_data2.sql") }
threads << Thread.new { tasker.execute_osql("dummy_data3.sql") }
threads << Thread.new { tasker.execute_osql("dummy_data4.sql") }
threads << Thread.new { tasker.execute_osql("dummy_data5.sql") }
#join threads
while ( t = threads.shift ) ; t.join ; end
end
**As usual, there may be a better way in Ruby. And, there may be multi-threading options in NAnt that I'm not aware of.
Tuesday, January 17, 2006
Moving from NAnt to Rake
If you are working with an existing NAnt script that is a burden to maintain consider converting the more complicated tasks into ruby scripts. When the majority of the complicated tasks are written in ruby it will make sense move the remaining tasks into a rakefile.
I used this approach recently at a client site. Whenever the NAnt tasks needed updating we converted them to a ruby script. When we finally decided to make the move to rake exclusively it took less than an hour to convert the remaining tasks. The resulting rakefile was about 1/2 as long. Additionally, the team agreed that the resulting rakefile was significantly more readable and maintainable.
Friday, January 13, 2006
Fragile Development
instead of refactoring duplicate code you just ignore it.
#region simianignore - logic same among all screensyou hear:
"I don't like to check in often, the tests take too long to run"
Friday, January 06, 2006
I prefer Rake to NAnt (#2)
Recently, I was asked to add a step to the build file that would delete all build outputs that were older than 2 weeks old. The build output is stored in a folder in the distrobution folder. I'm not even going to attempt this task in NAnt, but using Ruby's find, delete, and fileutils the code was quite easy to write. (I admit, this could probably be done even better, but this was the first thing that came to mind.)
require 'find'
require 'date'
require 'fileutils'
root_dir = "C:/Dist"
two_weeks_ago = Date.today - 14
puts "deleting files last modified before #{two_weeks_ago}"
Find.find(root_dir) do |path|
if File.dirname(path) == root_dir
file_modify_date = Date.parse(File.mtime(path).strftime("%m/%d/%Y"))
puts "#{path} last modified on #{file_modify_date}"
if file_modify_date < two_weeks_ago
puts "#{path} removed"
FileUtils.rm_rf(path)
end
end
end
I prefer Rake to NAnt (#1)
I prefer escape characters (\") and Q delimiters (%Q) to entity codes (").*option 2 provided by Martin
For example, executing an external program where the 1st parameter needs to be in quotes but not the second.
Rake (option 1):exec "foo.exe \"some text\" bar"
Rake (option 2)*:exec %Q[foo.exe "some text" bar]
NAnt:<exec program="foo.exe" commandline=""some text" bar"/>
NAnt exec: add quotes to commandline
A simple solution would be to use commandline and delimit the string with single quotes.
<exec program="ruby" commandline='parse_text.rb "some text file.txt"'/>However, this solution feels like a hack and isn't immediately obvious.
Another (even less obvious) solution is to use ".
<exec program="ruby" commandline="parse_text.rb "some text file.txt""/>This doesn't read very well, but it feels less like a hack because you can use a standard double quote delimiter.
Either option you choose isn't very pleasing. Which leads me to reason #1 why I prefer Rake to NAnt.
Trust Visibility
During the development of this framework I came up with the idea of Accessing Private Members using conditional compilation. While interviewing with ThoughtWorks I briefly discussed this situation with Greg Warren. He suggested (but did not take credit for the idea) using a correctly scoped interface and making the methods of the concrete classes public. At the time, this sounded like a large risk. I didn't trust the other team members enough to give them that option.
Since joining ThoughtWorks, my opinion has completely changed. I now subscribe to the idea that a language should only have public and protected access (which I first heard from Zak Tamsen). So many language constructs are designed to protect us from ourselves that we often tie our own hands together. I'd prefer to have the rope and see what I can do with it. However, I strongly believe that I changed my mind based on the fact that I now trust the team I am working with. Because of this trust I don't feel I need to tie their hands together. And, with untied hands, my teammates produce some pretty brilliant ideas.
To me, this proves once again that People Matter Most.




