[...a response to RefactoringFrameworkBasedApplications
- a question originally posted to a Yahoo refactoring discussion group]
Q: How is refactoring different when you're using a framework?
A: It's like interfacing with an external system:
Assuming that you can't redesign the framework at will, you'll have a potentially very large interface to an external system (the framework) that may not implement or expose exactly the abstractions most useful to your application.
You may have to implement an "abstraction layer" of components between you and the framework, to make up for any differences between the way the framework sees things and they way you need to.
The closer the framework is to what you need, the less you need to do this.
Conversely, if a poorly designed framework is forced on you for political reasons, or if the framework just isn't very well suited to your application's needs, you will probably find yourself writing a significant number of interface classes.
A: It's like adopting a religion:
If you accept the framework's way of looking at the world, and bend your requirements and application structure to it, you'll be happy.
Otherwise, you'll be in a world of grief. (...and be branded a heretic.)
(See also RefactoringWithDesawareNtServiceToolkit.)
I would not totally agree with the argument. I think an object-oriented framework behaves different than any other external system if you would like to refactor your application code. There are two examples that make me believe in this.
Some frameworks provide design alternatives for a designated problem. The JwamFramework
for example provides two to three different white-box frameworks to realize highly interactive graphical tools. The developer chooses one of the alternatives depending on the complexity of the tool. As time goes by you may have to switch from one alternative to another because your tool gets more complex. I regard this situation as a special framework-related refactoring. The code smell is that our implementation of the tool got too complex and that you should choose another framework alternative to improve the code for the tool. This refactoring is not as easy as it would be without the framework because both alternatives can be characterized as white-box frameworks. The special problems coming up in this situation are described in the next point. But this kind of refactoring seems closely related to the framework and to the character of the framework as object-oriented and white-box. That makes it different from other external stuff used in your application code. One of the interesting questions for me is: Is this situation special for the JwamFramework
or did you observe similar situations with other frameworks like JavaUnit
Lets imagine a situation where the framework provides a part of it as white-box framework. And lets imagine that you are not allowed to change the framework according to your needs. You have subclassed a white-box superclass of the framework and you have overridden a designated method of the superclass to inject your application-specific behavior. This kind of relationship between the framework and the application does not allow you to freely rename or move the method, for example. I am currently investigating this situation in more detail. But comments and further ideas are highly welcome.
Terminology question: "What is a WhiteBoxFramework
["Are we talking about CodeGeneration?" "No. CodeGenerationIsaDesignSmell."]
With a framework you have to think in terms of CompoundObjectProgramming
, as opposed to normal single-class object derivation. Most desirable refactorings will affect a cadre of classes. You might also want to consider a LayeredApplicationFramework
approach, where your desired specializations are kept separate from the core framework, which allows vertical growth of the frameworks usefulness without destabilizing the original uses. -- ScottJohnston
We use a LayeredApplicationFramework
(for the JwamFramework
) but I don't understand the effect of the layering technique on refactorings. Can you give us more details, focusing on the refactoring question?
Layering is immaterial when the goal of refactoring is completely internal to the framework, the re-organization of code without change to the external API. All I think you need for that is an awareness of the interrelated nature of the objects, the CompoundPatterns
you are dealing with. However, I imagine that often a framework refactoring is undertaken to address user requirements/desires for the external API. In this case there is a need to preserve behavior for existing uses, while adding new behavior. One way to do this is with augmentations and refactorings within the base framework. Another way is to leave the foundation alone, and build a layer on top. -- ScottJohnston
Now I see your point. Thanks. But you focus on refactorings of the framework itself. My colleague StefanRoock
is doing a lot of research in this area, it is the topic of his PhD thesis in some way. But for me it is more interesting to know how the usage of a framework for application development influences refactorings inside the application code. I wrote above two of my observations about design alternatives and white-box reuse structures. It would be interesting to know if you have any thoughts on that.
I wrote a good deal below that may or may not be interesting to you. I have some particular experience with Design Alternatives, but in the context of closely related frameworks with a shared lineage. In that case I've seen switches to alternate frameworks to get portability to a new operating system, or to get a more complete feature set. These switches were greatly accelerated by the shared source history and shared design patterns (one example was plugging DougSchmidt
under the pre-existing dispatcher class of InterViews
from which it was forked). As for White Box issues, I think layering is important aspect of that. Forgive me if I am having trouble discerning what thesis you are trying to support. The original question begs another question of "different from what?" -- ScottJohnston
I would say that layering adds an extra dimension to the refactoring of applications based on a framework. I once built a military mapping application on top of a military mapping framework on top of a civilian mapping framework on top of a multi-frame graphics framework on top of a scripted graphics framework on top of a vector-graphic components foundation (actually, I'm collapsing several layers for sake of simplicity). Highly speculative mechanisms were typically implemented as close to the top of the stack as possible, and propagated downward if they proved out, and had some applicability at lower levels. Obvious generic mechanisms were implemented as far down the stack as feasible. Each layer had its own unit test. With these layered unit tests you can separate concerns where desirable (why worry about mechanisms to decode 36 bit military data in a civilian mapping framework?), and you can quickly isolate newly introduced problems to their originating layer.
And with this kind of approach the ultimate application is little more than a unit test for the top-most layer of the framework.
After thinking this through at your request, I've tentatively concluded that refactoring frameworks without layering is like refactoring objects without inheritance. What do you think? -- ScottJohnston
This is an interesting sentence. I should put that point into the internal JwamFramework
discussion forum. But this still does not hit my main point of interest. I will try to make my concerns clearer. Take a look at RefactoringFrameworkBasedApplications
. Feedback and comments are highly welcome.