Archive

Archive for September, 2010

Tailoring Scrum

September 21st, 2010 2 comments

During the last big project, duration more than a year, we used scrum. But it was a tailored scrum process. The reasons for the tailoring were:

  • No scrum/agile experience in the company
  • Small team (4 developers)
  • Knowledge of tailoring RUP or Hermes
  • First project with agile methods

Normally I was the Scrum Master and mostly also the Product owner. The role of the Product owner should be fulfilled by the customer, but in our project, there were several customers with different opinions and interests. So it was our job to play a role like an advocate, in this scenario it means, that I have to be the Product owner for the developers. That wasn’t easy, because you have to understand what your customers want and explain that to them. But that’s daily business for a software engineer, isn’t it?
As an illustration I describe a typical week:

Monday Test 029
The first thing what I did as Scrum Master is a review of the last week with the team. We looked at our whiteboard (our sprint-backlog) where we could see all tasks of the last week and which of them were done. I calculated the rate in percent how much of the planed tasks are done. Normally we had a rate between 70% and 90%. If it was lower than 70% I knew that we planned too much. If the rate was 100% I knew we planned too less.

Here is the first tailoring: We used tasks rather than stories. This because we use in the company the term task and everybody knows what that is and which granularity it has. There was no need to introduce the concept of user stories.
And there is another tailoring: As you can see on the picture, the layout on the whiteboard isn’t like a scrum board. We chose a quite simple layout: The tasks have only two states: Not-done or done. Important Tasks are additional marked with an exclamation mark.
After the review meeting, I cleared all tasks on the board which are done. The tasks which weren’t done I asked the team if we would do those tasks this week. If the answer is no, I cleared also those tasks and entered them in our project management tool to not loose them.
Now the planning of the current week began: Every developer had access to our project management tool where he could see, what we had to do. And here is the next tailoring: In our company we have a project management tool, which we have to use. So I decided to use that tool as our product backlog. After the planning meeting you could see on the whiteboard all tasks which the team has committed to do this week. To some of the tasks on the whiteboard I added an exclamation mark to show the team the most important tasks for that week. The whole planning process was very democratic: Every developer could say what he thinks and I try to achieve a consensus.

Tuesday until Thursday
Every morning we did a short meeting (like the scrum daily meeting): I checked with the developers every task on the whiteboard and asked the state of the task. During this process there could happen, that I added new tasks on the whiteboard, but we never delete tasks on the whiteboard (because of the review meeting next Monday).
During the day I went to every developer and asked him if everything is OK or if I could do something for him. And this is another tailoring: In Scrum you have normally one daily meeting. Because our company had no experience in agile methods I decided to increase the communication between the Scrum master and the team members. If you are in a very agile experienced team there is much less need for that much communication, but communication is always a good thing.

Friday
On Friday we delivered the software with most of the tasks, which we planned. The most important tasks were always delivered.

Conclusion
Our sprint duration was one week and it was OK for us. The project was really tough and for that one week was perfectly. I used the project management tool to be transparent to the management and used the tailored scrum process to manage the creation of the software during the project.
The team members were all quite young and interested in learning new things. I enjoyed it very much to work in that team. But because the team members were young I had a big responsibility to coach and lead them.

Share
Categories: Agile, Software engineering Tags:

NHibernate presentations at DNUG Bern

September 2nd, 2010 No comments

dnugbe

I hold in August two presentations at the .Net User Group Bern together with René Leupold.  In both presentations the topic was object relational mapping in the .Net world. So we showed Microsoft Entity Framework 4.0 and NHibernate. My part was NHibernate and Rene showed EF.

In the first presentation which was on 16th August 2010, we presented the following stuff:

  • Introduction into ORM
  • Theory (ORM impedance mismatch, persistence ignorance and ORM isn’t a silver bullet)
  • Approaches how to map entities (top down, middle out, bottom up and meet in the middle)
  • Introduction into Entity framework (history, vote of no confidence, supported approaches)
  • Short demo of Entity framework (configuration, hello world sample)
  • Introduction into NHibernate (history, multiple options to do things, supported approaches)
  • Short demo of NHibernate (configuration, hello world sample)
  • Mappings and short demos of them (1:m, m:n, 1:1, self references, 1 class and multiple tables, 1 table and multiple classes, inheritance with TPH, TPT and TPC)

You can find the slides here.

In the second presentation which was on 23th August 2010, we presented the following topics:

  • Queries (I showed HQL, Criteria API with QBC and QBE, NativeSQL, Named Queries and QueryOver in NHibernate 3.0)
  • Lazy and Eager Loading
  • Debugging and Profiling (also with NHProf from Ayende)
  • Optimizations

We had more stuff for the second session like Concurrency, Auditing, Validation and Caching, but we hadn’t the time to show all these things. You can find the slides from the second session here.

The samples of both sessions are also available. If you use them commercially or for other public activities, please mention the authors (NHibernate: Patrick Weibel, EF: René Leupold). The samples for NHibernate could be found here and those for EF you find here.

