Thursday 23 July 2009

Do functional programmers need design patterns?

“Elements of Reusable Object-Oriented Software” is a book that I am sure all self respecting software developers have read. The infamous Gang of Four book seems to shape everything we do in modern object oriented software development and by applying the principles contained within generally results in a quality software product.

One common (but slightly controversial) view on design patterns is that generally they only exist to patch up any shortcomings of the language. If a language can solve a problem in a trivial way then it may well have no need for a design pattern at all. This can be demonstrated by developments within the .NET Framework, for example the “Iterator” design pattern is embedded within the language through the IEnumerable interface, reducing the need to implement the pattern yourself.

Microsoft F#, due to ship with Visual Studio 2010, is primarily a functional programming language and supports all the features you would expect, such as functions as first-class values, currying and immutable values. As F# is fully integrated into the .NET framework it can also be used in an imperative or object oriented way.

So in a multi-paradigm language is there a need for software design patterns? Do we need to worry about design patterns in F#, and if so how do we apply them.

Some articles I have read recently have gone so far as to suggest that the design of functional languages eliminates the need for design patterns completely. This is however only partially correct.

There are some design patterns that are rendered obsolete by functional languages, take the Command pattern as an example. The Command pattern as documented by the Gang of Four enables you to:

encapsulate a request as an object, letting you parameterize clients with different requests”.

This is simply an approximation of a first-class function. In F# you would simply pass a function as the argument to another function.

In an object oriented language, you have to wrap up the function in a class, which you then instantiate and pass the resulting object to the other function. The effect is the same, but in the object oriented world it's called a design pattern.

The same can be said about the Abstract Factory pattern. The Abstract Factory enables you to:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes”.

In F# this is known as currying. Currying is the process of transforming a function that takes multiple arguments into a function that takes just a single argument and returns another function if any arguments are still needed.

It is clear therefore that several design patterns are rendered redundant in F# because the language provides more powerful, succinct alternatives. There are however still design problems that are not solved within F#. There is no F# equivalent for the Singleton pattern for instance.

Interestingly it works the other way too. Functional languages have their own design patterns; you just tend not to think of them that way. You may have come across “Monads”, which are a kind of abstract data type and often used for handling global state within functional languages. This is a problem that is so simple to solve in object oriented languages that there is no equivalent design pattern.

So while it is true that some object oriented design patterns become redundant in functional code, many, such as MVC do not.

So if you’re working with F#, don’t forget about design patterns, you never know you may even come across some new ones.

Monday 13 July 2009

CardSpace and the Access Control Service

The Geneva Framework is designed to simplify the development of claims-aware applications that want to eternalize the authentication function. I wanted to the the Geneva Framework to help create an ASP.NET application that would enable users to authenticate with either a Windows Live ID or a CardSpace managed information card, and then apply some authorization rules that were defined in the Access Control Service (one of the cloud hosted .NET Services).

My initial working assumptions were:

1. The Windows Live ID authentication would use a passive mechanism (WS-Federation). My ASP.NET application (the Relying Party) would send an HTTP request to an Access Control Service (ACS) endpoint, which would then initiate a sequence of HTTP redirects to authenticate the user at www.live.com, and then deliver a set of authorization rules (claims) from ACS back to my application.

2. The CardSpace authentication would use an active mechanism (WS-Trust). The ASP.NET application would launch the CardSpace UI to enable the user to select a suitable card, which would then be delivered directly to ACS in a SOAP message. ACS would then examine the claims in the card and deliver a set of authorization rules (claims) from ACS back to my application.

Assumption 1 turned out to be valid, and easy to implement as there are plenty of available examples to work from. The only bit which is not perfect here is managing the sign out from Windows Live whilst remaining on a page of my ASP.NET application.

Assumption 2 however turned out to be problematic. The current version of CardSpace (a part of .NET Framework 3.5) will only work with a Security Token Service (STS) that returns at least 1 claim. Unfortunately the endpoint that ACS exposes has an associated policy that does not have any required claims – so CardSpace refuses to talk to it. The Geneva Framework includes a new (beta) version of Windows CardSpace which relaxes this restriction, but I then hit another obstacle: the ACS uses message security, but the new version of CardSpace currently only supports mixed-mode transport bindings. So again CardSpace will not talk to the ACS.

As a work around I reverted to using a passive approach for the CardSpace authentication. My ASP.NET website (the Relying Party) is configured to perform a passive logon to the ACS, but instead of the ACS redirecting to a Windows Live login page, it redirects to a login page on a custom STS (created using a template from the Geneva Framework). This custom STS operates as a proxy, and extracts the claims from the Information Card, before repackaging them as a new set of claims to send to the ACS in an HTTP redirect.

Hopefully, this will all be simplified in future releases of CardSpace and the ACS, when a direct login to the ACS using a managed card will be possible.

For anyone who’s interested I’ve posted some sample code and documentation here:

Thursday 9 July 2009

SharePoint, Search and Loopback Checking

Recently a client encountered a problem on a single server MOSS deployment on Windows Server 2008. After installing MOSS SP2 and some Windows updates, the client reported that:
  • The search service wasn't returning any results.
  • They couldn't access the SSP administration page from the server.

This turned out to be the loopback checking feature in IIS. This feature prevents you from accessing a Web site with a host header from the same machine - for example, you can access http://machinename/default.aspx, but not http://hostheader/default.aspx. When you attempt to access a site under these conditions, you'll be prompted for credentials three times and then have access denied with a 401.1 Unauthorized: Logon Failed error. The giveaway was that the Central Administration site was set up to use the machine name, whereas the SSP site was set up to use a host header.

Because this is a single server environment, the search service is attempting to crawl sites, by host header, that are hosted on the local machine. In each case, access is denied with a 401.1 error and you end up with a very empty search index.

This issue became a fairly well known problem for SharePoint administrators on Windows Server 2003 environments, and usually arose when the server was upgraded to SP1. I've never come across the issue in a Windows Server 2008 environment before - I guess an update must have triggered the loopback checking feature in IIS7, but I'm surprised it wasn't enabled already.

Anyway, I followed the workaround here (Method 1), restarted the IIS Admin service, started a full search crawl and we're up and running again.