An Introduction to Aspect-Oriented Programming in Microsoft .NET.Produce Cleaner Code with Aspect-Oriented ProgrammingGaël Fraiteurgael@sharpcrafters.comhttp://www.sharpcrafters.com/
AOP Facts
Featured PostSharp Customers
AgendaThe Problem with Conventional ProgrammingWhat is AOP?Why AOP?PostSharp FeaturesComparing AOP Frameworks
The Problem with Conventional ProgrammingPart 1
In the beginning           there was nothing.publicclassCustomerProcesses{}
Customer said: let there be business value.publicclassCustomerProcesses{publicvoid 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;    }}And there was business code.
internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource( typeof (CustomerProcesses).FullName ); publicvoid 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;        }    }}Testers said: Letthere be loggingAnd there was logging code.
internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoid RentBook(int bookId, int customerId)    {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("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;        }    }}Devssaid: Letthere be defensive programmingThenthere was precondition checking code.
internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoid RentBook(int bookId, int customerId)    {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("customerId");         trace.TraceInformation("Entering CustomerProcesses.CreateCustomer( bookId = {0},            customerId = {1} )“,  bookId, customerId); try        {for (int i = 0; ; i++)            {try                {using (var ts = newTransactionScope())                    {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;elsethrow;                }            }             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;        }    }}Let there be safe concurrent execution.And there was transaction handling code.
internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoid RentBook(int bookId, int customerId)    {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("customerId"); try        {            trace.TraceInformation("Entering CustomerProcesses.CreateCustomer(                  bookId = {0}, customerId = {1} )",                bookId, customerId ); try            {for ( int i = 0;; i++ )                {try                    {using ( var ts = newTransactionScope() )                        {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;elsethrow;                    }                }                 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;        }    }}Let there be user-friendly error messages.And there was exception handling code.
AKSEL BACHMEIER architectYOHJI YAMAMOTOcustomer
We want a nice separation of concerns (assembly > namespace > class > method)OOP forces us to write crap!Code ScatteringCode TanglingCode CouplingLayer 1Layer 2Why do we write ugly code?
SecurityException HandlingTracingMonitoringTransactionData BindingThread SyncCachingValidationNon-Functional RequirementsCross-Cutting Concerns
We have patterns. How to implement them?Template-Based Code GeneratorsAnonymous Methods (Functional Programming)Object-Oriented Alternatives
Encapsulating Infrastructure Concerns?
Aspects!
Strengthen Applications With AspectsShow 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. Source2. Compiler3. PostSharp4. Run Time
The Idea Behind AOPPart 3
Problem DomainCross-Cutting ConcernsSolution DomainSeparation of Concerns
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 codeApplyaspects to elements of code
15 Years of AOP HistoryHype YearsProductivity YearsResearch Years
Why You Should CareThe benefits of aspect-oriented programming
The benefits of aspect-oriented programmingDecrease Development CostsWriteFewer lines of codeReadFewer lines of code	Concise, clear, understandable codeSize-Cost relationship is superlinear
The benefits of aspect-oriented programmingImprove QualityFewer lines of code	-> Fewer DefectsMore automation	-> Fewer DefectsLess boiler-plate code 	-> More interesting work 	-> Increased attention 	-> Fewer Defects
The benefits of aspect-oriented programmingDecrease Maintenance CostsRemember: Fewer DefectsMaintenance = 75% Reading CodeHow do you change a pattern once it’s implemented?Better architecture metrics:Decreased component couplingIncreased component cohesion
The benefits of aspect-oriented programmingDecrease Maintenance Costs
The benefits of aspect-oriented programmingOptimize SkillsetsI understand provisioning processes better than anyone in this company,I master multithreading better than anyone on earthPicture © Darren Rogers and chatwoodsfp (Flicker)
Features
FeaturesCode Transformation PrimitivesModificationsIntroductionsAround MethodsMethod InterceptionProperty InterceptionField InterceptionEvent InterceptionInterface IntroductionMethod IntroductionProperty IntroductionEvent IntroductionMember ImportCustom Attribute IntroManaged Resource Intro
FeaturesComposite AspectsAspects composed of multiple primitive transformationsAdvice = Additional Behavior ≈ TransformationPointcut = Expression selecting target elements of codeDeclarativeLINQ over System.ReflectionAdding 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 InheritanceInterfacesClassesVirtual MethodsAssemblies (!)- or -
Robust Aspect CompositionMultiple aspects on the same element of codeAspect dependency frameworkOrderingRequirementConflictStrong ordering and commutativity Deterministic BehaviorDCBA
Visual Studio Extension1. Code Adornment + Clickable Tooltips“What aspects are applied to a given element of code?”1. Adornment + TooltipAspectsBase CodeBi-Directional Navigation2. Aspect Browser“Which elements of code is a given a given aspect applied to?”2. Aspect Browser
Comparing Aspect FrameworksPart 4
Comparing Aspect FrameworksWhat to compare?ExpressiveNon-InvasiveSupportedFrameworkRobustProductiveDynamic
Build-Time MSIL TransformationConsumer ObjectEnhanced ObjectAspects
AO InfrastructureTransparent ProxiesEnhanced ObjectConsumer ObjectTransparent ProxyRealProxyAspectsThe transparent proxy is type-compatible with the enhanced object(CLR-provided magic)
JIT-Emitted ProxyAO InfrastructureConsumer ObjectProxyEnhanced ObjectAspectsThe proxy implements an interface of the enhanced object.
JIT-Emitted SubclassAO InfrastructureConsumer ObjectProxyEnhanced ObjectAspectsThe proxy extends (inherits from) the enhanced object.
Comparing Aspect FrameworksStatic vs Dynamic AOPSpring.NETCastleMS Unity/PIABPostSharpLinFuBuild-Time:Very ExpressiveRobust ModelNot InvasiveStaticRun-Time:Less ExpressiveBrittle ModelInvasiveDynamicHybrid
Comparing Aspect FrameworksExpressiveness (1/2)What can you do with the framework?
Comparing Aspect FrameworksExpressiveness (2/2)How do you apply aspects to code?
Comparing Aspect FrameworksNon-InvasivenessCan you use aspects without deep refactoring?Require the use of factory methods
Comparing Aspect FrameworksRobustnessCan you prevent aspects from being improperly used?
Comparing Aspect FrameworksMisc.Other points that matter
Comparing Aspect FrameworksMy Own SummaryAspects 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/gael@sharpcrafters.com

Produce Cleaner Code with Aspect-Oriented Programming

  • 1.
    An Introduction toAspect-Oriented Programming in Microsoft .NET.Produce Cleaner Code with Aspect-Oriented ProgrammingGaël Fraiteurgael@sharpcrafters.comhttp://www.sharpcrafters.com/
  • 2.
  • 3.
  • 4.
    AgendaThe Problem withConventional ProgrammingWhat is AOP?Why AOP?PostSharp FeaturesComparing AOP Frameworks
  • 5.
    The Problem withConventional ProgrammingPart 1
  • 6.
    In the beginning there was nothing.publicclassCustomerProcesses{}
  • 7.
    Customer said: letthere be business value.publicclassCustomerProcesses{publicvoid 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; }}And there was business code.
  • 8.
    internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof (CustomerProcesses).FullName ); publicvoid 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; }   }}Testers said: Letthere be loggingAnd there was logging code.
  • 9.
    internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoidRentBook(int bookId, int customerId) {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("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; } }}Devssaid: Letthere be defensive programmingThenthere was precondition checking code.
  • 10.
    internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoidRentBook(int bookId, int customerId) {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("customerId");  trace.TraceInformation("Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )“, bookId, customerId); try {for (int i = 0; ; i++) {try {using (var ts = newTransactionScope()) {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;elsethrow; } }  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; } }}Let there be safe concurrent execution.And there was transaction handling code.
  • 11.
    internalclassCustomerProcesses{privatestaticreadonlyTraceSource trace =newTraceSource(typeof(CustomerProcesses).FullName); publicvoidRentBook(int bookId, int customerId) {if (bookId <= 0) thrownewArgumentOutOfRangeException("bookId");if (customerId <= 0) thrownewArgumentOutOfRangeException("customerId"); try { trace.TraceInformation("Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )", bookId, customerId ); try {for ( int i = 0;; i++ ) {try {using ( var ts = newTransactionScope() ) {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;elsethrow; } }  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; } }}Let there be user-friendly error messages.And there was exception handling code.
  • 12.
  • 13.
    We want anice separation of concerns (assembly > namespace > class > method)OOP forces us to write crap!Code ScatteringCode TanglingCode CouplingLayer 1Layer 2Why do we write ugly code?
  • 14.
    SecurityException HandlingTracingMonitoringTransactionData BindingThreadSyncCachingValidationNon-Functional RequirementsCross-Cutting Concerns
  • 15.
    We have patterns.How to implement them?Template-Based Code GeneratorsAnonymous Methods (Functional Programming)Object-Oriented Alternatives
  • 16.
  • 17.
  • 18.
  • 19.
    Show Me!1. Adda reference to PostSharp.dll
  • 20.
  • 21.
  • 22.
    Show Me!How doesit work?1. Source2. Compiler3. PostSharp4. Run Time
  • 23.
  • 24.
  • 25.
    What is AOP?Anextension 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 codeApplyaspects to elements of code
  • 26.
    15 Years ofAOP HistoryHype YearsProductivity YearsResearch Years
  • 27.
    Why You ShouldCareThe benefits of aspect-oriented programming
  • 28.
    The benefits ofaspect-oriented programmingDecrease Development CostsWriteFewer lines of codeReadFewer lines of code Concise, clear, understandable codeSize-Cost relationship is superlinear
  • 29.
    The benefits ofaspect-oriented programmingImprove QualityFewer lines of code -> Fewer DefectsMore automation -> Fewer DefectsLess boiler-plate code -> More interesting work -> Increased attention -> Fewer Defects
  • 30.
    The benefits ofaspect-oriented programmingDecrease Maintenance CostsRemember: Fewer DefectsMaintenance = 75% Reading CodeHow do you change a pattern once it’s implemented?Better architecture metrics:Decreased component couplingIncreased component cohesion
  • 31.
    The benefits ofaspect-oriented programmingDecrease Maintenance Costs
  • 32.
    The benefits ofaspect-oriented programmingOptimize SkillsetsI understand provisioning processes better than anyone in this company,I master multithreading better than anyone on earthPicture © Darren Rogers and chatwoodsfp (Flicker)
  • 33.
  • 34.
    FeaturesCode Transformation PrimitivesModificationsIntroductionsAroundMethodsMethod InterceptionProperty InterceptionField InterceptionEvent InterceptionInterface IntroductionMethod IntroductionProperty IntroductionEvent IntroductionMember ImportCustom Attribute IntroManaged Resource Intro
  • 35.
    FeaturesComposite AspectsAspects composedof multiple primitive transformationsAdvice = Additional Behavior ≈ TransformationPointcut = Expression selecting target elements of codeDeclarativeLINQ over System.ReflectionAdding aspects dynamically: IAspectProvider
  • 36.
    FeaturesAspect MulticastingUsing asingle line of code, apply an aspects to multiple elements of code based on:Attributes (public/private, virtual/sealed, …)Naming conventions
  • 37.
  • 38.
    Robust Aspect CompositionMultipleaspects on the same element of codeAspect dependency frameworkOrderingRequirementConflictStrong ordering and commutativity Deterministic BehaviorDCBA
  • 39.
    Visual Studio Extension1.Code Adornment + Clickable Tooltips“What aspects are applied to a given element of code?”1. Adornment + TooltipAspectsBase CodeBi-Directional Navigation2. Aspect Browser“Which elements of code is a given a given aspect applied to?”2. Aspect Browser
  • 40.
  • 41.
    Comparing Aspect FrameworksWhatto compare?ExpressiveNon-InvasiveSupportedFrameworkRobustProductiveDynamic
  • 42.
    Build-Time MSIL TransformationConsumerObjectEnhanced ObjectAspects
  • 43.
    AO InfrastructureTransparent ProxiesEnhancedObjectConsumer ObjectTransparent ProxyRealProxyAspectsThe transparent proxy is type-compatible with the enhanced object(CLR-provided magic)
  • 44.
    JIT-Emitted ProxyAO InfrastructureConsumerObjectProxyEnhanced ObjectAspectsThe proxy implements an interface of the enhanced object.
  • 45.
    JIT-Emitted SubclassAO InfrastructureConsumerObjectProxyEnhanced ObjectAspectsThe proxy extends (inherits from) the enhanced object.
  • 46.
    Comparing Aspect FrameworksStaticvs Dynamic AOPSpring.NETCastleMS Unity/PIABPostSharpLinFuBuild-Time:Very ExpressiveRobust ModelNot InvasiveStaticRun-Time:Less ExpressiveBrittle ModelInvasiveDynamicHybrid
  • 47.
    Comparing Aspect FrameworksExpressiveness(1/2)What can you do with the framework?
  • 48.
    Comparing Aspect FrameworksExpressiveness(2/2)How do you apply aspects to code?
  • 49.
    Comparing Aspect FrameworksNon-InvasivenessCanyou use aspects without deep refactoring?Require the use of factory methods
  • 50.
    Comparing Aspect FrameworksRobustnessCanyou prevent aspects from being improperly used?
  • 51.
  • 52.
    Comparing Aspect FrameworksMyOwn SummaryAspects 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!
  • 53.
  • 54.
  • 55.
    We have greatframeworks!and PostSharp happens to be the best in .NET :).
  • 56.