Pull to refresh

Comments 70

Cool story, Bro! Как раз читаю спринговый мануал и эти аспекты как то не особо интуитивно понятны (были).
Да, статью в избранное!

Кстати, для себя вывел рецепт первого комментария на Хабре, которым пользуются многие:
1) похвалить автора;
2) упомянуть, что тоже этим занимался/занимаешься/будешь заниматься;
3) сказать, что без статьи ничего/что-то не получалось;
4) профит.

Может стоит разнообразить, как думаете?
А то какой-то аналог первон@*а получается.
Ну а почему бы не похвалить автора если он этого действительно заслуживает? Или что, мне ждать пока выскажется десяток-другой критиков?
Меня искренне умиляют индивиды, ищущие в этом подоплеку.
Ну ладно, простите что минусанул коммент и умильнул вас :)
Просто мне кажется, можно похвалить авторов и иначе, и побогаче!
многие не знают, что на самом деле означает фраза cool story, bro! вот цитата из urban dictionary:

An appropriate response to a story that went nowhere and/or was completely uninteresting.
«This one time me and my brother were eating sandwiches and he was like 'dude, I hate mustard' and I was like 'yeah.'»
«Cool story bro.»


похвалы тут никакой нет, только сарказм.
ну вот, спасибо за минус в карму.
Это еще ничего, раньше встречалось часто нечто в духе «под кат». =)
Все отлично, но может кто-то сможет написать реальный, работающий пример? Такое банальное, как, например гостевая?
Такая же мысль, для общей завершенности статьи не хватает кода веб-сервиса в стиле АОП.
Интерпретатор брейнфака ^_^
В плане разработки, бесспорно, использовать АОР удобно. Но тогда назревает такой вопрос, как же это все скажется на быстродействии приложения?
сильно не скажется. тем более когда аспекты интегрируются изменением байткода — тогда это все равно что пример из первой части статьи
Приведу пример — практически все приложения под MacOS/iOS пишутся на Obj-C, а там вместо вызова методов используется посылка сообщений (наследство от smalltalk). Так вот практически каждое приложение в том или ином виде имеет у себя какую-то дополнительную обработку этих сообщений (по сути это похоже на техническую реализацию АОП). При этом особой нагрузки это не накладывает и считается нормой, причем в таком виде реализованы все фреймворки и визуальные элементы управления.

p.s.
Вы легко можете перехватывать сообщения (читай вызовы методов), менять их параметры и передавать дальше, передавать в другие обьекты, пересылать даже по сети, блокировать, обрамлять дополнительным кодом, создавать дополнительную логику и т.д.
Так что можно сказать что АОП довольно просто и часто используется в мак программах, хотя и скрывается под именами таких паттернов как прокси/декораторы, адаптеры, цепочки пересылки, фасады, уведомления и вариации.
Спасибо, буду иметь в виду.
Эта парадигма молодая только в Java мире. Аналогичный подход давно используется в Lisp и встроен в язык (макросы, иногда первоклассные функции)на порядок удобнее Java библиотек, работающих через reflection либо модификацию байт-кода.

Проблема как всегда в том, что мало у кого есть время и желание знакомиться с другими языками. После умножения на «модность» и поддержку корпоративного мира получается очередное изобретение велосипеда.
А она и в ava мире не молодая, ей уже 10 лет как минимум.

PS. По-моему, макросы в Лисп — это всё-таки другое.
Макросы — это другое. Но в Лиспе с 88-го года советы есть.

Заодно (карма не позволяет чаще комментить) хотелось бы заметить что в том же Лиспе (Common Lisp) ОО-парадигма реализована на порядок лучше чем в Java, не говоря уже о C++.

Базовй Common Lisp (без библиотек) позволяет использовать его как императивный или ОО. ФП там с небольшой натяжкой, не всё можно сделать чистыми функциями, в отличие от Haskell.

Это фактическая ошибка — исправьте, пожалуйста.
Если поставивший минус намекает что основная единица программы — это функция, то тоже мимо. «Функции» Лиспа в подавляющем большинстве случаев оказываются процедурами. Первого класса, возвращающие значение, но процедуры.

Если же он намекал на что-то другое, то хотелось бы услышать на что именно. Не стесняйтесь, пальцы не отсохнут. Гарантирую.
Извиняюсь, что лезу в разговор, но не могли бы Вы дать ссылки, где рассказывается, чем принципиально отличается процедура от функции, чтобы я мог восполнить пробелы в своих знаниях. Пока их хватает только на то, что процедура это ничего не возвращающая функция (ну или возвращающая void).
Определения противоречивы. В одних источниках функция *может* вернуть результат, в других — *должна* вернуть результат.

