La decisión: cuándo KMP compensa frente a dos apps nativas
La adopción de Kotlin Multiplatform es una decisión organizativa disfrazada de decisión técnica, y por eso las evaluaciones que solo miden líneas ahorradas fallan de forma sistemática. Esta lección construye el cálculo completo —el coste inicial de conversión, el impuesto permanente de coordinación, el efecto sobre la velocidad de entrega de cada plataforma y el valor real de la ausencia de divergencia— examina quién debe poseer el módulo común y qué ocurre cuando nadie lo posee, y ofrece un conjunto de señales contrastables que indican cuándo la respuesta correcta es adoptar, cuándo es esperar y cuándo es mantener dos aplicaciones nativas sin complejo alguno.
Después de cuatro lecciones sobre cómo funciona Kotlin Multiplatform queda la única pregunta que un ingeniero con responsabilidad tiene que responder: si conviene. Y conviene decir de entrada que la respuesta legítima incluye el no. Existen productos excelentes, con equipos excelentes, para los que mantener dos aplicaciones nativas separadas sigue siendo la decisión correcta en 2026, y existen equipos que adoptaron KMP por razones sólidas y a los tres años estaban peor que antes. Lo que distingue unos casos de otros casi nunca es la calidad técnica de la tecnología, que a estas alturas está fuera de discusión, sino si el equipo entendió que compartir código transforma la manera en que dos grupos de personas se relacionan, y si pagó por adelantado el coste de esa transformación en lugar de descubrirlo a plazos.
- Construir el cálculo completo de coste y beneficio, incluidos los términos que no aparecen en el código.
- Reconocer el impuesto permanente de coordinación y estimarlo antes de comprometerse.
- Decidir quién posee el módulo común y qué falla cuando la propiedad queda difusa.
- Aplicar señales contrastables para elegir entre adoptar, esperar o quedarse en dos apps nativas.
El cálculo que casi nadie hace completo
La evaluación habitual compara el coste de escribir una lógica dos veces con el de escribirla una y concluye lo obvio. El problema es que esa comparación ignora tres términos, y los tres tienen signo negativo.
El primero es el coste inicial de conversión, que no es el de mover archivos sino el de sustituir dependencias ancladas a la máquina virtual de Java, montar la infraestructura de compilación para iOS, publicar el framework, integrar el flujo de trabajo en la integración continua y enseñar a un equipo de iOS a leer Kotlin. Rara vez baja de un trimestre de trabajo real para una aplicación mediana, y durante ese trimestre el usuario no percibe absolutamente nada.
El segundo es el impuesto de coordinación, que es permanente y crece con el tamaño de la superficie compartida. Cada cambio en el módulo común afecta a dos productos con calendarios de publicación distintos, dos procesos de revisión de tienda distintos y dos ritmos de adopción de versiones distintos. Un cambio que en una aplicación nativa costaba una tarde pasa a costar una tarde más una conversación, y las conversaciones no escalan.
El tercero es la pérdida de autonomía, que es el impuesto de coordinación visto desde el lado humano: un equipo que antes decidía y ahora consulta pierde velocidad incluso cuando la consulta termina en un sí.
Conviene hacer explícito quién paga cada uno de esos tres términos, porque casi nunca es quien recibe el beneficio. El coste inicial lo paga el equipo que hace la conversión, que suele ser el de Android. El impuesto de coordinación lo pagan ambos equipos a partes iguales y para siempre. El beneficio, en cambio, lo recibe sobre todo la organización en forma de menos incidencias y de funcionalidades que llegan a la vez a las dos plataformas, y ese beneficio es difuso, tardío y difícil de atribuir. Un reparto así de asimétrico entre quien paga y quien cobra es exactamente el tipo de configuración que produce resistencia interna, y la resistencia interna es la causa de muerte más frecuente de estos proyectos. Anticiparla nombrándola en voz alta al principio cuesta una reunión; descubrirla a los diez meses cuesta el proyecto entero.
flowchart TD
A[Evaluar KMP] --> B{La logica es densa y compleja}
B -->|no| Z[Dos apps nativas]
B -->|si| C{Existen ya las dos apps con equipos vivos}
C -->|no, solo Android| D{Hay presupuesto para el equipo de iOS}
D -->|no| Z
D -->|si| E[Adoptar desde el inicio]
C -->|si| F{Los dos equipos se hablan hoy}
F -->|no| G[Arreglar eso primero]
F -->|si| H{Hay divergencias reales que duelen}
H -->|no| Z
H -->|si| I[Adoptar por capas empezando por datos]Estos tres términos comparten una propiedad incómoda: los tres se pagan en los primeros dieciocho meses y el beneficio llega después. Cualquier evaluación con horizonte de un año dará negativo aunque la decisión sea correcta, y cualquier evaluación con horizonte de cinco años dará positivo aunque la decisión sea desastrosa, porque a cinco años cualquier cosa se amortiza sobre el papel. El horizonte honesto es el de la vida esperada del producto, y si esa vida es corta o incierta la respuesta prudente es no.
No hace falta un modelo sofisticado, hace falta uno explícito. Suma el coste del trimestre de conversión, añade una estimación del sobrecoste de coordinación por cambio compartido multiplicado por el número de cambios que esperas al año, y réstalo del ahorro por no implementar dos veces cada funcionalidad nueva más el coste evitado de las incidencias específicas de una plataforma. El valor concreto importa menos que la conversación que provoca: la primera vez que alguien intenta rellenar la casilla del sobrecoste de coordinación es cuando el equipo descubre que nadie había pensado en él.
En la columna positiva hay un término que suele infravalorarse porque no se mide en horas: la ausencia de divergencia. Cuando la regla de negocio vive en un solo sitio, desaparece una familia entera de incidencias —el cálculo que da distinto en un teléfono, la promoción que se aplica en una plataforma y no en otra, el estado que se sincroniza mal solo desde iOS— cuyo coste no está en el tiempo de arreglarlas sino en el tiempo de diagnosticarlas y en la confianza que erosionan. Para un producto financiero, sanitario o regulado, este término puede dominar el cálculo por sí solo.
Quién posee el módulo común
La pregunta de propiedad es la que decide el resultado a tres años, y hay tres respuestas posibles de las cuales una es una trampa.
La primera es que el módulo común lo posea el equipo de Android, que es lo que ocurre por omisión cuando la migración parte de una aplicación Android. Funciona al principio y degenera con previsibilidad: las decisiones se toman con la cabeza en Android, iOS recibe un artefacto que no ha diseñado, y el equipo de iOS empieza a pedir puntos de extensión que en realidad son formas de esquivar el módulo.
La segunda es un equipo dedicado a la plataforma compartida, que funciona bien a partir de cierto tamaño y es lo que hacen las organizaciones grandes que han tenido éxito con KMP. Su riesgo es convertirse en un cuello de botella si no publica con la frecuencia suficiente.
La tercera es la propiedad compartida sin dueño, es decir, que cualquiera toque el módulo común. Es la trampa: en ausencia de un responsable, el módulo acumula parámetros condicionales por plataforma que nadie tiene autoridad para rechazar, y en dos años el código común contiene dos implementaciones que comparten archivo.
El síntoma de esa degeneración es tan reconocible que conviene tenerlo escrito, porque aparece siempre con la misma forma inocente y siempre justificado por una urgencia concreta.
// el primer parametro parece razonable; el quinto ya no lo es
class RepositorioSuscripcion(
private val cacheEnMemoria: Boolean = true, // iOS lo desactivo por un fallo
private val validarEnLocal: Boolean = true, // Android lo desactivo por rendimiento
private val reintentosMaximos: Int = 3, // distinto en cada plataforma
private val usarEndpointNuevo: Boolean = false, // iOS migro antes
)
Cuando una firma llega a ese estado, el módulo ha dejado de compartir una decisión y ha pasado a alojar dos, con el agravante de que ahora cada plataforma depende de una combinación de banderas que nadie prueba conjuntamente. La política que lo evita es aburrida y funciona: toda bandera nueva en el módulo común requiere una fecha de retirada y el nombre de quien la retirará.
Compartir código exige acuerdos sobre nomenclatura, sobre el modelo de dominio, sobre el calendario de publicación y sobre qué significa que algo esté terminado. Un equipo que ya tiene esos acuerdos gana mucho al compartir código. Un equipo que no los tiene descubre que el módulo común convierte cada desacuerdo latente en un conflicto de compilación, y que la tecnología ha hecho visible un problema organizativo sin aportar ninguna herramienta para resolverlo. El orden correcto es al revés: primero el acuerdo, después el código compartido.
Señales de sí, señales de no
Hay indicadores que se pueden comprobar antes de comprometerse y que predicen mejor que cualquier estimación de porcentaje compartido. La virtud de estas señales es que son observables hoy, con datos que el equipo ya tiene, y no dependen de estimar el futuro.
Antes de discutir arquitectura, abre el gestor de incidencias del último año y cuenta cuántas afectaban a una sola plataforma por una divergencia de lógica, no por una diferencia de interfaz. Si la respuesta es un puñado, el beneficio central de KMP no existe en tu producto y la decisión debe apoyarse en otra cosa. Si la respuesta es decenas, y sobre todo si algunas de ellas costaron semanas de diagnóstico porque nadie sabía en qué lado estaba la verdad, ya tienes el argumento más sólido que vas a encontrar, y además está expresado en el único idioma que entiende quien aprueba presupuestos.
Indican que sí: la lógica de negocio es densa y cambia con frecuencia; existe un historial documentado de errores presentes en una sola plataforma; el producto es regulado y la equivalencia entre plataformas es una obligación y no una aspiración; el equipo de iOS tiene disposición real a leer y escribir Kotlin, comprobada y no supuesta; hay un tercer destino plausible a medio plazo, como escritorio o web, que multiplicaría el retorno; y el producto tiene la longevidad suficiente para amortizar un trimestre invisible.
Indican que no: la aplicación es principalmente interfaz y su valor está en la interacción; los dos equipos publican en calendarios independientes y esa independencia es deliberada; la plantilla es demasiado pequeña para absorber un trimestre sin entregas visibles; buena parte de la funcionalidad depende de capacidades del sistema con modelos muy distintos; o la motivación principal declarada es reducir plantilla, que es la razón que peor predice el éxito porque presupone un ahorro que llega tarde y penaliza justamente la capacidad de coordinación que la decisión va a exigir.
Hay además una señal intermedia que merece nombre propio, porque es la más frecuente y la peor interpretada: el caso del equipo que solo tiene aplicación de Android y planea tener la de iOS algún día. Ese equipo suele concluir que debe adoptar KMP de inmediato para no tener que migrar después, y la conclusión es correcta solo si la segunda aplicación está presupuestada con fecha. Si no lo está, lo que ocurre es que se paga íntegro el coste de estructurar el proyecto para dos destinos, se acepta la restricción del catálogo de dependencias y se renuncia a bibliotecas cómodas de Android, todo ello para una segunda plataforma que quizá nunca llegue. Preparar el terreno separando dominio y datos en módulos limpios es siempre buena idea; configurar destinos que nadie compila no lo es.
Un plan de adopción que se puede deshacer
Cuando la decisión es adoptar, la forma importa tanto como el fondo, y la propiedad que hay que preservar por encima de todas es la reversibilidad. Un plan reversible se reconoce porque en cada uno de sus hitos existe una respuesta escrita a la pregunta de qué haríamos si paráramos aquí.
flowchart LR
A[Hito 0 - separar dominio y datos en la app Android] --> B[Hito 1 - convertir dominio a KMP y publicar solo en Android]
B --> C[Hito 2 - una pantalla real de iOS consumiendo el framework]
C --> D{Los dos equipos siguen entregando al ritmo anterior}
D -->|no| E[Parar y consolidar en la frontera actual]
D -->|si| F[Hito 3 - mover la capa de datos completa]
F --> G{Aparecen parametros condicionales por plataforma}
G -->|si| E
G -->|no| H[Hito 4 - evaluar presentacion compartida]El hito cero no es multiplataforma en absoluto y por eso es el mejor comienzo: separar el dominio y los datos en módulos con dependencias dirigidas es una mejora que beneficia a la aplicación de Android aunque el proyecto se cancele mañana. El hito uno tampoco arriesga nada visible, porque el módulo convertido se sigue consumiendo solo desde Android y cualquier regresión se detecta en el terreno conocido. El primer compromiso real llega en el hito dos, y por eso conviene que sea una pantalla auténtica con usuarios auténticos y no una demostración, porque solo una pantalla en producción produce la información que la decisión necesita.
La condición de parada del hito dos es la más importante de todo el plan y debe fijarse antes de empezar, no después: si el ritmo de entrega de cualquiera de los dos equipos cae de forma sostenida, se consolida en la frontera alcanzada y no se sigue subiendo. Esa regla protege contra el modo de fallo más habitual, que no es una catástrofe técnica sino una erosión lenta que nadie declara porque cada paso individual parecía razonable.
El indicador que mejor resume la salud de una adopción de KMP no es el porcentaje de código compartido ni el número de errores, sino el tiempo transcurrido entre que se decide un cambio de regla de negocio y que ese cambio está disponible para los usuarios de las dos plataformas. Si ese tiempo baja, la adopción está funcionando aunque el porcentaje compartido sea modesto. Si sube, no importa cuánto código se haya unificado: el módulo común se ha convertido en un punto de sincronización y está costando más de lo que ahorra.
Cuenta los tres costes
Conversión inicial, coordinación permanente y pérdida de autonomía; ninguno es opcional.
Un dueño explícito
La propiedad difusa del módulo común es la vía más rápida hacia dos lógicas en un archivo.
La divergencia tiene precio
En productos regulados, eliminar el error específico de plataforma puede justificarlo todo.
El no es una respuesta
Dos aplicaciones nativas bien mantenidas siguen siendo una arquitectura legítima en 2026.
Toda la literatura sobre multiplataforma está construida sobre una métrica equivocada, y la equivocación es tan cómoda que sobrevive a la evidencia: se cuenta el código que no se escribe dos veces. Pero el código nunca fue el activo escaso. Escribir por segunda vez una regla que ya se entiende es de las tareas más baratas que existen en desarrollo de software, y cualquiera que haya portado una funcionalidad de una plataforma a otra sabe que el tiempo se fue en decidir qué hacía, no en teclearla. Lo escaso, lo que de verdad se agota, es la capacidad de una organización para tomar decisiones coherentes y sostenerlas. Cuando una regla de negocio existe en dos sitios, cada cambio requiere que dos personas entiendan lo mismo, y ese entendimiento se degrada con cada rotación de personal, cada reorganización y cada trimestre en que las prioridades de los dos equipos divergen; la duplicación no es cara por las líneas, es cara porque obliga a reconstruir el mismo acuerdo una y otra vez y porque cada reconstrucción tiene una probabilidad no nula de salir distinta. Compartir código es, leído así, un mecanismo para convertir un acuerdo repetido en un acuerdo único y verificable por el compilador, y ese es su valor real: no ahorra escritura, ahorra deliberación. Pero el mismo razonamiento explica su fracaso más común. Si dos plataformas tienen motivos legítimos y persistentes para decidir distinto —porque sus usuarios se comportan distinto, porque sus mercados van a ritmos distintos, porque sus fabricantes imponen calendarios distintos—, entonces forzar un acuerdo único no elimina la deliberación: la traslada a una negociación permanente que consume más energía de la que ahorraba la duplicación. La prueba que hay que aplicar a cada pieza antes de moverla al lado común no es si el código coincide, sino si estás dispuesto a que la decisión que encierra se tome una sola vez para siempre y por una sola persona. Donde la respuesta sea sí, compartir es puro beneficio y la tecnología está lista. Donde la respuesta sea no, el mejor módulo común es el que nunca se escribió, y dos aplicaciones nativas no son una derrota sino el reconocimiento honesto de que dos productos con dos públicos merecen dos criterios.
- Revisa el historial de incidencias del último año y cuenta cuántas afectaban a una sola plataforma por divergencia de lógica, no por diferencia de interfaz.
- Estima el trimestre de conversión en tareas concretas y preséntalo a quien decide como coste sin entrega visible.
- Mide el coste actual de coordinación: cuánto tarda hoy un cambio de regla de negocio en estar publicado en las dos tiendas.
- Escribe el nombre de la persona que poseerá el módulo común; si no puedes escribirlo, no adoptes todavía.
- Redacta en una página la decisión y sus condiciones de reversión, y fija una fecha a seis meses para revisarla con datos.