Cómo desacoplar despliegue y release con feature flags y tests A/B usando Flagsmith

Escrito por picodotdev el .
programacion
Enlace permanente Comentarios

Desplegar sin liberar y experimentar sin intuición. En sistemas de software complejos, las feature flags y los tests A/B son herramientas clave para separar el despliegue del release y tomar decisiones basadas en métricas reales. En este artículo exploramos ambos conceptos y cómo implementarlos con Flagsmith en una aplicación Java.

Flagsmith

Un sistema de software complejo tiene muchas funcionalidades, para algunas de las cuales es casi seguro que surge la necesidad de activarla, desactivarla o cambiarla a demanda sin necesidad de hacer cambios de código simplemente por configuración o mediante un sistema externo que proporcione la configuración de las features.

Por otro lado, al liberar un cambio que pueda tener un impacto en el comportamiento de los usuarios es habitual realizar teses A/B para medir ese impacto y conocer si es positivo o negativo. En vez de guiarse por la intuición y sesgos es más objetivo guiarse por métricas.

Feature flags

Algunas de las features de un producto de software no se desarrollan por completo y despliegan de forma atómica. Siguiendo los principios de continuous delivery el despliegue o deploy se separa de la liberación o release. Con este principio hay algunos cambios de código que están desplegados pero aún desactivados y no visibles funcionalmente. Para poder implementar el continuous delivery una de las técnicas que se utilizan son las feature flags. Las feature flags no son más que un booleano que indica si una feature está habilitada o no.

Los feature flags son útiles también para cambiar el comportamiento del software sin necesidad de cambiar el código. Este cambio se hace a demanda por ejemplo a necesidades técnicas pero también por necesidades de negocio o legales.

Son una herramienta necesaria para servicios de backend, componentes de frontend y en las aplicaciones nativas donde liberar una nueva versión tarda varios días o hay usuarios que no las actualizan.

Un ejemplo de feature flags, podría ser si un determinado producto está disponible para la venta, una nueva forma de calcular los precios está activada o más sencillas como el clor de un botón.

Teses A/B

Por otro lado, al liberar un cambio que pueda tener un impacto en el comportamiento de los usuarios es habitual realizar teses A/B para medir ese impacto y conocer si es positivo o negativo. Un experimento de un test A/B puede tener varias variantes el resultado se mide con referencia al comportamiento existente en una variante y las otras variantes introducen cambios de las que se quiere medir el impacto.

Los teses A/B requieren de hacer uso de cierto estado para devolver a cada usuario siempre la misma variante y durante toda su interacción con el producto de software. Para ello es necesario un identificativo del usuario o segmentar a los usuarios por algunos criterios que se proporcionan en cada llamada al servicio que devuelve la variante del test A/B.

Las variantes se asignan a los usuarios en el mismo espacio de tiemmpo para comprobar cual proporciona mejor rendimiento. Una prueba sencilla de test A/B puede tener diferentes variantes para el color de los botones, tipografía del texto o tamaño.

Herramientas

No es necesario implementar un sistema personalizado y propio que permita hacer uso de feature flags y teses A/B, hay herramientas específicas con estos propósitos. En el landscape de CNCF hay varias opciones, el estándar de open feature y entre otras dos soluciones específicas Flagsmith, Flipt o Unleash.

Flagsmith

Flagsmith es una herramienta que proporciona ambas, feature flags y teses A/B además de soportar el estándar open feature. Aunque ofrece un modelo SasS también puede ser hospedado en infraestructura propia, una versión open source y una versión enterprise con features adicionales, un modelo de negocio similar a otros proyectos de software. Dispone de SDK para los lenguajes de programación más populares tanto de lado del cliente como del lado del servidor.

En la documentación de Flagsmith proporcionan una descripción de los feature flags, detallan que permiten, cuales son sus ventajas y cómo es un workflow de desarrollo usándolos.

El comando de Docker para iniciar una instancia de Flagsmith y su archivo de Docker Compose. Flagsmith usa una base de datos relacional en este caso PostgreSQL.

1
2
$ docker compose up

docker-compose-up.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# See https://docs.flagsmith.com/deployment/docker for more information on running Flagsmith in Docker
x-flagsmith-env: &flagsmith-env
  DATABASE_URL: postgresql://postgres:password@postgres:5432/flagsmith
  USE_POSTGRES_FOR_ANALYTICS: 'true'
  ENVIRONMENT: production
  DJANGO_ALLOWED_HOSTS: '*'
  FLAGSMITH_DOMAIN: localhost:8000
  DJANGO_SECRET_KEY: secret

  TASK_RUN_METHOD: TASK_PROCESSOR # other options are: SYNCHRONOUSLY, SEPARATE_THREAD (default)
  PROMETHEUS_ENABLED: 'true'

volumes:
  pgdata:

