Top Banner
An Introduction to Aspect-Oriented Programming in Microsoft .NET. Produce Cleaner Code with Aspect-Oriented Programming Gaël Fraiteur [email protected] http://www.sharpcrafters.com/
56

Produce Cleaner Code with Aspect-Oriented Programming

May 12, 2015

Download

Technology

Rather than giving us a nice separation of concerns (assembly > namespace > class > method), there are times when OOP forces us to duplicate boilerplate code, resulting in code scattering, tangling and coupling.

Gael Fraiteur, SharpCrafters Founder and Principal Engineer, speaks about the problem with conventional programming, give a gentle introduction to AOP, show how it works, and why you should be using it to eliminate boilerplate code from your life.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 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/

Page 2: Produce Cleaner Code with Aspect-Oriented Programming

AOP Facts

• AOP is 15 years oldMature

• Siemens, Hitachi, SAP, ASML• WebSphere, JBoss, WebLogic

Industry-Adopted

• -15% Lines of Code• -20% CouplingReal Benefits

Page 3: Produce Cleaner Code with Aspect-Oriented Programming

Featured PostSharp Customers

Page 4: Produce Cleaner Code with Aspect-Oriented Programming

Agenda• The Problem with Conventional Programming

• What is AOP?

• Why AOP?

• PostSharp Features

• Comparing AOP Frameworks

Page 5: Produce Cleaner Code with Aspect-Oriented Programming

The Problem with Conventional Programming

Part 1

Page 6: Produce Cleaner Code with Aspect-Oriented Programming

In the beginning there was nothing.

public class CustomerProcesses{}

Page 7: Produce Cleaner Code with Aspect-Oriented Programming

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.

Page 8: Produce Cleaner Code with Aspect-Oriented Programming

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; }   }}

Page 9: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 10: Produce Cleaner Code with Aspect-Oriented 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.

Page 11: Produce Cleaner Code with Aspect-Oriented 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");  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.

Page 12: Produce Cleaner Code with Aspect-Oriented Programming

YOHJI YAMAMOTOcustomer

AKSEL BACHMEIER architect

Page 13: Produce Cleaner Code with Aspect-Oriented Programming

• 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?

Page 14: Produce Cleaner Code with Aspect-Oriented Programming

• Security

• Exception Handling

• Tracing

• Monitoring

• Transaction

• Data Binding

• Thread Sync

• Caching

• Validation

Non-Functional Requirements

Cross-Cutting Concerns

Page 15: Produce Cleaner Code with Aspect-Oriented Programming

We have patterns. How to implement them?

• Template-Based Code Generators

• Anonymous Methods (Functional Programming)

Object-Oriented Alternatives

Page 16: Produce Cleaner Code with Aspect-Oriented Programming

Encapsulating Infrastructure Concerns?

Page 17: Produce Cleaner Code with Aspect-Oriented Programming

Aspects!

Page 18: Produce Cleaner Code with Aspect-Oriented Programming

Strengthen Applications With Aspects

Show Me!

Page 19: Produce Cleaner Code with Aspect-Oriented Programming

Show Me!1. Add a reference to PostSharp.dll

Page 20: Produce Cleaner Code with Aspect-Oriented Programming

Show Me!2. Write an aspect

Page 21: Produce Cleaner Code with Aspect-Oriented Programming

Show Me!3. Apply the aspect

Page 22: Produce Cleaner Code with Aspect-Oriented Programming

Show Me!How does it work?

1. Source 2. Compiler 3. PostSharp 4. Run Time

Page 23: Produce Cleaner Code with Aspect-Oriented Programming

The Idea Behind AOPPart 3

Page 24: Produce Cleaner Code with Aspect-Oriented Programming

Cross-Cutting Concerns

Separation of Concerns

Problem Domain

Solution Domain

Page 25: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 26: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 27: Produce Cleaner Code with Aspect-Oriented Programming

Why You Should Care

The benefits of aspect-oriented programming

Page 28: Produce Cleaner Code with 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

Page 29: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 30: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 31: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 32: Produce Cleaner Code with Aspect-Oriented Programming

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)

Page 33: Produce Cleaner Code with Aspect-Oriented Programming

Features

Page 34: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 35: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 36: Produce Cleaner Code with Aspect-Oriented Programming

FeaturesAspect MulticastingUsing a single line of code, apply an aspects to multiple elements of code based on:

• Attributes (public/private, virtual/sealed, …)

• Naming conventions

Page 37: Produce Cleaner Code with Aspect-Oriented Programming

FeaturesAttribute Inheritance• Interfaces

• Classes

• Virtual Methods

• Assemblies (!)

Object

Entity

Customer Order

Message

Update Message

Create Message

- or -

Page 38: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 39: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 40: Produce Cleaner Code with Aspect-Oriented Programming

Comparing Aspect FrameworksPart 4

Page 41: Produce Cleaner Code with Aspect-Oriented Programming

Comparing Aspect FrameworksWhat to compare?

Framework

Expressive

Non-Invasive

Robust

Dynamic

Productive

Supported

Page 42: Produce Cleaner Code with Aspect-Oriented Programming

Build-Time MSIL Transformation

Consumer Object

Aspects

Enhanced Object

Page 43: Produce Cleaner Code with Aspect-Oriented Programming

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)

Page 44: Produce Cleaner Code with Aspect-Oriented Programming

JIT-Emitted Proxy

AO Infrastructure

Consumer Object Proxy

Aspects

Enhanced Object

The proxy implements an interface of the enhanced object.

Page 45: Produce Cleaner Code with Aspect-Oriented Programming

JIT-Emitted SubclassAO Infrastructure

Consumer Object

Proxy

Aspects

Enhanced Object

The proxy extends (inherits from) the enhanced object.

Page 46: Produce Cleaner Code with Aspect-Oriented Programming

Comparing Aspect FrameworksStatic vs Dynamic AOP

Build-Time:Very ExpressiveRobust ModelNot InvasiveStatic

Run-Time:Less ExpressiveBrittle ModelInvasiveDynamic

Hybrid

PostSharp

Spring.NETCastleMS Unity/PIAB

LinFu

Page 47: Produce Cleaner Code with Aspect-Oriented Programming

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?

Page 48: Produce Cleaner Code with Aspect-Oriented Programming

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?

Page 49: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 50: Produce Cleaner Code with Aspect-Oriented Programming

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?

Page 51: Produce Cleaner Code with Aspect-Oriented Programming

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

Page 52: Produce Cleaner Code with Aspect-Oriented Programming

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!

Page 53: Produce Cleaner Code with Aspect-Oriented Programming

Summary

Page 54: Produce Cleaner Code with Aspect-Oriented Programming

We need Aspects!

Page 55: Produce Cleaner Code with Aspect-Oriented Programming

We have great frameworks!

and PostSharp happens to be the best in .NET :).

Page 56: Produce Cleaner Code with Aspect-Oriented Programming

http://www.sharpcrafters.com/[email protected]