Monday, August 17, 2009

SharePoint: The Wild West of Software Development

Some argue that Microsoft developers lack rigor -- that techniques like unit testing and continuous integration are virtually unheard of in this space. That’s rubbish. I would be shocked if the percentage of developers that track code coverage is significantly different for the .Net or Java spaces (not quite mainstream, but respectable). Mind you I’m talking .Net development in general. SharePoint, now that’s another story.

The shadowy world of SharePoint is one in which source control is a distant memory, where no distinction is drawn between development, test and production environments, and where roaming bandits take over small towns with no fear of the law.

Why is this? How has it come to be? The answer is that for the most part SharePoint treats code and data as one in the same. End users can modify data stores: they can add, delete and modify tables (Lists) and columns (Fields) at will. They can open up SharePoint Designer and modify pages, customize workflows, rob banks, and run local Sherriff’s out of town.

And that’s why end users love SharePoint. It removes the slow, burdensome bureaucracy involved in doling out development resources from large centrally planned corporate or government IT departments and places that power directly in the hands of end users, allowing them to get their jobs done faster and to adapt to change quicker. And that is why I maintain that as software developers SharePoint, or a product like it, is in our future -- like it or not.

But the power given to end users makes rigor and good design extremely hard for developers because the production machine you deployed to last month may look completely different now that you’re ready to redeploy. And Microsoft makes good design even harder with an inflexible API. Critical classes like SPSite (think SqlConnection) contain no public constructor, rendering them completely unmockable (unless you’re willing to spend $450 per developer for some TypeMock Isolator magic). And vital classes like SPList (think DataSet) are marked final, crippling your ability to make nice strongly typed entities in your architectures.

So what is a Type-A, quality minded software developer to do?

The thing to keep in mind is that the challenges that SharePoint places on developers and architects simultaneously make good coding practices harder (but not impossible) while making them more important than ever.

Because that column you thoughtfully added as required may get reset to optional by an end user in production, you need to write more good tests that validate once solid assumptions. Because you can’t inherit SPList, you’ll need to encapsulate it, requiring more code per entity. Because you can’t mock essential SharePoint classes you will need to write more integration tests instead of unit tests. Because you’re writing integration tests your tests will be more fragile and you’ll spend more time fixing the test code than the real code.

And because you’re spending more time focusing on quality while your Wild West, short term focused competition in the SharePoint world slings code together, they will appear faster and better able to get applications out the door. It can be frustrating, because over time your well designed and well tested application will be more maintainable and will cost IT departments less. But end users frequently don’t understand this, so as long term minded SharePoint developers we must focus on educating end users.

Combat the short term focused mindset by keeping everything in .wsp files, storing code in source control, avoiding the temptation to apply fixes in production, using continuous integration (yes, for SharePoint!), and most importantly tracking code coverage (yes, code coverage for SharePoint code!). Put quality metrics in status reports for management to see. Track defects and make your stats publicly available (since you’ll have significantly fewer over time than code slingers, and you want end users asking for stats). In short remind the world that quality counts, even in the shadowy realms of SharePoint. If we work together we can bring law and order to the … um, West.

Tuesday, August 4, 2009

You cannot grant a user a permission level that is not attached to a web

If you receive this error message that looks like this:

Microsoft.SharePoint.SPException: You cannot grant a user a permission level that is not attached to a web.
  at Microsoft.SharePoint.SPRoleDefinitionBindingCollection.AddInternal(SPRoleDefinition roleDefinition)
  at Microsoft.SharePoint.SPRoleDefinitionBindingCollection.Add(SPRoleDefinition roleDefinition)

When you’re doing something like this:

private static SPRoleDefinition FindAddEditListItemsRoleDefinition(SPWeb site) {
    SPRoleDefinition definition = site.RoleDefinitions
        .Cast<SPRoleDefinition>()
        .FirstOrDefault(def => def.Name == ROLE_DEFINITION_TITLE);

    if (definition != null) return definition;

    definition = new SPRoleDefinition {
        Name = ROLE_DEFINITION_TITLE,
        Description = "Can view and edit list items only.",
        BasePermissions = SPBasePermissions.EditListItems
            | SPBasePermissions.ViewListItems
            | SPBasePermissions.ViewFormPages
            | SPBasePermissions.ViewPages

            | SPBasePermissions.Open
        };
    site.RoleDefinitions.BreakInheritance(true, true);
    site.RoleDefinitions.Add(definition);
    site.Update();
    return definition;
}

It may be because SharePoint doesn’t allow you to use the SPRoleDefinition you just created and you have to return the one you just added. Stupid, but hopefully it will help someone somewhere.

    ...
    site.Update();
    // you can't just return definition because SharePoint gives you
    //    "You cannot grant a user a permission level that is not
    //    attached to a web" when you attempt to use it, so
    //    you need to return it again
   
return site.RoleDefinitions
        .Cast<SPRoleDefinition>()
        .First(def => def.Name == ROLE_DEFINITION_TITLE);
}