Planning SharePoint Solution Packages (WSPs)
SharePoint architects and developers often wonder how best to design solution packages for long-term ease of use, especially through upgrade cycles. In a survey of SharePoint developers I found a range of strategies from one monolithic WSP to hold everything, up to practically one per feature which resulted in as many as 50 WSPs for a project. The variance depended on the developer's goals for maintenance. Application vendors want to keep things simple for admins, so a single solution per product makes sense. When downtime needs to be absolutely minimized and you need absolute granular control over each and every feature, maybe you want to maintain dozens of packages so that upgrading one will minimally affect the others.
But what I wanted was a strategy that recognized the average case rather than the extremes. From there, as with any taxonomy, specific implementations can either generalize up to the monolithic, or specialize down to the highly granular. Reza's strategy used 5 packages (follow the link for details), so I started there and through several trials arrived at the recommendations found here. Along the way, principles emerged to guide a general strategy.
Principles of SharePoint Development Structures and
Packaging
- You need naming standards. Plan your .NET namespaces, feature names, content types, list ID numbers, internal names for site columns, custom field types, and every other possible element so that related work sorts together in the \bin, the Global Assembly Cache (GAC), the \TEMPLATE\FEATURES subtree, and any other folder, and is easily differentiated from other work as you walk through elements in code. Across projects you need to maintain a central index of List Type IDs (starting from 10000) to avoid collisions.
- Think of your source control as a series of snapshots kept in step with your WSP packages. If you need to roll back to a previous version, that means going back to a previous set of WSPs, and that means being able to compare that complete working code set with the broken one. More often you'll see the benefit in code reviews, during which any decent differencing utility will help you review the sections that changed from the old to current version.
- It is preferable to have more (not fewer) Visual Studio projects and assemblies (DLLs) packaged as more (not fewer) Features. The benefit is that it is often (though not always) sufficient to only regression-test the assemblies that changed from version-to-version, rather than to build do-it-all assemblies [of course this depends on how specialized or loosely-coupled your assemblies are in the first place]. When the changes of many developers need to be tested in a release, it is harder to isolate the work of each in monolithic projects and assemblies. If your namespaces are consistent so your project assemblies are easily identifiable, then server administrators should prefer this selective strategy too; it's when dozens of assemblies with random names are scattered across the GAC that people justifiably complain.
- It is preferable to package your VS projects and features as fewer (not more) WSPs. The more WSP packages you have, the longer they take to install, and the more complicated your deployment scripts. That said, smaller teams will tend towards fewer WSPs, and larger teams will have more. But keep it within reason. Each developer will own different areas of functionality, and people "get in each other's way" less often when team roles map to distinct solutions.
- You do not need to create WSPs to develop, you do need WSPs to deploy. It takes a long time to retract, delete, add, and deploy a solution, and the cycle provides no benefits in a dev environment. Obviously, this applies until it's time to test packaging and deployment. If you only need to test a code change then copy the updated assembly to the GAC and recycle the Application Pool. If deploying to the \bin, you can even skip the recycle. You do not need to redeploy an entire solution to test discrete changes to code or ghosted aspx files.
- When deploying solutions with STSADM you have the option of going through the full retract, delete, add, and deploy cycle or to use the "-o upgradesolution" switch. While upgradesolution is faster than going through the complete cycle, it does only upgrade existing features. Any new features in the solution will need to then be installed individually to each Web Front End (WFE) in the farm. Only the complete cycle ensures that new features will be installed automatically to every WFE in the farm.
- It ain't easy to version Content Types. Your options are to a) once deployed, never upgrade a content type; b) only update content types through the UI; or c) update content types in code. I prefer to upgrade content types in code, albeit through a generic tool (based on code by Søren Nielsen wrapped in an STSADM extension by Gary Lapointe) that propagates the content type schema down ot existing instances. John Holliday also described an iterative approach to content type updates in chapter 11 of Professional SharePoint 2007 Development.
Standard Operations
There are four installation
and upgrade operations to plan for:
1. Installing and activating features (packaged as WSPs),
2. Creating content with features (e.g. site provisioning and list instances),
3. Deactivating and removing features, and
4. Removing the content created by features.
During an upgrade you normally don’t want to alter
existing content, you want to remove current functionality
and replace it with a newer version. If you keep these four
operations in distinct packages, it’s easy. When you start
mixing list definitions with list instances, or mixing
deactivation with cleanup, you can no longer manage these as
distinct operations. Therefore guidance to "always clean up
after yourself in the feature deactivated receiver" is wrong
if your goal is to update functionality without affecting
existing content.
Recommended solution packages (WSPs)
1. Global (assemblies and server controls)
2. SP Administration features (e.g. Central Admin features, web services, and STSADM extensions)
3. SP Base Features (elements re-used among projects and site types)
4. SP Site Features (e.g. stapled features or site definitions)
5. Chrome and Branding (e.g. gallery content including master pages, style sheets, and layout pages)
6. Instances (e.g. site-provisioning feature receivers, features containing list instances, and cleanup receivers)
Notice the narrowing trend in this order from
farm-wide down down to specific instances. Another way to
see it is as a layering of features from a foundational base
up through presentation. Any of these packages can be
divided further. For example you may want to manage separate
solutions for instance creation vs. instance cleanup. Or you
may want to maintain different site definitions and their
constituent features (or stapled feature sets) in separate
packages. Also, any of the elements can move around where it
makes sense. For example, if you prefer to put list instance
features (usually in #6) in the same solution as their list
definitions (in #3 or 4), do it. Just be sure you don't
reactivate your instance features (and create new redundant
lists) every time you upgrade your list definitions. The
decision is whether to simplify the maintenance of code, or
maintenance of your deployment scripts.
When
creating the actual Visual Studio Solutions to support each
of these packages, it helps to name the folders to sort in a
natural order, for example:
MyCompany1Global,
MyCompany2SPAdmin,
MyCompany3SPBase,
MyCompany4SiteTypeThis,
MyCompany4SiteTypeThat,
MyCompany5ChromeDefault,
MyCompany5ChromeHalloween,
MyCompany6InstancePortal,
MyCompany6InstancePersonalSites.
I hope you find this to be a useful strategy for
organizing your own solutions and packages. As always I'd
love to hear feedback about other approaches, exceptions to
the rules, and other thoughts on the topic. Another time
we'll dig into sample solutions to further explore namespace
structures and automated build strategies.
Acknowledgements
Thank-you to Reza Alirezaei, Jake Dan Attis, and Dan
Larson who shared their strategies on solution design. Also
thanks to Robert Bogue for reminding me of the weaknesses of
upgradesolution and Brendon Schwartz for rekindling the
whole topic, that was the kick I needed to finally commit
these ideas to a post.