Monday, May 05, 2008
Small'ish turn out last Thursday.. but interesting discussions, including:

Hiring graduates - and what's more important, raw intellectual horse power or some demonstration of existing skills, the value of a bachelors vs. masters/honors degree... And how you can determine a candidates passion, and desperate lack of talent out there at the moment.

Discussed Database migrations - and different strategies for migrating (both data-centric and object-centric) and the missing database-agnostic "ETL" requirement for transforming data during a migration...

Database structure problems were discussed, i.e. legacy databases, and the problems they can present when attempting to work/map/scale them.

2D Barcodes also got a mention (i.e. QR Code) - including the Microsoft research project into high capacity color barcodes.

The impedance mis-match between Amazon's SimpleDB and SQL Server, and how you can implement SimpleDB constructs in a SQL Database for testing etc.

Steganography got a bit of a mention - i.e. encrypting hidden messages into images, and how transformation/cropping tolerant you can make these processes.

I mentioned the LinqBridge project - which gives you access to Linq for objects in .Net Framework 2.0 projects.  Great for those of us on projects which can't shift to 3.5 just yet for one reason or another.

FYI - Beware Resharper 4.0 EAP's though, they have a tendency to get confused by 2.0 Projects with Extension methods, turning your Linq statements in a nested set of Enumerable.Where(... etc. calls.

Keith mentioned Pourable computing - which is not something I'd come across before (you can find it briefly discussed in this TED talk by Neil Gershenfeld - part of the CBA @ MIT)

We also talked about LiveMesh - including the flaw in Vista (pre SP1) which prevented you from installing the LiveMesh software without UAC enabled... and Peter raised the question "why aren't you using UAC" ... annoying messages was the response - at which point he suggested we just disable them in the registry by setting HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ConsentPromptBehaviorAdmin to 0.

And then a recurring topic around source control, file versioning (i.e. never overwriting a file) and how office-wide mesh computing could help.

Thanks all for coming - see you all on the 15th of May.
posted @ Sunday, May 04, 2008 10:42:52 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, April 30, 2008
Architecture chat tomorrow, 1st May, 11:30am at Garrisons, Syliva Park.

Last week was a nice general discussion, I wouldn't mind doing something similar again - so I'm pretty topic light at the moment... other then a few general observations from the community.

If you have any other topic suggestions just leave a comment on this post.

See you all tomorrow!
posted @ Tuesday, April 29, 2008 9:26:50 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Wednesday, April 23, 2008
Good turn-out for the Architecture chat last week... thanks for coming along all (I believe there was 8 of us)

What we talked about:

Jabber / XMPP got a brief mention – as I’m currently investigating it for some side-projects as a scalable way to interact with a cloud of servers/devices... but nobody else had much interest/experience so we moved on.

Silverlight 2.0 beta ‘s - talked briefly about beta 1 and upcoming beta 2 - including Deep Zoom and the NBC Olympics silverlight player which looks to deliver a better experience then TV ever could.

We also had an in-depth discussion around the woes of working with/without app-domains and loading and unloading assemblies from either disk or byte arrays into the current app domain, security implications etc.

Bunch of points were made, and it was a pretty interesting discussion:
  • Briefly discussed Cecil – The swiss army knife of IL :)
  • PostSharp – which provides an interesting tool set for implementing AOP and other concepts (such as software transactional memory).
  • Garbage collection of types.
  • .Net Framework 3.5 add-in system (System.AddIn & System.AddIn.Contract) - we also posed the question, can it run without the 3.5 framework installed – a quick reverse engineer and compile via .Net reflector in VS2005 suggests that yes, yes it can work quite well without the rest of the the 3.5 libraries.
  • Altering IL at run-time, and the ruby-like concepts of a class is “never done” down to the concept of being able to break apart a routine at runtime and alter the IL, and where JIT’ing fits into the life cycle of IL and Execution.
Automatic unit test generation got a mention – I had a total mind blank and couldn’t remember the name of the product (which we have discussed in the past) – which of course was pex... Sadly still no public beta for us to try yet!

Amazon web services – we discussed the dev pay limited beta (takes the pain out of dealing with customers/billing when developing apps for EC2/S3) – this included discussing the development of applications for the “cloud” and what opportunities exist when leveraging the Amazon services, including the recently added support for persistent local disks to the EC2 platform.

