Produce Cleaner Code with Aspect-Oriented Programming
-
Upload
postsharp-technologies -
Category
Technology
-
view
2.432 -
download
3
description
Transcript of Produce Cleaner Code with Aspect-Oriented Programming
An Introduction to Aspect-Oriented Programming in Microsoft .NET.
Produce Cleaner Code with Aspect-Oriented Programming
Gaël [email protected]://www.sharpcrafters.com/
AOP Facts
• AOP is 15 years oldMature
• Siemens, Hitachi, SAP, ASML• WebSphere, JBoss, WebLogic
Industry-Adopted
• -15% Lines of Code• -20% CouplingReal Benefits
Featured PostSharp Customers
Agenda• The Problem with Conventional Programming
• What is AOP?
• Why AOP?
• PostSharp Features
• Comparing AOP Frameworks
The Problem with Conventional Programming
Part 1
In the beginning there was nothing.
public class CustomerProcesses{}
public class CustomerProcesses{ public void RentBook( int bookId, int customerId ) { Book book = Book.GetById( bookId ); Customer customer = Customer.GetById( customerId ); book.RentedTo = customer; customer.AccountLines.Add( string.Format( "Rental of book {0}.", book ), book.RentalPrice ); customer.Balance -= book.RentalPrice; }}
Customer said: let there be business value.
And there was business code.
Testers said: Let there be
logging
And there was logging code.
internal class CustomerProcesses{ private static readonly TraceSource trace = new TraceSource( typeof (CustomerProcesses).FullName ); public void RentBook( int bookId, int customerId ) { trace.TraceInformation( "Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId ); try { Book book = Book.GetById( bookId ); Customer customer = Customer.GetById( customerId ); book.RentedTo = customer; customer.AccountLines.Add( string.Format( "Rental of book {0}.", book ), book.RentalPrice ); customer.Balance -= book.RentalPrice;
trace.TraceInformation( "Leaving CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId ); } catch ( Exception e ) { trace.TraceEvent( TraceEventType.Error, 0, "Exception: CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} ) failed : {2}", bookId, customerId, e.Message ); throw; } }}
Thenthere was
precondition checking code.
internal class CustomerProcesses{ private static readonly TraceSource trace = new TraceSource(typeof(CustomerProcesses).FullName); public void RentBook(int bookId, int customerId) { if (bookId <= 0) throw new ArgumentOutOfRangeException("bookId"); if (customerId <= 0) throw new ArgumentOutOfRangeException("customerId"); trace.TraceInformation( "Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId); try { Book book = Book.GetById(bookId); Customer customer = Customer.GetById(customerId); book.RentedTo = customer; customer.AccountLines.Add(string.Format("Rental of book {0}.", book), book.RentalPrice); customer.Balance -= book.RentalPrice; trace.TraceInformation( "Leaving CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )“, bookId, customerId); } catch (Exception e) { trace.TraceEvent(TraceEventType.Error, 0, "Exception: CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} ) failed : {2}", bookId, customerId, e.Message); throw; } }}
Devs said: Let there be
defensive programming
internal class CustomerProcesses{ private static readonly TraceSource trace = new TraceSource(typeof(CustomerProcesses).FullName); public void RentBook(int bookId, int customerId) { if (bookId <= 0) throw new ArgumentOutOfRangeException("bookId"); if (customerId <= 0) throw new ArgumentOutOfRangeException("customerId"); trace.TraceInformation( "Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )“, bookId, customerId); try { for (int i = 0; ; i++) { try { using (var ts = new TransactionScope()) { Book book = Book.GetById(bookId); Customer customer = Customer.GetById(customerId); book.RentedTo = customer; customer.AccountLines.Add( string.Format("Rental of book {0}.", book), book.RentalPrice); customer.Balance -= book.RentalPrice; ts.Complete(); }
break; } catch (TransactionConflictException) { if (i < 3) continue; else throw; } } trace.TraceInformation( "Leaving CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId); } catch (Exception e) { trace.TraceEvent(TraceEventType.Error, 0, "Exception: CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} ) failed : {2}", bookId, customerId, e.Message); throw; } }
}
And there was transaction handling code.Let there be safe concurrent execution.
internal class CustomerProcesses{ private static readonly TraceSource trace = new TraceSource(typeof(CustomerProcesses).FullName); public void RentBook(int bookId, int customerId) { if (bookId <= 0) throw new ArgumentOutOfRangeException("bookId"); if (customerId <= 0) throw new ArgumentOutOfRangeException("customerId"); try { trace.TraceInformation( "Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId ); try { for ( int i = 0;; i++ ) { try { using ( var ts = new TransactionScope() ) { Book book = Book.GetById( bookId ); Customer customer = Customer.GetById( customerId ); book.RentedTo = customer; customer.AccountLines.Add( string.Format( "Rental of book {0}.", book ), book.RentalPrice ); customer.Balance -= book.RentalPrice;
ts.Complete(); } break; } catch ( TransactionConflictException ) { if ( i < 3 ) continue; else throw; } } trace.TraceInformation( "Leaving CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId ); } catch ( Exception e ) { trace.TraceEvent( TraceEventType.Error, 0, "Exception: CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} ) failed : {2}", bookId, customerId, e.Message ); throw; } } catch ( Exception e ) { if (ExceptionManager.Handle(e)) throw; } }}
And there was exception handling code.Let there be user-friendly error messages.
YOHJI YAMAMOTOcustomer
AKSEL BACHMEIER architect
• We want a nice separation of concerns (assembly > namespace > class > method)
• OOP forces us to write crap!
• Code Scattering
• Code Tangling
• Code Coupling
Layer 1
Layer 2
Why do we write ugly code?
• Security
• Exception Handling
• Tracing
• Monitoring
• Transaction
• Data Binding
• Thread Sync
• Caching
• Validation
Non-Functional Requirements
Cross-Cutting Concerns
We have patterns. How to implement them?
• Template-Based Code Generators
• Anonymous Methods (Functional Programming)
Object-Oriented Alternatives
Encapsulating Infrastructure Concerns?
Aspects!
Strengthen Applications With Aspects
Show Me!
Show Me!1. Add a reference to PostSharp.dll
Show Me!2. Write an aspect
Show Me!3. Apply the aspect
Show Me!How does it work?
1. Source 2. Compiler 3. PostSharp 4. Run Time
The Idea Behind AOPPart 3
Cross-Cutting Concerns
Separation of Concerns
Problem Domain
Solution Domain
What is AOP?An extension of (not an alternative to) OOP that addresses the issue of cross-cutting concerns by providing a mean to:
• Encapsulate cross-cutting concerns
into Aspects = collection of transformations of code
• Apply aspects to elements of code
15 Years of AOP History
1994-1996
• First efforts on program transformation
1997
•AOP coined by Gregor Kiczales (Xerox PARC)
2001
•AspectJ published;• First AOSD
Conference
2003
•AspectJ released to the Eclise OSS community
• Spring Framework 1.0
• .NET 1.0
2004
•Build up of Interface21, later SpringSource, around IoC and AOP
•Works Begins on PostSharp
• JBoss AOP•WebSphere AOP•AJDT• SAP Enhancement
Framework
2007-2008
• PostSharp 1.0• PostSharp 1.5•ALCOB (AOP for
COBOL)
2009
• SpringSource acquired by VMWare, $400M
2010
• PostSharp 2.0
Research Years Hype Years Productivity Years
Why You Should Care
The benefits of aspect-oriented programming
The benefits of aspect-oriented programmingDecrease Development Costs• Write Fewer lines of code
• Read Fewer lines of code
• Concise, clear, understandable code
• Size-Cost relationship is superlinear
The benefits of aspect-oriented programmingImprove Quality• Fewer lines of code
→ Fewer Defects• More automation
→ Fewer Defects• Less boiler-plate code
→ More interesting work → Increased attention
→ Fewer Defects
The benefits of aspect-oriented programmingDecrease Maintenance Costs• Remember:
• Fewer Defects• Maintenance = 75% Reading Code
• How do you change a pattern once it’s implemented?
• Better architecture metrics:
• Decreased component coupling
• Increased component cohesion
The benefits of aspect-oriented programmingDecrease Maintenance Costs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 160
5
10
15
20
25
30
RedesignRedesign
Redesign
Redesign
Redesign
Conventional AOP Redesign
Time
Com
plex
ity
The benefits of aspect-oriented programmingOptimize Skillsets
System Developers Prepare Aspects 1
UI/Business Developers Use Aspects n
I master multithreading
better than anyone on earth
I understand provisioning processes better than anyone in
this company,
Picture © Darren Rogers and chatwoodsfp (Flicker)
Features
FeaturesCode Transformation Primitives
• Around Methods
• Method Interception
• Property Interception
• Field Interception
• Event Interception
• Interface Introduction
• Method Introduction
• Property Introduction
• Event Introduction
• Member Import
• Custom Attribute Intro
• Managed Resource Intro
IntroductionsModifications
FeaturesComposite Aspects• Aspects composed of multiple primitive transformations
• Advice = Additional Behavior ≈ Transformation
• Pointcut = Expression selecting target elements of code
• Declarative
• LINQ over System.Reflection
• Adding aspects dynamically: IAspectProvider
FeaturesAspect MulticastingUsing a single line of code, apply an aspects to multiple elements of code based on:
• Attributes (public/private, virtual/sealed, …)
• Naming conventions
FeaturesAttribute Inheritance• Interfaces
• Classes
• Virtual Methods
• Assemblies (!)
Object
Entity
Customer Order
Message
Update Message
Create Message
- or -
Robust Aspect Composition• Multiple aspects on the same element of code
• Aspect dependency framework
• Ordering
• Requirement
• Conflict
• Strong ordering and commutativity
Deterministic Behavior
D
CB
A
Visual Studio Extension
Aspects Base Code 2. Aspect Browser“Which elements of code is a given a given aspect applied to?”
1. Code Adornment + Clickable Tooltips“What aspects are applied to a given element of code?”
2. Aspect Browser
1. Adornment + Tooltip
Bi-Directional Navigation
Comparing Aspect FrameworksPart 4
Comparing Aspect FrameworksWhat to compare?
Framework
Expressive
Non-Invasive
Robust
Dynamic
Productive
Supported
Build-Time MSIL Transformation
Consumer Object
Aspects
Enhanced Object
AO Infrastructure
Transparent Proxies
Enhanced Object
Consumer Object
Transparent Proxy
RealProxy
Aspects
The transparent proxy is type-compatible with the enhanced object(CLR-provided magic)
JIT-Emitted Proxy
AO Infrastructure
Consumer Object Proxy
Aspects
Enhanced Object
The proxy implements an interface of the enhanced object.
JIT-Emitted SubclassAO Infrastructure
Consumer Object
Proxy
Aspects
Enhanced Object
The proxy extends (inherits from) the enhanced object.
Comparing Aspect FrameworksStatic vs Dynamic AOP
Build-Time:Very ExpressiveRobust ModelNot InvasiveStatic
Run-Time:Less ExpressiveBrittle ModelInvasiveDynamic
Hybrid
PostSharp
Spring.NETCastleMS Unity/PIAB
LinFu
Comparing Aspect FrameworksExpressiveness (1/2)
PostSharp Linfu Spring.NET Castle Unity/PIAB
Method Interception Yes Yes Yes YesInterface Introduction Yes Yes Yes YesPrivate/Sealed Member Interception Yes Yes
Event Interception YesMember Introduction YesComposite Aspects Yes
What can you do with the framework?
Comparing Aspect FrameworksExpressiveness (2/2)
PostSharp Linfu Spring.NET Castle Unity/PIAB
Custom Attributes Yes Yes Yes YesCustom C# Code Yes Yes Yes FeasibleAspect Inheritance YesXML Config. Yes Yes
How do you apply aspects to code?
Comparing Aspect FrameworksNon-Invasiveness
PostSharp Linfu Spring.NET Castle Unity/PIAB
No change required in base source code Yes Yes
Use on any object (e.g. WPF control) Yes Yes
Can you use aspects without deep refactoring?
Require the use of factory methods
Comparing Aspect FrameworksRobustness
PostSharp Linfu Spring.NET Castle Unity/PIAB
Aspect Validation Yes FeasibleAspect Dependency Framework Yes
Can you prevent aspects from being improperly used?
Comparing Aspect FrameworksMisc.
PostSharp Linfu Spring.NET Castle Unity/PIAB
Dynamic: change aspects without recompiling
Yes Yes Yes
Productive: Visual Studio tooling Yes
No Impact on Build Time Yes Yes
Support: Extensive Documentation, Commercially Supported
Yes Yes Yes
Other points that matter
Comparing Aspect FrameworksMy Own Summary• Aspects on Service Boundaries:
use your favorite application framework.
• Aspects on Ordinary and GUI Objects: use PostSharp.
• You can mix PostSharp with your favorite application framework!
Summary
We need Aspects!
We have great frameworks!
and PostSharp happens to be the best in .NET :).
http://www.sharpcrafters.com/[email protected]