Аспе́ктно-ориенти́рованное программи́рование (AOP) довольно популярная парадигма программирования. В статье на Wikipedia хорошо объяснена мотивация этого подхода.
AOP является отличным инструментом для глобальных концепций, таких как: логирование, которое, напрямую, не влияют на логику кода.
Однако, проблемы с AOP обнаруживаются, когда он используется для бизнес-требований, таких как авторизация. Такие аспекты должны быть четко видны в соответствующем коде, чтобы разработчик мог сразу увидеть, при чтении исходного кода, правильно ли они реализованы. AOP фреймворки обычно решают эту проблему с помощью аннотаций:
AOP является отличным инструментом для глобальных концепций, таких как: логирование, которое, напрямую, не влияют на логику кода.
Однако, проблемы с AOP обнаруживаются, когда он используется для бизнес-требований, таких как авторизация. Такие аспекты должны быть четко видны в соответствующем коде, чтобы разработчик мог сразу увидеть, при чтении исходного кода, правильно ли они реализованы. AOP фреймворки обычно решают эту проблему с помощью аннотаций:
@RequireRole(Role.Admin) // clearly visible aspect
fun updateUserPermissions(…) {
// logic here
}
Однако, с точки зрения читабельности, он не сильно отличается от функционального подхода, использования метода requireRole вместо аннотации.
Примечание переводчика: в оригинальной статье используется выражение when rewritten in a functional way или functional approach что можно трактовать как использование функционального подхода так и прямого/конкретного вызова функции. В статье есть примеры которые можно трактовать по-разному.
Так же:
1. В дальнейшем мы вернемся к понятию Higher-Order Functions
2. В статье встречается слово аспект, что является англицизмом и понятием в AOP aspect
fun updateUserPermissions(…) {
requireRole(Role.Admin) // throws SecurityException
// logic here
}
Более того, функциональный подход имеет преимущество масштабирования до более сложных проверок прав доступа, таких как анализ параметров метода, прежде чем решить, какая роль пользователя требуется.
То же самое верно и для других типов аспектов, таких как транзакции. К сожалению, функционально представлять более сложные концепции в Java громоздко и неудобно, что создает искусственную популярность AOP фреймворков в Java экосистеме.
В Kotlin вместо Java-подобного подхода к транзакциям с помощью AOP и аннотаций, вроде этого:
@Transactional
fun updateUserPermissions(…) {
// logic here
}
Он так же читабелен и выглядит чисто, когда переписан без применения аннотаций, с функциональным подходом.
fun updateUserPermissions(…) = transactional {
// logic here
}
Преимущество этого подхода заключается в том, что всегда можете нажать Ctrl / Cmd + Click на объявлении функции transactional в вашей IDE и сразу увидеть, что именно она делает. Что обычно невозможно с любым из обычно используемых AOP фреймворков. Даже когда навигация к коду аспекта обеспечивается с помощью плагина IDE, для расшифровки его логики требуется знание отдельного многофункционального API и/или соглашений.
К сожалению, есть проблемы с масштабированием способа замены AOP аннотаций в Kotlin. Для случая когда несколько аспектов применяются к одной и той же функции, с накоплением фигурных скобок и отступов:
fun updateUserPermissions(…) = logged {
transactional {
// logic here
}
}
Обходное решение — создать higher-order function, чтобы сохранить приемлемый код при применении нескольких аспектов:
fun updateUserPermissions(…) = loggedTransactional {
// logic here
}
Другим недостатком функционального подхода является то, что такие аспекты, как логирование, требуют доступа к параметрам метода. Они обычно доступны в AOP фрейморках через специальные API, но с использованием стандартные функции языка Kotlin нельзя легко получить к ним доступ. Таким образом, для того, чтобы на самом деле представить реальный пример аспекта логирования, в чисто функциональном виде, все еще нужно написать значительное количество boiler-plate кода:
fun updateUserPermissions(params: Params) =
logged("updateUserPermissions($params)") {
// logic here
}
Это соображение все еще делает AOP предпочтительным инструментом для логирования, когда вам действительно необходимо иметь его глобально и согласованно в вашем приложении. При этом использование AOP для такой функциональности как авторизация и транзакции, является злоупотреблением, учитывая богатые функциональные абстракции, которые доступны в Kotlin. Функции справляются с этими требованиями лучше и чище.
В заключение я бы сказал, что дальнейшее усовершенствование функциональных абстракций для обеспечения еще лучшей замены АОП могло бы стать многообещающим вектором будущего развития языка Kotlin. AOP фреймворки, основанные на Java, обычно специфичны для JVM и воспринимаются как магия, в то время как функциональные абстракции Kotlin действительно кроссплатформенны и прозрачны для пользователя.
Примечание переводчика:
1. Cтатья на medium (eng) .
2. Автор оригинальной статьи является Roman Elizarov (Team Lead JetBrains, working on Kotlin coroutines and libs, sports programming/ICPC, concurrency & algorithms, math/quantitative finance; formerly Devexperts). На Хабре elizarov
Смотри также популярное:
Когда Java наконец помрёт, что с этим делать и что будет с JPoint. https://fetisovvs.blogspot.com/2018/11/java-jpoint-java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html
Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html
JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
Руководство по Java 9 для тех, кому приходится работать с legacy-кодом. http://fetisovvs.blogspot.com/2018/08/java-9-legacy-java.html
Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html
Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
Java Challengers #2: Сравнение строк. https://fetisovvs.blogspot.com/2018/11/java-challengers-2-java.html
Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html
Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
Раздача халявы: нетормозящие треды в Java. Project Loom. http://fetisovvs.blogspot.com/2018/09/java-project-loom-java.html
Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html
Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html
Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson,
LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html
Java EE Concurency API. http://fetisovvs.blogspot.com/2018/08/java-ee-concurency-api-java.html
Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
TDD приложений на Spring Boot: работа с базой данных. https://fetisovvs.blogspot.com/2018/12/tdd-spring-boot-java.html
Руководство: Thymeleaf + Spring. Часть 1. https://fetisovvs.blogspot.com/2019/01/thymeleaf-spring-1-java.html
Введение в Spring Boot: создание простого REST API на Java. https://fetisovvs.blogspot.com/2019/01/spring-boot-rest-api-java-java.html
Максимально простой в поддержке способ интеграции java-клиента с java-сервером. http://fetisovvs.blogspot.com/2018/09/java-java-java.html
Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html
Проекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html
Реактивное программирование с JAX-RS. http://fetisovvs.blogspot.com/2018/09/jax-rs-java.html
Компактные строки в Java 9. https://fetisovvs.blogspot.com/2018/10/java-9-java.html
Динамический прокси Java: что это и как им пользоваться? https://fetisovvs.blogspot.com/2018/12/java-java.html
Абстрактный CRUD от репозитория до контроллера: что ещё можно сделать при помощи Spring + Generics. http://fetisovvs.blogspot.com/2018/09/crud-spring-generics-java.html
Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html
Блеск и нищета Java для настольных систем. http://fetisovvs.blogspot.com/2018/04/java-haulmont-java.html
Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html
Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html
Открытый урок Java Enterprise «CDI in action». http://fetisovvs.blogspot.com/2018/09/java-enterprise-cdi-in-action-java.html
«Мы все стремимся к сложности, а потом с ней боремся»: интервью с Венкатом Субраманиамом. http://fetisovvs.blogspot.com/2018/09/java_16.html
Комментариев нет:
Отправить комментарий