¿Te ha pasado que lanzas una aplicación y de repente un usuario te dice: «Oye, me encanta, pero solo necesito la mitad de las funciones y no quiero pagar el precio completo»? O peor aún, el cliente corporativo que quiere todo pero con límites infinitos.
Si estás intentando gestionar esto con un montón de if (user.IsPremium) esparcidos por tu código, detente. Estás creando una pesadilla técnica. Hoy vamos a construir un sistema de suscripciones multinivel en .NET que hasta a tu equipo de Marketing le va a encantar.
Imagina que construyes un edificio de departamentos. No puedes simplemente decir que alguien «vive ahí» o «no vive ahí». Tienes al que alquila el estudio pequeño, al de la oficina del cuarto piso y al magnate que tiene el penthouse con helipuerto. Intentar manejar quién tiene acceso a la piscina o al gimnasio usando una sola llave maestra que abre todo (o nada) es la receta perfecta para que te roben hasta las alfombras. En el software, esa «llave maestra» es el booleano IsAdmin que todos hemos abusado alguna vez.
¿Por qué importa?
No es solo cuestión de dinero. Un modelo de suscripción bien estructurado te permite:
- Escalabilidad: Atender desde un desarrollador solitario hasta una empresa de 50 personas.
- Retención: Ofrecer modelos Freemium para que prueben el producto antes de sacar la tarjeta.
- Orden Mental: Separar qué es una «Feature Flag» (DevOps/Global) de lo que es un nivel de suscripción (Granular/Usuario).
Manos a la Obra
Primero, necesitamos una base sólida. Olvida los strings mágicos; vamos a usar Enumeration Classes.
La Estructura de Datos
Necesitamos dos tablas básicas: Plan (los niveles) y PlanFeature (qué incluye cada uno).
Referencia: Ver esquema de base de datos en la página 7 del documento original.
Código espagueti de validación
if (user.Plan == "Gold" && user.ProjectCount < 20) {
// Esto es un dolor de muelas de mantener...
}
Definimos nuestras características de forma elegante:
// Models\AppFeature.cs
public class AppFeature : Enumeration {
public static readonly AppFeature ProjectSize = new(0, "Tamaño del Proyecto", new[] { 1, 2, 3 }, true);
public static readonly AppFeature CreateVendors = new(1, "Puede crear proveedores", new[] { 4, 5 });
[cite_start]// El 'true' final indica que 0 significa "Ilimitado" para los jefes [cite: 382, 386]
}
El Servicio Maestro (FeatureService)
Este es el «portero» que revisa qué tiene permitido cada usuario según su plan.
public class FeatureService : IFeatureService {
[cite_start]// Buscamos si la funcionalidad está permitida para el plan del usuario [cite: 408]
public Feature FindFeature(AppFeature featureEnum, PlanType plan) {
var features = GetFeaturesByPlanId(plan);
return features.FirstOrDefault(f => f.AppFeature.Equals(featureEnum));
}
}
Lo bueno y lo malo
Pros:
- Cero llamadas extra: Si implementas caché, el sistema vive en memoria y es ultra veloz.
- Marketing Feliz: Puedes crear un «Plan Diamante» en la base de datos y el código ni se entera.
Contras:
- Rigidez Inicial: Tienes que definir muy bien tu «Matriz de Funcionalidades» antes de tirar la primera línea de código.
- Sincronización: Tienes que mantener los IDs de tu base de datos alineados con tus clases Enumeration en C#.
Conclusión
Ya no tienes excusa para cobrarle lo mismo al usuario que solo quiere subir fotos de su gato que a la multinacional que quiere trackear 10,000 activos. Implementar esto es como pasar de jugar con bloques de madera a usar piezas de ingeniería de precisión.
Reto del día: Configura un plan «Zombie» que solo permita el acceso a la aplicación entre las 3:00 AM y las 5:00 AM. Si un usuario lo compra, ¡felicidades, has encontrado a tu público objetivo más extraño!.
