Override interface mappings and creata a generic entity version filter

by Tom 20. April 2010 15:02

Introduction

For one of my customers I needed to have some kind of versioning for a whole bunch of entities on my database. Since I use my very own MvcExtensions framework, I wanted to include a functionality which would automatically filter all entities based on this interface :


    public interface IVersionAware
    {
        string Version { get; set; }
    }

In short, I only want to get the entities of the current version through my repository. This interface would then automaticly imply that all data could be filtered by setting a version filter.

I took me quite some time, but spending a weekend at the Dutch coast cleared my mind a bit, and after the weekend I managed to get it working...

The void (tm)

 

Hit the road, Jack !!

Ok, so how can we do this ?

In MvcExtensions I map my domain classes to my database in the following way :


    public class MyDomainDefinition: IDomainDefinition
    {
        public MyDomainDefinition() { }

        public Assembly DomainAssembly
        {
            get { return typeof(Model.Kit).Assembly; }
        }

        public DomainType GetDomainType(Type t)
        {
            if (t.Namespace==typeof(Model.Kit).Namespace)
                return DomainType.Class;
            else
                return DomainType.None;
        }

        //if !=null write mapping files to disk
        public string WriteHbmFilesToPath
        {
            //get { return @"c:\tmp"; }
            get { return null; }
        }
    }

This might look quite simple, but it is an extensive abstraction layer over fluent nhibernate which takes away most of the complexity, and adds a lot of functionality (bitmap storage, multilingual fields to name a few).
After looking around for some info on the net about filtering using fluent nhbernate, I found a solution: one could define a system-wide filter using the following Filterdefinition and mapping.ApplyFilter :


    public class VersionFilter : FilterDefinition
    {
        public static readonly string FILTERNAME = "MyVersionFilter";
        public static readonly string COLUMNNAME = "Version";
        public static readonly string CONDITION = COLUMNNAME + " = :" + COLUMNNAME;

        public VersionFilter()
        {
            WithName(FILTERNAME)
              .WithCondition(CONDITION)
              .AddParameter(COLUMNNAME, NHibernateUtil.String);
        }

        public static void Enable(NHibernate.ISession session, string version)
        {
            session.EnableFilter(FILTERNAME).SetParameter(COLUMNNAME, version);
        }

        public static void Disable(NHibernate.ISession session)
        {
            session.DisableFilter(FILTERNAME);
        }
    }

And this would be the code to map it for some class.


automapping.Override<SomeClassImplementingIVersionAware>(
  mapping=>
  {
    mapping.Id(x=>x.Id);
    mapping.Map(x=>x.Version).Column(VersionFilter.COLUMNAME);
    mapping.ApplyFilter<VersionFilter>();
  }

Since I do not want to call this override for each class implementing IVersionAware, I decided to create a workaround. I spent quite some time in trying to implement this, until I noticed why my workaround was not working: there was a (small bug) in the fluentnhibernate framework.
So I forked fluentnhibernate, fixed the bug, and sent a pull request to the fluentnhibernate guys, and Paul Batum reported to me that my bugfix will be integrated into the next merge, together with some unit tests. For now, you can get the fixed sourcecode from my github version.

... And don't you come back no more....

So, after fixing this, I could get to work again. Since I first tried using IAlterations and Overrides for fluent nhibernate, but all were failing due to the bug, I finally got to this code (which worked after I fixed the bug in fluent nhibernate):


    public static class AutoPersistenceModelExtensions
    {
        public static AutoPersistenceModel OverrideInterface<I,C>(this AutoPersistenceModel model
            , IEnumerable<Type> MyTypes)
            where C:IInterfaceMap<I>,new()
        {
            var modeloverride = model.GetType().GetMethod("Override");
            var interfacemap = new C();
            var cm = typeof(C).GetMethod("Map");
            foreach (var t in MyTypes.Where(x => typeof(I).IsAssignableFrom(x)))
            {
                var act = cm.MakeGenericMethod(t).Invoke(interfacemap,null);
                modeloverride.MakeGenericMethod(t).Invoke(model, new object[] { act });
            }
            return model;
        }
    }

    public interface IInterfaceMap<I>
    {
        Action<AutoMapping<T>> Map<T>() where T:I;
    }

This extension method allows you to override the mappings for interface fields in a very simple way; here is the example for the IVersionAware interface:


    public class VersionAwareInterfaceMap : IInterfaceMap<IVersionAware>
    {
        public Action<AutoMapping<T>> Map<T>() where T : IVersionAware
        {
            return mapping =>
                {
                    mapping.Map(x => x.Version).Column(VersionFilter.COLUMNNAME);
                    mapping.ApplyFilter<VersionFilter>();
                };
        }
    }

And in the MvcExtensions database bootstrapper, I would call this :


        protected Database(IPersistenceConfigurer pcfg, IDomainDefinition mappings)
        {
             // some stuff deleted because it is not relevant here
            var cfg = Fluently.Configure()
                .Database(pcfg)
                .Mappings(m => {
                    var am1 = AutoMap.Assembly(mappings.DomainAssembly)
                        .Where(t => clsmaps.Contains(mappings.GetDomainType(t)))
                        // some stuff deleted because it is not relevant here
                        );
                    var types = mappings.DomainAssembly.GetTypes().Where(x =>
                                typeof(IVersionAware).IsAssignableFrom(x) &&
                                mappings.GetDomainType(x) != DomainType.None);
                    if (types.Count()>0)
                    {
                        am1.OverrideInterface<IVersionAware,VersionAwareInterfaceMap>(types);
                        am1.Add(new VersionFilter());
                    }
                        // some stuff deleted because it is not relevant here

                })
                .BuildConfiguration();
            // some stuff deleted because it is not relevant here
        }