(defun test (x)
(if (> x 0)
t
(values)))

При передаче в эту функцию положительного аргумента, она вернёт t (true), отрицательного — не вернёт ничего. Как её называть? :)

По теме: Программа на CL может быть и просто скриптом. Фанаты «ненормального программирования» могут писать и на макросах.

Вообще, классификация в статье достаточно странная. С этой точки зрения (основная единица кода) можно просто поменять местами C и Common Lisp. И будет больше правды, т.к. код на C обязательно должен быть в функциях или процедурах, а на Лиспе — может быть и в макросах и просто в toplevel'е.
В тех языках, где есть собственно понятие процедуры — отличие одно, и реальное: функция возвращает значение и сама по себе является элементарным вычислимым выражением. Некоторые языки требуют, чтоб её значение любого выражения было обязательно использовано — передано или присвоено. Процедура значений не возвращает, и является самостоятельной командой.
Да, макросы шире чем «советы», но позволяют легко их реализовывать.

Найти код макроса намного проще, чем найти код, который реализует соответствующую аннотацию в java подходе.
AOP в buzzword-языка[ соотвествует такому понятию, как комбинация методов в CLOS — объектной системе Common Lisp. И если посмотреть на тех, кто придумывал CLOS и кто потом пропогандировал AOP, то пересечение этих множеств будет непустым ;)

Кратко поясню, что в CLOS можно добавлять :around, :before и :after-методы, которые вписываются в схему вызовов по стандартному алгоритму, позволяя без проблем реализовать все описанное в статье :)

И напомню, что стандарт ANSI Common Lisp (включающий в себя CLOS) выпущен в 1994 г., но первые реализации появились ещё в 80-х (конечно, они не были 100% совместимыми с последующим стандартом, но обсуждаемая функциональность там была).
Когда я вижу как джависты начинают вытворять вещи подобные вышеописанному компилятору для встраивания АОП в язык мне страсть как хочется воскликнуть: «Понеслась п*зда по кочкам» Реализация 80% части описанного АОП-фреймворка в Clojure — лиспе поверх JVM — это, бл**ь, 70 строк кода zahardzhan.github.com/2010/clojure-hooks.html.
Правильно ли я понимаю, что смысл АОП заключается в том, чтобы дать разработчику возможность создавать типовые декораторы для вызовов функций/методов/конструкторов и всего остального, что назвали «точками соединения», и применять их к интересующим точкам соединения автоматизированно, при помощи дополнительного набора инструкций?
Мне тоже ровно так же показалось. А ещё стало интересно, насколько код читаемым получается. Не рождается ли не просто write only язык, а write only подход?

Я так понимаю, что, наверное, IDE должна многое показывать. Есть ли специализированные IDE? Под все платформы?
Что вот тут нечитаемого?:)
[Cache(typeof(DynamicField))]
private static bool ShowMultiLink(string entityName, string fieldName)
{}
Я не знаю этот синтаксис, так что не могу ничего сказать.
Что-то типа того
В ООП есть замечательный паттерн «chain of responsibility»
По крайней мере кэширование, логирование и проверку прав с ним делать на ура
В последней «ссылке по теме» в одном из пунктов COR как раз сравнивается с AOP
Мне этот пункт показался каким-то неубедительным…
Дело даже не в том, что я там против АОП по религиозным соображениям или еще почему-то. Я уже слышал эту аббревиатуру и честно пытался понять, что же это такое, и не может ли оно мне пригодиться. Статья сделала смысл технологии чуть более понятным, последняя ссылка — еще сильнее разъяснила, но я пока склонен верить части перечисленных по этой ссылке мифов. Возможно, дело в языке программирования. Я достаточно давно занимаюсь разработкой на perl и знаю, какими комбинациями ООП-приемов, паттернов проектирования и средств языка действовать, чтобы быстро и прозрачно реализовать нужный функционал, включая декораторы. Те же атрибуты функций позволяют легко добиться эффекта, сильно похожего на приведенный в статье пример из java. Возможно, если бы я выбрал более строгий язык, АОП был бы актуален.
Или я все-таки чего-то не понимаю? Буду рад, если кто-то сумеет разъяснить.
А так же есть signal-slot, event-driven programming, но все они решают одну проблему — устранение дублирования и зависимостей при реализации сквозной функциональности.

Пример из жизни: когда вы заходите в магазин, что бы купить продуктов, вы заходите и покупаете продукты, не обращая внимания на охрану и камеры видео-наблюдения. Это все потому, что охрана (security) и камеры (log) — это сквозная функциональность. Вы в этом случае — объект наблюдения, на действия которого «подписываются» другие заинтересованные объекты.

