FuncionesPreciosDocumentaciónBlog
Obtener mote
← Blog
Ingeniería·28 de junio de 2026·6 min de lectura

Por qué construimos shells específicos para cada plataforma sobre un único núcleo en Rust

Para lanzar el mismo editor en tres sistemas operativos, existe la opción de crear la interfaz una sola vez. Nosotros seguimos ese camino, dimos marcha atrás y colocamos varios shells ligeros específicos para cada plataforma sobre un único núcleo.

m
mote
Los shells están arriba, el núcleo en el centro, y el renderizado de texto y las puertas de control abajo. La interpretación de Markdown, las operaciones de edición y la escritura de archivos están íntegramente dentro del recuadro central.
Los shells están arriba, el núcleo en el centro, y el renderizado de texto y las puertas de control abajo. La interpretación de Markdown, las operaciones de edición y la escritura de archivos están íntegramente dentro del recuadro central.

Para lanzar el mismo editor en Linux, macOS y Windows, hay que crear la interfaz tres veces.

Al principio queríamos evitar ese coste. Dibujamos la misma pantalla en los tres sistemas operativos con un único toolkit multiplataforma. Gracias a esa decisión, superamos la primera puerta de rendimiento y también el primer hito de introducción de texto en coreano.

Pero entonces cambiaron las prioridades.

El rendimiento es más importante que el diseño, y el diseño es más importante que el coste. El tiempo y el coste quedan fuera de las restricciones.

Al reconsiderarlo según estos criterios, la respuesta también cambió.

Renunciamos a una única interfaz

Los toolkits multiplataforma tienen ventajas evidentes. Una funcionalidad creada una vez puede utilizarse en varios sistemas operativos.

Pero también había un precio que pagar. Consumía entre 40 y 60 MB más de memoria y la ejecución era entre 150 y 200 ms más lenta. La representación de los caracteres era inferior a la de los motores de texto nativos de los sistemas operativos, y tampoco podíamos aprovechar plenamente los efectos visuales propios del sistema.

Era una elección razonable cuando el coste de desarrollo era importante. Pero, al quitar el coste de las restricciones, ya no había motivos para asumir esas desventajas.

Por eso decidimos crear en Rust el núcleo que procesa los documentos y desarrollar por separado el shell responsable de la interfaz para cada sistema operativo.

No fue porque la tecnología anterior fuera mala. Cuando cambian las prioridades, las mismas opciones pueden conducir a respuestas distintas. Decidimos asumir el coste de crear las funcionalidades tres veces para recuperar el rendimiento, la calidad tipográfica y una experiencia propia de cada sistema.

Sin embargo, no lo descartamos todo.

Conservamos intacto el conjunto de reglas de medición. Colocar el puntero fuera de la ventana, localizar la ventana con precisión por su nombre y contar los fotogramas de forma síncrona. También trasladamos los principios de diseño para la introducción de texto en coreano. Al sistema operativo solo le mostramos la línea en la que se encuentra el cursor y no aplicamos estilos a los caracteres que están en proceso de composición. Si el estado deja de coincidir, no hacemos suposiciones: volvemos a sincronizarlo.

Aunque se descarte el código, los principios validados permanecen.

Definimos un papel reducido para el shell

Si los shells específicos de cada plataforma empiezan a asumir demasiadas tareas, los tres productos no tardan en diferenciarse. Por eso definimos con claridad lo que el shell debe hacer y lo que no debe hacer.

El shell crea la ventana y dibuja los caracteres. Transmite al núcleo la entrada del teclado y del puntero, y convierte la introducción de texto en coreano en comandos de edición. También aplica los efectos visuales del sistema operativo.

En cambio, no interpreta Markdown. Tampoco decide el diseño, salvo los saltos de línea, ni guarda archivos ni evalúa las licencias.

No nos limitamos a escribir este principio en un documento. Si se introduce código de interpretación de Markdown en un shell, una comprobación automática detiene la compilación.

Si empezamos a procesar la sintaxis en un solo shell, los resultados pueden diferir ligeramente entre sistemas operativos. Estos problemas también son difíciles de detectar. Una tabla puede verse distinta únicamente en un shell, aunque la causa real quizá no esté en el código que dibuja la tabla.

Hicimos que solo el núcleo perdurara

El núcleo no depende de ninguna tecnología de interfaz. Puede probarse por separado desde una terminal, incluso sin una ventana.

El núcleo se encarga de la edición de documentos, la interpretación de Markdown, la función de deshacer, la búsqueda, el esquema, el guardado de archivos, la exportación y la validación de licencias.

