Saturday, June 4, 2011

This is no Domain Service

After reading this blog entry about why and how to use the command processor pattern in your service layer. While the blog post is worth reading a code example provided by Ian made me think.

public class MyFatDomainService
{
    public void CreateMyThing(CreateMyThingCommand createMyThingCommand)
    {
        /*Stuff*/
    }

    public void UpdateMyThingForFoo(FooCommand fooHappened)
    {
       /*Other Stuff*/
    }

     public void UpdateMyThingForBar(BarCommand barHappened)
     {
        /*Other Stuff*/
     }

     /*Loads more of these*/
}

The service signature looks more than a repository, we have these CRUD methods with the "create" and "update" prefix.

Is this a domain service? I don't think so...

My suggestions is to step back and ask yourself whether you need all this "best practice"/layered architecture/DDD stuff when providing API methods like create, update and delete? Are you building the next excel like business tool creating and updating cells and rows while doing a couple of validations on the input object?

And in case you really identify a domain service give the methods some semantic names :)

Tuesday, May 31, 2011

Partitioning code in namespaces

Partitioning code in namespaces will always fail in a layered architecture. Fail in a sense that you can't get a perfect partitioning!
In layered architectures we have two (and possibly more) reasonable category systems to group our code. The first is to group it by a layer fashion, that means that your UserService and your BillingService would both be in the My.Startup.Services namespace with all the pros and cons. Second system is to group classes in namespaces by their functional responsibility which means that UserService, UserRepository and User can be found in the My.Startup.Users namespace.

You can't get both in OO languages. We would need a taxonomy instead of a category system for a "perfect partition" but I would not want to work with that :)

In my daily work I avoid partitioning in a layered fashion because it's terrible to navigate, terrible to pull out functional components in reusable libraries and from design view the classes in a namespace have almost no cohesion.

Sunday, May 29, 2011

Test Doubles compacted

This post is more a personal cheat sheet and a compacted extract of Effective Tests: Test Doubles.

Test Doubles can be grouped by their interaction with the System Under Test (SUT). Satisfy dependencies without interaction, provide input to the SUT or check/record output of the SUT.

No Interaction

The role of the Dummy is to satisfy a dependency of the SUT but the dummy does not interact with the SUT.

Input

A Stub is thick as a brick and provides canned responses to the SUT.
Fakes simulate a component by providing responses based on the call history or context to the SUT.

Output

Spies record the output of a SUT and leave it to the test to verify the output.
A Mock records output and makes assertions on the output for example checks that a Order(int amount) method is called with an amount greater than0.
Mocks and Spies may also provide input to the SUT.

Do we need these terms?

Not at all. But in case a conversation in your team comes up about whether to use Stubs, Fakes, Spies, Mocks, Dummies you'll need some ubiquitous language in the testing domain to establish a discussion. I prefer to use the Mock and Stub terms to clarify if we want to check the output or to simulate some input.

For all interesting in an overview of testing and testing strategies I can recommend reading the blog series by Derek Greer at LosTechies

Sunday, November 21, 2010

Taking Decisions

This post is not a coherent text or story but a collection of thoughts about taking decisions in a software project. The idea to blog about "taking decision" arose when in one of my company's project recently everything went wrong. The lead developer disappeared (really, never seen him again!), no design documentation, we had to dig for what design was intended...
We had to get the project back on track as soon as possible. We had to take decisions!

My summarized thoughts in mantra style


There are no right or wrong decision, there are decisions suited better or worse for the current requirements.

You can evaluate the quality of a decision only in the future with changed requirements, new requirements or a fully changed environment.

If you want to take a decision in a group first step is to find and write down assessment criteria. Develop a consistent understanding of your assessment criteria.

What's worse than a bad decision is no decision.

Take requirements that are likely to be changed into consideration. If that makes your decision taking process to complex don't do it.

Using a strategy pattern is no decision. It's a deferred decision. You will have to take that decision in future.

If you stumble about the product of a worse decision in code - change your decision.

Decisions are subject of change! Accept that not all of todays decisions will not stand the test of time.

Don't be afraid to take decisions.

Don't treat decisions equal. Evaluate the impact of a decision, take time for decisions with a
high impact, take trivial decisions fast.

Communicate decisions!

Sunday, August 15, 2010

Microsoft.Data is so wrong!

