Framework Callbacks Are Shells
From Programmer 97-things
Your framework is not your application. Containers and frameworks are supposed to help you, yet they can also get in the way of writing quality code.
What good programmers have known for a long time is that you don't write real code into your framework entry points. Whether they be code-behinds, interrupts, action delegates, or callbacks of any variety, they can seriously impair your ability to test and debug your code.
For instance, how much setup do you need to test a function that takes an HttpContext as a parameter? One will quickly find it necessary to create objects that are needed to create the context, and probably will also have to mock objects that would be contained in/behind the HttpContext. In addition, such a function has to establish its context within the application and so it will likely access static methods/variables and may instantiate objects directly if no dependency injection is being used.
In many instances, we find programmers abandon testing code that is called from a Web UI or graphical UI. It simply becomes too difficult to initialize all of the framework bits that are needed to carve out a testable unit. Often developers will create a large, unwieldy test harness to test the code "in context" rather that struggle with extensive setup.
Instead, the framework's call into your code has to be as thin as possible. It should collect data from the context it is given and possibly from the various factories or object mothers that live in the system, and then call plain-old methods to do any useful work. "Plain old methods" in "plain old objects" are easily testable. The less they interact with the application's static objects, static methods, and framework objects the easier they are to test.
An example of this principle is the Model/View/Controller pattern. All of the "real work" is done by the model, as instructed by the controller. The View is left as thin as possible because views are notoriously hard to test. The Presenter First method ensures that the view is kept as thin as possible. It also encourages the author to push functionality into the model, away from the view.
Inevitably it will seem convenient to code real functionality directly into framework callbacks, but practice indicates that it is seldom wise to do so. Whatever is hard to test is also hard to debug.