... No more ....

In order to filter my data I would call this :


VersionFilter.Enable(sUnitOfWork.Session,"v1.3.2");

And disabling it again goes like this :


VersionFilter.Disable(sUnitOfWork.Session);

That's all there is to it; all entities implementing the IVersionAware interface will be automatically filtered if you do set the filter....

For a full version you can check out the sourceode over at github.

If you have any questions or remarks, do not hesitate to post them...

Enjoy

Bookmark and Share

Tags: , , , , , , ,

CodeProject | Development | Howto | News

"Var keyword is for JavaScript" - about using the var keyword & other coding guidelines

by Tom 31. March 2010 04:28

Introduction

Today I was reading an article on Codeproject, and I was really astounded by the way some people rate articles and give comments...

It was an article about someone who had implemented a simple service locator which contained the following code sample :


using System;
using CuttingEdge.ServiceLocation;
using Microsoft.Practices.ServiceLocation;

public class Global : System.Web.HttpApplication
{
  protected void Application_Start(object sender, EventArgs e)
  {
     // 1. Create a new Simple Service Locator container
     var container = new SimpleServiceLocator();

     // 2. Configure the container

     // Register a delegate that will create a new
     // instance on each call to GetInstance.
     container.Register<ISamurai(() =>
     {
        var weapon = ServiceLocator.Current .GetInstance();
        return new Samurai(weapon);
      });

      // Register a single object instance that always
      // be returned (must be thread-safe).
      container.RegisterSingle(new Katana());

      // 3. Register the container to the Common Locator
      ServiceLocator.SetLocatorProvider(() => container);
    }
}

Which seems quite obvious to me. Since I noticed a comment titled 'my vote of 2', I was curious why this article would be voted such a low score (2 out of 5). I checked the comment and I was astounded:

Please note: the keyword "var" is supposed to be used with anonymous types. You should not use it for anything else. Otherweise please start
programming java script

Who cares ?

Actually, I do.

Since I could not resist I posted the following comment:

Ahum... there have been numerous issues about this, but in general it should not pose a problem, because it is quite clear what it's intentions are at the beginning; i.e. :

var sl = new SimpleServiceLocator();



Is not really more obvious then :

SimpleServiceLocator sl = new SimpleServiceLocator();



In fact, the information in there is the same, but the second one is more verbose, so every person in his right mind would opt for the first alternative.
This might be different if you use a function which does not directly expose the return type in the function name; i.e. :

var x = SomeFunction(y,z);



This is considered bad practice by most.

This one is not :

var myservice = sl.Resolve<IMyService>();



Because the initialization contains enough obvious info to give pointers to the var's type.

So, if this is the only reason why you are giving a 2 (the author has obviously invested quite some time in this article), then you might need to start doing some JavaScript yourself

 

After tweeting about this, I had an interesting conversation with @JacoPretorious about this, who says he uses var everywhere, but pays more attention to variable names.

While I understand what he means, IMHO variable names should not infer the type, only the meaning of the content if necessary.

I personally think there is nothing wrong with using single letters as variable names, as long as the intent is obvious. This is an example that is perfectly valid imho :


public bool InvalidateCustomer(int CustomerId)
{
  var c = sRepo.GetById<Customer>(CustomerId);
  if ( c.Orders.Where(o=>o.PaymentReceivedOn==null).Any())
    return false;
  c.Valid=false;
  sRepo.SaveOrUpdate(c);
  sUOW.Commit();
  return true;
}

This one is not IMO :


public class MyProcessQueue
{
  public void ProcessQueue()
  {

    for(;;)
    {
       var p = Queue.Next();
       if (p==null)
         break;
       sProcessor.Process(p);
    }
  }
}

Since you can not infer the type from Queue, you should make the type explicit :


public class MyProcessQueue
{

  public void ProcessQueue()
  {

    for(;;)
    {
       Order o = Queue.Next();
       if (o==null)
         break;
       sProcessor.Process(o);
    }
  }
}


This would change if the MyProcessQueue would be a generic class :


public class MyProcessQueue<T> where T:ISomeInterface
{
  public void ProcessQueue()
  {

    for(;;)
    {
       var p = Queue.Next();
       if (p==null)
         break;
       sService.Process(p);
    }
  }
}



In this case, I think you have enough information available to know that the type should be about the generic class. Using more explicit names for the variables does not add a lot info for me; I do not find the following (exagerated) example more abvious than the previous one; in fact, it takes more time to get the intent here, because your mind needs to process more information (also note the comments, which do not provide any extra info to me) :


