Article originally posted in the Orlando Developer blog.
A goal in writing any application should be to write the application logic outside the framework then within your framework write a wrapper to use your module. This facilitates the migration process between frameworks and versions.
The examples below suggests that you can inject your framework-specific libraries into your extracted module. You can do this but I would suggest against it in place of using another framework-agnostic library from the start and locking the version of the dependency. Then during a migration, you can run your tests to verify that it still works and refactor if not. There will be times when you will have to fix the module upon migration to allow for an updated injected library since updating libraries during a migration is an opportune time to do so. In most cases, fixing a module is a lot easier than re-writing the whole module.
Even better than injecting libraries, I suggest using built in browser functions. In the case of Angular’s
$http, I suggest using the browser’s
fetch() function (and Github’s fetch polyfill for not yet supported browsers). Then when the module is used elsewhere, it works exactly as it did to begin with because it has no reliance on a specific framework.
Now let’s compare this to the component syntax for Angular 2.
You’ll notice that the MyComponent class looks an awful lot like the BusinessLogic class in the first example. This creates the reusability factor mentioned in the beginning of this article and makes migrations from framework to framework (or updated versions of your framework) that much easier.
One caveat to the approach for modularity is that you end up with multiple instances of your module. Behind the scenes each time it’s being called, it’s instantiating a new object. To avoid this you could use a singleton (example in ES6). Be careful when using singletons though as they are considered an anti-pattern and generally considered poor practice to use.
Another caveat is when you have to call
$scope.$apply(). In this case, you will need to inject
$scope into your module to allow you to run this. This is an easy refactor when migrating though because it is easy to find and remove these calls.
I hope I’ve inspired you to think more critically about the way you approach your applications. I would thoroughly enjoy hearing your thoughts on this pattern as well as suggestions for improvement.
Writing your modules outside the framework lets you test them easier, creates more modular/reusable code, and yields to easier migrations from framework to framework and updating versions of a framework.