Попался build.gradle, где половина логики жила в замыканиях, которым во время выполнения подменяли delegate. Долго разбирался, что здесь что значит.
Groovy это только поощряет. По умолчанию замыкание ищет неквалифицированные имена сначала у владельца, а DSL меняет порядок, выставляя resolveStrategy в Closure.DELEGATE_FIRST. Для задокументированного блока настроек нормально. Мучение начинается, когда вспомогательная функция из другого файла меняет делегат и голое version тихо начинает значить что-то другое.
Скрипты сборки читают гораздо чаще, чем пишут, и читает обычно тот, кто пришёл поднять версию одной зависимости. Поэтому правило у меня скучное. В скрипте только декларативные блоки. Всё, где есть цикл или условие, уходит в класс плагина с именем и тестом. Никаких фокусов с metaClass в сборке.
Обычно возражают, что файлов становится больше. Да. Зато только так следующий читатель узнает, на что ссылается version, не проходя сборку по шагам в отладчике.