In this recent post I mentioned that in response to the recent release of updated versions of Developer Express’ Visual Studio productivity tools (2009.2.6), I was not only providing an updated build of the CR_ClassCleaner plug-in compiled against the latest DXCore release, but that I also decided to incorporate the patch to CR_ClassCleaner mentioned in this post by Brendan Kowitz. This patch doesn’t change any of the intrinsic capabilities of CR_ClassCleaner per-se, but does provide for adding its invocation to the ‘Refactor’ context menu when its activated and the cursor is in an appropriate location as seen in the following screenshot (admittedly appropriated from Brendan’s own blog post):
In doing so, however, I unwittingly introduced a new dependency into the CR_ClassCleaner project. Since the ‘Refactor’ context menu only exists in the DevExpress CodeRush, Refactor! Pro, and CodeRushXpress products, adopters of CR_ClassCleaner are no longer able to use the plug-in unless they have one of those products installed in their instance of Visual Studio. Since Developer Express has done the amazing thing of making CodeRushXpress available to all developers for free, thankfully this doesn’t introduce a cost requirement for using CR_ClassCleaner. But plenty of CR_ClassCleaner adopters are only interested in installing CR_ClassCleaner and don’t want to use even the free CodeRushXpress functionality in their IDE, usually because they have already settled on a competing IDE productivity tool and don’t need either CodeRush, Refactor! Pro, or even CodeRushXpress.
By introducing a dependency for CR_ClassCleaner on having one or more of these other products installed, its now more difficult for interested parties to adopt and use the CR_ClassCleaner tool because it now requires one or more of the ‘higher level’ DevExpress IDE tools be installed.
What’s in a Name?
Despite the fact that the name of the plug-in is ‘CR_ClassCleaner’, its fundamental behavior didn’t actually require CodeRush (or even CodeRushXpress) be installed in order for a developer to make use of the CR_ClassCleaner plug-in. In fact, its only dependency was on the DXCore library that DevExpress uses as a common abstraction layer upon which its other Visual Studio products (CodeRush, Refactor! Pro, and CodeRushXpress) are designed. This distinction isn’t helped by the use of the ‘CR_’ prefix for the CR_ClassCleaner plug-in, which would seem to at least hint at the need for CodeRush (or at least CodeRushXpress) to be installed in order to make use of the plug-in.
So that everyone can better understand how all these dependencies work, its probably worth digging into the dependencies of the DevExpress Visual Studio Tool for bit…
Understanding the DevExpress Visual Studio Tools Stack
The figure at left is an attempt to depict the ‘dependency’ stack for the DevExpress Visual Studio extensibility tools in a single, simple diagram that all can comprehend.
At the very bottom (in blue) is the ‘native’ Visual Studio extensibility API layer as provided by Microsoft. This is the extensibility point with which developers must interact when developing Visual Studio add-ins if not working at all with any DevExpress VS integration tools.
Immediately atop this lowest layer is the ‘DXCore API Layer’ (in red). This layer represents the abstraction API developed by DevExpress for their own use in simplifying their development of their own CodeRush and Refactor! Pro tools (and now, also their freeware CodeRushXpress tool). Although its neither open-source nor redistributable directly by third-parties, DevExpress makes the DXCore ‘engine’ available for anyone to build plug-ins atop and provides it for free for anyone to download and install into their copy of Visual Studio.
The DXCore layer and the manner in which it simplifies, abstracts, and makes consistent the otherwise messy and complex native VS API is one of the main reasons why I gravitate to the DevExpress productivity tools for my IDE productivity suite. It represents a significant competitive advantage for me to be able to leverage it to create my own Visual Studio plug-ins atop it much faster than I could if forced to interact with the native VS extensibility API myself.
The next layer is where things really start to get interesting for both plug-in developers and for Visual Studio end-users. At this layer, you see the commercial (for-fee) offerings from DevExpress: CodeRush and Refactor! Pro as well as the free offering from DevExpress: CodeRushXpress. These are all three built atop the common DXCore API ‘engine’. Where it gets interesting is that this is also where you find the box ‘DXCore-based Plugins’. With enough time, effort, and energy anyone can write a Visual Studio plug-in atop DXCore that’s every bit as powerful and functional as CodeRush, Refactor! Pro, and CodeRushXpress.
I’m pretty sure that the DXCore license specifically enjoins you from using DXCore to produce a commercial product that competes with the DevExpress commercial offerings (which seems only fair and is probably one of the reasons that you are enjoined from actually distributing the DXCore API libraries yourself), but by leveraging the DXCore API library and copious amounts of your own spare time, you could create a Visual Studio plug-in that does anything that you see the commercial DevExpress IDE tools doing. After all, CodeRush itself is ‘just’ a bunch of code that DevExpress wrote themselves by leveraging the very same DXCore APIs that you can make use of as well.
Best of all, take careful note of where such plug-ins are in the dependency chart: they are directly atop only the DXCore layer and are not on top of either CodeRush or Refactor! Pro. This means that plug-ins written as this level require only the free download of DXCore in order to function and don’t require the purchase of either CodeRush or Refactor! Pro nor the installation of even the free CodeRushXpress tool in order to function. This means that people who wish to use such plug-ins don’t have to worry about the installation of any software that will conflict (behaviorally) with any other installed Visual Studio productivity tools (e.g., JetBrains Resharper, etc.). Since DXCore by definition is just a set of libraries that abstract away the underlying VS API and provide powerful convenience services to other plug-in authors, installing DXCore won’t affect any other installed Visual Studio tool.
Plug-ins that fit into this category are things like my own DX_SourceOutliner plug-in and the CR_ClassCleaner plug-in mentioned at the start of this post.
By convention (which is completely unenforceable by anyone), these plug-ins are prefixed with ‘DX_’, indicating their dependence on only DXCore. I follow this convention in my own development of such plug-ins as do many others, but as you can see in the naming of CR_ClassCleaner, not everyone else does this. This isn’t a ‘knock’ on the original author of CR_ClassCleaner at all as this situation is exacerbated by several unfortunate factors that conspire to make this problem quite common:
- DevExpress’ own ‘create-new-plug-in wizard’ provided with CodeRush hints that you should use ‘CR_’ as a prefix for your plug-in; this actually makes some sense since the wizard is actually a part of CodeRush and so its reasonable to assume that people launching it are then going to create a plug-in for CodeRush rather than the less-fully-featured DXCore or even Refactor! Pro
- Once you install CodeRush, its incredibly difficult for a plug-in developer to know whether the plug-in they just wrote requires anything specific to CodeRush, Refactor! Pro, or just the free DXCore infrastructure as there’s no real clarity re: which assemblies containing which objects ship with which product.
- This situation is made worse (for plug-in developers) by the introduction of the freeware CodeRushXpress which contains a subset of the overall CodeRush + Refactor! Pro libraries. The only way I can think of to mitigate this issue (and believe me, I have considered taking the time to do exactly this) would be to install and uninstall each product (DXCore, CodeRushXpress, Refactor! Pro, and CodeRush) one by one, taking careful note of which assemblies are installed with which product and making a map of all these dependencies for future reference [are you listening, Developer Express??? I — and others — could really use this!!!]
As a result, anyone developing a plug-in is really just ‘playing it safe’ when they prefix their plug-in with ‘CR_’ indicating a dependency on CodeRush…it may not actually require CodeRush, but saying so is the safest thing to do since CodeRush is a superset of everything else in the stack.
People like myself that can afford CodeRush often lose sight of the fact that many are in situations where they cannot and so developing a plug-in and unnecessarily labeling it as requiring CodeRush (commercial) leaves many who would otherwise choose to use the plug-in thinking that they are unable to do so because they don’t own a CodeRush license. If fact, in many cases, all they need to use a particular plug-in is just the DXCore library or even just the freeware CodeRushXpress.
This last layer is the top of the stack, where the most powerful stuff lives. Here, developers can build custom plug-ins that leverage not only the capabilities of DXCore, but also the capabilities of CodeRush and Refactor! Pro themselves. In the same way that DXCore provides powerful tools to interact with the underlying VS API, developers building atop CodeRush and Refactor! Pro have access to a rich object model replete with methods for interacting with the Code DOM, performing low-level refactoring via simple method calls, painting to the screen with all kinds of rich UI widgets, and much more.
By convention, such plug-ins are prefixed either with ‘Refactor_’ or ‘CR_’, indicating their dependency on either Refactor! Pro or CodeRush to function. Examples of such plug-ins are my own Refactor_UpdateNamespace and many others available at the DXCommunity Plug-Ins Google Code Site and elsewhere on the Internet. Sadly , not everyone follows this naming convention either, and many plug-ins that turn out to only require a license for Refactor! Pro are needlessly prefixed with ‘CR_’, making many assume that they need a full license of the more expensive CodeRush tool in order to use the plug-in.
Interestingly, my own recently-released Refactor_UpdateNamespace plug-in was initially thought by myself to require at least the commercial Refactor! Pro only to have someone inform me that (luckily) it also seems to work just fine with the freeeware CodeRushXpress. Obviously, whatever (very limited) functionality of Refactor! Pro I am using in Refactor_UpdateNamespace turns out to also be present in the CodeRushXpress toolset. Who knew? And more importantly, who could know???
This is the reason that the two blocks, ‘CodeRush-based Plugins’ and ‘Refactor! Pro-based Plugins’ sit atop not just the commercial CodeRush and Refactor! Pro components but also combine to straddle the freeware CodeRushXpress component in the above diagram. Sometimes, it appears, its possible for a plug-in requiring CodeRush to work just fine under CodeRushXpress, for example. This kind of thing (disappointingly) further muddies the water both for plug-in authors and for would-be plug-in adopters: if you cannot tell with any certainly what the prerequisites are for your being able to use a particular plug-in, you’re quite likely to just pass it up while assuming you don’t have the prerequisites to use it.
What does this mean for CR_ClassCleaner?
So what’s a plug-in author to do in this case where the underlying functionality of the CR_ClassCleaner plug-in requires only a dependency on DXCore but there is still value in wanting to expose the functionality using the ‘Refactor’ context menu (which introduces a dependency on either CodeRush, Refactor! Pro, or CodeRushXpress)? How can we safely expose the CR_ClassCleaner to people who only want to install the DXCore API library and at the same time provide for the richer UI experience of invoking CR_ClassCleaner via the ‘Refactor’ context menu for those that are adopters of either CodeRush, Refactor! Pro, or CodeRushXpress?
The answer I came up with is deceptively simple: separate the two functions into two different plug-ins. One plug-in, the original CR_ClassCleaner, will continue to depend only on DXCore and must still be invoked by whatever keyboard shortcut you should choose to assign to it. The second plug-in – let’s call it Refactor_ClassCleaner_Menu – will provide the menu choice for the Refactor context menu and internally delegate the actual work to the CR_ClassCleaner plug-in.
As depicted in the diagram at left, this results in a situation where the Refactor_ClassCleaner_Menu plug-in ‘wraps’ the functionality of the CR_ClassCleaner plug-in.
If you have either CodeRush, Refactor! Pro, or CodeRushXpress installed (and you want the integrated menu functionality for CR_ClassCleaner) then you want to grab both plug-ins and drop them into your plug-ins folder so that Visual Studio can find them.
But if you only want to install DXCore and none of the other mentioned DevExpress Visual Studio IDE productivity tools, then you drop only the lone CR_ClassCleaner plug-in into your plug-ins folder and interact with it just as always via only the keyboard shortcut(s) to which you assign its actions as always.
This approach gives CR_ClassCleaner adopters the best of both worlds – the ability to run it atop just DXCore if that’s your choice or the ability to get the Refactor context menu integration if you have one of the DevExpress add-in tools that supports that level of integration too.
You can get the latest build of both of these plug-ins here:
CR_ClassCleaner (original functionality, compiled against the DevExpress 2009.2.6 release of their Visual Studio productivity tools suite); requires only that you install DXCore 2009.2.6
Refactor_ClassCleaner_Menu (provides the Refactor context menu integration); requires that you have the 2009.2.6 release of either CodeRush, Refactor! Pro, or CodeRushXpress installed; includes the ‘correct; build of CR_ClassCleaner in the download as well for convenience reasons
When I have a moment, look for me to post the source for Refactor_ClassCleaner_Menu to the DXCommunity Plugins Google Code site (which is really just the code that Brendan wrote in his patch mentioned in his blog post extracted into a stand-alone plugin project). This whole process should make it dirt-simple for users to adopt whichever of the two approaches to integrating CR_ClassCleaner into their Visual Studio environment best suits them.
As always, Happy coding~!