Aspektově orientované programování prakticky

V práci teď dělám na jednom jednoduchém interním systému a protože si nechci nechat ujet vlak nových trendů v programování, rozhodl jsem se tam použít pár nových technologií. Konkrétně jsem začal používat Entity Framework s LINQ To Entities (objektově-relační mapper – uvolněno asi před měsícem), ASP.NET MVC (ještě neuvolněno, v době psaní článku používám Preview 5) a PostSharp. Postupně bych tu chtěl napsat pár článků o těchto technologiích a začnu poslední z jmenovaných.

Nechci tady rozebírat teorii okolo aspektově orientovaného programování, ale chci se podívat na celou věc z čistě praktické stránky.
Mějme třídu BL (business layer), která dělá nějakou business operaci:

public class BusinessLayer
{

    public void DoSomeBusinessOperation(object par1, object par2)
    {
        // Do some business operation.
    }

} 

No ale co se stane, když nám někdo zavolá tuhle naší metodu se špatnými parametry? A co když volající vůbec nemá právo tuhle operaci provést? A co když dojde během vykonávání operace k výjimce? Náš krásný kód se začne stávat poněkud obludným:

public void DoSomeBusinessOperation(User user, object par1, object par2)
{
    Logging.WriteEnteringMethod();

    if (user == null)
    {
        throw new ArgumentNullException("user");
    }
    if (par1 == null)
    {
        throw new ArgumentNullException("par1");
    }
    if (par2 == null)
    {
        throw new ArgumentNullException("par2");
    }
    if (!user.CanDoThisOperation())
    {
        throw new SecurityException();
    }

    try
    {
        // Do some business operation.
    }
    catch (DataLayerException e)
    {
        Logging.WriteException(e);
        throw new BusinessLayerException(e);
    }
    Logging.WriteLeavingMethod();
} 

A co když budeme chtít to samé zajistit také u ostatních business operací? To byl šel DRY (don’t repeat youself) princip pěkně do háje, kdybychom museli všude opakovat tentýž kód. A zde právě přichází ke slovu aspektově orientované programování (AOP), které pracuje napříč funkcionalitou, tedy aspektu nezáleží na tom, jakou business operaci používáme (tzv. průřezový koncern). AOP nám umožňuje přiřadit každé metodě, třídě nebo assembly aspekty, které jsou v C# reprezentovány atributy. Pak nám stačí např. označit metodu atributem (tedy přiřadit jí aspekt), který zajistí automatické vyvolání výjimky, pokud chce operaci provést neoprávněný uživatel, nebo provede zápis do logu na začátku a konci metody.

Pro podporu AOP v C# existuje více frameworků, ale mně se nejvíce líbí projekt PostSharp. Pro jeho zprovoznění potřebujete jen si ho stáhnout a ve svém projektu si nareferencovat assemblies PostSharp.Laos a PostSharp.Public.
Dále si vytvoříte své vlastní aspekty, které nejsou nic jiného než atributy odvozené od třídy PostSharp.Laos.OnMethodBoundaryAspect a tyto nově vytvořené třídy označíte atributem Serializable.
Třída OnMethodBoundaryAspect má několik virtuálních metod, které můžeme v našem aspektu overridnout – jsou to především metody OnEntry, OnExit, OnSuccess a OnException. Všechny tyto metody jsou volány v tom okamžiku, jak naznačuje jejich jméno. Dále stojí za zmínění metoda CompileTimeValidate, pomocí které můžeme určit, jestli lze aspekt aplikovat na danou metodu.
Jednoduchý aspekt pro logování může vypadat například takto:

using PostSharp.Laos;
using System.Diagnostics;

namespace Augi.Aspects
{
    public class TraceAttribute : OnMethodBoundaryAspect
    {

        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            Trace.TraceInformation("Entering " + eventArgs.Method.ToString());
            Trace.Indent();
        }

        public override void OnExit(MethodExecutionEventArgs eventArgs)
        {
            Trace.TraceInformation("Leaving " + eventArgs.Method.ToString());
            Trace.Unindent();
        }
    }
} 

Celé to pak funguje tak, že po kompilaci je assembly upravena takovým způsobem, že na příslušná místa metod je automaticky doplněn požadovaný kód. Tedy ve zdrojácích máme pouze implementaci našich aspektů a jejich aplikaci na metody (pomocí atributů) a celý proces úpravy assembly probíhá až po kompilaci „na binární úrovni“. I po tomto zásahu do assembly ale vše funguje jak má – funguje tedy normálně debugging i podepisování assemblies.
Předchozí obludný kód pak může po použití PostSharpu vypadat takto:

[Security, AllParametersNotNull, Logging, ExceptionsLogging]
public void DoSomeBusinessOperation(User user, object par1, object par2)
{
    // Do some business operation.
} 

No není to nádhera? PostSharp umí ještě další kouzla, ale OnMethodBoundary aspekt osobně považuji za nejvíce přínosný. Kód je pak pěkně přehledný, je zachován DRY princip a nedochází ke zbytečnému míchání funkčních a nefunkčních principů.
Pomocí AOP lze tedy velmi efektivně (deklarativně) popsat aspekty programu, které se netýkají funkcionality, jako např. bezpečnost, logování, exception handling, defenzivní programování (kontrola parametrů) nebo cachování.

Zanechat odpověď

Vyplňte detaily níže nebo klikněte na ikonu pro přihlášení:

Logo WordPress.com

Komentujete pomocí vašeho WordPress.com účtu. Odhlásit /  Změnit )

Facebook photo

Komentujete pomocí vašeho Facebook účtu. Odhlásit /  Změnit )

Připojování k %s

Tento web používá Akismet na redukci spamu. Zjistěte více o tom, jak jsou data z komentářů zpracovávána.