Ayende @ Rahien

It's a girl

Developing on Microsoft CRM

I am currently in the process of leading a team in a project that is built around Microsoft CRM. A while ago I posted what I consider essential requirements for working effectively with business platforms. Since then, I had had a lot of time to play with MS CRM and see what the development story is.

Please remember, this is an evaluation of Microsoft CRM from a developer perspective. I don't touch on any of the other aspects that it may have.

I have already started to dislike it, and I have a feeling that it would only grow more acute in the future. The executive summary of this post is here:

Developing on MS CRM is building on a CRUD platform where all your business logic reside inside triggers.

Let me go over the points that I have outlined in my earlier post, again, those points are brought up without any particular order.

Source Control

MS CRM supports the creation of new entities and customizing existing ones. Those customizations are kept in a dark cave, to be let out at irregular interval for a slow walk around the block. The source control story on MS CRM is similar to the source control story of the average DB, except that you need to imagine that any DDL operation takes between one to thirty minutes to complete. And there is not textual representation that you can keep on the side.

Further extension points are available as plugins (callouts), which are triggers for CRUD operations on the CRM, and JavaScript customizations which you are supposed to write in a small text area inside the browser and allows you to respond to such events as changed / load. The SCM story for the plugins is a standard plugin issue, but for the JS customization there is literally no option except full import / export of the changes made from the CRM baseline image. See the previous paragraph about the performance implications of this, unacceptable.

Let me make it simple, if you want me to develop on your platform, source control is not a negotiable attribute. It should be as natural as breathing. If I have to do extra work to get it working, this is a critical issue.

Ease of deployment

You deploy a CRM installation by export your changes from the dev machine and importing to the staging/production installation. This is a lengthy process, and it doesn't capture all the changes that were made, you need to make several others (moving callouts, configuration, etc) from one environment to another.

Oh, and get ready to be intimately familiar with IISReset, and apparently resetting three other services is mandatory as well. And you need to do those on a regular basis just to get it deployed.

Debuggable

Well, you can attach to the CRM process, if you really feel like it, but that is frustrating, because you get to control only a small part of what is going on. It also looks like the CRM is throwing a lot of exceptions in normal operation, since I am unable to keep debugging in a "stop on all thrown exception", because it keeps throwing a lot of those.

Testable

There isn't any real way to do testing on the CRM without resorting to UI level testing, which is painful, to say the least. A lot of the methods in the extension API available expose such things as "string preEntityXml", which make writing the code hard, and testing harder.

Automation of deployment

As far as I can see, that is not doable easily, and it is a painful process (see deployment above) that really should be done with a click of a button.

Separation of Concerns & Don't Repeat Yourself

One of the issues that I have run into so far is that the entire development model for the CRM is reactive, and that doesn't really lend itself to keeping concerns separated and duplication minimized. The main problem is that the exposed API is primitive in the extreme and doesn't really lend itself to good practices (see extension options below).

In particular, the decision to base the extension options on non-portable Web Services and XML is a big mistake in this regard.

Doesn't shoot me in the foot

No comment on that so far, I haven't dug into it enough to know whatever this is an issue yet.

Make sense

This refers to what goes under the covers, and how I need to interact with it. So far, I had been told countless times "That is the way the CRM does it" in response to "WTF is this doing?!"

Possible to extend

Hacks are not something that I enjoy doing, and the more I dig into MS CRM, the more I feel like I need to resort to black magic hacks just to get things working. Let us go over some of the issues that I have run into so far.

Programming Model

If I were to suggest building a platform where users will have direct access to the DB tables' and all the logic for the system would be implemented using triggers, I would be called a madman. Nevertheless, this is the programming model that you have when you work in the CRM. Responding to actions in the CRM using plugins (called callouts).

Those callouts have signatures such as this one:

public override PreCalloutReturnValue PreCreate(
	CalloutUserContext userContext, 
	CalloutEntityContext entityContext, 
	ref string entityXml, 
	ref string errorMessage)

Then, you need to configure them in a config file, which lets you limit what this function will get. In that function, you can use the provided information to do something, but there is a lot of boiler plate code that you need to handle just to get out of the ugliness of this.

Configuration

Let us assume that you had the unmitigated goal to actually do try to develop a non trivial plugin to the CRM. You now need to supply it with some configuration, but the standard app.config / web.config approach will not work for you. The plugins are loaded into IIS's process, and I am not about to change w3wp.exe.config, that is taking it too far, and it violate the configuration / code should be a single unit issue.

Public Interface & API

The decision to base the entire extensibility model on web services and XML was a big mistake. It is mistake because the API that you get into the CRM is about the worst you can think of. Procedural, generated code, with very little flexibility or any way to supply layers on top of it that would allow you to present a nicer interface.

The generated code from the web service reference suffers from the usual awkwardness of WS code everywhere. Let us take this example, I want to change the customer preferred restaurant type and whatever he has a discount in it. Un order to do that, I need to write something like:

//preparing to call to the CRM
CrmService svc = new CrmService();
svc.Credentials = CredentialsHelper.GetCredentials();
svc.CallerIdValue = new CallerId();
svc.CallerIdValue.CallerGuid  = currentUserId;
ColumnSet columnsNeeded = new ColumnSet();
columnsNeeded.Attributes = new string[] {"name","new_customerpreferredresturanttype"};

//calling to the CRM
customer customer = (customer)svc.Retrieve("customer", customerGuid, columnsNeeded);

//updating customer value
customer.new_customerpreferredrestauranttype = new Picklist();
customer.new_customerpreferredrestauranttype.Value = 13;// Japanese 
customer.new_customerhasrestaurantdiscount = new CrmBoolean();
customer.new_customerhasrestaurantdiscount.Value = true;

svc.Update(customer);

Let us count the number of issues in this example:

  • It take 15 lines to do something as simple of that, and only two of those lines are actually doing anything useful, the rest are just there to make the API happy.
  • customer as a type name. .Net follows the PascalCase convention, and it is annoying in the extreme to see this in the middle of my code.
  • Magic strings all over the place. You don't have any way to avoid that.
  • Awkward API - CrmBoolean, anyone? Yes, they needed that to support nullable value types in 1.1, but it goes back to the problems with relying on the Web Service generated API to handle this scenario.
  • Magic values. Do you see the restaurant type constant there, it is a magic number that was defined in the CRM and it has no textual representation. You have the ID and the display value, and nothing else.

I couldn't get Microsoft's flagship web services' product to talk to the CRM successfully, so I am going to assume that the CRM is only accessible to ASMX platform (feel free to tell me if you can get Axis to successfully interact with MS CRM). That being the case, and since .Net is the obviously technology to work with the CRM, it would have been much better if MS would have simply supplied us with the ability to generate a DLL from the CRM with all the entities definitions and useful approach for interfacing with it. CodeDOM make it about as easy as providing a web service, so I have no idea why they choose not to do it.

Being able to ship an actual development platform, rather than anemic set of Web Service would have significantly improve the possibilities of improvements.

This shows itself in many other places, where the API hands me a string of XML and expect me to do something with it. Well, what am I supposed to do with it? Why not give me an object instance that I can actually work with?

The problem is that it can't do that, because there is no way for me to get the type that it is using for the entity. The best I can do is use the generated class from the generated proxy, and obviously the CRM has no way to give me that type, since it exists in my plugin assembly alone.

Subverting Intent

You may have noticed that the field names are stuff like "new_customerpreferredrestauranttype", that is because the CRM, in its wisdom, has decided that you don't really need to have readable (PascalCase) names, even if you took the care to put them into the CRM in this manner, it will lower case them and make your life harder.

Team Development Story

This is something that is at least as big as the source control issues, and for the same reason. The CRM doesn't support any sort of team development on a project. The main issue is that you don't have a way to work locally on a CRM instance, and then commit those changes to the trunk. The entire is forced to work on the same instance, with all the associated problems that this entails.

This has a lot of scary implications, some of which are:

  • I have no control over what goes into the system, no way to review changes, no way to revert or selectively modify what goes in.
  • I can't just pull out a debugger and try to find an issue in an errant plugin, because doing so will send the entire team into a screeching halt.

 

Performance

So far I had issue with it from a developer perspective, it moves from a simple request causing the DB to take 100% for minutes to stuttering under the load of a single user. I understand that there are several fixes for those issues, but that is on a clean machine, just trying to get to grips with the way that the CRM works.

Conclusion

As you can imagine, that is not a situation that sits very well with me, and I am actively working to overcome as much of those limitations as I can. I am making good inroads, but I can't believe how bloody hard the platform make it to use it.

Comments

Tomas Restrepo
08/24/2007 12:00 AM by
Tomas Restrepo

The sad part is; most other "business platforms" are not any better (and many worse). You clearly stated out one key problem: Most of these were tools were made to provide the illusion that the platform can be customized by either (a) end users or (b) business/technical analysts that are not developers.

It's clear that doesn't work; but people all over the world keep insisting on it based on the false impression that this is actually cheaper than having a developer do it right (our own fault, in many cases).

Mark Monster
08/24/2007 01:17 PM by
Mark Monster

I've worked on two Dynamics CRM projects (not very large) and hated this most of the time.

Everyone wants the ability to automate the customazations import and export, at least the export for Source Controll.

I really hated workflows. Every once in a while a specific workflow stopped being editable (at least let the changed be saved). Solution create a new one with exactly the same contents.

I really hated the update call-outs. You can specify the columns you want in the update call-out, but all you are getting are really changed columns. And changing data in a callout is also a bit harsh, changing XML :-S.

And what about integration? This is only real possible using SQL Server Triggers. The only way to be sure the database action succeeded and the ability to recall it if integration collapsed.

I think we will have to wait for Dynamics CRM Titan release (4.0).

Mike
08/24/2007 03:14 PM by
Mike

I would love to hear more of your experiences and opinions on MS CRM.

BigJimInDC
08/24/2007 03:16 PM by
BigJimInDC

Agreed. This is more or less the same in SharePoint too, which I've recently been working with.

As I've described to my peers on the project, it's like getting paid to do SQL Server work and planning on performing the deployments without version/change controlled DDL/TSQL scripts. If you have no idea that scripts even exist, or better yet, like a recent client of mine who did not "TRUST" MSSQL scripts (huge WTF), then ok. But if you get paid to do this stuff and are "winging it" by performing deployments via 1000+ mouse clicks and copy/paste operations, you might want to rethink your profession.

Lately, with SPS/MOSS and CRM as but two examples, MSFT is enabling extensive customization of those products via more or less rich API's, essentially targeting the developer community, but the "development effort" as a whole is nearly unmanageable, given the lack of ability to put the development effort properly into a change management system.

Dries
08/24/2007 04:01 PM by
Dries

Although I have little experience with either, the story is pretty much the same with Reporting Services and to certain extend with Biztalk.

As I keep repeating to everybody I work with:

"What's wrong with writing code?!"

Where does this notion come from that pointing and clicking and dragging and dropping is quicker or easier than writing code, especially considering the quality of IDEs we have these days.

Same goes for configuration. I am not a sys admin, but I find it astonishing how hard I find it to set up and configure an IIS instance on a server compared to Apache. The Apache config file is by no means pleasant for the "casual user", but at least you know you'll find everything in one place, you can read what's there and documentation to hand you can work out what it means and what to do. With IIS, by the time you have figured out which applicaition to open, which tree structure to expand, which option to choose, which tab to click on, which box to tick, you're lost! So I'll say it again:

"There's nothing wrong with TYPING"

Mark Monster
08/24/2007 05:25 PM by
Mark Monster

Hmm. I read some people are talking about Biztalk and Sharepoint development having the same kind of troubles.

I don't fully agree here. Biztalk projects consist mostly of maps, pipelines and orchestrations. Those are all developed from within Visual Studio. Maybe the configuration of the outboud-ports is a little difficult, but this is just a small thing.

Sharepoint projects can make use of the Visual Studio Extension for Sharepoint Server. But there are some things that are difficult, like the forms and styles. You are able to develop most things as a feature.

After all I think Microsoft should put some effort in the development environments for Dynamics CRM but also enhance the Biztalk and Sharepoint development.

Rémy van Duijkeren
08/25/2007 01:07 PM by
Rémy van Duijkeren

I understand the problems you have with CRM, but if you look it the value of the application\platform, can you accept these problems?

Products like CRM and Sharepoint solves about 85% of a customer needs, with out-of-the-box functionality. Only the last 15% has to be coded and customized, which gives you more time to do the fun things on a project. Therefore I accept these problems, but I like to know if you are willing to make this trade. If not why not? You think the price is to high ;-)?

Rémy van Duijkeren
08/25/2007 01:07 PM by
Rémy van Duijkeren

I understand the problems you have with CRM, but if you look it the value of the application\platform, can you accept these problems?

Products like CRM and Sharepoint solves about 85% of a customer needs, with out-of-the-box functionality. Only the last 15% has to be coded and customized, which gives you more time to do the fun things on a project. Therefore I accept these problems, but I like to know if you are willing to make this trade. If not why not? You think the price is to high ;-)?

Ayende Rahien
08/25/2007 01:18 PM by
Ayende Rahien

I am sorry, but I am failed to be impressed with a CRUD platform. The platform may give me a lot OOTB, but having to jump through those hops just to get something trivial working is unacceptable.

I can envision building such a system where the thing is actually viable to develop on.

I do not enjoy fighting with a platform, or using worst practices just to get something done.

Give me a platform that I can develop on in a normal manner, and I would take it in a heartbeat, but a platform where something as basic as source control is a chore is not an acceptable choice by any meaning of the word.

James Kovacs
08/26/2007 10:30 PM by
James Kovacs

Oh, admit it, Oren. You're going to write Rhino CRM next.

Ayende Rahien
08/27/2007 04:34 AM by
Ayende Rahien

I have no interest in doing that, nor any wish to.

Grrr... stupid CRM. Must. Not. Write. Code.

Troy DeMonbreun
09/17/2007 09:22 PM by
Troy DeMonbreun

Oh, yes! Please write Rhino CRM! :-)

I also second the suggestion above for you to keep us up to date on your CRM adventures. It's great to see someone who has great "coding values" also in the fray.

Comments have been closed on this topic.