Share
Categories: .NET, Private Tags:

ConfORM – Another NHibernate mapping possibility

September 1st, 2010 2 comments

I recently hold two presentations at the .Net User Group Bern (DNUG) with René Leupold about object relational mapping in the .Net world. We showed Entity Framework 4.0 and NHibernate. My part was NHibernate. You could download the slides and samples from the DNUG website.

In the two presentations I showed the mapping possibilities with hbm.xml files, attributes and Fluent NHibernate. In a previous blog post I already showed those possibilities.ConfOrmBigTransparent

During the preparations I hadn’t time to try a new way to map your entities to the database. This new way is offered by the framework ConfORM, created by one of the contributors of NHibernate Fabio Maulo.

In a previous post I showed the other possibilities how you can map your entities. In this post I show you the most simplest way I found to map the entities with ConfORM. I used for this example the version 1.0.2 (Alpha 2) of ConfORM and the version 3.0.0 Alpha 2 of NHibernate. The current version of ConfORM is available here.

Domain

The domain for this sample is quite simple. It is a one to many mapping between Order and its OrderItems. The associations is bidirectional. Below you see the class diagram of the two classes:

ClassDiagram

Database

The following ERD show the two tables Order and OrderItem in the database. Between the two tables exists a foreign key constraint. None of the fields are nullable.

database

Configuration

First, we need to declare the connection string, so that we could connect to the database. I could do it in the code, but even for a such simple example it is too dirty for me. So I added an application configuration file (app.config) and added following lines:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<connectionStrings>
		<add name="default" connectionString="Server=localhost;database=ORMSamples;Integrated Security=SSPI;"/>
	</connectionStrings>
</configuration>

Now I have a connectionstring named “default” which points to my local database ORMSamples.

When you are familiar with NHibernate, you know that you have to have a place where your session factory lives and will be created. For this purpose I normally create a class called PersistenceManager. The field factory, the property Factory and the method OpenSession are the code I would create also when I map my entities with hbm.xml files or with Fluent NHibernate or with attributes.

Where it starts to be different is the CreateConfiguration method. In this method I could create the configuration part by code. This fluent API to create a configuration is called Loquacious. Normally I would declare all this stuff in the application configuration file.

I think for a such simple application it is OK to do it like that, but I prefer the way over the application configuration file. The reason for that is, that I could configure my application for each scenario (depends on database product, etc.).

namespace ORMSamples.ConfORM.Utils
{
	public class PersistenceManager
	{
		private static ISessionFactory factory;

		private static ISessionFactory Factory
		{
			get
			{
				if(factory == null)
				{
					Configuration config = CreateConfiguration();
					factory = config.BuildSessionFactory();
				}

				return factory;
			}
		}

		public static ISession OpenSession()
		{
			return Factory.OpenSession();
		}

		private static Configuration CreateConfiguration()
		{
			var configure = new Configuration();
			configure.SessionFactoryName("Demo");

			configure.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>());
			configure.DataBaseIntegration(db =>
			{
				db.Dialect<MsSql2008Dialect>();
				db.Driver<SqlClientDriver>();
				db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
				db.ConnectionString = ConfigurationManager.ConnectionStrings["default"].ConnectionString;
				db.LogSqlInConsole = true;
				db.HqlToSqlSubstitutions = "true 1, false 0, yes 'Y', no 'N'";
			});

			configure.AddDeserializedMapping(GetMapping(), "ORMSamples_ConfORM");

			return configure;
		}

		private static HbmMapping GetMapping()
		{
			return null;
		}
	}
}

Yet I didn’t map one entity but there is an empty method GetMapping. In this method we will program our mapping in the next section.

Mapping

Below you see the completed class PersistenceManager. The implementation was created based on the example in the source code of ConfORM. The main method here is the GetMapping method. It implements a template method pattern to create the mapping.

Very important for the mapping is the method DomainDefinition. There you define your domain what means you declare all root entities. In our case it means that we have to add Order and OrderItem as root entities. For this purpose you have to call TablePerClass on the instance of the ObjectRelationalMapper class for each entity (or call it once for a collection of entities).

The patterns in ConfORM I will leave here out and come directly to the Customize method. In this method I implemented again a template method pattern. In the method CustomizeRelations I define all specialties of my entities, in the method CustomizeTables I define the DB-Schemas and finally in the method CustomizeColumns I define that the properties are all not nullable.

namespace ORMSamples.ConfORM.Utils
{
	public class PersistenceManager
	{
		private static ISessionFactory factory;

		private static ISessionFactory Factory {...}

		public static ISession OpenSession() {...}

		private static Configuration CreateConfiguration() {...}
		
		private static HbmMapping GetMapping()
		{
			ObjectRelationalMapper orm = new ObjectRelationalMapper();
			orm.Patterns.PoidStrategies.Add(new NativePoidPattern());
			Mapper mapper = new Mapper(orm);
			
			var entities = new List<Type>();

			DomainDefinition(orm);
			RegisterPatterns(mapper, orm);
			Customize(mapper);

			entities.AddRange(GetEntities());

			return mapper.CompileMappingFor(entities);
		}

		private static void DomainDefinition(ObjectRelationalMapper orm)
		{
			orm.TablePerClass(GetEntities());
		}

		private static void RegisterPatterns(Mapper mapper, IDomainInspector domainInspector)
		{
		}

		private static void Customize(Mapper mapper)
		{
			CustomizeRelations(mapper);
			CustomizeTables(mapper);
			CustomizeColumns(mapper);
		}

		private static void CustomizeRelations(Mapper mapper)
		{
			mapper.Class<Order>(cm =>
			{
				cm.Id(o => o.Id, im => im.Generator(Generators.Identity));
				cm.Bag(
					o => o.Items,
					x =>
						{
							x.Key(k => k.Column("OrderId"));
							x.Lazy(CollectionLazy.NoLazy);
						}, 
					x => { });
			});
			mapper.Class<OrderItem>(cm =>
			{
				cm.Id(o => o.Id, im => im.Generator(Generators.Identity));
				cm.ManyToOne(
					x => x.Order,
					m =>
						{
							m.Column("OrderId");
							m.Fetch(FetchMode.Join);
							m.NotNullable(true);
						});
			});
		}

		private static void CustomizeTables(Mapper mapper)
		{
			mapper.Class<Order>(cm => cm.Schema("OneToMany"));
			mapper.Class<OrderItem>(cm => cm.Schema("OneToMany"));
		}

		private static void CustomizeColumns(Mapper mapper)
		{
			mapper.Class<Order>(
				cm =>
					{
						cm.Property(x => x.OrderNumber, m => m.NotNullable(true));
						cm.Property(x => x.CompanyName, m => m.NotNullable(true));
						cm.Property(x => x.Street, m => m.NotNullable(true));
						cm.Property(x => x.PostalCode, m => m.NotNullable(true));
						cm.Property(x => x.City, m => m.NotNullable(true));
					});
			mapper.Class<OrderItem>(
				cm =>
				{
					cm.Property(x => x.Quantity, m => m.NotNullable(true));
					cm.Property(x => x.ProductId, m => m.NotNullable(true));
				});
		}

		private static IEnumerable<Type> GetEntities()
		{
			return typeof(Order).Assembly.GetTypes().Where(t => t.Namespace == typeof(Order).Namespace);
		}
	}
}

How to test it

Normally I would start with the test first, but this post is about ConfORM and not about TDD or the test first approach. To test our simple example is quite easy: You could create some CRUD-Tests. To not clutter this blog post I publish here just a Create-Test. As you can see, it’s normal NHibernate code and the whole mapping is encapsulated in the PersistenceManager class.

namespace ORMSamples.ConfORM.Test.OneToMany
{
	[TestFixture]
	public class OneToManyCRUDTest
	{
		private Order order;
		private OrderItem orderitem;

		[SetUp]
		public void SetUp()
		{
			order = new Order();
			orderitem = new OrderItem();
		}

		[TearDown]
		public void TearDown()
		{
			using(ISession session = PersistenceManager.OpenSession())
			using(ITransaction tx = session.BeginTransaction())
			{
				session.Delete(order);
				tx.Commit();
			}
		}

		[Test]
		public void TestCreate()
		{
			// Arrange
			order.OrderNumber = "12345";
			order.CompanyName = "Test Company";
			order.Street = "Hauptstrasse 1";
			order.PostalCode = "1234";
			order.City = "Zürich";
			orderitem.Order = order;
			order.Items.Add(orderitem);
			orderitem.ProductId = 234;
			orderitem.Quantity = 1;

			// Act
			using(ISession session = PersistenceManager.OpenSession())
			using(ITransaction tx = session.BeginTransaction())
			{
				session.Save(order);
				tx.Commit();
			}

			// Assert
			Assert.AreNotEqual(0, order.Id);
			Assert.AreNotEqual(0, orderitem.Id);
		}
	}
}

Conclusion

The first impression of ConfORM was that it seemed to me more complicated than Fluent NHibernate. But after a while I was able to work with. I’m sure, that I didn’t understand all implemented ideas, but the framework still in alpha so I have time to learn them.

ConfORM doesn’t say you how to manage the code where you specify your mappings like Fluent NHibernate. So, you have to be cautious not to code all your mappings in one class (as I did with the PersistenceManager). In this point I find the more stricter way of Fluent NHibernate a bit better.

The owner and contributor of ConfORM, Fabio Maulo, has react very fast as I asked him to implement the missing fetch attribute for collections. If you have questions about ConfORM, you can ask him directly via twitter or the community via the Google user group. ConfORM is definitively an interesting alternative for mapping entities in a fluent way.

Share