Also in relation to EC2 we discussed writing apps for EC2 using C#/Mono - this led to a discussion on the state of Mono, i.e. where it's .Net 3.5 support is at and if/when WPF might be ported to Mono.

Thanks for all coming along, the next meeting is slated to be next Thursday, May 1st.
posted @ Wednesday, April 23, 2008 3:55:46 AM (New Zealand Standard Time, UTC+12:00)    Comments [3] | Trackback |
 Monday, April 14, 2008
SylviaParkArchitectureChat.JPG

Hi All, I'm back from my honeymoon... and so that means it's time to resume the Sylvia Park Architecture Chat.

Next one is scheduled for this Thursday, 17th April 2008 at 11:30am at Garrisons.

No set topics this week - just an open floor / general catch up - though if anyone has any ideas just leave a comment on this post or send me an email.

Look forward to seeing you all there!

posted @ Sunday, April 13, 2008 10:00:56 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
Someone recently sent me an email letting me know my NUnit "support" for IronPython project only targeted NUnit 2.2 and was a little out of date. 

(For those not sure what I'm talking about - perhaps take a look back at these posts (1, 2) from October of 2006)

I didn't realise anyone was actually using it - but I see it's being linked too from the IronPython cookbook, so I decided to take half an hour and update it to target NUnit 2.4 - I left it targeting IronPython 1.1 however instead of 2.0 (IronPython users should be able to handle that task if required).

The usage changes a little from NUnit 2.2 to 2.4, instead of deriving your tests from a custom TestSuite class you now just annotate an empty class with some attributes... makes everything a little cleaner as your project doesn't need to reference IronPython etc. any more.

[PythonSuite, Script(FileName = "MyPythonFixture.py")]

public class MyPythonSuite

{

}


The python files are embedded resources by default (though it's a minor code change to support external python files as well) - you can include multiple Script attributes for a single suite as well, if required.

If you want to dynamically include python resource files based on their content i.e. all embedded resources with a first line containing "#test" then you would do this:

[PythonSuite(DiscoverEmbeddedResources = true, DiscoveryKey = "#test")]

public class DynamicPythonSuite

{

}


The project is now split into two assemblies.
  • IronPythonTest.Addin
  • IronPythonTest.Framework
The Addin assembly needs to be installed into your NUnit 2.4 add-ins directory i.e. C:\Program Files (x86)\TestDriven.NET 2.0\NUnit\2.4\addins - you will need to place the IronPython assemblies in there as well if they're not registered in the GAC.

Only the framework assembly needs to be referenced in your project so you can have access to the PythonSuite and Script attributes.

And that's about it, all other questions should be answered in the posts from 2006, or just leave a comment on this post if you have any trouble.

Code can be downloaded from here.

posted @ Sunday, April 13, 2008 9:25:23 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Tuesday, March 11, 2008
So just a short note to say that I got married on the 23rd of Feb to the love of my life Renee... a good time was had by all, even though the weather was horrific (rained non-stop for 2 days) - big thanks to Ben, Nick, Stu, Sacha (my Entourage) and everyone else for helping with the last minute re-organisations :)

I'm now on honeymoon in Europe... currently lurking in Rome for a few days to take in the local sights - however we'll be making our way to England soon to catch up with some family.

For anyone curious about the Architecture Chat, it'll start up again in April once I'm back in New Zealand and my life has returned to some semblance of normality.

alex_and_renee.jpg

alex_colleseum.jpg

posted @ Tuesday, March 11, 2008 7:24:17 AM (New Zealand Daylight Time, UTC+13:00)    Comments [7] | Trackback |
 Wednesday, February 20, 2008
So a few weeks back there was a post on the Genome TeamBlog which included a link to one of my lambda abuse posts from last year.

At any rate - the problem they faced was that with code like this:

DataContext Context = new DataContext();

string connStr = "";

 

DataDomainSchema schema = DataDomainSchema.LoadFrom("SomeMappingFile");

schema.CreateDbSchema(connStr);

 

DataDomain dd = new DataDomain(schema, connStr);

 

using (Context.Push(ShortRunningTransactionContext.Create()))

{

    Customer tt = dd.New<Customer>();

    tt.Name = "TechTalk";

 

    RootProject tt_hk = dd.New<RootProject>();

    tt_hk.Name = "Housekeeping";

 

    ChildProject tt_hk_hol = dd.New<ChildProject>();

    tt_hk_hol.Name = "Holiday";

    tt_hk.ChildProjects.Add(tt_hk_hol);

 

    ChildProject tt_hk_ill = dd.New<ChildProject>();

    tt_hk_ill.Name = "Illness";

 

    tt_hk.ChildProjects.Add(tt_hk_ill);

 

    tt.RootProjects.Add(tt_hk);

 

    RootProject tt_g = dd.New<RootProject>();

    tt_g.Name = "Genome";

 

    ChildProject tt_g_dev = dd.New<ChildProject>();

    tt_g_dev.Name = "Development";

    tt_g.ChildProjects.Add(tt_g_dev);

 

    ChildProject tt_g_mnt = dd.New<ChildProject>();

    tt_g_mnt.Name = "Maintenance";

    tt_g.ChildProjects.Add(tt_g_mnt);

    tt.RootProjects.Add(tt_g);

 

    Context.CommitCurrent();

}


You ended up with a very flat member initialization structure plagued with:
  • Having to explicitly name child instances being added to collections - there's a lot of unnecessary noise.
  • Where you can't easily see the structure i.e. it's not visually hierarchical, so at a glance you're not sure just what the structure is compared to say looking at an xml document with nested elements where it's quite obvious.
At any rate, the guys at the Genome project attempted to overcome this using the nested lambdas (what I coined a "DSL" at the time, though It's a terrible and inaccurate term for what's effectively just a bit of a "trick" relying on side effects of evaluation) - it didn't go so well though because of course at first glance the syntax look strongly typed, the reality is it's anything but, and refactoring tools just aren't going to do things like renaming of keys in the hash style syntax i.e. key => value, because the key is just a Lambda parameter.

But all is not lost - of course with C# 3.0 we already have a great syntax for doing this kind of hierarchical initialization, say for this set of types:

public class BlogPost

{

    private readonly List<string> _tags = new List<string>();

    private readonly BlogUser _createdBy = new BlogUser();       

 

    public string Title { get; set; }

 

    public string Body { get; set; }

 

    public List<string> Tags

    {

        get { return _tags; }

    }

 

    public BlogUser CreatedBy

    {

        get { return _createdBy; }

    }

 

    public BlogUser LastEditedBy { get; set; }

}

 

public class BlogUser

{

    public int Age { get; set; }

    public string Name { get; set; }

}


We could do something like this to initialize an instance of BlogPost:

BlogPost post = new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {

        Name = "Joe Bloggs",

        Age = 25

    }

};


