4. How AOP can help
• Introduce consistency
• Aspects are isolated and centralized features
• Require minimal effort
• Make use of pre-existing aspects
• Introduce limited risk
• Granularity choices
• AOP is reversible
5. AOP choices
• Interceptors
• Depends on Inversion of Control Containers
• Requires Dependency Inversion/Injection patterns in the code
• Existing frameworks
• Many have injection points
• Isolated functionality added at these points is AOP
• IL Weaving
• Modifies the code post compilation
• Limited codebase changes
6. IL Weaving
• Each aspect is an implementation
• Granular attachment options
• Changes are usually additive
10. Implied Functionality
public class OrderFulfillmentService
{
public void Fulfill( Order order )
{
try
{
// Do stuff.
}
catch ( Exception e )
{
if ( ExceptionHandler.Handle(e) )
throw;
}
}
}
12. Existing implementations
• Toolkits exist for many common needs
• Logging
• INotifyPropertyChanged
• Exception handling
• Some will be difficult to use in brownfield scenarios
13. Moving forward with AOP and Brownfield
• IL weaving is the
• Easiest technique to add non-functional requirements
• Lowest impact to existing code
• Easiest to back out
• Make use of existing aspects
• Don’t forget to leverage frameworks already used
Lots of brownfield codebases are a messed mix of procedural, OO and functional programming styles. It’s not uncommon to see an OO language used to write an application in purely procedural code. The result is that the code is tightly coupled through out. Add to this a lack of file, code and namespace organization and you’ll quickly feel like you’re running around in circles when you’re trying to navigate through the code.Once you do get a feeling for the code you’ll notice that there are glaring consistency issues. One API might have logging enabled on it while another doesn’t. When logging is implemented the messages entered into the log may differ method to method. Different techniques for transaction management may be used in different locations. In short, every time you step into a section of code it’s a learning experience.All of these things culminate in one undeniable fact; any change you make to the codebase is a dangerous change. No matter how trivial the change you make there will always be some unintended side effect that cascades through the application breaking something. You can’t easily protect yourself from this either. The previous developers didn’t create a full suite of unit/integration tests for you to rely on, and those that they did create don’t really test anything of significance. To add tests that protect you from breaking changes you need to change the code to make it more testable; a classic chicken and egg issue.
Consistency - how features are implemented - where features are implementedEvery new feature, or gain in consistency, can’t require a rewrite.Have to understand the risk in each change and be able to back out the change if the risk assessment was wrong
Granularity – each aspect can be attached where appropriate; class, method, event, etc.Reversibility – AOP can be backed out and individual aspects can be backed out
Existing frameworksMVC inherit from HandleError and apply via ConfigWCF add transaction mgmt to every callNhibernate add auditing to every CUD action
- Implementation isolationapplication, class, method/property/event level attachment gives optionsAdditive changes are the least risky. Modification