SheepAspect: Mixin

SheepAspect Preview-3 was released today, and one of the most important new features is Mixins. In Preview-2, there were only one advice implementation: [Around]. In preview-3 we introduce two more advices: [DeclareMixin] and [DeclareAttributes].

[DeclareMixin] advice allows you to add new interface implementations on existing classes. As an example, here is a plain simple Customer class:

public class Customer
{
	public string FirstName {get; set;}
	public string LastName {get; set;}
}

And a completely unrelated IEmailable interface:

public IEmailable
{
	public string EmailAddress {get; set;}
	public void SendEmail(string subject, string body);
}

Now let’s stitch these two together using SheepAspect mixin

[SingletonAspect]
public class SmtpAspect
{
	[SelectTypes(typeof(Customer))]
	public void Customer(){}

	[DeclareMixin("Customer")]
	public IEmailable CreateCustomerEmailable(Customer customer)
	{
		return new CustomerSmtpEmailable(customer);
	}

	private class CustomerSmtpEmailable: IEmailable
	{
		private readonly Customer _customer;

		public CustomerSmtpEmailable(Customer customer)
		{
			_customer = customer;
		}

		public string EmailAddress { get; set; }

		public void SendEmail(string subject, string message)
		{
			/* Just pretend this code is going to an SMTP server, not to a console */
			Console.WriteLine("To: {0} {1} ({2})", _customer.FirstName, _customer.LastName, EmailAddress);
			Console.WriteLine("Subject: {0}", subject);
			Console.WriteLine("\nMessage:");
			Console.WriteLine("Hola {0},", _customer.FirstName);
			Console.WriteLine(message);
			Console.WriteLine("\nSincerely yours");
			Console.WriteLine("Sheep");
		}
	}
}

With this aspect in place, your Customer class now magically implements IEmailable interface. The invocation will be directed to the implementation we have provided in our aspect (CustomerSmtpEmailable), which contains the infrastructure code of sending an email through an SMTP server or background tasks. Now you can actually cast your Customer arbitrarily to an IEmailable:

var customer = new Customer {FirstName = "Henders", LastName = "Sheep"};

var emailable = (IEmailable) customer; // Casting a Customer into IEmailable!

emailable.EmailAddress = "henders.sheep@foo.com";
emailable.SendEmail("Buy now!",
    "We have a great collection of sheep for you to buy.\nHurry, while stock lasts!");

That actually works, and you did not get InvalidCastException. Instead you’ll get this little output on your console window:

image

All source-code in this example can be found in SheepAspect.Example project on SheepAspect code repository.

Binding Mixins to Fields

Instead of declaring Mixin implementation factory method, you can also bind your Mixin implementations on aspect fields. For instance:

[SingletonAspect]
public class SmtpAspect
{
	[DeclareMixin("CustomerTypePointcut")]
	public IEmailable _customerEmailable;
}

Now your Customer will implement IEmailable interface that directs its execution to the IEmailable instance held by this _customerEmailable field on your SmtpAspect. Swapping the implementation of your Customer’s IEmailable is as simple as setting the value of this field.

Dependency Injection: Reborn

Some time in our career, we have learnt about separation of concerns, about how you should split domain-code from infrastructural concerns. Usually this is achieved by means of dependency-injection, the goal of which is to promote loose-coupling, maintainability, and testability. Dependency-injection has become one of the most fundamental principle in OO application development. But this is a principle that might no longer be relevant in AOP world.

The premise of dependency-injection does not necessarily hold true in AOP development process. There is no longer much need of rearchitecting your classes to fit into dependency-injection scheme just to achieve separation of concerns. You can in fact just implement your infrastructural concerns directly as part of your Customer domain class. For typical CRUD applications, you can do away without repository classes: you just simply inject ActiveRecord capability straight onto your entities through mixin.

Feeling dirty? Not quite. Separation is still maintained because these implementations are actualised as separate mixins that are injected externally by aspects where you consolidate all your infrastructural plumbing.

In our Customer/IEmailable example, neither your Customer class, IEmailable interface, nor their consumers are aware of any SMTP implementation. They are pure POCO. Then somewhere completely external to the core of your application code, you just introduce SmtpAspect mixins aspect where you actually implement your SMTP plumbing, and will statically enhance your customer class with SMTP capability. But from code perspective, your Customer class remains a simple POCO model.

For unit-testing, you can mock SmtpAspect class, and reimplement the IEmailable behavior with mocked behaviors.

Yes you do violate dependency-injection principle, you sinfully commit God-Object anti-pattern, but hey, those wisdoms was invented before the birth of AOP into static languages.

Advertisements

SheepAspect Preview 3

This is not a massive release or anything. The idea is to push new changes rapidly to the public to attract early feedbacks, especially because this Preview3 release comes with a good set of new features and improvements that I genuinely feel very excited about. Many of these changes are based on feedbacks I have received from early adopters. So thanks to everyone who has shared their inputs.

What’s New

There is no significant changes on the underlying SheepAspect framework itself. This release is more of implementing new functionalities and natural progression of the feature-set of the library. Some of these new features are:

  1. The most significant new feature in Preview3 release is the Mixins support. With the new [DeclareMixin] advice, you can now statically add interface implementations to existing classes. I will write have written the details of this in a separate post.
  2. We also now have [DeclareAttributes] advice attribute. With this advice, you can statically add attributes to existing types, methods, properties, fields, and constructors. This will also be covered in the upcoming posts.
  3. IAspectAware interface, so you can now intercept when your aspects get instantiated by AspectRuntime so you can execute some initialisation routine. Again, this will be covered in the upcoming posts.
  4. A more complete set of pointcut implementations. Preview-2 advices could only target methods, properties, and instructions (method-calls, field gets/sets). In preview-3, they can also target types, constructors, fields, and property getters/setters. Events are only partially supported at the moment.
  5. Intellisense documentation. I understand that SheepAspect has a very steep learning curve. It can be overwhelming for users to get started or to figure out what each attribute does. In this Preview 3 release, most of SheepAspect’s public API is well documented.
    image10image9
  6. In Preview 2, SheepAspect required pdb files of all target binaries (so that SheepAspect can preserve debuggability of your weaved binaries). This has caused a problem for users who do not have pdb files of their target binaries. In Preview 3, pdb files are optional.

Get It Now

As usual, SheepAspect Preview3 is installable from NuGet: https://nuget.org/packages/SheepAspect. SheepAspect-Query-Analyzer for Preview-3 version is still due to come soon, and will be downloadable separately on the SheepAspect homepage.

UPDATE: SheepAspect-Query-Analyzer is now always included when you install via NuGet, under the Tools directory within the SheepAspect package folder.

SheepAspect Preview 3

This is not a massively dramatic release over the previous version. The idea is to push new changes rapidly to the public to get early feedbacks. All that said, there are good set of new features and improvements in this release that I genuinely feel very excited about. Many of these changes are based on feedbacks I have received from early adopters. Thanks to everyone who has shared their inputs.

What’s New

There is no significant changes on the underlying SheepAspect framework itself. This release is more of implementing new functionalities and natural progression of the feature-set of the library. Some of these new features are:

  1. Mixins. With the new [DeclareMixin] advice attribute, you can now statically add interface implementations to existing classes. I will write have written the details of this on a separate post.
  2. [DeclareAttribute] advice is now also introduced in SheepAspect. With this advice, you can add new attributes to existing types, methods, properties, fields, and constructors.
  3. In Preview 2, SheepAspect required pdb files of all target binaries (so that SheepAspect can preserve debuggability of your weaved binaries). This has caused a problem for users who do not have pdb files of their target binaries. In Preview 3, pdb files are optional.