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

Sunday, July 18, 2010

Determining if a Property is declared virtual via Reflection

Today I was trying to determine if a property is declared virtual via Reflection but I could not find a "IsVirtual" property in the PropertyInfo class.

The solution is quite simple - a property itself is not virtual but the accessor methods have the desired "IsVirtual" property defined. This code snippet demonstrates how to determine if a property is declared virtual:

var stringType = typeof(string);
var props = stringType.GetProperties();

foreach (var prop in props)
{
  foreach (var accessor in prop.GetAccessors())
  {
    Console.WriteLine("Property {0} accessor {1} declared as virtual {2}", prop.Name, accessor.Name, accessor.IsVirtual);
  }
}

I cannot imagine a situation in c# where I can declare a property that has a virtual set method but a non virtual get method or vice versa!

If you can point me to a situation where I'm able to do this in c# I would highly appreciate that :)

Sunday, June 20, 2010

SubSonic CRUD Controller for ASP.NET MVC

I'm using SubSonic in my projects quite often because of migrations and the code first approach of Simple Repository. To make my (ASP.NET MVC 2) life easier I decided to create a simple controller base class to get CRUD functionality out of the box. To use the AbstractCrudController for a model you will need to derive from AbstractCrudController supply a SimpleRepository instance to the constructor and scaffold your views via VS templates.

The source code can be found on Github.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SubSonic.Repository;
using System.Web.Mvc;
using System.Linq.Expressions;

namespace SubSonic.Contrib.Web
{
    public abstract class AbstractCrudController<T> : Controller where T : class, new()
    {
        protected IRepository Repository { get; private set; }

  protected virtual Expression<Func<T, bool>> FilterIndex { get; set; }

        public AbstractCrudController(IRepository repo)
        {
            Repository = repo;
        }

        public virtual ActionResult Index()
        {
            var model = Repository.All<T>();
            
            if (FilterIndex != null)
            {
                model = model.Where(FilterIndex);
            }

            return View(model);
        }

        public virtual ActionResult Details(int id)
        {
            var model = Repository.Single<T>(id);

            return View(model);
        }

        public virtual ActionResult Create()
        {
            return View();
        } 

        [HttpPost]
        public virtual ActionResult Create(T entity)
        {

            if (!ModelState.IsValid)
            {
                return View();
            }

            try
            {
                Repository.Add(entity);

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
        
        public virtual ActionResult Edit(int id)
        {
            var model = Repository.Single<T>(id);

            return View(model);
        }

        [HttpPost]
        public virtual ActionResult Edit(int id, T entity)
        {
            if (!ModelState.IsValid)
            {
                return View();
            }

            try
            {
                Repository.Update<T>(entity);
 
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        public virtual ActionResult Delete(int id)
        {
            var model = Repository.Single<T>(id);
            
            return View(model);
        }

        [HttpPost]
        public virtual ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                var model = Repository.Delete<T>(id);
            
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}