Pruebas del núcleo ejecutadas en una terminal sin interfaz. Se superaron 194 pruebas unitarias y una prueba independiente de bloques incrementales.
Pruebas del núcleo ejecutadas en una terminal sin interfaz. Se superaron 194 pruebas unitarias y una prueba independiente de bloques incrementales.

Cuando el usuario pulsa una tecla, el shell transmite esa entrada al núcleo. El núcleo modifica el documento y vuelve a interpretar únicamente la zona que rodea la parte modificada. Después de calcular solo el contenido visible en pantalla, devuelve al shell los resultados que han cambiado. El shell vuelve a dibujar únicamente las líneas afectadas y completa un fotograma.

Si durante este proceso se vuelve a leer todo el documento, no se trata simplemente de un problema de rendimiento. Significa que se ha incumplido el presupuesto establecido al principio.

La exactitud también se valida una sola vez en el núcleo. Deben superarse los 652 ejemplos oficiales de CommonMark, y la compilación falla si disminuye el número de ejemplos superados. También realizamos pruebas de fuzzing que introducen continuamente entradas imprevistas.

Comprobamos asimismo que el archivo guardado sea idéntico al original byte por byte. Si la proporción de ida y vuelta no alcanza 1,0, no significa que sea lento, sino que hemos perdido el archivo.

Aunque cambie el shell, el núcleo permanece intacto. En Linux y Windows conectamos el núcleo directamente, mientras que en macOS utilizamos código de enlace en Swift. Estamos creando el shell de macOS con AppKit y TextKit 2, y el de Windows con DirectWrite.

El objetivo es mantener el mismo documento y hacer que la experiencia de uso sea propia de cada sistema operativo.

El documento es el mismo, pero la experiencia de uso es distinta

Al definir los límites, también quedó claro qué debía unificarse.

Lo que debe ser igual es el documento. Independientemente del sistema operativo en el que se guarde, el contenido del archivo debe ser idéntico byte por byte. La alineación de las tablas, los finales de línea y el salto de línea final tampoco deben cambiar.

La exactitud de Markdown ya se valida en el núcleo. No es necesario volver a demostrarla cada vez que creamos un shell nuevo. En cada nueva plataforma solo hay que comprobar la experiencia de uso y el rendimiento.

En cambio, no unificamos la experiencia que percibe el usuario directamente.

Los caracteres se dibujan con el motor de texto de cada sistema operativo. Para la introducción de texto en coreano también utilizamos directamente el método del sistema operativo. En macOS y Windows, los efectos de transparencia también utilizan funciones del sistema, mientras que en Linux, donde no existe la misma función, dibujamos directamente solo las partes necesarias.

Tampoco intentamos igualar a la fuerza la posición de los botones de la ventana, la forma de los menús ni las teclas modificadoras de los atajos. Mostrar los mismos píxeles en sistemas operativos distintos no es el objetivo. Es más importante que la experiencia resulte natural en cada sistema operativo.

También definimos los requisitos de lanzamiento por sistema operativo. Una versión solo puede publicarse después de superar los criterios de rendimiento y completar pruebas reales con el método de entrada de coreano predeterminado.

La fila correspondiente a una plataforma tampoco aparece en la tabla de benchmarks hasta que existe una compilación real. Si escribimos por adelantado una fila que no hemos medido, también resulta difícil confiar en las demás filas de la tabla.

Esta elección tiene un coste evidente

Hay que crear la misma funcionalidad tres veces. También hay que implementar tres veces la introducción de texto en coreano y mantener tres entornos de compilación.

No podemos compilar ni depurar Windows y macOS en la máquina que utilizamos actualmente. Necesitamos hardware y entornos de automatización independientes. Por eso no indicamos fechas para esas dos plataformas.

También dejamos establecidos los criterios para revisar esta decisión. La decisión parte de la premisa de que el coste queda fuera de las restricciones. Si no podemos conseguir el hardware necesario, solo retrasaremos el calendario de la plataforma correspondiente. El lanzamiento en Linux seguirá adelante según lo previsto.

Una decisión necesita no solo motivos, sino también condiciones para reconsiderarla. Así, cuando cambien las circunstancias, no habrá que repetir el debate desde el principio.

Lo que debe perdurar es el núcleo. El shell debe poder descartarse en cualquier momento.

Solo dejamos en manos de cada plataforma aquello que puede descartarse.

← AnterioresAunque cambies de modo, el documento sigue siendo uno soloMás recientes →Por qué dejamos el renderizado del texto en manos de la plataforma
Siga las novedades por RSS.
Que solo quede la escritura.
Español
© 2026 mote