Cursos que formaram meu caráter: Desenvolvimento web com Quarkus - Gerenciador de versões de bibliotecas com Versions
Tags: gradle, java, benmanes, dependabot
Published: 2022-12-14 03:16:01

---
title: Cursos que formaram meu caráter: Desenvolvimento web com Quarkus - Gerenciador de versões de bibliotecas com Versions
published: true
description: O que aprendi com cursos realizados e como apliquei outras técnicas conhecidas para evoluí-los
tags: gradle, java, benmanes, dependabot
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8uazy3rfnxc4ha6mn6r.jpg
# published_at: 2022-12-13 14:09 +0000
---

> "Você torna o mundo um lugar melhor fazendo melhorias diárias para se tornar a melhor versão de si mesmo". Roy T. Bennett, The Light in the Heart

Nesse terceiro posts falaremos sobre o gerenciamento de versões utilizando o [Gradle Versions Plugin](https://github.com/ben-manes/gradle-versions-plugin) do [Ben Manes](https://github.com/ben-manes). Isso nos ajudará a manter nosso projeto com as dependências atualizadas.

Discutiremos também os problemas que isso pode causar, e o porque não termos um fluxo de [Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html) pode nos dar grandes dores de cabeça.

Por fim, falarei do [Dependabot](https://dependabot-gitlab.gitlab.io/dependabot/). Não apliquei nesse projeto, mas vou colocar no backlog, e quem sabe escrever em um outro post.

Esse artigo faz parte de uma série, abaixo é possível encontrar a [lista completa de artigos](#serie_completa).

Estamos nos baseando no curso [Desenvolvimento web com Quarkus](https://www.udemy.com/course/des-web-quarkus) do @viniciusfcf.

O repositório que estamos utilizando é:

{% embed https://gitlab.com/arthurfnsc-udemy/desenvolvimento-web-quarkus/ifood/ %}

---

## O tempo passa, o tempo voa

{% embed https://www.youtube.com/watch?v=cgk3daHqeJc %}

O tempo é implacável! Mudanças acontecem constantemente, e isso impacta decisões passadas que tomamos.

No mundo do desenvolvimento de software essa máxima permanece!  Bibliotecas e frameworks são atualizados ou descontinuados; outras vezes podemos descobrir uma vulnerabilidade nas nossas dependências e sermos forçados a realizar mudanças (falaremos um pouco disso em um post futuro chamado Plugins do Gradle: Validação de vulnerabilidades de dependências com OWASP Dependency Check).

Uma das primeiras ideias que temos é: Vamos deixar o nosso projeto sempre com a última versão das bibliotecas disponíveis!

> "Para todo problema complexo existe sempre uma solução simples, elegante e completamente errada". H L Mencken

Qual é o problema podemos ter nessa primeira abordagem? 

Para atualizar uma dependência em um projeto é importante termos algumas coisas em mente, como: 
* Existe uma equipe de sustentação que precisa garantir que as bibliotecas que estamos usando estão em conformidade com uma arquitetura corporativa?
* As bibliotecas que estamos usando funcionam corretamente se todas forem atualizadas para sua última versão?
* O servidor em que a solução será implantada tem suporte a tais bibliotecas?
* dentre outros.

Nesse post falarei de uma estratégia para essa atualização, porém, é importante ressaltar que isso não é a bala de prata para todos os projetos, e que sempre é bom acordar as decisões com o time, equipe de arquitetura e/ou liderança técnica responsável.

---

## Utilizando um plugin

Um plugin bem interessante do **Gradle** é o [Gradle Versions Plugin](https://github.com/ben-manes/gradle-versions-plugin) do [Ben Manes](https://github.com/ben-manes). Sua aplicação é bem simples.

Utilizando o nosso [projeto de referência](https://gitlab.com/arthurfnsc-udemy/desenvolvimento-web-quarkus/ifood/), no nosso arquivo **build.gradle** na raiz do projeto podemos ver algo como o seguinte:

```groovy
plugins {
    ...
    id "com.github.ben-manes.versions" version "$versionsVersion" apply false
    ...
}

...

subprojects {
    if (it.name != 'applications') {
        ...
        apply from: "$rootDir/plugins/docs.gradle"
        ...
    }
}
```

As configurações do arquivo **plugins/docs.gradle** serão melhor explicadas adiante.

Caso você esteja com dúvida sobre esses **$** no código, dá uma olhada no [post anterior](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-utilizando-gradle-ao-inves-de-maven-1lcn) em que falamos sobre **Variáveis de projeto**.

Essa primeira parte da configuração nos ajuda a buscar as atualizações de todas as nossas bibliotecas através da seguinte task do **Gradle**:

```sh
foo@bar:~$ ./gradlew dependencyUpdates
```

Executando a task vamos ter um resultado semelhante a:

```
./gradlew dependencyUpdates

------------------------------------------------------------
:applications:cadastro Project Dependency Updates (report to plain text file)
------------------------------------------------------------

The following dependencies are using the latest milestone version:
 - com.approvaltests:approvaltests:18.5.0
 - com.github.database-rider:rider-cdi:1.35.0
 - com.github.database-rider:rider-core:1.35.0
 - com.google.code.gson:gson:2.10
 - org.mapstruct:mapstruct:1.5.3.Final
 - org.mapstruct:mapstruct-processor:1.5.3.Final
 - stax:stax:1.2.0

The following dependencies have later milestone versions:
 - io.opentracing.contrib:opentracing-jdbc [0.2.4 -> 0.2.15]
     https://github.com/opentracing-contrib/java-jdbc
 - io.quarkus:io.quarkus.gradle.plugin [2.14.3.Final -> 3.0.0.Alpha2]
 - io.quarkus:quarkus-arc [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-arc-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-config-yaml [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-config-yaml-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-core-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-flyway [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-flyway-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-orm-panache [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-orm-panache-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-validator [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-validator-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-jdbc-postgresql [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-jdbc-postgresql-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-junit5 [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-resteasy-jsonb [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-resteasy-jsonb-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-jwt [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-jwt-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-metrics [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-metrics-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-openapi [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-openapi-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-opentracing [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-opentracing-deployment [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus
 - io.quarkus.platform:quarkus-bom [2.14.3.Final -> 3.0.0.Alpha2]
     https://github.com/quarkusio/quarkus-platform
 - io.rest-assured:rest-assured [4.5.1 -> 5.3.0]
     http://code.google.com/p/rest-assured
 - org.testcontainers:postgresql [1.17.5 -> 1.17.6]
     https://testcontainers.org

Gradle release-candidate updates:
 - Gradle: [7.6: UP-TO-DATE] 
------------------------------------------------------------
```

Nesse caso, removi os logs referentes aos demais subprojetos só para termos um resultado menor.

Podemos ver por exemplo que as seguintes dependências estão atualizadas no nosso projeto:

```sh
The following dependencies are using the latest milestone version:
  - com.approvaltests:approvaltests:18.5.0
  - com.github.database-rider:rider-cdi:1.35.0
  - com.github.database-rider:rider-core:1.35.0
  - com.google.code.gson:gson:2.10
  - org.mapstruct:mapstruct:1.5.3.Final
  - org.mapstruct:mapstruct-processor:1.5.3.Final
  - stax:stax:1.2.0
```

E que a dependência do **opentracing-jdbc** está desatualizada:

```
The following dependencies have later milestone versions:
  - io.opentracing.contrib:opentracing-jdbc [0.2.4 -> 0.2.15]
``` 

No entanto, temos um efeito colateral da forma como o plugin está funcionando. E isso pode ser visto em todas as dependências do **Quarkus** que estamos usando, a sugestão de atualização para versão **3.0.0.Alpha2**:

```
  - io.quarkus:io.quarkus.gradle.plugin [2.14.3.Final -> 3.0.0.Alpha2]
```

Na maioria das vezes não queremos bibliotecas de **Release**, **Alpha** ou **Beta** no nosso projeto por não serem versões finais, e poderem conter alterações futuras. Para resolver esse problema, o próprio plugin nos oferece uma solução em suas configurações. No nosso caso, podemos encontrar elas em **plugins/docs.gradle**; eu havia comentado elas para evidenciar o problema anterior:

```groovy
apply plugin: "com.github.ben-manes.versions"
...

dependencyUpdates {
    checkForGradleUpdate = true
    outputFormatter = "json"
    outputDir = "build/reports/docs/dependencyUpdates"
    reportfileName = "report"

    resolutionStrategy = {
        componentSelection { rules ->
            rules.all { ComponentSelection selection ->
                boolean rejected = ["alpha", "beta", "rc", "cr", "m"].any { qualifier ->
                    selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
                }
                if (rejected) {
                    selection.reject("Release candidate")
                }
            }
        }
    }
}
```

Executando novamente a task, nosso resultado para **:applications:cadastro** é o seguinte:

```
./gradlew dependencyUpdates

------------------------------------------------------------
:applications:cadastro Project Dependency Updates (report to plain text file)
------------------------------------------------------------

The following dependencies are using the latest milestone version:
 - com.approvaltests:approvaltests:18.5.0
 - com.github.database-rider:rider-cdi:1.35.0
 - com.github.database-rider:rider-core:1.35.0
 - com.google.code.gson:gson:2.10
 - io.quarkus.platform:quarkus-bom:2.14.3.Final
 - org.mapstruct:mapstruct:1.5.3.Final
 - org.mapstruct:mapstruct-processor:1.5.3.Final
 - stax:stax:1.2.0

The following dependencies have later milestone versions:
 - io.opentracing.contrib:opentracing-jdbc [0.2.4 -> 0.2.15]
     https://github.com/opentracing-contrib/java-jdbc
 - io.quarkus:io.quarkus.gradle.plugin [2.14.3.Final -> 2.15.0.Final]
 - io.quarkus:quarkus-arc [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-arc-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-config-yaml [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-config-yaml-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-core-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-flyway [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-flyway-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-orm-panache [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-orm-panache-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-validator [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-hibernate-validator-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-jdbc-postgresql [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-jdbc-postgresql-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-junit5 [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-resteasy-jsonb [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-resteasy-jsonb-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-jwt [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-jwt-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-metrics [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-metrics-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-openapi [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-openapi-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-opentracing [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.quarkus:quarkus-smallrye-opentracing-deployment [2.14.3.Final -> 2.15.0.Final]
     https://github.com/quarkusio/quarkus
 - io.rest-assured:rest-assured [4.5.1 -> 5.3.0]
     http://code.google.com/p/rest-assured
 - org.testcontainers:postgresql [1.17.5 -> 1.17.6]
     https://testcontainers.org

Gradle release-candidate updates:
 - Gradle: [7.6: UP-TO-DATE]

------------------------------------------------------------
```

Problema de atualização de bibliotecas resolvido? É só ir no nosso **gradle.properties** e pronto.

{% embed https://giphy.com/gifs/ionedigital-hellobeautiful-madamenoire-listen-to-black-women-NlXJKUUSnkN5BsOtl0 %}

O que fizemos foi apenas uma forma de evidenciar quais as bibliotecas que estão desatualizadas. 

Antes de mudar as versões de todas as que estão aparecendo como desatualizadas é importante validarmos se isso não impacta as outras bibliotecas do nosso projeto. Em muitos casos, uma biblioteca utiliza outras bibliotecas, o que chamamos de **dependências transitivas**. Com isso, para que uma biblioteca funcione corretamente é importante que suas **dependências transitivas** também estejam.

Pegue por exemplo a [Spring Boot Starter Data JPA](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa). Não vou me lembrar da versão exata, mas o **Java teve uma grande mudança na versão 8**, dentre elas, a adição de **Optional**.

Me lembro quando utilizei o plugin de versões para mudar a versão do **Spring Boot** em um outro projeto que eu estava trabalhando há alguns anos atrás, e de repente minhas classes de service começaram a dar problema. Ao investigar, percebi que a assinatura de alguns métodos mudaram, e ao invés de retornar uma entidade, estavam retornando **Optional**.

Nesse caso em específico, eu consegui mudar o meu código para que a atualização fizesse sentido, mas imagina se o problema fosse em uma classe de **dependência transitiva** que temos no projeto.

Como então resolver o problema de saber se a atualização de uma dependência impacta ou não outras dependências, e consequentemente o projeto? Podemos ir na tentativa e erro, subindo nossa aplicação e vendo se todos os fluxos dela continuam funcionando. Mas será que não tem uma forma melhor?

### Continuous Integration

Em posts mais adiante falaremos sobre [GitLab](https://about.gitlab.com/) e pipelines. Quando falarmos sobre pipelines discorreremos sobre a importância do processo de automação dado o número de alterações de um projeto por várias pessoas.

Uma forma que poderíamos fazer seria então termos a nossa fase de testes executada em nossa pipeline sempre que um **merge request** for realizado, por exemplo.

Podemos agora fazer mudanças em versões de uma biblioteca e ver se nossos testes não quebram. Para essa abordagem é importante que **confiemos nos nossos testes** e na **quantidade de camadas cobertas por eles**.

Quando digo em confiar em nossos testes, me refiro aos seguintes testes que muitas vezes encontramos em nossos projetos:

```java
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class Teste {

    private int adicao(int a, int b) {
        return a + b;
    }

    @Test
    void deveAdicionar() {
        Assertions.assertNotNull(adicao(1, 2));
    }
}
```

O teste com **assertNotNull** pode nos dar um falso positivo sobre o funcionamento do nosso método. Imagine por exemplo que um desenvolvedor subiu uma versão mudando o método para algo como:

```java
private int adicao(int a, int b) {
    return a - b;
}
```

Nosso teste não iria quebrar! Bem importante usar testes com **assertNotNull** com parcimônia.

Esse foi apenas um exemplo de teste que poderia ser melhor testado, mas imagina se fizermos testes que não quebrem, porém, quando fizermos o deploy em produção aparecerem incompatibilidades.

Uma abordagem que podemos seguir para saber se temos bons testes foi escrita por @alexandreaquiles:

{% embed https://www.alura.com.br/artigos/testes-de-mutantes %}

Mas voltando à atualização das nossas bibliotecas, não seria maravilhoso se tivesse uma forma melhor do que nós mesmos abrirmos **merges request** para cada mudança?

![Não seria maravilho se...?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n0j2ve9pojff9vph99bj.jpg)

### Dependabot

O [Dependabot](https://dependabot-gitlab.gitlab.io/dependabot/) é uma solução que funciona com **Ruby**, **JavaScript**, **Python**, **PHP**, **Elixir**, **Elm**, **Go**, **Rust**, **Java** e **.NET**.

E seu funcionamento se dá em uma constante validação de novas versões e abertura de **merge requests** para um repositório configurado. Não configurei nesse projeto, mas vocês podem ver a ideia dele [nesse outro repositório](https://github.com/arthurfnsc/bands-REST-api/pulls?q=is%3Apr+is%3Aopen+label%3Adependencies) que criei.

Com isso, é possível aprovar ou não os **merge requests** que o **Dependabot** fará para o nosso projeto.

---

##  Conclusão

A atualização de dependências de um projeto é um processo que poderá ser necessário em projetos, porém é importante avaliarmos os impactos das mesmas e consequências em outras bibliotecas do projeto.

Soluções como [Gradle Versions Plugin](https://github.com/ben-manes/gradle-versions-plugin) ou [Dependabot](https://dependabot-gitlab.gitlab.io/dependabot/) podem fazer parte do nosso processo para uma maior assertividade na alterações de tais versões, atrelados a processos como **Continuous Integration**.

---

<a name="serie_completa"></a>

Esse post faz parte de uma série sobre **Cursos que formaram meu caráter: Desenvolvimento web com Quarkus**.

A série completa é:

* [Talk is cheap show me the code](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-talk-is-cheap-show-me-the-code-2k91)
* [Utilizando Gradle ao invés de Maven](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-utilizando-gradle-ao-inves-de-maven-1lcn)
* Plugins do Gradle: Gerenciador de versões de bibliotecas com Versions
* [Plugins do Gradle: Saudades do  Maven, relatórios com Project-report](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-saudades-do-maven-relatorios-com-project-report-51d6)
* [Plugins do Gradle: API First com o OpenAPI Generator](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-api-first-com-o-openapi-generator-42pm)
* [Plugins do Gradle: API First com o OpenAPI Generator para APIs reativas](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-api-first-com-o-openapi-generator-para-apis-reativas-3o9b)
* [Plugins do Gradle: Validação de vulnerabilidades de dependências com OWASP Dependency Check](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-validacao-de-vulnerabilidades-com-owasp-dependency-check-2a2l)
* Plugins do Gradle: Lint com Spotless [não publicado]
* GitLab: Motivação para a escolha [não publicado]
* GitLab: Considerações sobre o Prettier em pipelines [não publicado]
* Gitmoji [não publicado]
* SDK Man [não publicado]
* Pré commit hook [não publicado]
* application.yml: Utilizando YML em propriedades de aplicação [não publicado]
* application.yml: Utilizando variáveis de ambiente [não publicado]
* application.yml: Sobrescrevendo opções em teste [não publicado]
* Mapstruct: Utilizando expressões para mapeamentos [não publicado]
* Microprofile SecurityScheme: Sobrescrevendo tokenUrl [não publicado]
* Prometheus: O problema simples que me custou algumas horas [não publicado]
* quarkus-hibernate-reactive-panache: Utilizando as vantagens do Hibernate em projetos reativos [não publicado]
* Testcontainers: Configuração para projetos reativos [não publicado]