Desktop Engineering
Follow one desktop fact at a time from an event and command to owned state, files, processes, synchronization, rendering contracts, and release boundaries. Every chapter runs a small Node.js core and states what windows, assistive technology, installers, signing, and operating systems still leave unproved.
Your first desktop core: event, command, state, and exact output
Objective Run one complete JavaScript program that converts a menu event into a validated document command and a new immutable state.
Core explanation
A desktop interface receives events from menus, keys, pointer controls, accessibility actions, files, and operating-system activation. The interface should translate an event into a small semantic command instead of placing durable document rules inside a click callback. A command names one user intention and carries validated values; a pure transition applies it to one prior state and returns one next state, so the learner can predict the result before a window framework exists. The first program uses a RenameDocument command and an immutable object. It proves JavaScript parsing, execution, validation, and exact local output under Node.js. It does not create a window, dispatch a native menu event, prove event-loop responsiveness, integrate with assistive technology, persist a file, or package an application. Those are later adapters with separate evidence. A desktop process can own several windows, documents, menus, commands, background tasks, platform services, and persistent stores whose lifetimes do not match one view. Separate presentation, window state, application commands, domain rules, repositories, filesystem adapters, and operating-system integration. Choose native, cross-platform, or Web-based shells from accessibility, platform fidelity, distribution, memory, update, and team constraints rather than fashion. The application root should create dependencies and own shutdown. Save durable user work independently from transient selection or window geometry, restore only validated identifiers, and handle second-instance requests, abrupt termination, sleep, resume, display changes, and files opened before initialization completes.
Run the event-to-command core before opening a framework
The required program contains one menu-shaped event, one RenameDocument command, one immutable reducer, and three exact evidence lines. Trace the old and new objects before thinking about Electron, .NET, native windows, threads, installers, or operating-system APIs. A beginner should be able to point to the exact line that validates title and document identity.
This Node.js result proves a language and domain boundary only. A real desktop adapter separately proves native event dispatch, command wiring, visible state, keyboard equivalence, assistive action, window lifetime, and packaged execution. The later laboratory names those observations without pretending they occurred in the core.
Compare native, managed, Web-based, and cross-platform desktop stacks
Windows, macOS, and Linux expose different window systems, application lifecycles, package formats, security models, file conventions, accessibility APIs, update mechanisms, and signing. .NET, Electron, Qt, Java, native Swift or C++, and other frameworks trade bundle size, runtime, integration, performance, reach, and maintenance. Select from product constraints and team evidence rather than trend.
A desktop process can run for days, own many windows and documents, access broad local files, integrate with shells, and receive external events after startup. Define supported OS versions, architectures, display densities, install scopes, user-data locations, portable mode, offline behavior, single or multi-instance policy, and enterprise restrictions. Process lifetime is long but still interruptible by crash, update, logout, or power loss.
Separate event-loop UI from domain, commands, and adapters
The UI thread owns window-framework objects and processes input, layout, painting, and accessibility. Views render state and emit intents. A UI model coordinates use cases. Domain values and commands protect rules. Repositories, files, search, sync, platform integration, and updates remain adapters. Business logic must run in a test harness without creating a window.
The composition root creates app-wide services, document or window scopes, and background owners. Avoid global service locators and mutable singleton state that leaks across windows or tests. Multi-document interfaces need one owner per document plus shared application resources under explicit synchronization. Closing a window does not necessarily mean exit; exiting must coordinate every open document and worker.
Own the event loop, startup, activation, and shutdown
Startup validates configuration, initializes logging and crash identity, acquires single-instance coordination if required, opens local state, creates windows, and becomes ready only after recoverable initialization. A second invocation may send validated arguments to the existing instance through IPC. Platform activation can arrive without command-line startup. Keep external paths and URLs untrusted.
Shutdown asks documents to save or resolve dirty state, stops admission, cancels or drains background work, persists layout safely, closes databases and IPC, flushes required diagnostics, and exits before the operating-system deadline. Avoid blocking modal loops that deadlock workers waiting for UI. A forced termination path still relies on earlier autosave and journal durability, not a final callback.
Laboratory: establish a multiwindow knowledge-base skeleton
Create framework-independent Note, Command, and repository use cases, one UI-model per window, an app-level composition root, and a controlled background executor. Open a note by stable ID from menu, command line, and second-instance message. Persist only bounded window layout and selected ID for restoration.
Test two windows, same document policy, second invocation, malformed path, startup database failure, framework exception, close with dirty data, worker during exit, process crash, and restoration. Seed domain import of UI toolkit, global currentDocument, and blocking disk on event thread. Acceptance runs core tests without the framework and closes every owned resource.