services:
  postgres:
    image: postgres:15.5-alpine
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: flagsmith
    container_name: flagsmith_postgres
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -d flagsmith -U postgres']
      interval: 2s
      timeout: 2s
      retries: 20
      start_period: 20s

  flagsmith:
    image: docker.flagsmith.com/flagsmith/flagsmith:latest
    command:
      - serve
    environment:
      <<: *flagsmith-env
    ports:
      - 8000:8000
    depends_on:
      flagsmith-migrate-db:
        condition: service_completed_successfully

  flagsmith-task-processor:
    image: docker.flagsmith.com/flagsmith/flagsmith:latest
    environment:
      <<: *flagsmith-env
    ports:
      - 8001:8000
    depends_on:
      flagsmith-migrate-db:
        condition: service_completed_successfully
    command: run-task-processor

  flagsmith-migrate-db:
    image: docker.flagsmith.com/flagsmith/flagsmith:latest
    command:
      - migrate
    environment:
      <<: *flagsmith-env
    healthcheck:
      disable: true
    depends_on:
      postgres:
        condition: service_healthy
docker-compose.yml

En su panel de administración accesible mediante un navegador en la dirección http://localhost:8000 es posible configurar los feature flags y teses A/B de los que queremos hacer uso. Los teses A/B tienen la particularidad que requeiren segmetar a los usuarios en una de las variantes, para ello es necesario utilizar cierta información del ususario, esta información en Flagsmith se conocen como traits como pudiera ser el navegador del usuario o país.

Consola web de Flagsmith Consola web de Flagsmith Consola web de Flagsmith

Consola web de Flagsmith

Para asignar los feature flags y las variantes de los teses A/B a un usuario se utiliza la siguiente petición con un comando curl.

1
2
3
curl -i 'http://localhost:8000/api/v1/flags/' \
	 -H 'Accept: application/json' \
     -H 'X-Environment-Key: K5DcsiSmbvpSDFisFF9Yxt'
curl-feature-flags.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
curl -L 'http://localhost:8000/api/v1/identities/' \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json' \
     -H 'X-Environment-Key: K5DcsiSmbvpSDFisFF9Yxt' \
-d '{
  "identifier": "d4cb38f6-9945-4730-b779-e699039592f0",
  "traits": [
    {
      "trait_key": "country",
      "trait_value": "spain"
    }
  ],
  "transient": false
}'

curl -L 'http://localhost:8000/api/v1/identities/' \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json' \
     -H 'X-Environment-Key: K5DcsiSmbvpSDFisFF9Yxt' \
-d '{
  "identifier": "53b0780f-a55c-4e09-8dab-78fbad3f9a3f",
  "traits": [
    {
      "trait_key": "country",
      "trait_value": "united-kingdom"
    }
  ],
  "transient": false
}'

curl -L 'http://localhost:8000/api/v1/identities/?identifier=d4cb38f6-9945-4730-b779-e699039592f0' \
     -H 'Content-Type: application/json' \
     -H 'Accept: application/json' \
     -H 'X-Environment-Key: K5DcsiSmbvpSDFisFF9Yxt'
curl-test-ab.sh

La respuesta devuelta contiene los valores de todas las feature flags y de los teses A/B con la variante seleccionada.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[
    {
        "id": 1,
        "feature": {
            "id": 1,
            "name": "show-prices",
            "created_date": "2026-06-27T16:14:48.924175Z",
            "description": null,
            "initial_value": "true",
            "default_enabled": false,
            "type": "STANDARD"
        },
        "feature_state_value": true,
        "environment": 1,
        "identity": null,
        "feature_segment": null,
        "enabled": true
    },
    {
        "id": 3,
        "feature": {
            "id": 2,
            "name": "button-color",
            "created_date": "2026-06-27T16:15:46.651323Z",
            "description": null,
            "initial_value": "default",
            "default_enabled": false,
            "type": "MULTIVARIATE"
        },
        "feature_state_value": "green",
        "environment": 1,
        "identity": null,
        "feature_segment": null,
        "enabled": true
    }
]
curl-test-ab-response.json

En una aplicación Java y utilizando el SDK proporcionado por Flagsmith este es el código para obtener el valor de un feature flag.

1
2
3
Flags flags = flagsmith.getEnvironmentFlags();
Boolean enabled = flags.isFeatureEnabled("show-prices");
Object value = flags.getFeatureValue("show-prices");
Main-feature-flag.java

Y de un test A/B.

1
2
3
4
5
6
7
String identifier = "d4cb38f6-9945-4730-b779-e699039592f0"
Map<String, Object> traits = new HashMap<String, Object>();
traits.put("country", "spain");

Flags flags = flagsmith.getIdentityFlags(identifier, traits);
Boolean enabled = flags.isFeatureEnabled("show-prices");
Object value = flags.getFeatureValue("show-prices");
Main-test-ab.java

Finalmente, el código para crear la conexión entre el servicio como cliente y Flagsmith.

1
2
3
4
private static FlagsmithClient flagsmith = FlagsmithClient
    .newBuilder()
    .setApiKey(System.getenv("0cff2ed56eae3ff3f0a663208a7ee49336c79ccd"))
    .build();
Main-init.java


Comparte el artículo: