I’m happy to announce that I have managed to complete a new plugin for the DeveloperExpress Refactor!Pro product: Refactor_MoveTypeToFileInProject.
You can download a binary of the the new plugin here.
Why Would Anyone Need This?
Users of the DevExpress Refactor!Pro tool will probably be aware of the built-in Move Type to File refactoring that does exactly what its name suggests: permits you to easily move a type declaration (class, interface, struct) into a new file all by itself. As shown in the following screenshot, this can be useful as a follow-up refactoring to something like the Declare Class refactoring that places the new class into the same source file as the one you’re in when you invoke the Declare Class refactoring…
In the above screenshot, the result of the Declare Class refactoring will be that the new class, TheNewClass, will be declared in the same file as the current class, SomeClass which is just fine as an ‘intermediate’ refactoring, but is rarely exactly what you most often want as an end-state for the refactoring process. To address this ‘problem’ of most developers not wanting more than one type declared in each source file, DevExpress also provides the Move Type to File refactoring. As shown in the following screenshot, the Move Type to File refactoring is available whenever the cursor (caret) is in the name of a type declaration…
Invoking this refactoring will result in the type declaration being moved to a new source file in the current project.
What’s So Wrong With That?
So that seems pretty helpful, you would probably say – it does what I really want 90% of the time. And you would probably be correct – unless you were doing TDD 🙂
In Test-Driven Development (TDD) we want to write a failing test first, then move on to write the implementation code that makes the failing test pass. Usually (though certainly NOT always) we tend to want to separate the projects where we are writing the tests from the projects where the production code resides so that we don’t end up deploying tests into production assemblies when the project is ready to be released.
The usual TDD process looks something like this:
- write a test in the test project; often this will include calls to classes that don’t exist, methods that don’t exist, etc.
- use CodeRush/Refactor!Pro to create classes and methods in the same source file as the test in order to get it to pass; usually we tend to want to stay in the same source file to minimize the amount of navigation between the source file with the test and the source file with the class(es) that we’re evolving
- when we finally get a passing test, its time to ‘clean up’ the source file with the test and the class(es) being tested to move the ‘production code’ out of the test project and into one or more ‘production’ projects in the solution
- Use Move Type to File refactoring to get the class(es) being tested moved to separate source file(s) in the test project
- Use VS solution explorer to drag-and-drop the source file from the test project into the proper ‘production’ project (with SHIFT to ensure a MOVE vs. a COPY operation)
This pattern repeats itself over and over again in the TDD process and really means that if we’re writing the tests in Project A and the production code is in Project B, when we are in our test project (A) and running the Move Type to File refactoring, 99% of the time what we really want to do is move the type to a file in another project rather than the current project. With the present tools (refactorings) at our disposal we have to first move the type into a new file in the (current) test project (A) and more often than not the very next thing that we need to do is move that new source file out of Project A (the test project) and into Project B (the production project).
Anytime you find yourself frequently repeating the same manual task over and over again, its a good candidate for a tool and this is no exception 🙂
My new plugin, Refactor_MoveTypeToFileInProject does just what its name suggests: it mimics the behavior of the built-in Move Type to File refactoring but provides the ability to select a target project for the new source file to be created in other than the current project. As you can see in the following screenshot, this is provided for in a convenient fly-out menu that list all of the projects in the current solution (sorted alphabetically by project name) other than the current project…
If you look closely at the popup menu, you can see that the original built-in refactoring, Move Type to File, is still available as well. If you really want to move the type declaration into a new source file in the same project, then simply select this refactoring instead of the new one provided by the new plugin. But if you want the type declaration moved to a new source file in another project in your solution, then simply select that target project from the fly-out menu and you’re good to go.
Note that once you invoke this refactoring to move the type declaration to a new project, a great follow-on refactoring to apply to the newly-extracted type in its new project home would be the Update to Default Namespace refactoring provided by my Refactor_UpdateNamespace plugin. Since the type declaration in its new file will still retain its original namespace from its source location before its extraction (which is probably inappropriate for its new location in its new project), the Refactor_UpdateNamespace plugin provides just the fix you will most often need to properly move the new type into the ‘proper’ namespace for the project that now contains it as shown in the following screenshot…
Of Note, a Complimentary Plugin: CR_DeclareClassInProject
Its probably worth pointing out a (relatively) new plugin by Rory Becker called CR_DeclareClassInProject that tries to solve more or less this same problem in a slightly different (but, I think, complimentary, way). Available just as with my own Refactor_MoveTypeToFileInProject in the DXCoreCommunityPlugins repository on Google Code, CR_DeclareClassInProject solves the problem in reverse order: it enables you to declare the class in a new source file in a different project in the first place rather than first declaring it in the same project and then moving it into a new file in a new project later.
I think that Rory’s approach solves the issue in a pretty clever way with CR_DeclareClassInProject and when paired with my new Refactor_MoveTypeToFileInProject, provides just about all the flexibility one might need to support more effective TDD with DXCore/CodeRush/Refactor!Pro in the manner in which most TDD-practitioners tend to work.
Following is a quick screenshot of the CR_DeclareClassInProject plugin in action…
Just as with the Refactor_MoveTypeToFileInProject plugin, note that the built-in Declare Class refactoring is still available to you so if you still want to declare the class in the same project (in fact, in the same source file) then you still can do so of course.
Wishing for just one more thing…
The only thing missing from Rory’s plugin is support for the other common ‘type declarations’ that .NET provides: notably interface and struct. I’m going to reach out to Rory to see if he would be interested in extending his plugin to more broadly offer ‘Declare Interface in Project’ and ‘Declare Struct In Project’ rather than just ‘Declare Class in Project’ and hopefully he will be amenable to that.
If you’re interested in checking out the CR_DeclareClassInProject plugin in its present state (supporting class types only), you can download a ‘convenience’ build of the plugin from my own site here or else just grab the source yourself from the DXCoreCommunityPlugins site on Google Code and build it for yourself!
A Pretty Comprehensive Suite of Refactorings for TDD is Shaping Up
If Rory is amenable to extending his plugin as I suggest, then the killer combination of the built-in functions for dealing with types…
- Declare Class
- Move Type to File
…when coupled with my new plugin and Rory’s offering (if extended to support interface and struct types) which would provide the following additional capabilities…
- Declare Class in Project
- Declare Interface in Project
- Declare Struct in Project
- Move Type to File in Project
…then paired with the Update to Default Namespace plugin can collectively provide a pretty comprehensive suite of TDD-centric refactorings for CodeRush and Refactor!Pro adopters.
What’s Still Missing?
Presently I’m unhappy with the level of UNDO/REDO support that my Refactor_MoveTypeToFileInProject plugin offers (read: very little!) and so I have on my agenda to do some research into how the CodeRush API offers support for UNDO/REDO of actions like adding files to projects, etc. that aren’t all that easy to undo because they involve interaction with the file system. Until then, just recognize that the plugin doesn’t really offer first-class support for undoing its actions in an acceptable manner so any post-CTRL-Z cleanup is on you for now 🙂 so use with caution!
As usual, any feedback, comments, etc. (positive –or- negative) would be welcomed!
Till then, Happy Coding to all~!