Есть проблема понимания того, какая функциональность для в каждом конкретном случае (домене) является сквозной, а какая — специфичной.
В ООП есть много замечательных паттернов, которые по-сути обозначают одно и тоже :)
Спасибо за просвещение! Давно в голове крутилась мысль, что подобная парадигма просто обязана существовать, т.к. бизнес логика рано или поздно просто тонет в «обвязке» из служебного кода.

правда, что-то для Qt ничего ничего подобного не найду
Хм, привязка множества слотов к одному сигналу и возможность генерировать свои сигналы в слоте разве не что-то подобное?
сигналы-слоты не упростят ту же задачу логирования, например. Или я чего-то не понимаю :)
Ну, вместо
@Loggable
public void method(int arg)
{
  doSomething();
}

надо будет написать
public void method(int arg)
{
  emit enterMethod(arg);
  doSomething();
  emit leaveMethod(arg);
}

А уж на enter/leave можем повесить и несколько видов логирования (или не вешать), и проверку прав.

Не так красиво, но управление кодом, имхо, упрощает даже по сравнению с традиционным DI (одна и только одна реализация интерфейса). Сложность вызывает использование чего-то (или ничего) вместо вызова метода или оборачивание его в конструкции типа try… catch, но вот перед и после нет проблем.
вместо emit точно также можно просто вызывать обычные методы, содержащие пересекающую логику. сигналы конечно гибче, но принципиально разницы нет.

Я вот думаю, нельзя ли как-то в шаблон или макрос эти эмиты завернуть?
>… судя по сравнениям с сайта PostSharp, лидирующую позицию занимает именно он.

Фраза напомнила об одном небезизвестном браузере, который тоже по сравнениям со своего сайта лучший в мире :) (Ничего личного, просто позабавила формулировка)
Я только начал изучать Spring, но у меня сложилось устойчивое мнение, что аспектами лучше добавлять функциональность, чем делать декораторы. Декораторы естественнее делать в виде аннотаций. А например в Spring Roo аспекты используются для добавления функционала в сущности или скафолда контроллеров. Например, реализация таких методов как геттеров/сеттеров, toString() и пр.
А можете привести пример с сеттерами-геттерами? Плз…
Spring Roo сам генерирует геттеры/сеттеры для сущностей, помеченных аннотацией @RooJavaBean. Cущность выглядит примерно так:
@RooJavaBean //
@RooToString
@RooEntity
public class PackageName {

@NotNull
@Column(unique = true)
private String name;
}


Для нее он генерирует аспект типа такого:
privileged aspect PackageName_Roo_JavaBean {

public String PackageName.getName() {
return this.name;
}

public void PackageName.setName(String name) {
this.name = name;
}

}


Красиво и понятно, без всякой магии :)
Благодарю, хороший пример. Похоже, АОП полностью открывается именно в нединамических языках. В динамических, как правило, есть возможность добиться того же самого привычными встроенными средствами.
Назвать статью понятной — сложно. Даются общие определения, какие-то примеры, но суть куда-то ускользает.
Все это ИМХО, конечно. Я бы с целью ознакомления аудитории сделал иначе — привел бы примеры на псевдокоде
и на этих примерах объяснил бы, где тут срезы, где советы и т.д.
Вот интересно, для платформы .NET каких-нибудь IOC-контейнеров — два десятка, а АОР фреймворков — кот наплакал
Если нужно только то, что описано в статье, то это делается через IoC-контейнеры. Например в unity такая фича есть, смотри здесь: msdn.microsoft.com/en-us/library/ff647107.aspx
Мне всегда интересно было, почему ООП выделяют в отдельную парадигму. Я лично не знаю ни одного языка, где был бы ООП без какой-либо другой парадигмы, например императивной или функциональной.
Скорее это разные измерения: динамический-статический, комплируемый — интерпретируемый, императивный-декларативный, ООП — не ООП :)
вот с такой терминологией я согласен, просто все это называют одним словом — парадигмой, как бы подразумевая что это единая характеристика.
С вики:
Термин «парадигма программирования» впервые применил Роберт Флойд в своей лекции[2] лауреата премии Тьюринга.

Флойд отмечает, что в программировании можно наблюдать явление, подобное парадигмам Куна, но, в отличие от них, парадигмы программирования не являются взаимоисключающими


