Как стать автором
Обновить

AOP в Golang: как рефлексировать, и почему вам не стоит этого делать

Уровень сложностиСредний
Время на прочтение6 мин
Количество просмотров3.4K
Всего голосов 8: ↑7 и ↓1+10
Комментарии9

Комментарии 9

Хочу продолжение!

Фишка АОП же вроде в том что там компилятор сам генерирует обертки. А здесь нужно все руками делать - создавать функциональный объект и явно его везде вызывать вместо исходной функции.

Правильно, у автора явное проксирование на вызове, а не статичная подмена

Пожалуйста, не пишите так на Go. Оставьте эту дрянь для джавы. Решайте реальные задачи вместо построения сферических коней в вакууме — и обнаружите, что они прекрасно решаются простыми средствами. Например, через замыкание.

var nCalls = 0

func count(fn func()) {
    fn()
    nCalls++
}

func main() {
    sum := func(a int, b int) int {
        return a + b
    }

    total := 0
    count(func() { total += sum(1, 2) })
    count(func() { total += sum(3, 4) })
    count(func() { total += sum(5, 6) })

    fmt.Println(total)
    // 21
    fmt.Println(nCalls)
    // 3
}

песочница

По сравнению с приведенным в статье примером, конечно, Ваше решение быстрее. Однако, вам приходится использовать замыкание, чтобы каждый раз пробрасывать в count и аргументы функции sum, и переменную для сохранения результата. В моем же примере я использую запроксированную функцию так, как будто для нее ничего не изменилось. А еще обертка знает и аргументы вызванной функции, и ее результат, и может, например, выводить их в консоль. Или, допустим, проверять, вернула ли исходная функция ошибку. И если да, то попробовать выполнить ее еще несколько раз, пока она не вернет результат. При разумном использовании это может быть довольно интересным инструментом.

Но, как я и отмечал в конце статьи, использование рефлексии сильно замедляет код. И да, не очень-то типично для Go, ратующего за прозрачность. Отсюда и название "... и почему вам не стоит этого делать" )))

Откуда эта страсть к переусложнению на ровном месте?

Если уж делать AOP в го, то логичней использовать кодогенерацию через AST пакет. Но лучше AOP не делать вообще и дело вовсе не в производительности(для большинства приложений лишние 200 наносекунд на вызове функции абсолютно незаметны). Дело в том, что в го, как в языке, есть концепция - код должен быть простым, однозначным и очевидным. Должен быть только один путь сделать что-то. Именно по этому в го нет такого количества синтаксического сахара, как в других языках и сами программы выглядят более многословными, но хорошо читабельными. Да, вы можете пытаться использовать в го AOP, DI, ORM и т.д., эмулировать ООП, делать политики создания абстрактных фабрик, но делать это будет неудобно и выглядеть оно будет неогранично. Мое субъективное мнение, что го отлично подходит для рапид-девелопмента, когда вам надо быстро сделать какой-то тул или создать еще один микросервис, которые будет небольшим и сосредоточеным на одной конкретной задаче. В этом случае вам никакие AOP просто не нужны, вы всю нужную логику напишите быстрее, чем будете гуглить документацию и писать обязательный бойлерплейт. А если вам надо делать огромный монореп, с миллионами строк кода, кучей объектов предметной области в одном приложении-сервисе, с множеством правил их взаимодействия, исключений из правил, самой разной бизнес логики, над которым одновременно работают десятки программистов и все это не возможно поддерживать без множества слоев абстраций, то лучше просто не использовать го, а посмотреть в сторону других языков - той же джавы, котлина, сишарпа.

Не надо так... Пожалуйста, оставайтесь на java и не пишите код на go. Зачем забивать гвозди микроскопом? Потом обычным гошникам очень тяжело будет после вас поддерживать проект, проще будет выкинуть всё и переписать.

Возможно, вы невнимательно читали, и не заметили, что я никого не заставляю так делать. Более того, даже не рекомендую =D

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории