01 · THREAD iOS y Flutter · 2019 → hoy
El frame dura dieciséis milisegundos
Toda discusión de concurrencia en un equipo móvil es, en el fondo, sobre un solo número. Una pantalla debe un frame cada 16,7 ms, y todo — async/await, actors, isolates, cancelación — trata de lo que puedes hacer dentro de él. Abajo está la misma lista cargada de tres formas, con el gráfico de frames que te mostraría un profiler.
Una pantalla debe un frame cada 16,7 ms. Esta está cargando veinticuatro filas, y lo único que cambia entre los tres botones es dónde ocurre el decode. Mira el gráfico de frames, no la lista.
dentro perdido
Un frame que dura casi trescientos milisegundos. La lista no tartamudea — se detiene, y el sistema operativo empieza a plantearse si tu app sigue viva. Todo ingeniero móvil ha publicado esto una vez.
Lo que acabas de aprender → El botón del medio es el capítulo entero. await suspende una función, no la mueve — la continuación se reanuda en el main actor y el trabajo caro sigue cayendo dentro de un frame. Código asíncrono que nunca sale del hilo principal es el bug de rendimiento más común en móvil, y es invisible hasta que alguien lo perfila.
Acto uno
La pantalla
Una lectura no vale nada hasta que alguien la ve, y un teléfono da 16,7 milisegundos para mostrarla. Siete años entregando apps, nativas y multiplataforma — y antes de ellas tres años un nivel más abajo, en firmware, placas y piezas mecanizadas, que la Apple Developer Academy convirtió en esto: la misma ingeniería, movida hacia arriba en la pila. Este acto son los últimos centímetros de ese trayecto — llegar a tiempo, seguir legible en condiciones que nadie diseñó, y alcanzar solo a la persona correcta.
02 · CRISTAL Swift y Flutter · 2019 → hoy
La tarjeta que sobrevive al mundo real
Cualquiera construye la tarjeta del diseño. El trabajo es construir la que sigue siendo legible cuando la persona que sostiene el móvil puso el texto en el mayor tamaño de accesibilidad, está en vista dividida, en un idioma cuyas palabras son más largas, leyendo de derecha a izquierda, en una conexión que nunca entregó la imagen. El diseñador te da un estado. Tú entregas seis.
Una tarjeta, dos builds. A la izquierda la tarjeta tal como sale del diseño: una fila, cada texto en una línea, una altura en puntos. A la derecha la misma tarjeta construida para sobrevivir. Enciende las condiciones y mira cuál sigue siendo legible — el tamaño de letra que la persona realmente eligió, una vista dividida estrecha, una traducción más larga, un idioma de derecha a izquierda, una imagen que nunca llegó, un error sin sitio donde aparecer.
// The whole fix is three decisions.
HStack(alignment: .firstTextBaseline, spacing: 12) {
if let image { Thumbnail(image) } // no image, no box
VStack(alignment: .leading, spacing: 2) {
Text(position.symbol)
.font(.headline)
.lineLimit(nil) // let it wrap
if let error { Text(error).foregroundStyle(.red) }
else { Text(position.summary).font(.subheadline) }
}
Spacer(minLength: 12)
Text(position.pnl, format: .currency(code: code))
.monospacedDigit()
}
.padding(.horizontal, 16).padding(.vertical, 12)
.frame(minHeight: 44) // grows, never clips
.dynamicTypeSize(...DynamicTypeSize.accessibility5)
.accessibilityElement(children: .combine)
.accessibilityLabel(position.spokenLabel) // Same three decisions, same order.
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (image != null) Thumbnail(image!),
const SizedBox(width: 12),
Expanded( // min-width: 0, in Flutter
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(p.symbol, style: t.titleMedium, softWrap: true),
error != null
? Text(error!, style: t.bodySmall!.copyWith(color: cs.error))
: Text(p.summary, style: t.bodySmall),
],
),
),
const SizedBox(width: 12),
Text(p.pnl, style: t.titleMedium),
],
)
// Directionality mirrors the row; Semantics gives it one spoken label. Lo que acabas de aprender → El layout dibujado al comp sobrevive a una de las siete condiciones de abajo — justo aquella para la que fue dibujado. La diferencia no es gusto, es qué pregunta hace el layout: no "¿la letra es grande?" sino "¿esto cabe?". Haz la segunda pregunta y una traducción más larga deja de ser un reporte de bug.
03 · PUERTA Tradx · 2022 → hoy
El login es por donde entran a una app
Todo lo demás en una app móvil falla de forma visible. Esto falla en silencio: el login funciona, la persona entra, y el flujo estuvo abierto todo el tiempo. Rehice esta parte en Tradx después de leer nuestra propia implementación con atención — son las cincuenta líneas que preguntaría en cualquier entrevista sénior.
Autenticar a alguien por el navegador y devolver el resultado a la app son las cincuenta líneas más sensibles de un código móvil. Empieza por la versión que muestra todo tutorial y ciérrala interruptor a interruptor. El orden importa más de lo que te gustaría.
- The app opens the browser ASWebAuthenticationSession, not a web view — the session cookie has to be the real one
- The user signs in and the authorisation server redirects back
- The device routes the redirect to whichever app claims that address
- The app reads the callback off the URL, which is written to logs and history
- The app exchanges it for a session, over TLS, from the app itself
- Somebody presents it again the same value, a second time
- The session lands in the keychain and the user is in
- Scheme hijack any other app on the device can register tradx:// and receive the redirect instead
- Token in the logs an access token on a query string is written to system logs, browser history and the referrer
- Code replay a code that is accepted twice is an access token with extra steps
- Code interception without PKCE the exchange proves nothing about who started the flow, so whoever holds the code can spend it
- Forged callback without an unguessable state value the app accepts a sign-in the user never started
Empieza por la versión del tutorial y ciérrala interruptor a interruptor. Mira hasta dónde llega el redirect.
Lo que acabas de aprender → Cambiar el token por un código de un solo uso es la primera corrección que todos intentan, y por sí sola abre dos agujeros para cerrar uno. Un código necesita PKCE para que solo la app que inició el flujo pueda gastarlo, y un solo uso para que no se gaste dos veces. Media migración de seguridad es peor que ninguna, porque parece terminada.
Acto dos
Con qué habla la app
Vuelve hacia atrás desde la pantalla y encuentras el trayecto que hizo el número para llegar. Tiene que llegar mientras todavía es verdad, ser encontrado entre cientos de miles de hermanos, aguantar que todos pregunten a la vez, y por fin merecer una decisión. Cuatro capítulos — y en el último, las cuatro decisiones son mías.
04 · PULSO Tradx · 2022 → hoy
El cliente no debería tener que preguntar
Casi todo lo que una app muestra es la respuesta a una pregunta que hizo. Un precio en vivo no: cuando llega la respuesta la pregunta ya cambió, y volver a preguntar gasta una petición entera para oír, casi siempre, que no pasó nada. Este capítulo es la diferencia entre un endpoint que responde y un canal que te avisa.
Un minuto de un feed de precios, reproducido. Elige cómo se entera el cliente — preguntar con un temporizador, o que le avisen — y luego mira los dos números: lo que hace el mercado, y lo que el lector está mirando de verdad.
Una conexión, {bytes} en todo el minuto, y llegaron los {emitted} ticks. La pantalla mostró un precio ya superado el {behind} del tiempo — el vuelo en sí, y nada más.
Lo que acabas de aprender → Preguntar una vez por segundo costó ocho veces más bytes que mantener un socket abierto, y aun así se perdió un cuarto de los ticks. Frecuencia no es actualidad: la única forma de dejar de llegar tarde es dejar de preguntar.
05 · SERVICIO Backend · 2018 → hoy
Alguien tiene que recordarlo todo
Una lectura que nadie guardó es una lectura que no ocurrió. Detrás de cada dispositivo y de cada cliente hay una API y una base de datos, y la diferencia entre un producto rápido y uno lento suele ser una sola decisión tomada aquí. La tabla de abajo tiene doscientas cuarenta mil lecturas de sensor — del tipo que la sonda de la otra página pasó dos años produciendo.
Una tabla de lecturas de sensor, 240.000 filas. Elige una consulta, decide qué columnas llevan índice, y ejecútala. La franja de abajo es la tabla; fíjate en cuánta tiene que tocar la base de datos.
SELECT * FROM readings WHERE reading_id = 128374
índice · árbol B
18 pages
tabla · readings · 240.000 filas
—
Lo que acabas de aprender → Sin índice, la base lee todas las filas para responderte. Con uno, salta directo al punto. Misma consulta, mismos datos, mismo servidor — mil veces más rápido.
06 · ENJAMBRE Backend · 2018 → hoy
Una sola máquina nunca alcanza
Un lector es una consulta; diez mil a la vez es una arquitectura. El tráfico no llega con educación — llega de golpe, a las 3 de la mañana, el día del lanzamiento. Los contenedores y Kubernetes son cómo respondes a eso sin despertarte.
El tráfico de este servicio se dispara cada pocos segundos, como en un día de lanzamiento. Añade réplicas y la latencia baja; añade demasiadas y pagas por máquinas ociosas. Después déjaselo al autoscaler y mira dónde sigue perdiendo.
listos 0 arrancando 0
Estás escalando a mano. El pico llega estés listo o no.
Lo que acabas de aprender → No hiciste el código más rápido — hiciste más copias de él. El escalado horizontal cambia dinero por latencia, y un autoscaler hace ese cambio por ti, solo.
07 · FLUJO Tradx · 2022 → hoy
Y entonces construí la herramienta
Tradx es mi sandbox — el lugar donde tomo todas las decisiones y convivo con todas ellas. Un cliente de trading de escritorio escrito en Flutter, donde una estrategia es un grafo que conectas en vez de código que escribes, publicado en la Mac App Store y en la Microsoft Store, con unas quince mil descargas entre las dos. Lo construimos dos: Luiz Veloso y yo, por pull request, con revisiones que ninguno se salta.
Esto es lo que hace Tradx, en miniatura. No escribes el bucle — cableas la lógica, y el motor la ejecuta sobre las velas. Mueve los parámetros y mira cómo cambian a la vez el grafo y las operaciones.
Dos personas, pull requests, y revisiones que ninguno se salta.
Ajústalo hasta que el número sea bonito. Esa es la parte fácil, y es lo que te enseña cualquier captura de backtest de internet.
Lo que acabas de aprender → Un backtest es una hipótesis, no un resultado. Cualquiera ajusta una curva hasta que queda bonita con los datos que ya tiene; todo el oficio está en saber cuánto vale ese número con los datos que no tiene.
Acto tres
Y los modelos por debajo
Todo hasta aquí mueve una lectura que ya existe. Este inventa la siguiente — y es donde las dos mitades de este sitio resultan ser una sola. Entrené el modelo con datos de mercado; corre aquí sobre una sonda de suelo que enterré años antes, sin cambiar una línea, porque una serie temporal no sabe qué mide.
08 · MENTE StockGAN · 2021
Enseña a la máquina a adivinar qué viene después
En 2021 construí desde cero una red generativa adversaria para series temporales — el trabajo en el que mi posgrado en IA y mi máster en Bioingeniería dejan de ser líneas en un diploma — dos redes, una intentando inventar la siguiente lectura y otra intentando pillarla mintiendo. La entrené con datos financieros. Aquí corre sobre una sonda de suelo que diseñé y enterré años antes, sin cambiar nada, porque una serie temporal no sabe qué mide.
En 2021 escribí una GAN que pronostica el siguiente valor de una serie temporal — generador, discriminador y bucle de entrenamiento desde cero. La entrené con treinta años de barras diarias, porque ahí era donde había histórico limpio y gratis, pero la red lee log-retornos y no tiene ni idea de qué miden los números. Así que aquí está corriendo sobre una sonda de suelo que construí años antes de todo esto. Lo que vale la pena mostrar es esto: el discriminador nunca juzga una lectura prevista por sí sola. La lectura se pega a las nueve reales que vinieron antes, y la red tiene que decir si la ventana entera salió del sensor. Ese es el juego. Tú eres el discriminador.
StockGAN · LSTM(128) · ventana de 10 · entrenada con 30 años de barras diarias, corriendo aquí sobre soil-1
Una de estas dos ventanas termina con una lectura que la sonda tomó de verdad. La otra termina con una que inventó el generador. ¿Cuál es cuál?
Elige una. Nueve lecturas reales, y una décima que es la sonda o mi generador.
generador LSTM(128, stateful) → Dropout(0.3) → Dense(n_features) discriminador LSTM(128, stateful) → Dropout(0.1) → Dense(1, sigmoid) RMSprop con decaimiento polinómico de 2.5e-4 a 1e-4 a lo largo de mil pasos. Entropía cruzada con label smoothing en 0.2, para que al discriminador nunca se le permita estar completamente seguro de nada. Objetivo real y objetivo generado multiplicados por ruido con σ = 0.25 durante el entrenamiento, para que no gane notando qué números están demasiado limpios. Doce indicadores — MACD, EMA, RSI, Bollinger, ROC, volatilidad — reducidos por PCA y XGBoost antes de que la red viera nada; en una sonda de suelo esos mismos doce se convierten en medias móviles y tasa de variación de la humedad, y ese es justamente el punto: la arquitectura cambió de dominio y el pipeline de features apenas parpadeó. Las funciones de pérdida de esta página son portes de las reales, constantes incluidas; el generador de aquí es un sustituto que reproduce el dilema sin meter 128 unidades LSTM en tu navegador.
Lo que acabas de aprender → Dos modelos, una función de pérdida y una perilla entre ellos. Exígele al pronosticador que quede cerca y responde con el promedio de todo, que es seguro e inútil. Exígele que sea creíble y responde con algo que se mueve como el sensor y no sabe nada. Cada modelo que entrego es ese intercambio hecho a propósito, escrito y medido.
Acto cuatro
Y entonces salió de la pantalla
Y ahora la medida es el objeto. En Eldorado, en macOS y visionOS, una cosa tridimensional deja de ser algo que un ingeniero dibujó y pasa a ser algo que una cámara midió — el mismo movimiento que hice en 2019, repetido, ahora sobre el mundo.
09 · CAMPO Eldorado · 2022 → hoy
Y ahora el objeto está hecho de luz
El capítulo anterior inventó el siguiente número de una serie. Este deja de tratar el mundo como algo que alguien dibuja. Una escena deja de ser una superficie que alguien modeló y pasa a ser una nube de gaussianas orientadas, ajustadas por descenso de gradiente hasta que sus renders coinciden con las fotografías — lo que significa que nadie la dibuja, y no queda malla alguna que convertir. Las reconstrucciones reales empiezan con una cámara recorriendo una sala. La demo de abajo deliberadamente no: usa una pieza que yo mismo diseñé e imprimí, porque la única manera de ver qué cambia el método es mirar el mismo objeto construido de las dos formas.
Un objeto, construido dos veces. A un lado del interruptor es la malla con la que se imprimió la pieza. Al otro es un campo de gaussianas sobre esa misma malla — repartidas aquí en vez de ajustadas, para que los dos queden lado a lado y la diferencia sea el método y nada más.
cargando la malla…
997 triángulos, cada uno colocado por alguien en SolidWorks en 2017.
Lo que acabas de aprender → Una malla dice dónde están las superficies, y un ingeniero dibujó cada una. Un campo de splats dice dónde está la luz, y nadie dibujó nada de eso — se ajustó hasta que el render dejó de contradecir a la fotografía.
10 · TRAYECTORIA
Las pruebas
Nueve capítulos de demostración. Este es solo evidencia. Arrastra por los años y mira qué estaba corriendo a la vez — porque el titular honesto de esta línea de tiempo no es ningún empleo concreto, es lo poco que hubo uno solo.
Formación
Investigación
Industria
Emprendimientos
De trainee a sénior en cuatro años
Entré en el proyecto Apple en 2022 como trainee y sigo en el mismo producto, hoy como sénior. Nadie asciende por calendario: cada escalón vino de coger algo que nadie quería — el proceso de release, la suite inestable, la pantalla que todos reescribieron dos veces — y convertirlo en un problema fácil para los demás. Arrastra el año y mira la franja de industria: las cuatro barras seguidas son el mismo producto y el mismo equipo, vistos desde cuatro niveles de responsabilidad distintos.
Seis empresas
Fundadas o cofundadas. Algunas crecieron, otras no — que es justamente el motivo de fundar seis.
- Tradx Cofundador · fintech
- Agrom.IO Fundador · agritech
- Dommuz Cofundador · casa inteligente
- Psiu Cofundador · proptech
- Hubli Cofundador · edtech
- PreditChart Cofundador · fintech
Publicado y premiado
Seis trabajos académicos, tres de ellos con revisión por pares, y ninguno sobre móvil — y ese es justamente el punto. Ahí aprendí a equivocarme en público: a describir un método con precisión suficiente para que otro lo ataque, aceptar la revisión y cambiar la afirmación. Ese hábito vale más en un code review que cualquiera de los resultados.
- Instrumento para la Medición de Factores y/o Elementos Naturales del Suelo 2016 · Control & Automation Engineering, PUC-PR
- A Tool to Select FES Parameters for chronic SCI 2019 · 41st Annual International Conference of the IEEE EMBS · leer el artículo ↗ · doi:10.1109/EMBC.2019.8857421 · código ↗
- Indoors Wi-Fi Fall Detector Buckle for the Elderly 2019 · Advanced Materials Proceedings, 4(1), 40–45 · leer el artículo ↗ · doi:10.5185/amp.2019.1450 · código ↗
- Aplicación, in silico, de estímulos eléctricos en un modelo neuromuscular compatible con lesión medular crónica 2019 · M.Sc. dissertation in Bioengineering, PUC-PR · leer el artículo ↗ · código ↗
- Modelado matemático del sistema de mantenimiento del equilibrio mediante identificación de sistemas 2018 · V Congresso Brasileiro de Eletromiografia e Cinesiologia · X Simpósio de Engenharia Biomédica · leer el artículo ↗
- Predicción de Series Financieras con Redes Generativas Adversarias 2020 · Applied AI specialization, PUC-PR
En la prensa
- Hubli, creado en la Apple Developer Academy — Apple me nombra entre sus cinco creadores Apple Newsroom · 2021 · leer el artículo ↗
- Neon Wave, juego de iOS cubierto por MacMagazine MacMagazine · 2020 · leer el artículo ↗
Construyo la app, y construyo aquello con lo que habla. La pantalla, el estado en ella, la API que la llena, la base de datos debajo, y el modelo que lo lee. La mayoría domina una de esas. Yo he entregado todas, y sigo sabiendo cuál es la parte difícil.
Con qué trabajo
Todo lo de abajo está acreditado por algún capítulo de esta página o está en un repositorio público. Nada aquí es aspiracional.
- iOS · Swift
- Swift · SwiftUI · UIKit · visionOS · macOS · Swift Concurrency · async/await · actors · Combine · MVVM · Coordinators · Clean Architecture · Dependency injection · SwiftData · Core Data · URLSession · Swift Package Manager · XCTest · XCUITest · Instruments · Xcode · App Store Connect · TestFlight · VoiceOver · Dynamic Type · Localization · Push notifications · Deep linking
- Multiplataforma
- Flutter · Dart · Riverpod · Bloc · Provider · Kotlin · Jetpack Compose · Android · Platform channels · Offline-first · State management · Widget testing
- Publicación y release
- fastlane · Xcode Cloud · GitHub Actions · CI/CD · App Store review · Phased release · Firebase Crashlytics · Crash-free rate · Analytics · Feature flags · Semantic versioning
- Lenguajes
- Swift · Dart · Kotlin · Java · TypeScript · JavaScript · Python · C · C++ · MATLAB · SQL
- Backend y APIs
- Node.js · NestJS · Express · Java · REST APIs · WebSockets · Microservices · OAuth 2.0 · JWT · API versioning · Distributed systems · System design · Event-driven architecture · API design
- Datos
- MongoDB · PostgreSQL · Redis · BullMQ · Database design · Indexing and query planning · Time series · Data pipelines
- Cloud y DevOps
- AWS · Amazon S3 · CloudFront · Route 53 · AWS IoT Core · IAM · EC2 · Docker · Kubernetes · Terraform · Infrastructure as Code · GitHub Actions · CI/CD · OIDC · Observability · Scalability · Linux
- Web
- Astro · HTML · CSS · Accessibility · Design systems · Responsive layout
- IA y 3D
- Machine learning · PyTorch · TensorFlow · Keras · GANs · LSTM · Deep learning · Feature selection · PCA · XGBoost · Gaussian Splatting · 3DGS · CUDA · Photogrammetry · Computer vision
- Embebidos y hardware
- Embedded C · ESP32 · PIC18F4550 · ATmega · PWM · ADC · MQTT · IoT · PCB design · EAGLE · Altium · SolidWorks · CAD · 3D printing · Design for manufacturing
- Forma de trabajar
- Git · Code review · Unit testing · Technical leadership · Mentoring · Product engineering · Backtesting · Paper trading
Hablemos
Si algo de esto tiene la forma de un problema que tienes, quiero saberlo. Correo o LinkedIn, lo que prefieras — el CV es un PDF de dos páginas y el código está en GitHub.