public class MyProcessQueue<T>
  where T:ISomeInterface

  // Process all jobs in the queue, until there is nothing left  
  public void ProcessAllISomeInterfacesInTheQueue()
  {
    // loop forever
    for(;;)
    {
       // get the next instance to process from the queue; 
       // if it returns null there are no more processes left on the queue 
       ISomeInterface TheNextISomeInterfaceInstanceToProcess = Queue.Next();

       if (TheNextISomeInterfaceInstanceToProcess==null)
       {
          //exit the infinite loop 
         break;
        }
       // process it 
       sServiceThatProcessesSomeInterfaceInstance
          .Process(TheNextISomeInterfaceInstanceToProcess);
       // go to the next one
    }
   // return 
  }
}

There is way too much info here which can all be easily derived from the code, and if you change the code and forget the comments, this might actually do the opposite: cause confusion.

In conclusion

While this is all about preference and highly dependent on you point of view and background, I do think that the approach I am personnaly using is one of the better ones. They offer all the amount of information that you could need with the minimum amount of code.

If you do have another opinion, do not hesitate to let me know...

 

Bookmark and Share

Tags: , , ,

CodeProject | Development | Howto | News

Screencast: Build an Asp.net MVC application quickly using MVCExtensions

by Tom 29. January 2010 20:16

Introduction

This is my first screencast for my MVCExtensions project, it shows you how to get started and build a simple tasklist.

PS: This is the direct link to the powerpoint used:
http://docs.google.com/present/view?id=dgt3mk3c_6fmhrd9c5

Some background info

This was my first screencast, and it took me about 7 attempts to finally get it to a point where it was more or less acceptable. For my sixth and seventh attempt I finally found some good screencap software : BBFlashback Express.

Anyway, this has been an interesting experience, and now enjoy mvcextensions !!!

More...

Tags: , , , , ,

CodeProject | Development | Howto | News

Howto+why using a prototype & bdd for a project estimate + personal rant

by Tom 22. December 2009 13:57

Introduction

As you might or might not now, estimating the budget for a project can be very hard sometimes. In order to get started on a project we first need a real estimate of what the client will need, and the client should know what I am going to deliver to him/her.
What I personally learned from the past is that one can never be fine-grained enough, since there will always be mismatches somewhere.

We can however try to offer the client something that he/she can both understand and work with, next to a description of what everything should do (from a business point of view).

How can we do this, while investing as little work as possible ?

 

Unfortunately one can not correctly estimate projects without doing some work

As straightforward as this might seem, most people do not seem to be able to grasp this ( do not be ashamed; I have been guilty as well ).

In order to give a correct estimate, you have to INVEST a decent amount of TIME.

More...

Tags: , , , , ,

CodeProject | Development | Howto | News | Tom's blog

Published a new Article on CodeProject : Getting started with BDD + new version of aubergine

by Tom 9. November 2009 06:39

Hi again,

I just published a brand new article on CodeProject : Getting started with BDD.

I also modified my Aubergine Framework a bit by adding a new feature : automatic case-insensitive DSL enum conversion.

You can download the latest version here (it also contains  the example for codeproject )

 

Aubergine_v0.04.zip (18,72 kb)

Enjoy !!

Edit

Since the article state on CodeProject is still "Pending", I simply posted it in the pages section of this blog; you can read it here.

Edit #2

v0.05 is released !!

Bookmark and Share

Tags: , , , , , , , ,

CodeProject | Development | Howto | Tom's blog

w00t : Building a new app from the ground up : IOC, database and other stuff; a real framework

by Tom 20. October 2009 05:04

This is one of the articles in our series; the parts are:

  1. Methodology, technology & tools used
  2. Setting up the environment
  3. First specs and getting started
  4. IOC, database and other stuff; a real framework 

 Happy reading !

Finally a framework !

 When I went to bed last night, I was thinking about a few things, so I said to myself : "Ok, I'll quickly implement them". But, as one can expect, a few minutes became a few hours, so in the end I did not get much sleep. I decided to finish it this morning, so the now the main stuff of the framework is finsished, and I'll write a little post about this.

 

Back to the drawing board

After taking a closer look at simplerepository to know the domain model conventions I noticed that the support for relationships was a mess (i.e. you have to join data yourself using Id's etc, so I decided to go back to the one thing I know : fluent nhibernate.

In the mean time my specs were constantly evolving… It lead me to do a complete refactoring of my code; you can see the current state of the spec in the end :

 

Delete subsonic and get FluentNhibernate, Nhibernate.Linq and Castle.Windsor

1. In the project folder, delete the folder "SubSonic-3.0"
2. Start a git bash in the project folder, and type :
git clone git://github.com/jagregory/fluent-nhibernate.git
3. look for fluentnhbernate.csproj and build it (make sure the configuration mode is set to release)
4. look for machine.Specifications.sln and build it
5. Change the batch file tools\copydependenciesandtools.cmd to the following : 

@Echo off
echo.
echo   Copying all tools and dependencies
echo.
copy ..\machine.Specifications\Build\Release\*.dll
copy ..\machine.Specifications\Build\Release\*.exe
copy ..\machine.Specifications\Build\Release\*.dll ..\lib\*.*
copy ..\fluent-nhibernate\src\FluentNHibernate\bin\Release\*.dll ..\lib\*.*
pause
6. execute tools\copydependenciesandtools.cmd
7. execute tools\cleanup.Cmd
8. Download Castle.Windsor for IOC and put the dll’s in the lib folder
9. Download NHibernate.Linq and put the dll’s in the lib folder

Setup your business logic project

11. Creat a new class lib project and name it “xxx.Core”
12. Add references to the following libs in both your specs project and your Core project :
..\lib\Castle.Core
..\lib\Castle.MicroKernel
..\lib\Castle.Windsor
..\lib\FluentNHibernate
..\lib\NHibernate
..\lib\NHibernate.ByteCode.Castle
..\lib\NHibernate.Linq
..\lib\System.Data.SqlLite
..\lib\System.Data.SqlLite.Linq

Add the core project as a  ref to your specs project .

13. Create your model classes according to the fluentnhbibernate conventions. An example :


  // models\_ModelBase.cs
//
// the abstract base class for the domain objects
//
namespace Be.HorecaTouch.Core.Models
{
    public abstract class ModelBase
    {
        public virtual int Id {get;set;}
        public virtual string Description { get; set; }
    }
}
// models\Product.cs
//
// a product
//
namespace Be.HorecaTouch.Core.Models
{
    public class Product : ModelBase
    {
        public virtual int Number { get; set; }
        public virtual ProductGroup Group { get; set; }
        public virtual bool Available { get; set; }
        public virtual bool PrintOutToReceipt { get; set; }
        public virtual bool PrintOutToKitchen { get; set; }
        public virtual string CourseName { get; set; }
        public virtual bool NonProfit { get; set; }
        public virtual ICollection<Lookup> Lookups { get; set; }
        public virtual int SellingPrice1 { get; set; }
        public virtual int SellingPrice2 { get; set; }
        public virtual int SellingPrice3 { get; set; }
        public virtual int SellingPrice4 { get; set; }
        public virtual int SellingPrice5 { get; set; }
    }
}"font-size: 10pt; font-family: 'Courier New'">

14. After this I created the interfaces in the core project :


// Interfaces \ IIOC.cs
namespace Be.HorecaTouch.Core.Services.Interfaces
{
    public interface IIOC
    {
        T Resolve<T>();
        T Resolve<T>(string name);
    }
}
// interfaces\IRepository.cs
namespace Be.HorecaTouch.Core.Services.Interfaces
{
    public interface IRepository<T> where T:Models.ModelBase
    {
        T GetById(int id);
        IQueryable<T> Find { get; }
        void SaveOrUpdate(T instance);
        void Delete(T instance);
    }
}
// interfaces\IUnitOfWork.cs
namespace Be.HorecaTouch.Core.Services.Interfaces
{
    public interface IUnitOfWork : IDisposable
    {
        void Commit();
        Dictionary<string, object> SessionVars { get; }
    }
}
// interfaces\IUnitOfWorkFactory.cs
namespace Be.HorecaTouch.Core.Services.Interfaces
{
    public interface IUnitOfWorkFactory
    {
        IUnitOfWork CurrentUnitOfWork {get;}
    }
}
// interfaces\IUnitOfWorkFactory.cs
namespace Be.HorecaTouch.Core.Services.Interfaces
{
    public interface IXmlAdapter
    {
        void Import(string xml);
    }
}"font-size: 10pt; font-family: 'Courier New'">

15. Implement concrete classes that implement the interfaces


//implementations\database.cs
//
// Automaticly creates an sqllite db based on the classes in the Models namespace.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Automapping;
using Be.HorecaTouch.Core.Models;
using Be.HorecaTouch.Core.Services.Interfaces;
using NHibernate.Tool.hbm2ddl;
namespace Be.HorecaTouch.Core.Services.Implementations
{
    public abstract class Database : IUnitOfWorkFactory
    {
        protected ISessionFactory SessionFactory;
        protected static ISession LocalSession;
        protected Database(IPersistenceConfigurer pcfg)
        {
            var cfg = Fluently.Configure()
            .Database(pcfg)
            .Mappings(m => m.AutoMappings.Add(
                AutoMap.AssemblyOf<Product>()
                .IgnoreBase<ModelBase>()
                .Where(am => am.Namespace == typeof(Product).Namespace)))
                .BuildConfiguration();
            SessionFactory = cfg.BuildSessionFactory();
            LocalSession = SessionFactory.OpenSession();
            new SchemaExport(cfg).Execute(false, true, false, LocalSession.Connection, null);
        }
      

 

        #region IUnitOfWorkFactory Members
        public virtual IUnitOfWork CurrentUnitOfWork
        {
            get {
                LocalSession = null;
                return new UnitOfWork(()=>SessionFactory.OpenSession(),true,false );
            }
        }
        #endregion
    }
    public class SqlLiteInMemoryDatabase : Database
    {
        public SqlLiteInMemoryDatabase() : base(SQLiteConfiguration.Standard.InMemory())
        {
        }
        public override IUnitOfWork CurrentUnitOfWork
        {
            get
            {
                return new UnitOfWork(() => LocalSession, false, true);
            }
        }
    }
    public class SqlLiteDatabase : Database
    {
        public SqlLiteDatabase(string filename) : base(SQLiteConfiguration.Standard.UsingFile(filename))
        {
        }
        public override IUnitOfWork CurrentUnitOfWork
        {
            get
            {
                return new UnitOfWork(() => SessionFactory.OpenSession(), false, false);
            }
        }
    }
}
// implementations\IOC.cs
//
// use the default castle windsor IOC container
//
using Be.HorecaTouch.Core.Services.Interfaces;
namespace Be.HorecaTouch.Core.Services.Implementations
{
    public class IOC : Castle.Windsor.WindsorContainer, IIOC {}
}
// implementations\Repository
//
// a generic repository for nhibernate
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Be.HorecaTouch.Core.Services.Interfaces;
using FluentNHibernate;
using NHibernate.Linq;

namespace Be.HorecaTouch.Core.Services.Implementations
{

    public class Repository<T> : IRepository<T> where T:Models.ModelBase
    {
        NHibernate.ISession session;
        public Repository(Database db)
        {
            session = ((UnitOfWork)db.CurrentUnitOfWork).Session.Instance  ;
        }

        #region IRepository<T> Members
        public T GetById(int id)
        {
            return session.Get<T>(id);
        }
        public IQueryable<T> Find
        {
            get { return session.Linq<T>(); }
        }

        public void SaveOrUpdate(T instance)
        {
            session.SaveOrUpdate(instance);
        }
        public void Delete(T instance)
        {
            session.Delete(instance);
        }
        #endregion
    }
}

So what is the Result until now ?

Now you have a fully setup environment with an (inmemory/file) database for your domainmodel,  acessible with a generic iRepository. All your service interfaces are available through an IOC, and your data can be easily persisted…

Your development can now also be driven by specs

Adjust the spec file to your likings;this is currently mine :


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Machine.Specifications;
using Be.HorecaTouch.Core.Models;
using Be.HorecaTouch.Core.Services.Interfaces;
using Be.HorecaTouch.Core.Services.Implementations;
namespace Specs
{
    public abstract class with_empty_database
    {
        protected static IIOC ioc;
        Establish context = () =>
            {
                var cont = new IOC();
                cont.AddComponent<Database, SqlLiteInMemoryDatabase>();
                cont.AddComponent<IRepository<Product>,Repository<Product>>();
                cont.AddComponent<IRepository<Lookup>, Repository<Lookup>>();
                cont.AddComponent<IXmlAdapter, XmlAdapter>();
                ioc = cont;
            };
    }
    public class when_products_are_imported_from_external_xmlfile : with_empty_database
    {
        Because of = () => ioc.Resolve<IXmlAdapter>().Import(Properties.Resources.ExternalProductsXml);     
        It should_contain_multiple_products = () =>
            ioc.Resolve<IRepository<Product>>().Find.Count().ShouldBeGreaterThan(0);
     
        It should_have_a_product_called_steak_with_cooking_and_sauce_lookups = () =>
            ioc.Resolve<IRepository<Product>>().Find
                .Where(a => a.Description == "Steak").Count().ShouldBeGreaterThan(0);
        It should_contain_multiple_lookups = () =>
            ioc.Resolve<IRepository<Lookup>>().Find.Count().ShouldBeGreaterThan(0);      
        It should_contain_multiple_cookings;
        It should_contain_multiple_courses;
    }
    public abstract class with_filled_database : with_empty_database
    {
        Establish context = () =>
            {
                ioc.Resolve<IXmlAdapter>().Import(Properties.Resources.ExternalProductsXml);

            };
    }
"font-size: 10pt; font-family: Arial">}

Finally, this is what my current Spec build html looks like :

Specs    

1 concern, 1 context, 5 specifications, 2 not implemented specs

 



specifications    

1 context, 5 specifications, 2 not implemented specs

when products are imported from external xmlfile    

5 specifications, 2 not implemented specs

 

  • should contain multiple products
  • should have a product called steak with cooking and sauce lookups
  • should contain multiple lookups
  • should contain multiple cookings< NOT IMPLEMENTED
  • should contain multiple courses< NOT IMPLEMENTED

 


Conclusion

Et voila, in a few easy steps we have created a framework which offers quite some advantages, and should be easy to extend... and is BDD (hype hype hype !!) I do not offer the holy grail however, so always make sure you adapt the code to your wishes.

Since blogging about this does take quite some time, and the development now becomes really specific, I think this will probably be my last post about this new project, but he, never say never !!!

Maybe if I have some issues regarding MVC testing I might blog about it, but I can not guarantee anything... Happy coding !!<-->

Bookmark and Share

Tags:

CodeProject | Development | Howto | Tom's blog

w00t : Building a new app from the ground up : First specs and getting started

by Tom 19. October 2009 09:21
This is one of the articles in our series; the parts are:
  1. Methodology, technology & tools used
  2. Setting up the environment
  3. First specs and getting started
  4. IOC, database and other stuff; a real framework 

 Happy reading !

Automating specs 

Ok, this step took quite some time to figure out, but once you know how to do this this should be really simple.

1. Open the solution and go to the properties of the Specs project
2. Go to the build events, and put the following text in the post-build event command line :

del "$(TargetDir)*.html"
"$(ProjectDir)..\..\tools\Machine.Specifications.ConsoleRunner.exe" "$(TargetPath)" --html $(TargetDir) 
ren "$(TargetDir)$(TargetName)*.html" output.html
"$(TargetDir)output.html"
exit 0 

This will make sure that everytime you do a build, the old Mspec html file  gets deleted, mspec is ran, and the html is renamed to output.html and shown in your default browser.

Please do note that as long as you have the browser open, you build will not be considered finished, so you should close this window in order to continue developing.
Another possibility would be to build the html file somewhere in your project path, and add it to the project, so you can load it in your project each time, and get a message if it has changed.

3. Add a reference to ..\lib\Machine.specifications.dll
4. Remove the bogus class and start writing your specs.

Regarding this part there might be some discussions. I created a file called ProductSpecs.cs, which has the following content :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Machine.Specifications;
namespace Specs
{
    public class Product { };
    public interface IRepository<T>
    {
        IQueryable<T> Find {get;}
        bool Add(T instance);
        bool Delete(T instance);
        bool Update(T instance);
    }
    public interface IUnitOfWork : IDisposable 
    {
        void Commit();
    }
    public interface IProductRepository : IRepository<Product>
    {
         ICollection<Product> GetFromXml(string xml);
    };
    public abstract class with_empty_productlist
    {
        protected static IProductRepository productrepo;
        protected static ICollection<Product> products;
        Establish context = () => 
            {
                products = new List<Product>();
            };
    }
    public abstract class with_productlist : with_empty_productlist
    {
        Establish context = () =>
        {
            products = new List<Product>();
            products.Add(new Product());
            products.Add(new Product());
            products.Add(new Product());
        };
    }
    public class when_products_are_imported_from_external_xmlfile : with_productlist
    {
        Because of = () => products = productrepo.GetFromXml(Properties.Resources.ExternalProductsXml);
        It should_contain_xx_products;
        It should_have_an_article_matching_xx;
    }
}

So as you might see I added some of my code to be in order to be able to start writing some code in my specs; the next thing I am going to do is write code to match these simple specs, and move the respective app code in a proper project of it's own.

Once this is finished, I am going to extend my specs to match a bigger part of the scope...

I'll keep you all posted !!

Bookmark and Share

Tags:

CodeProject | Development | Howto | Tom's blog

w00t : Building a new app from the ground up : setting up the environment

by Tom 19. October 2009 07:34
This is one of the articles in our series; the parts are:
  1. Methodology, technology & tools used
  2. Setting up the environment
  3. First specs and getting started
  4. IOC, database and other stuff; a real framework 

 Happy reading !

Ok, here are the steps to setup the development environment for my new project :

Prerequisites

 

The steps

1. Create a project folder
2. Start Git bash on this folder (right click in windows explorer)
3. Get MSpec : type in git bash :

git clone git://github.com/machine/machine.specifications.git

4. Get Subsonic : type in git bash :

git clone git://github.com/subsonic/SubSonic-3.0.git 

5. Search for Subsonic.Core.csproj and build it
6. Search for Machine.specifications.sln and build it
7. Make a folder Tools in the project folder
8. Make a folder Lib in the project folder
9. Make a folder Source in the project folder
10. In the folder Tools create a file named "CopyDependenciesAndTools.cmd" with the following content:

@echo off
echo.
echo   Copying all tools & dependencies
echo.
copy ..\machine.Specifications\Build\Release\*.dll
copy ..\machine.Specifications\Build\Release\*.exe
copy ..\machine.Specifications\Build\Release\*.dll ..\lib\*.*
copy ..\machine.Specifications\Build\Release\*.dll ..\lib\*.*
copy ..\subsonic-3.0\lib\*.dll ..\lib\*.*
copy ..\subsonic-3.0\subsonic.core\bin\release\*.dll ..\lib\*.*
pause

11. Execute this cmd-file
12. Make another cmd file in the tools-folder : "CleanUp.cmd" with the following content:

@Echo off
echo.
echo   Cleaning up
echo.
dir /ad /b /s ..\bin > folderstodelete.txt
dir /ad /b /s ..\obj >> folderstodelete.txt
dir /ad /b /s ..\build >> folderstodelete.txt
for /f %%i in (folderstodelete.txt) do rd %%i /s /q
pause

13. Execute it
14. Start up Visual studio and create a new ASP.NET MVC 2 application in the src folder (make sure the checkbox create directory for this solution is off)
15. Once the project is created choose File/New project / Windows/Class library, name it "Specs", and make sure you choose the option "Add to solution"
16. Save and close visual studio
17. Execute "Tools\CleanUp.Cmd"

15. Go back to the Git Bash and type (line by line, do not copy and paste this in one block):
git init
git add .
git commit -m "+ Initial commit"


That's all there is to  it; our initial setup. In the next post we'll get started writing specs !!

Bookmark and Share

Tags:

CodeProject | Development | Howto | Tom's blog

w00t : Building a new app from the ground up : methodology, technology & tools used

by Tom 19. October 2009 03:45

This is one of the articles in our series; the parts are:

  1. Methodology, technology & tools used
  2. Setting up the environment
  3. First specs and getting started
  4. IOC, database and other stuff; a real framework 

 Happy reading !

Introduction

Since I have always been very interested in the latest technology developments, and I needed to start a new and initially very simple project, I decided to do some studying and opt for new things...
After reading quite some articles, I decided to write about my experiences in my blog, in order to learn some things about my experiences, and even help you decide on some aspects...

If you disagree in any way with my opinions, or have some interesting suggestions please comment, since I am always eager to know about the opinion of somebody else.

 

Methodology : the paradigm shift

Since my programming in TRS-80-basic as a 7-year old, a lot has changed... This is an overview of my personal evolution :

Procedural programming

Initially I got started with BASIC, since it was the most understandable development platform at the time, very easy to get started with. A few years later, I had been developing in MASM, Turbo Pascal and even C-- in the demoscene (only limited tracks available), all choices that opted my preference for execution speed, before I really entered my next level of programming consciousness...

Object oriented programming

Since I had been a hardcore developer in the demo-scene, most OO-concepts were a stranger to me (speed was king)... It has only been a few years later in my professional carreer that the advantages of OO were becoming obvious to me. Unfortunately, until then I reinvented the wheel for just about each problem I had, since I never heard about the next part..

Design patterns

After hearing about factories, services, command patterns, all kinds of interfaces etc. I decided that that was the next thing for me, so I started studying the GOF design patterns, Martin Fowler's blog and all kinds of reference material that I could find. Slowy some of the more interesting concepts were getting to me, but in the meantime there was a new buzz on the development scene...

Unit testing

What's that ? Testing your code by programming tests as well ? Although I read a lot about this subject, it never seemed to be able to convince me, since i was more of a fan of the higher level automated testing, aka

Functional/acceptance testing

I allready used this from the beginning on, I wrote programs that did some kind of black box testing, before tools like Fitnesse were available by means of simple input/output. This seemed more usefull then writing unit tests. Until now : the next buzz

Behavior driven development

Finally something that replaces the ubiqutous unit tests with a more interesting approach, write in "business language" what a program has to do, and implement that in code afterwards.. Since I am quite new to this I expect that I will have some problems on the go, so I will share them with all of u in the future..

 

Technology

Regarding the technology : my choice is quite simply based on my experience :

Development platform  : ASP.Net MVC / C#

2 very simple reasons : It needed to be web-based, and I have had lots of experience with  this platform since the early betas. (The design of ASP.NET MVC also encourages seperation of concerns.)

DB/ORM : Subsonic SimpleRepository

On the database part I am not quite sure yet, but I think a good ORM should not make me obliged to keep using the same DB after all, so I think I will use SqlLite initially, but switch later on to a better one. Strict POCO is not a necessity for me
Since I have no interest whatsoever on the db part, I think i have to choose between 2 options :

While I have been using FluentNhibernate in the past, I have a gut/good feeling about Subsonic SimpleRepository, so I will initially probably start with the second one. Since I wil be using an interface anyway I should be able to switch between two versions quite quick.

IOC container : Castle Windsor

Since I have no idea about an IOC container, I will probably use the one I have the most experience with : Castle Windsor.

BDD : MSpec

Because I am new to this mather,I will choose the one that got me interested in this : MSpec.

 

Tools

There is only a very limited list of extra tools I need :

IDE

For the programming/web design : Visual studio. For the initial SqlLite management I will use SqlLiteAdmin.

Source control

No doubt about this : GIT .
Because of :

  • Atomic commits
  • Ease to setup
  • Ease to do branching/merging/pulling other sources etc

 You can read more about this in my other blog article.

Timetracker

Even though this is not a project that I can bill by the hour, I like to keep track of the hours I invested in this. Here I simply use google calendar, as I do for all my customers. I even wrote an article about this here.

Summary

Those are the inital choicesI have made. I will now setup my development environment and I'll keep you all posted on my blog (articles with tag w00t ).

Bookmark and Share

Tags:

CodeProject | Development | Howto | News | Tom's blog

To git or not to git - Source control done right / intro and quick tutorial

by Tom 6. May 2009 06:35

Introduction 

Source control has always been a really annoying issue for me, since it was either :

  • Too complicated too manage
  • Too restricted
  • Too slow
  • Too much a hassle to setup
  • Badly integrated
  • One or more of the above

I have been working with Subversion/TortoiseSVN for a little while, but I was noticing that I really had to force myself into using the source control repository. A few times in the last month I noticed that I did not do enough commits, forcing me into re-implementing stuff again. I was also lacking a very good diff tool to compare different versions

I have been looking for different alternatives every now and then, but without much success, until recently...

The holy grail : git

I found git.
Getting started with git has been a real pleasure. Setup/Commits/history checking is all really easy with git. As a proof of concept I will show you a small walkthrough in a Windows environment.

1. Download (g)it

Download the windows version from here : http://code.google.com/p/msysgit/downloads/list
(I downloaded the latest preview.)
Use the default install.

2. Create git repository

Start windows explorer; right click on the source folder and choose "Git Bash here".
You will then get a unix-like prompt. Now type

$ git init
$ git add .
$ git commit -m "Initial checkin"
$ exit

That's it. You can now start modifying your code as you wish.

3. Save/check in changes, a.k.a. commit 

Start windows explorer; right click on the source folder and choose "Git GUI here". A new app will start.

On the left side you will see what changes are available : staged and unstaged changes. If you do not see any files here this means that you have not changed anything since the last commit. Go ahead and change something.
You can leave this window open, and just press the "Rescan" button to refresh in order to look for changed files.

You can click on any of the listed changes to see the details. If a change is sourcecode that has been changed you will see the lines that are removed in red, and the lines that are added in green.

Only files that are listed in the "Staged changes" box will be commited on pressing commit.
You can stage a file (make it committable) by clicking on it, and pressing CTRL-T (or commit/stage in the menu).

If you have all your files that you want to commit in the "Staged changes" box, you just need to enter a short description i.e. "* fixed bug abc", and press the "Commit" button. That's it, your changes are checked in.

A small remark :
I personally use the following description convention:
- "+" if I add something (feature)
- "*" if I change something (bugfix etc)
- "-" if I remove something (redundant code)

So the history will basicly look like this after three commits :

+ Webdav support implemented
* illegal exception when deleting a non-empty folder
- Removed Log4Net
4. View commit log

If you want to view the commit log, you can do it like this :

Start windows explorer; right click on the source folder and choose "Git Bash here". Then type :

$ git log

You will get a long alphanumeric key and the description. An example :

commit 4f62ca99c026e0c7ee2bd2beb8f39f232c0d6072
Author: Tom Janssens <Tom@xx>Date:   Wed May 6 11:04:55 2009 +0200
    Installer fix
commit 6f8a7888b223d9aee7adbef105aca9a0adc8eb11
Author: Tom Janssens <Tom@xx>Date:   Wed May 6 10:53:32 2009 +0200
    Make sure necessary DLL's are deployed to the build folder
commit a289f8a70b961f83110c96a91e9ed97edb900909
Author: Tom Janssens <Tom@xx>Date:   Wed May 6 10:28:53 2009 +0200
    Inital checkin from http://xx.unfuddle.com/svn/xx_htm/tags/v1.3.0.3404/

 

5. Check out a version

If you want to check out a certain version, you you must know the commit code from the log (step 4). You can then check out a version by typing

$ git checkout XXXXXXX

Where "XXXXXXX" is the first few characters of the commit code in the log. Since this is not very user friendly, we can fix this by tagging :

6. Tag a version

If you have a version that is to be publicly released you can tag it. Later on you can reference to this version with this tag. You can create a tag like this :

Start windows explorer; right click on the source folder and choose "Git Bash here". Then type :

--- create a tag :
$ git tag v1.2.3.4 
--- delete a tag :
$ git tag -r v1.2.3.4
--- show differences between the current version and a tagged version (type ":q" to quit):
$ git diff v1.2.3.4
--- check out the tagged version (do not forget to commit your current changes first) :
$ git checkout v1.2.3.4 .
--- check out the last version
$ git checkout .
$ exit

7. Branching and merging(advanced)

Basicly branching allows you to have different versions of the source simultaneously (for example specific code for a client).
By default you start in a branch called "master".

To create a new branch called "experimental" we type the follwing in the git console:

$ git branch experimental

You can checkout code from different branches like this :

$ git checkout experimental
$ git checkout master

If you want to merge you current branch (master) with code from another branch (experimental) you can do it like this:
$ git checkout master
$ git merge experimental

If you want to undo this:
$ git reset

Update :

Appearantly it is not advised to do any work on the master branch, so you should always create a branch for everything you do. There is however a very helpfull command : "stash".
Suppose you are working on a branch, but would like to switch to another branch without commiting your changes, and getting back later to the original branch :
$ git checkout experminental
-- some changes, until someone wants you to adjust something on the master branch
$ git stash
$ git checkout master
-- do your stuff
$ git commit -m "some stuff"
-- go back to the last state of the experimental branch, including non-commited files
$ git checkout experminental
-- apply the master changes to the experimental branch :
$ git pull master

There is a lot more to this, but this should get you started.

8. Other tools

There are a lot of ins and outs in git that I do not know about, but these should cover the basics. To get help just type the following in the git console :

$ git help

In conclusion

While this was meant to be a really short introduction to git, it seems to be longer then intially planned. However, I am hoping that this article is helping people considering to switch to git, or looking for a simple source control system.

For me, the answer to "To git or not to git", is definately "to git"

Bookmark and Share

Tags: ,

Development | Howto | Tom's blog | CodeProject

About me

Tom Janssens op LinkedIn

Tom Janssens op twitter

Core bvba RSS

My name is Tom Janssens and I am the owner of Core bvba, a software and consultancy company.
I am married to Liesbeth and have 2 sons named Quinten and Matisse.
ICT is both my job and passion.
Next to this my other hobby is actively playing music (mostly guitar).

More info about me and my company...

Recent Comments