But the catch for the Genome guys is that it looks like they need to construct their entities using their DataDomain class ...  I don't know about how there product works but I can only assume it's either to get a transparent proxy for change tracking purposes or to enlist it into the current session etc. (though if it's just to enlist the entity I can't see why they need to bother with getting the DataDomain to create a new instance, surely they could manually enlist it).

At any rate that's irrelevant :)

So I got to thinking that of course member initialization is one of the Lambda-friendly things we can do because it's expressed in a single statement - so we can happily take the above code snippet and express it like so:

BlogPost post = evaluator.Create(() => new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {                   

        Name = "Joe Bloggs",

        Age = 25

    }

});


Where evaluator is an instance of a class I wrote called ServiceInjectionEvaluator ... the Create method (as you can probably guess) has the following signature:


  public
T Create<T>(Expression<Func<T>> expression)


The service injection evaluator just relies on being configured with an IServiceProvider capable of resolving instances of types... at this point we just unwind the expression, substituting our own instance activation mechanism wherever we stumble upon a NewExpression and walking through the expressions executing each bit as required - though it makes the assumption that you're going to have either a New or MemberInit expression at the top level of the Lambda, otherwise we just compile the whole thing and throw it back without any changes (because I don't want to bother writing code to visit the other types of expression node).

public class ServiceInjectionEvaluator

{

    private readonly IServiceProvider _serviceProvider;

 

    public ServiceInjectionEvaluator(IServiceProvider serviceProvider)

    {

        _serviceProvider = serviceProvider;

    }

 

    public T Create<T>(Expression<Func<T>> expression)

    {

        switch (expression.Body.NodeType)

        {

            case ExpressionType.New:

            case ExpressionType.MemberInit:

                return (T)EvaluateExpression(expression.Body);

            default:

                return expression.Compile().Invoke();

        }

    }

 

    private object GetInstanceWithInit(MemberInitExpression expression)

    {

        object instance = GetInstance(expression.NewExpression);

        foreach (MemberBinding binding in expression.Bindings)

        {

            ApplyBinding(instance, binding);

        }

        return instance;

    }

 

    private void ApplyBinding(object instance, MemberBinding binding)

    {           

        switch (binding.BindingType)

        {                   

            case MemberBindingType.Assignment:

                ApplyAssignmentBinding(instance, (MemberAssignment)binding);

                break;

            case MemberBindingType.ListBinding:

                ApplyListBinding(instance, (MemberListBinding)binding);

                break;

            case MemberBindingType.MemberBinding:

                ApplyMemberBinding(instance, (MemberMemberBinding)binding);

                break;

            default:

                throw new NotImplementedException();

        }

    }

 

    private void ApplyMemberBinding(object instance, MemberMemberBinding binding)

    {

        PropertyInfo property = (PropertyInfo)binding.Member;

        object memberValue = property.GetValue(instance, null);

        foreach (MemberBinding childBinding in binding.Bindings)

        {

            ApplyBinding(memberValue, childBinding);

        }

    }

 

    private void ApplyListBinding(object instance, MemberListBinding binding)

    {

        object list = ((PropertyInfo)binding.Member).GetValue(instance, null);

 

        foreach (ElementInit elementInit in binding.Initializers)

        {

            Delegate compiled = Expression.Lambda(Expression.NewArrayInit(typeof(object), elementInit.Arguments.ToArray())).Compile();

            object[] arguments = (object[])compiled.DynamicInvoke();

            elementInit.AddMethod.Invoke(list, arguments);

        }

    }

 

    private void ApplyAssignmentBinding(object instance, MemberAssignment assignment)

    {

        object value = EvaluateExpression(assignment.Expression);

 

        PropertyInfo info = (PropertyInfo)assignment.Member;

        info.SetValue(instance, value, null);

    }

 

    private object EvaluateExpression(Expression expression)

    {

        switch (expression.NodeType)

        {

            case ExpressionType.New:

                return GetInstance((NewExpression) expression);

            case ExpressionType.MemberInit:

                return GetInstanceWithInit((MemberInitExpression) expression);

            default:

                return Expression.Lambda(expression).Compile().DynamicInvoke();

        }

    }

 

    private object GetInstance(NewExpression expression)

    {

        return _serviceProvider.GetService(expression.Type);

    }

}


The only thing left is to then either provide an existing instance of IServiceProvider (i.e. the Windsor container) or creating an adaptor

public class DataDomainServiceProvider : IServiceProvider

{

    private readonly DataDomain _domain;

    private static readonly MethodInfo member = typeof(DataDomain).GetMethod("New");

 

    public DataDomainServiceProvider(DataDomain domain)

    {

        _domain = domain;

    }

 

    public object GetService(Type serviceType)

    {           

        return member.MakeGenericMethod(serviceType).Invoke(_domain, null);           

    }

}


There's a few things the enterprising mind can do with substitutions and member initialization I can think of, especially around IoC - anyone else have some ideas or thoughts on using/abusing them?

 |  | 
posted @ Wednesday, February 20, 2008 1:01:38 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | Trackback |
 Wednesday, February 13, 2008
I have to say SharePoint just continues to underwhelm me (as a developer, I don't mind the product itself I should probably make that clear)...

A couple of quick examples:

Configuration over Convention

Regional settings and dates are a prime example - for instance you get a <SharePoint:DateTimeControl /> which brings with it a common look and feel for date pickers in SharePoint... and on the various pre-canned forms etc. everything appears to display with the current user/sites regional settings. 

However whenever you use this control you end up resorting to code along the lines of:

SPRegionalSettings regionalSettings = SPContext.Current.Web.CurrentUser.RegionalSettings ?? SPContext.Current.Web.RegionalSettings;

myDatePickerControl.LocaleId = (int)regionalSettings.LocaleId;


Or extending your control yourself to do the same... why on earth would I not want the control to default to the current regional settings?

Again the lack of convention rears it's ugly head when working with SharePoint's SPGridView - if it's going to a render a date, why doesn't it render it with the current user's Locale in mind (which I've talked about in this hack last year) - shouldn't these controls be taking that burden of responsibility away from me?

Useless Extensions Points

When something is extensible in SharePoint, then generally:

  1. It's not documented (except by the community)
  2. It doesn't really work for the most common scenario.

Take the SPGridView and SPDataSource combo - with this you can setup a grid to feed from a CAML query pretty easily ... and it's smart enough to add the required <OrderBy/> to the underlying CAML query when you sort on a column... so far so good.

But what if you want to sort on more then one column?

Well, you could try specifying more then one column in the grid's SortExpression - but this causes the SPDataSource to spit the dummy... so obviously the first question is why doesn't that work, when it works for other data sources, and would have been trivial to implement.

But not all hope is lost after opening reflector and perusing the code (which thankfully wasn't obfuscated in this case, though quite a bit of it is) you see that in fact you can specify additional sort columns in the original query and the SPDataSource is smart enough to keep them and insert the new field references into the existing <OrderBy/>... a handy way for extending your query to have a number of default sort columns.

But there's a catch, it sticks the entries in the wrong position, so it will sort by the fixed columns first - rather then last - making it all but useless in most cases (users expect to click on a column and see the results sorted by the selected column first) .. And to be honest this still wouldn't worry me if I was given at least one virtual method to override allowing me to mutate the CAML query appropriately.

posted @ Tuesday, February 12, 2008 8:28:02 PM (New Zealand Daylight Time, UTC+13:00)    Comments [2] | Trackback |
 Thursday, February 07, 2008
Hi all...  So first off, there's no Architecture Chat today - I'm tied up with prior commitments (due to the short week) so it's going to be held Thursday next week -14th of February, appologies to anyone who was going to attend.

As far as possible topics, what about:
  • All the interesting stuff that came out of Lang.Net (or at least was brought to my attention by that symposium)
  • Cosmos - a cute operating system written in C#.
  • Charlie Calvert's started posting on the future of C# (4.0).
  • Jumbala - another interesting step down the MDA road, this time as an action language for UML state machines... which can actually be compiled.
  • .Net Mass Downloader - here's something I was thinking of doing myself, a mass download for all the .Net Framework source code.
  • Resharper 4 EAP delayed.
  • Lightspeed 1.2 released.
  • The rise of WPF vs WinFroms.
  • The Auckland dev community are slackers compared to Tauranga.
  • Vista SP1 and Windows 2008 RTM.
No doubt there will be plenty more.

See everyone next week!

posted @ Wednesday, February 06, 2008 6:39:37 PM (New Zealand Daylight Time, UTC+13:00)    Comments [2] | Trackback |
 Monday, February 04, 2008


So the sun has set on day 1 of the Summer Road Trip 2008 in Auckland - The Presentation was done by JB, Chris and Myself this afternoon - it went very well, people enjoyed the content and the mix of integration, server management, database and development topics really meshed together nicely I thought... 

There was enough to keep everyone interested, regardless of the hat you wear - and plenty of prizes too - well all love swag right?!

Big thanks to our MC Jaqcui, who handled the Intro and Outro and let everyone know about the local Ellerslie & Central Auckland user group's - where I'll be sure to run a few sessions later in the year... and of course Darryl for handling some of the finer details like the venue, lunch, and the dinner afterwards - much appreciated.

For all those that came along - first off thanks for coming, obviously without participation in these events they'll just dry up and stop happening - and second don't forgot that there is no time like the present to start picking up these technologies and developing applications with and for them - the products are all but ready, so why can't you be (and not only are they great technologies, they're fun too).

The next presentation is in Tauranga - and there are still places left, so sign up here - It's going to be on tomorrow (5th of Feb) at 1:00pm I believe.

And finally a short plug ;o)

SylviaParkArchitectureChat.JPG

For anyone that found this presentation interesting and would like to discuss the technical details of things like emerging technologies, general software Architecture, Developer Tools, Running software businesses etc.  I also organise the local Sylvia Park Architecture Chat - which is a pretty casual meeting of some very smart people in the .Net Community. 

We normally get together on a fortnightly basis at Garrisons in Sylvia Park and are always keen to have more people/fresh faces to come along and join in our discussions or even just float some development/architecture questions or problems you might have that the group can help solve - keep an eye on my blog, or the dot.net.nz mailing list for announcements of when we'll next be meeting up :)

And all are welcome of course!

posted @ Monday, February 04, 2008 8:24:40 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | Trackback |
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation