Wednesday, 7 March 2012

If broken it isn't, fix it you shouldn't...

From speaking to some old friends of mine I heard about a cataclysmic implosion of a project I used to work on. This was a project that initially started as an extremely badly coded asp.net application (with horrors like functions with 1000+ lines of code). A project that we spent over a year on trying to upgrade to use much better patterns and practices and add tonnes of test coverage on while changing/adding features to the application. It was by no means perfect when we brought it over the finishing line, but it was a very solid and decent bit of code. The damn thing even won an award!

Anyway, it led me on to writing this blog post. And my tip of the day is:

"If broken it isn't, fix it you shouldn't..."

The basic concept I put forward is if something isn't broken then why change it? If you're changing something just because it's not agile enough, or you don't like the code, then you're not really following agile principles, or at least not following one of my favourites: Take the first bullet. Some people call it "fool me once, shame on you, fool me twice, shame on me". Effectively, if a requirement or story "fools" us into not making that abstraction, or into writing code that doesn't protect us from that bug, then that's the first bullet. When we get hit by that bullet it's time to abstract away or protect that code so that we don't get hit again.

Here's a really basic example: Let's say I ask you to write some code to sort a list of contacts by their name. You might write me a sorter class that takes in the list of contacts and returns a list sorted by their name. You might even go as far as passing in a parameter so that you can sort it by any field you want.

Then comes a second requirement - I want to sort it by email address as well as name, because I have 20 joe bloggs. Ok, so we didn't account for the ability to sort by multiple fields. One solution to this problem is add a parameter to allow you to add a second field to sort by. But what if we get 3 fields? Or what if the new field didn't have the same way of sorting as name? A better solution would be to introduce Comparer objects or something of that manner. That way you let the invoker tell you how to compare the objects and that way you've taken the first bullet. What we have in effect done is followed up by closing off a possibility of further sorting issues. (For more information on this look up OCP, or Open/Closed principle).

This is exactly what didn't happen in this "cataclysmic" project. Things were deemed "not agile enough" so changes were being made to modules and pages and classes that weren't taking any "bullets". Next thing you know things stopped working, because the whole project architecture started to change and remould over time. This is probably very much expected. So this (every so slightly) changed the situation into "broken it is (now), so fix it you bloody well should!". Their decision? Rewrite the whole project. My jaw left a dent on the floor when I heard that bit, no word of a lie... Such madness!

Finally, if you're astute you may have recognised that my blog entry title was very much inspired by an excellent blog by Tess Ferrandez! (If broken it is, fix it you should)

Thursday, 1 March 2012

Silverlight MSCRM Dashboards - SoapHelper throwing "Object reference not set..." errors

So, you've created that shiny dashboard using Silverlight. You're using the SoapHelper provided by the SilverCrmSoap library. But any time you try to hit Dynamics you get a big dirty "Object reference not set to an instance of an object" error. What could be going on?

In the associated HTML page that loads the XAP file make sure you've referenced the correct javascript library:

<script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script>

9 times out of 10 you'll have referenced the Silverlight.js by mistake. I keep falling into this trap. I must have a memory like a sieve!

Tuesday, 28 February 2012

How do you change/get rid of the default "name" field in Dynamics 2011!

There are many situations where the default "Name" field is not applicable to an entity. A couple of examples to explain what I mean:

Order
An order doesn't have a name as such, but an ID. What we can do in this instance is change the name of the default field rather than keep the default "pfx_name". A more appropriate name might be "pfx_OrderId" or maybe "pfx_OrderRef". You do this when creating the entity on this screen:


Using the Primary Field tab we can decide exactly what the name of the field is and other things such as business requirement and length etc.


Order Detail
This is an even more interesting one. For Order Detail we don't really have primary field whatsoever. We have a few options as to what we may consider the primary field:
  1. It's probably a combination of Order ID/Ref and the Order Line Number?
  2. Maybe it's the Product Name we're ordering?

Either way, it's not a text field. So what are our options? Initially from a look at the above screen for editing the Primary Field properties we get some false hope... it looks like you can change the Type of field this is! Unfortunately we only have 1 option in the dropdown: Single Line of Text.

So, the only real option is remove it from the form. If you've ever tried this before you'll know that it's not as straight forward as a custom field because it's locked on the form. How do we do it:
  1. Change the business requirement to "Not Required"
  2. Open up the Main form
  3. Open up the properties of the field
  4. Turn off the "Visible by Default" flag



This has a few further implications. Firstly, any lookups to the Order Line will have blank lookup fields on the form. For example maybe we had a "Guarantee" entity that needed to reference an Order Detail record. On the Guarantee form this lookup will look like it's empty. There are a couple of ways around this, but my personal preference is to add some Javascript to the Order Detail form so that it populates the hidden name field on save with data from another field - E.g. the Product name.

Other implication is some view cleaning up to be done. If you open up the views you will see they will all display this name by default. All of these will have to be customized to allow for this.

Monday, 27 February 2012

Dynamics 2011 - Cannot Delete Relationship!

Recently we ran into a really interesting problem within our company when trying to delete a relationship between 2 entities. We kept getting 1 of 2 errors:
  1. Cannot delete EntityRelationship because one or more components require it.
  2.  
  3. An error about an attributemap that no longer existed (I couldn't recreate this error to get the exact wording)

Obviously you'll have checked for the obvious like ensuring the field doesn't exist on a form or removing any connections if applicable. None of this solves the problem, so what could it be?

One of the most common reasons I've found is you've edited the site map and changed where the related link is displayed. So let's say you have an entity called Product and one called Component referencing it (i.e. Component has a look up to Product). There will also be a related list/link on the left navigation of Product where you can see all of it's Components. If you use a sitemap editor to reorder or change how this is displayed this can cause you a problem when trying to delete the relationship.

The second problem is quite an unusual, and I'm not sure why dynamics doesn't automatically do this for you. Let's go back to our example above but add a third entity:

1. Supplier
2. Product (Which has a look up to the Supplier entity)
3. Component (Which has a look up to the Product and Supplier entity)


Here's the scenario I came across, I try to delete the relationship between Product and Supplier and it says:



But what else could possibly require this? I click on details within the error and it points me to the relationship between Product and Component... ok, so what's going on here then?

9 times out of 10 you've added a mapping. In my case whenever I created a new Component from the Product screen I had a mapping to automatically use the supplier from Product to populate Component. So, open up that relationship and check for any mappings! Dynamics should really remove this mapping for you, but such is life.

Just a few things to be aware of when working with relationships.

Monday, 13 February 2012

MS CRM Dynamics - Q2 Release

Many of you might be aware of some major updates coming with the Q2 release of Dynamics (see here for a preview of the release). The major part that was originally of interest to me was multi browser support, but the preview has given me a few other surprises!

1. Business Intelligence / Power View.

Power View is a new reporting services Add-in for SharePoint that came with the release of SQL Server 2012. I believe this is the first stepping stone towards far more powerful reporting within dynamics. Looking forward to playing with this to see what exactly we can do with it.

Only Gotcha is that this is only available on-premise with the Q2 release. Fingers crossed for Q3!

2. Custom Workflow Activities on the Cloud!!

Finally! This one is a big one for me. No more thoughts of plugins and custom entities to handle "special" workflow code. I'm not sure why they weren't selling this one more (or maybe I had my head in the sand for a while!), but this is one I've been looking forward to for a while.

Thursday, 2 February 2012

Convention over Configuration - Case sensitivity?

Today I had a debate with a fellow employee about the naming conventions of some fields on a CRM form. It's a slightly off the norm of "convention vs configuration" arguments, instead it was more of a "Convention A vs Convention B" type argument. Take this example, the particular field that was added was a web resource. For other reasons we have some javascript that passes over the form to try locate these web resources. I designed the javascript so that it will always look for web resources that start with the following naming convention:

WebResource_DS*

So, if we follow this convention we don't need to configure anything. Note that DS is a recognised acronym in our organisation. Unfortunately we ran into some problems in our testing environment, some of the controls weren't being detected. I take a look at the controls and they've been named:

WebResource_ds*

Now, my gut reaction is to fix the script to allow for case sensitivity... but after a quick think this feels wrong to me. If we're following convention shouldn't it be case sensitive? For example, if we introduce camel casing on database field names then "productname" is incorrect, it should read "productName".

So instead of changing it I argued that it should follow the convention of _DS including upper case. I argued that if you follow "convention over configuration" it should include case sensitivity. This should be especially the case for known acronyms (if the convention states all upper-case for acronyms). The debate that he put forward is if you've ever read something like "the design of everyday things" everything should be intuitive, so 'DS' or 'ds' shouldn't matter.

I see his point... but I stick by my guns!

Monday, 5 December 2011

Mocking out Environment.Exit

Question I came across recently on Twitter.

"How do I write a test when there's an Environment.Exit?! :("

Very good question... My answer was basically rewrite the code! A really quick way to do this is create a static action that will allow you to mock it out. What if I created a class called MyEnvironment with this Action:

    public class MyEnvironment
    {
        public static Action Exit = exitCode => Environment.Exit(exitCode);
    }


In code I can just replace the call with this:

    MyEnvironment.Exit(0);


And now, in my testing I can do something like this:

    MyEnvironment.Exit = exitCode => { };


Voila! No more interrupted tests :)