AOP vs функции

Аспект-ориентираното програмиране (AOP) е доста популярно. Мотивацията за него е добре обяснена в съответната статия в Уикипедия.

AOP е чудесен инструмент за наистина глобални концепции като логване, които не влияят пряко върху логиката на кода. Проблемите с AOP обаче се появяват, когато той се използва за повече неща, свързани с бизнеса, като упълномощаване. Тези аспекти на приложението трябва да бъдат ясно видими в съответния код, така че програмистът да може веднага да види дали са внедрени правилно, когато чете съответния изходен код. AOP-базирани рамки обикновено решават за това с помощта на пояснения за метода:

@RequireRole (Role.Admin) // ясно видим аспект
забавно актуализиранеUserPermissions (...) {
    // логика тук
}

От гледна точка на четливостта обаче не се различава много от функционалния подход към същия проблем, използвайки функцията RequRole вместо пояснение @RequireRole:

забавно актуализиранеUserPermissions (...) {
    RequRole (Role.Admin) // изхвърля SecurityException
    // логика тук
}

Нещо повече, функционалният подход има предимството, че той мащабира до по-сложни проверки на разрешения, като анализиране на параметрите на метода, преди да се реши коя потребителска роля е необходима.

Същото важи и за други аспекти като транзакциите. За съжаление е тромаво и неудобно функционално да представят по-сложни концепции в Java, което създава изкуствена популярност за AOP рамки в Java екосистемата.

Не е така обаче с Котлин. В Kotlin вместо Java-подобен подход за транзакции с AOP и пояснения като този:

@Transactional
забавно актуализиранеUserPermissions (...) {
    // логика тук
}

Точно толкова четливо и чисто изглежда, когато е пренаписано по функционален начин:

забавно актуализиранеUserPermissions (…) = транзакционен {
    // логика тук
}

Предимството на този функционален подход е, че винаги можете да Ctrl / Cmd + да кликнете върху декларацията за транзакционната функция във вашия IDE и веднага да видите какво точно прави, което обикновено не е възможно с нито една от често използваните AOP рамки. Дори когато навигацията до изходния код на аспекта се осигурява от IDE плъгин, дешифрирането на неговата логика изисква познаване на отделен богат API и / или конвенции.

За съжаление, този функционален заместител на AOP на базата на анотации в Котлин не се разраства веднага, когато няколко аспекта се прилагат към една и съща функция, тъй като къдравите скоби и отстъпите започват да се трупат:

fun updateUserPermissions (…) = влезли {
    транзакционен {
        // логика тук
    }
}

Работата е да се създаде комбинирана функция от по-висок ред, за да се поддържа мястото на използване на множество аспекти в чисто състояние:

fun updateUserPermissions (…) = loggedTransactional {
    // логика тук
}

Друг недостатък на функционалния подход е, че аспекти като регистрация се нуждаят от достъп до параметрите на метода. Обикновено те са директно достъпни в традиционните AOP рамки чрез специални API, но наличните функции на Kotlin не могат лесно да получат достъп до тях. Така че, за да представите в действителност аспект на логване в реално време по чисто функционален начин, човек все още трябва да напише значително количество код на плочата на котела:

забавно актуализацияUserPermissions (params: Params) =
    logged ("updateUserPermissions ($ params)") {
        // логика тук
    }

Това съображение все още прави AOP инструмент за избор за регистриране, когато наистина трябва да го имате глобално и последователно във вашето приложение, но вярвам, че използването на AOP за аспекти като оторизация и транзакции е злоупотреба, предвид богатите функционални абстракции, които са налични в Kotlin , Функциите се справят с тези аспекти по-добре и по-чисто.

В заключение бих казал, че по-нататъшните подобрения на функционалните абстракции за осигуряване на още по-добра замяна на AOP могат да бъдат обещаващ вектор за бъдеща еволюция за езика на Котлин. Java-базирани AOP рамки обикновено са специфични за JVM и се възприемат като някаква непрозрачна магия, докато функционалните абстракции на Kotlin са наистина кросплатформен и са прозрачни за потребителя.