I'm currently tasked with building a web-based tool that helps social event coordinators keep track of their invitees--who has been contacted, who has sent in an RSVP, who has paid, what particular activities a person will be participating in, etc. It's essentially a big contacts list with a lot of enhanced functionality around registration and payment. The basic domain model and data layer are in place, and I've spent the past month building a user interface in Silverlight. It's been an interesting journey, and there's a lot about Silverlight that I really, really like, but in the end I've finally decided a monolithic Silverlight application is not the right path. I probably should have heeded Shawn Wildermuth's warning about not building a monolithic Silverlight line-of-business application before I got started, but it's hard to know how to use or how not to use a platform if you've never built anything with it. So I tried, and it was working, but in the end it just became too laborious.
Why? Because even though Silverlight has a super-cool UI model, gives you mini .NET framework, and let's you program in C#, it still can't give me what I really want: my domain objects.
Traditional web applications are strange in that the server is responsible--in one way or another--for building and adjusting the UI that will run on the client. Stop and think about that. JavaScript aside, the client is just a dumb terminal, and the server is in command. Web 2.0 has changed a lot of that, with AJAX frameworks that are putting more burden on the client, but the fact that the initial rendering of so many web UI's is still done server-side shows the strange sort of blurring of the client/server boundary line that exists in traditional web development.
Silverlight, on the other hand, makes a complete break. It is the client in command. At runtime it is the client itself which builds the UI and which is responsible for updating it, not the web server. That is a big paradigm shift from traditional web development and it brings with it some consequences, one of which is interaction with your domain model. In a traditional web app you can dynamically build up the HTML to send to the client using the domain model that lived on the server. But in Silverlight, any part of the UI that depends on server-side assemblies will need to make calls to the server to maintain itself. At first this doesn't seem so bad since Silverlight comes with an impressive networking stack. But after a month of laborious and painful development, I've finally decided it's just too complex for my style of development.
Now, if you're not particularly interested in being domain-driven, if you just need to get the data into the UI so you can mess with it, you can probably get a basic data-driven Silverlight app running without too much hassle. But if you like to build robust domain models that the UI layer depends on, you need to carefully consider the development cost of using a UI platform that requires you to do all of your communication with your domain model via web services and forbids you from dynamically building the UI on the server (unless you're planning to send XAML over the wire).
For the application I've been developing it wasn't that Silverlight wasn't capable of doing what I wanted, but that what I wanted took too long to do and required too much busywork. Here is a summary of my pain points:
Data Transaction Objects. Sprinkling my domain model with lots of WCF data contract attributes was out of the question, not only because I didn't want to pollute the model, but because not everything that needed to go over the wire was in the form of a property. So a lot of the hassle came from the unavoidable evil of converting domain objects to stale DTOs and then re-hydrating them after they come back from the client. The conversion to and from a DTO involved lots of mundane property assignments with sprinkles of complexity to handle constructors, immutable types, and lists. It wound up being an unusual combination of boring and yet error-prone code that required a lot of maintenance.
WCF Service Configuration. It took a lot of head-banging to figure out how to successfully update my WCF services during development, and it only got uglier when I implemented ASP.NET-based authentication to keep the services locked down. Eventually it became second nature, but I spent an awful lot of time adjusting authentication in web.config, deleting the service reference in the Silverlight project, re-adding it, etc.
The Lack of SOAP Faults. This one really got to me. The inability for exceptions to travel across the wire as SOAP faults was extremely frustrating. It made debugging difficult, and sending useful error messages cumbersome. I wound up wrapping all of my service return values to include a possible exception information object. What a mess.
The Lack of Domain Object Functionality. Initially the idea of a pure separation of client/server was very attractive to me. After all, why should the burden of updating the user interface be split between the client and server as in most Web 2.0 web apps? But in practice, the inability to send the functional side of my domain objects across the wire made things difficult. I realize this is what services are for, but there were so many times when I had a simple problem to solve and the web services barrier was getting in the way.
For example, my domain model includes a rather robust object for a person's name (first, middle, last, friendly, preferred, prefix, suffix, etc.). I also have a PersonNameFormattingService object which I use to build different strings, from the formal "Dr. L. David McClister" to the simpler "McClister, Dave". There are even methods to take a current and former name to generate a name string that includes a maiden name. The point is that all of that formatting logic is housed in the PersonNameFormattingService, on the server, and I don't want to duplicate it.
Now, on the Silverlight side, there were lots of times when I needed a person's name formatted in different ways. But the service I need to format the data lives on the server. This left me with two options, neither of which I liked: 1) create an identical PersonNameFormattingService in a Silverlight library that does essentially the same thing, or 2) format the name on the server and send the result over the wire as needed.
The problem with the first approach is that it forces me to update two copies of the code base. And, while it may work just fine for simple name formatting, if it involves heavier lifting in the .NET framework, it may not be entirely portable to a Silverlight library. It's an option to consider, but it's not a silver bullet. The problem with the second approach is that it's a big hassle, and it forces you to build lots of services and DTOs just to get leverage your domain model logic. This is just one example. I fought this sort of stuff on a daily basis. It seemed the more robust my domain model, the more difficult it was to use.
I'm sure experienced SOA developers would have better intuition than I do about how to organize and build services and DTOs to appropriately leverage their domain layer from a remote Silverlight client, but I got to the point where I was spending more time building a bridge to access my domain model rather than using the model to get real work done.
So now I'm using ASP.NET MVC, and I'm loving it. I can build a clean, testable UI layer that leverages the full power of my domain model. Add in some jQuery for AJAX, and I can leverage the client to get partial page updates while still leveraging the server to generate the UI. From my perspective, a beautiful compromise.