How Four Native Developers Wrote An Electron App
Today we released the new GitHub Desktop Beta, rewritten on Electron.Electron is a well-known on-ramp for web developers to build desktop apps using familiar web technologies: HTML, CSS, and JavaScript.
Today we released the new GitHub Desktop Beta, rewritten on Electron.
Electron is a well-known on-ramp for web developers to build desktop apps using familiar web technologies: HTML, CSS, and JavaScript. Our situation was different. Everyone on the GitHub Desktop team is a native developer by trade—three from the .NET world and one from Cocoa. We knew how to make native apps, so how and why did we end up here?
Why Rewrite?
First, the elephant in the room: why? Rewrites are rarely a good idea. Why did we decide to walk away from two codebases and rewrite?
From the start, GitHub Desktop for macOS and Windows were two distinct products, each with their own team. We worked in two separate tech stacks using two different skill sets. To maintain parity across the codebases, we had to implement and design the same features twice. If we ever wanted to add Linux support, we’d have to do it all a third time. All this meant we had twice the work, twice the bugs, and far less time to build new features.
As it turns out, building native apps for multiple platforms doesn’t scale.
Why Electron?
This isn’t a new or unique problem. Over the years we explored various ways for evolving the existing applications towards a shared codebase, including Electron, Xamarin, a shared C++, or in our wildest dreams, Haskell.
We’d already experimented with web technologies to share work. The gravitational pull of the web was too strong to resist.
Beyond our own experience, we had to acknowledge the critical mass accumulating around web technologies. Companies like Google, Microsoft, and Facebook, not to mention GitHub, are investing incredible amounts of time, money, and engineering effort in the web as a platform. With Electron, we leverage that investment.
Tradeoffs
The web isn’t a perfect platform, but native apps aren’t built on perfect platforms either. Rewriting on Electron does mean swapping one set of tradeoffs for another.
Now we can share our logic and UI across all platforms, which is fantastic. But Windows and macOS are different and their users have different expectations. We want to meet those expectations as much as possible, while still sharing the same UI. This manifests in a number of ways, some big and some small.
In the small, some button behaviors vary depending on your platform. On macOS, buttons are Title Case. On Windows they are Sentence case. Or on Windows, the default button in dialogs is on the left, where on macOS it’s the right. We enforce the latter convention both at runtime and with a custom lint rule.
On macOS, Electron gives us access to the standard app menu bar, but on Windows, the menu support is less than ideal. The menu is shown in the window frame, which doesn’t work with our frameless window design. The built-in menu’s usability is also rough around the edges and doesn’t support the keyboard accessibility Windows users expect.
We worked hard to recreate a Windows-appropriate menu in web technologies, complete with access keys and appropriate focus states.
There were times when the web platform or Electron didn’t provide us with the APIs we needed. But in contrast to building a web app, building on Electron meant that we weren’t stuck. We could do something about it.
We added support in Electron for importing certificates into the user’s certificate store, using the appropriate platform-specific APIs.
The web’s internationalization support doesn’t provide fine-grained localization information. For example, we can’t format numbers in a locale-aware manner, distinct from the preferred language defined by the user. Similar to adding the import certificate support, we plan to add better localization support to Electron.
Development Experience
If you’re making a native app, your tech stack choices are pretty limited. On the macOS side, you’ll use Xcode, Swift, and AppKit. On Windows, you’ll use Visual Studio, C#, and WPF or UWP. But in the web world, choices abound. React? Angular? CSS? SASS? CSS in JS? Some compile-to-JavaScript language? Browserify? Webpack? Gulp? Grunt? The ecosystem is enormous. The relative openness of the web platform also means developers are able to experiment and innovate, independent from the constraints of any single vendor. This cuts both ways: the array of choices can be overwhelming, but it also means you’re more able to pick the right tool for the job.
We were coming from C#, Objective-C, and Swift where static type systems let the compiler watch our back and help us along the way. For us, the question wasn’t if we’d choose a compile-to-Javascript language but rather which one.
At the same time, one of the big benefits to writing an Electron app is JavaScript itself. It’s the lingua franca of programming. This lowers the barrier of entry for an open source project like ours. So while languages like Elm and PureScript are interesting and would scratch our static types itch, they were too far outside the mainstream for us to consider.
Our best two options were Flow and TypeScript. We landed on TypeScript. At the time we started the project, Flow’s Windows support lagged far behind macOS. For a team like ours where more than half of the engineers live on Windows, this was an instant deal-breaker. Thankfully, TypeScript has been fantastic. Its type system is incredibly expressive, the team at Microsoft moves fast and is responsive to the community, and the community grows every day.
We learned to take the long feedback cycles of native development as a given. Change the code, compile, wait, launch the app, wait, see the change. This doesn’t seem like much, but it adds up. But every minute spent waiting for the compiler to compile or the app to launch is waste. It is time where we could lose our focus, fall out of the flow, and get distracted.
Using web technologies tightens up our feedback cycle. We can tweak designs live, in the app, as it shows real data. Code changes reload in place. Our feedback cycle went from minutes to seconds. It keeps us motivated!
We’ve been working on GitHub Desktop Beta for just over a year. We’re happy with how far we’ve been able to come in that time, but it’s far from done. Check it out, leave us your feedback, and get involved!
Authors
Written by
Related posts
Unlocking the power of unstructured data with RAG
Unstructured data holds valuable information about codebases, organizational best practices, and customer feedback. Here are some ways you can leverage it with RAG, or retrieval-augmented generation.
GitHub Availability Report: May 2024
In May, we experienced one incident that resulted in degraded performance across GitHub services.
How we improved push processing on GitHub
Pushing code to GitHub is one of the most fundamental interactions that developers have with GitHub every day. Read how we have significantly improved the ability of our monolith to correctly and fully process pushes from our users.