Their was some rumor in the last days about microsoft addressing a developer type called "Mort" with a new Data Layer called Microsoft.Data. Mort is described by Nikhil Kothari's blog post as

Mort, the opportunistic developer, likes to create quick-working solutions for immediate problems and focuses on productivity and learn as needed. Elvis, the pragmatic programmer, likes to create long-lasting solutions addressing the problem domain, and learn while working on the solution. Einstein, the paranoid programmer, likes to create the most efficient solution to a given problem, and typically learn in advance before working on the solution. In a way, these personas have helped guide the design of features during the Whidbey product cycle.


While their were voices that addressing the Mort developer type is just plain wrong I support the idea to address Mort's way to develop on the .NET platform but I can't support the how microsoft tries to achieve this.

The how is just plain wrong! If you read the original announcement of Microsoft.Data David Fowler outlines the "pro" of Microsoft.Data by comparing these two code snippets:

using (var connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Northwind.mdf;Initial Catalog=|DataDirectory|\Northwind.mdf;Integrated Security=True;User Instance=True")) {
  using (var command = new SqlCommand("select * from products where UnitsInStock < 20", connection)) {
    connection.Open();
    using (SqlDataReader reader = command.ExecuteReader()) {
      while (reader.Read()) {
        Response.Write(reader["ProductName"] + " " + reader["UnitsInStock"]);
      }
    }
  }
}
Compared to the Microsoft.Data approach:
using (var db = Database.OpenFile("Northwind")) {
  foreach (var product in db.Query("select * from products where UnitsInStock < @0", 20)) {
    Response.Write(product.ProductName + " " + product.UnitsInStock);
  }
}

The "mental approach" of both code snippets does not fit Mort's needs! The assumption of both code snippets is: "If we want to access or store data we need to do that using SQL"! This assumption is just plain wrong!

Why bother Mort with SQL? Why should Mort learn how to prevent SQL Injections? Why should Mort be concerned about connection strings? Transactions? Why should be Mort concerned about Data modelling? And again - Why should Mort need to learn yet another language (SQL) to do just the simplest data access?

It's not the case that SQL is the best approach to store and access data objects! If we take a look at mongoDB with a mongoDB driver like NoRM or RavenDB we do not need SQL, we do not need to worry how to persist our object in an SQL server!

What I want as Mort is code like that (stolen from RavenDB tutorials)
using (var session = store.OpenSession())
{
    var order = session.Load<Order>("orders/1");
    Console.WriteLine("Customer: {0}", order.Customer);
    foreach (var orderLine in order.OrderLines)
    {
        Console.WriteLine("Product: {0} x {1}", orderLine.ProductId, orderLine.Quantity);
    }
    session.SaveChanges();
}

Dear Microsoft, don't try to hide the complexity dealing with a relational database and get the mental shift towards some (NoSQL) alternatives! And Mort will follow!

Saturday, August 7, 2010

SubSonic Custom Property Mapping Attributes

Some commits ago we opened SubSonic's property mapping attribute implementation to allow developers to extend how properties are mapped to database columns when using SimpleRepository with migrations.
In this post I'll show you how to implement a custom property mapping attribute that declares a property to be mapped to a database column of type "xml" instead of just a plain nvarchar.

Custom property mapping attributes have to inherit (obviously) from Attribute and implement the IPropertyMappingAttribute interface from namespace SubSonic.SqlGeneration.Schema.

IPropertyMappingAttribute defines the methods Accept and Apply where Accept defines if the Apply method should be invoked for this property. For our implementation we only want to accept properties of type "string". In our apply method we get an IColumn instance passed that we can modify. We can access the Table and Provider property through that IColumn instance if we need it. For our simple implementation this is not needed.

So our final implementation looks like this

public class SubSonicXmlStringAttribute : Attribute, IPropertyMappingAttribute
{
  public bool Accept(IColumn column)
  {
    return column.IsString;
  }

  public void Apply(IColumn column)
  {
    column.DataType = DbType.Xml;
  }
}

If you're using SimpleRepository with auto migratons you'll get every property marked with SubSonicXmlStringAttribute mapped to a database column of type xml. That was easy!

Saturday, July 24, 2010

SOLID Talk

Here are the prezi "slides" (what is the name for these prezi slides - prezis?)


Free to use and extend! SOLID design principles @ prezi