✦Ingegneria

Perché abbiamo scelto il nativo al posto di Electron (e lo rifaremmo)

Tutti ci hanno detto di usare Electron. Si scrive una volta, gira ovunque. Muoversi in fretta. Noi abbiamo fatto l'opposto — SwiftUI su Apple, Jetpack Compose su Android, C++/WinRT su Windows, Metal e Vulkan puri dove ci servivano pixel a tempo. Ecco cosa abbiamo imparato costruendo quattro client nativi per un solo prodotto.

La strada facile contro la strada giusta

Quando dici che nel 2024 stai costruendo da zero un'app di desktop remoto, la prima domanda è sempre: «Perché non usare semplicemente Electron?»

È una domanda legittima. Electron alimenta alcune delle app di maggior successo del pianeta — VS Code, Slack, Discord, l'involucro desktop di Figma. Ti permette di scrivere una volta e distribuire ovunque. I tuoi sviluppatori web diventano sviluppatori desktop dall'oggi al domani. Il vantaggio nel time-to-market è reale.

Abbiamo guardato i numeri, pesato i compromessi e scelto la strada più difficile possibile: completamente nativo su ogni piattaforma. SwiftUI su iOS e macOS. Jetpack Compose su Android. C++/WinRT su Windows. Metal per il rendering su Apple. Vulkan su tutto il resto. Un server Go personalizzato al centro.

Non perché ci piaccia soffrire, anche se certi giorni sembra di sì. Ma perché per questo tipo di app il nativo non è un lusso. È un requisito.

La tassa di Electron è reale

Cominciamo da cos'è davvero Electron: una finestra del browser Chromium che finge di essere un'app desktop. Non è una critica — è architettura. E per molte applicazioni va benissimo.

Ma per un desktop remoto? Stai trasmettendo pixel da un altro computer e li disegni in tempo reale mentre catturi ogni evento di input e lo rimandi indietro. La latenza non è un di più. È l'intero prodotto.

Ecco cosa abbiamo misurato quando abbiamo fatto il prototipo di entrambi gli approcci:

I 380 MB non sono Electron che si gonfia. È Chromium che fa il suo lavoro — V8, un processo GPU, processi di utilità, un intero motore da browser. È ingegneria impressionante. Ma è ingegneria progettata per un problema diverso.

I fotogrammi contano più delle funzioni

Il desktop remoto è una delle poche categorie di app in cui ogni singolo fotogramma conta. Perdi un fotogramma e l'utente lo sente. Aggiungi 16 ms di latenza di input e un designer non riesce a tracciare curve fluide. Aggiungi 32 ms e un giocatore non riesce a giocare.

Con il rendering nativo parliamo direttamente con la GPU. Sulle piattaforme Apple, VideoToolbox ci dà accesso diretto alla decodifica video hardware. Prendiamo un fotogramma H.265 dalla rete, lo decodifichiamo in hardware e lo mostriamo — senza che il fotogramma tocchi mai la memoria principale. La catena dalla decodifica alla visualizzazione gira in meno di 4 ms su un Mac moderno.

In Electron lo stesso fotogramma attraversa il compositor di Chromium, passa dal ponte IPC, viene disegnato da Skia e poi composto di nuovo dal sistema operativo. Ogni salto aggiunge latenza. Ogni salto aggiunge jitter. E il jitter — la temporizzazione irregolare dei fotogrammi — è ciò che fa sembrare il desktop remoto sbagliato anche quando gli FPS medi sembrano a posto.

Non abbiamo scelto il nativo per purismo. L'abbiamo scelto perché la fisica del nostro problema lo imponeva — circa 8 ms di elaborazione in LAN (il resto è la cadenza di aggiornamento a 60 Hz del tuo display), non lasciano spazio a un browser nel mezzo.

Registro delle capacità: nativo contro web

Il dibattito Electron contro nativo resta spesso bloccato sulle sensazioni. Così abbiamo messo per iscritto le sette capacità del sistema operativo da cui Remio dipende in ogni secondo di ogni sessione e ci siamo chiesti, semplicemente: come se la cava ciascuna con ciascun runtime?

CapacitàNativoWeb / Electron
Decodifica hardware a 60 fps● VideoToolbox / D3D11VA diretti○ Via WebCodecs, con jitter
Audio USB a bassa latenza● CoreAudio / WASAPI— Isolato, 40 ms+
Monitoraggio dell'input da tastiera● CGEvent / SendInput— Bloccato fuori dal focus
Accesso alla GPU Metal / D3D11● Texture zero-copy○ WebGPU, salti di copia
File system locale● Completo, delimitato dal sistema operativo○ Solo selettore, richieste
Più finestre, più display● Gestione finestre nativa del sistema○ Adattatori BrowserWindow
Persistenza in background● LaunchAgent / servizio— Sospeso quando nascosto

Ogni riga è una funzione che rilasciamo oggi. Ogni — nella colonna web è un ripiego che dovremmo inventare, documentare e di cui scusarci. Andare nativi significa trattare quelle capacità come primitive e non come polyfill.

Cittadinanza della piattaforma

Ecco una cosa di cui chi sostiene «scrivi una volta, gira ovunque» parla di rado: gli utenti se ne accorgono.

Si accorgono quando un'app non rispetta le transizioni della modalità scura di sistema. Quando la fisica dello scorrimento sembra un po' sbagliata. Quando l'app non compare in Spotlight o non gestisce bene la gestione finestre di macOS. Quando il menu contestuale sembra una pagina web invece di un menu nativo.

Non sono dettagli da poco. Sono la differenza tra un'app che le persone tollerano e un'app che amano. Su iOS è particolarmente critico — la revisione dell'App Store rifiuta le app che non sembrano native, e giustamente.

Con SwiftUI otteniamo tutto questo gratis. Dynamic Type, accessibilità VoiceOver, feedback aptico di sistema, multitasking su iPad, scorciatoie da tastiera su Mac. Non reimplementiamo funzioni della piattaforma. Le usiamo.

Anche il costo è reale

Siamo onesti sul lato negativo: andare nativi è costoso. Non in dollari — in tempo e complessità.

Manteniamo quattro basi di codice per l'interfaccia. Il nostro strato di rete e codec è condiviso (Go per la segnalazione, C++ per il protocollo di streaming), ma ogni pixel che vedi sullo schermo è codice specifico della piattaforma. Una funzione che in Electron richiede un giorno a noi ne richiede da tre a cinque, perché la costruiamo quattro volte, tarata per ogni piattaforma.

Ci sono state settimane in cui una singola animazione funzionava splendidamente su iOS, era rotta su Android e scattava su Windows. La matrice di debug è spietata.

Ma ecco cosa abbiamo imparato: la strada più difficile e la strada giusta sono spesso la stessa strada. I nostri utenti non conoscono né si curano della nostra architettura. Sanno che Remio è veloce, ha la sensazione giusta e non si mangia la loro batteria a colazione.

Lo rifaremmo?

Senza esitazione.

L'approccio nativo ci ha dato prestazioni che Electron, per questo caso d'uso, non può fondamentalmente eguagliare. Ci ha dato app che sembrano appartenere a ciascuna piattaforma. Ci ha dato un'impronta di memoria sotto i 45 MB invece di 380 MB. Ci ha dato circa 8 ms di elaborazione in LAN (il resto è la cadenza di aggiornamento a 60 Hz del tuo display), dove un concorrente avvolto in un browser sta sopra i 60 ms.

Soprattutto, ci ha dato un fossato tecnico. Costruire nativo su quattro piattaforme è abbastanza difficile da far sì che la maggior parte dei concorrenti non lo faccia. Quella difficoltà è il nostro vantaggio.

La categoria del desktop remoto è stata dominata da app web avvolte in Electron e da app native datate che non vengono aggiornate in modo significativo da anni. C'è spazio per qualcosa di moderno e nativo insieme — qualcosa costruito da zero pensando all'hardware di oggi.

Questo è Remio. Costruito nel modo difficile, perché alcune cose valgono la pena di essere fatte bene.

Icona dell'app Remio

Senti la differenza che fa il nativo

Remio è gratuito, nativo su ogni piattaforma e cifrato end-to-end. Impronta sotto i 45 MB, circa 8 ms di elaborazione in LAN (il resto è la cadenza di aggiornamento a 60 Hz del tuo display) — costruito nel modo difficile perché dia la sensazione giusta.

Gratuito100% nativoCifrato end-to-end