ru.wikipedia.org/wiki/Парадигма_программирования
Да, я это читал. У меня другая мысль: некоторые парадигмы являются самостоятельными (есть языки, которые основаны только на этой парадигме), а некоторые нет (то есть могут допольнять другую парадигму)
Не очень понял, но это то же самое, что декораторы в Python?
По сути — да.
Если говорить формально, то AOP — это парадигма, а декораторы — это синтаксис. И в python AOP удобнее всего реализуется при помощи декораторов.
А различные хуки, middleware и т. п. к АОП имеют отношение или это нето совсем другое? Цели-то вроде бы те же.
Не могу сказать что являюсь противником или последователем данной технологии. У всего есть свои плюсы и минусы. Но недолюбливаю AOP за его «скрытность». Когда читаешь метод, должно быть понятно что он делает. И довольно неприятно каждый раз, натыкаясь на аннотацию AOP вспоминать что этот метод может НЕЯВНО (в коде то в методе этого НЕТ) делать ещё что-то. И это скажите спасибо если метод аннотирован, а если используется любимое spring-way-xml-programming, то всё — тушите свет. Что на самом деле делает код, можно понять только после поллитры. =\

PS: Мнение рождено не на пустом месте. Пришлось пару лет поработать на проекте, где кэшинг (и ещё что-то, уже не помню что) активно прикручивали на Аспектах. Не могу сказать чтобы код блистал понятностью своей.

PPS: А за статью спасибо, конечно, она довольно понятно всё объясняет. Только вот определения Аспекта и Совета выглядят (для меня по крайней мере) весьма размыто.
Ну, вообще говоря, «вспоминать что этот метод может НЕЯВНО (в коде то в методе этого НЕТ) делать ещё что-то» приходится постоянно, если метод использует хотя бы стандартную библиотеку, а не является «вещью в себе». Хотя я сталкивался только с аннотациями, xml описания у меня как-то не прижились в php :)
Либо я Вас не понял, либо наоборот.

Когда метод что-то использует, он делает это ЯВНО, вызывая что-то ЯВНО. (Ну или как там правильно говорить, посылая сообщения ;)). В случае же с AOP в методе НЕТ явного обращения к кэшу, или логгирования (ну или ещё какой хитрой логики). Оно происходит «за сценой», скрыто от вас при прочтении. Это, намой взгляд, ужасный недостаток. ДАЖЕ с аннотациями (которые какбэ намекают, ага).

Ну а насчёт xml… Это как раз spring-way (по крайней мере был раньше). Автор в статье как раз про него и говорит в конце…
Ну вызывает явно, но что вызывает мы можем посмотреть, только открыв вызываемый код, в этом отношении не вижу разницы между:
@Loggable
public void method() {...}

и
public void method() {Log.writeForMethod; ...}

С одной стороны ужасный, с другой сосредотачивает внимание на основной задаче метода.

Активно используемый мною php-фреймворк позволяет использовать для конфигурации, например, DI три способа YAML, XML и нативный php-код, предпочитаю первый и последний, XML как-то уж слишком многословен, имхо, за деревьями не видно леса.
Очень печально, что Вы не видите разницу между явно написанным кодом и неявно.

PS: Ещё один момент: нормальное IDE (вроде Eclips'а), для джавы, даст вам в один щелчок перейти к телу «writeForMethod», а вот определение @Loggable хоть и откроется, но читабельность его будет ниже (пойди ещё разбери чего там в классе нафигачили).

В общем, если вам нравится — пользуйте, конечно, но крайне рекомендую ознакомиться и с точкой зрения противников метода. Вы правильно говорите, иногда за деревьями не видно леса. Вот AOP зачастую бывает теми деревьями. Как правило всегда можно проще и читабельнее…
Да я только теоретизирую, на практике использовать АОП в обозримом будущем вряд ли будет возможность.
а как это себя ведет при рефакторинге кода?

насколько я понял аспекты привязываются к методам по именам. что происходит, если имя метода меняется — авторизация перестает проверятся, логи — записываться? есть-ли для таких случаев поддержка со стороны среды разработки, предупреждения какие-то?
Хороший вопрос. Я с рефакторингом этих методов не сталкивался. Надо будет посмотреть :)

В целом, если построено на аннотациях, должно по идее работать нормально.
Скажите, а обязательно point-cut задавать как аннотацию к методу? Ведь, насколько я понял, роль метода заключается лишь в том, что он задает имя point-cut, которое, очевидно, можно было бы задавать и в самой аннотации.
Нет, совершенно не обязательно. В случае с Spring AOP срез можно определить как в описании совета (например, в аннотации @Around), так и в XML-конфиге.
Ну насчет XML-конфига я и не сомневался (Java такая Java :) ), а насчет advice это интересно. Спасибо!
Я так понимаю, в примере вы выбрали этот способ, чтобы явно показать разделение между point-cut и advice? Но это немного путает: непонятно, что методы webserviceMethod и loggableMethod ничего не выполняют, а по сути являются метаданными.
Sign up to leave a comment.

Articles