March 2021 by Alexander Rinass

Tower — Developing a Native Git Client for macOS and Windows

About the Author
Alex Rinass is the CTO and Co-founder of the Tower Git desktop GUI. He and his team have built the popular desktop app, used by over 100,000 developers all over the world.

Starting off our series of interviews with the developers behind popular desktop applications, it's none other than Alex from the Tower team! In this conversation, Alex gives an insight into building apps for the desktop with native technologies on macOS and Windows, what kind of problems this entails, what technologies are used and much more.

Tell us a little bit about your application: what does it do and when did you start working on it?

Tower is a native Git client for Mac and Windows. We started working on Tower for Mac in 2010 and shipped the first version in 2011, with subsequent major releases in 2014 and 2018. Tower for Windows development started in 2012 in parallel with Tower Mac 2 and we shipped the first version 2016 and released a major version upgrade in 2018. Since then we switched to a different release schedule. Instead of collecting various features for a big release, we now publish smaller releases regularly. This allows us to ship new features much faster.

Our goal is to provide a simple yet powerful interface to the Git version control system.

What technologies are you using to develop it?

We are using native frameworks on each platform for development. I'd consider an app “native” if it uses the native UI framework, adheres to the design guidelines and conventions of the platform and offers common system integrations.

Tower Mac is still mainly written in Objective-C, but we recently started to use Swift for new code components and are gradually replacing Objective-C. We don't use any special third-party frameworks but stick to the frameworks provided by Apple.

Tower Windows is written in C# using the .NET and WPF (Windows Presentation Foundation) frameworks. We also don't use any special third-party frameworks here.

Why did you choose those particular technologies?

When we started with the development of the Mac version, we didn't plan for a Windows version. Therefore choosing a cross-platform technology wasn't something we initially thought about. However, we briefly looked into cross platform stacks using web technologies (and also MacRuby / RubyCocoa) as our experience was in web development at that time.

We quickly discarded this idea though as these technologies didn't feel mature enough and as we also gained experience in Apple platforms by developing a couple of iPhone apps (which turned out to be a great developer experience) we decided to go with native Apple platform development.

Once we decided to develop a Windows version of Tower around 2012, we reviewed cross-platform technologies again but weren't convinced of existing solutions in terms of delivering the user experience we wanted and Electron (or Atom Shell at first) wasn't around then. We were also very happy with how Mac development went and did not want to give it up, so we decided to develop Tower Windows natively as well.

We discussed sharing code between platforms but that would have meant to use C/C++ which no one in the team was really proficient in. This would have also meant rewriting a lot of important code and you would have still needed bindings for each language. Also during that time, Tower 2 Mac was still in active development and large parts of the code still in flux so taking all things into account we decided to re-implement the business logic in C#.

Tell us about the good parts: what’s great about those technologies?

Developing for Apple platforms is overall a great experience. You get a lot of powerful functionality for free and creating a compelling user interface is very simple with just the standard UI controls. There are also very extensive and detailed UI guidelines for all Apple platforms which requires less design decisions on your end.

You can also rely on Apple to steadily evolve and to improve existing frameworks rather than trying to reinvent the wheel every few years. Even when there is a big change – like the introduction of their new Swift language – they offer a clear migration path and give you time to adapt.

As a platform developer, it really is important to rely on a solid foundation, which evolves but doesn't radically change unnecessarily often. After all, we want to invest the majority of our time into developing our product rather than into adopting new vendor technologies.

Using native APIs directly allows you to offer the best integration into the operating system and following its conventions. It enables you to adopt and support new system features right from the start, which is very important on the Mac as users quickly demand support for new features. You can achieve great performance and low memory management more easily as there is no extra layer between you and the system you are targeting.

On Windows, .NET and WPF are powerful frameworks and the tooling is great with a wide range of development tools to choose from.

Did you encounter any problems or disadvantages connected to those technologies?

When you develop natively on technically different platforms, you need to either share as much code as possible between platforms or you need a strategy to exchange knowledge and specifications on how features are supposed to work and about their implementation details.

Unfortunately, the choice of languages that can be shared and easily adopted across platforms is very limited. As the shared code will make up a large and important part of your code base, your team has to be very proficient in it in addition to each platform's main language.

Effectively sharing common logic is the main challenge you're facing if you develop natively on technically different platforms.

Along the way, was there anything that took you by surprise - any pros / cons, any insights that you hadn’t been aware of when you started?

The biggest surprise certainly was and is the difference between Mac and Windows regarding developer experience. While the experience on the Mac is overall very good and you constantly receive improvements to the frameworks year over year, the experience on Windows is a bit stagnating, especially regarding UI/UX platform improvements that you can adopt and ship to the user.

For example, over the years Apple introduced Full Screen Apps, Window Restoration, Tabs, Dark Mode and many other UI features. With a very minimal amount of time you can add support for these features into your existing app. On Windows, you have to implement this all by yourself, which leads to less consistent solutions and conventions across apps.

The WPF UI framework we (and others) use – while powerful – is not actively developed anymore. At the same time Microsoft does not provide a new UI framework for developing Desktop-class apps. Their latest UI framework Universal Windows Platform (UWP) is primarily designed with simple touch interfaces in mind (and it's also unclear what the future of UWP will be).

Because of this, WPF does not offer as many great view components out-of-the-box as you get on the Mac and a lot more work goes into UI development as you need to design and develop your own view components on Windows. There are also no consistent UI design guidelines for Windows Desktop-style apps. All of this makes it much harder to design a great looking app on Windows compared to the Mac.

Aside from that it's surprisingly hard to find good resources about Mac development as iOS is the much more popular Apple platform (although the Mac has been around much longer). This might change with Apple's Catalyst, which aims to ease porting iOS apps to the Mac (or other Apple platforms).

How do you see those technologies in a "broader context", beyond your particular app?

We have chosen native technologies because we believe that this provides the best user experience on each individual platform. When you use a cross platform technology you will always be making compromises in various areas: performance, native UI feeling, system conventions and system integration, adoption of new platform features, and so on.

But the more platforms you want to support, the harder it gets to natively support all platforms even if you succeed in sharing a lot of core logic. Aside from the economics, you also need the expertise to develop for each platform.

In the end it depends on various factors which technology is the best for your needs.

With the introduction of Smartphones, Tablets and Smart TVs, and also the rise of more sophisticated Web apps, supporting multiple platforms has become significantly more important over the last 10 years. I don't feel like there currently is a really good answer to that problem as every solution has its disadvantages.

What about the development tools that are available? What’s great and what could be better?

On the Mac, your toolchain is pretty much set as there is not really a way around Xcode, Apple's IDE for developing apps for Apple platforms. While it has its quirks, it gets the job done. Even if it could definitely take some lessons from other IDEs in terms of features, speed and stability. All development tools are available through the command line which means you can automate workflows if you need to.

The advantage of being locked into the Apple toolchain is that they provide all essential tools to ship a product directly to end users: writing code, signing it and deploying the app to the AppStore. If you distribute your application outside the AppStore (like we do), there's the Sparkle Updater Framework - the de-facto standard for delivering updates.

There are more options on Windows regarding IDEs with Microsoft Visual Studio and JetBrains' Rider, for example. However, finding a maintained framework to install and updating your application is harder on Windows. Also Code Signing is a topic that is completely in your hands (and the costs associated with it).

When thinking about the future of those technologies, what do you expect or hope for?

In short, I hope for a more viable way to develop natively for platforms. While I understand the motivation behind the need of cross-platform frameworks, it would be sad to see the relevance and strengths of individual platforms go away by enforcing application-specific over platform-specific UI/UX conventions and by targeting a lowest-common-denominator platform feature set.

macOS and other Apple platforms provide strong UI/UX conventions which is beneficial for users working with different apps on the same platform and which is the reason why these platforms have so many fans and why users on those platforms are more sensible when it comes to native vs. non-native apps.

It would be great to use a modern, higher level language to share code between platforms, ideally one that is already actively used for development on one platform. Apple has started re-implementing their core frameworks in Swift, which could make it possible to share code using Swift across multiple platforms, as Swift is available on both Linux/Android and Windows.

There's also Kotlin and .NET Core that both provide an option for sharing code on multiple platforms. We don't have any hands-on experience, but it's something we would like to experiment with.

If people want to start developing with those technologies, what should they look at and what advice would you give them?

When we started the Mac version of Tower, Apple's documentation was still in a pretty good shape. Since a few years, along with the introduction of Swift, they have deprecated a lot of documentation but haven't replaced it adequately yet. Luckily, the Swift community has grown extremely fast and there are tons of great books and online tutorials for developing on Apple platforms with Swift, objc.io and Hacking with Swift are good examples.

For Mac development, use what is offered and don't try to work around existing patterns. Only customize UI controls when absolutely necessary, you will have less work later on. Learn and follow the design guidelines provided by Apple.

Pay attention to Apple's annual developer conference WWDC and block some time to learn and adopt new frameworks and new system features so changes don't pile up to a point when it becomes too much work. On the other hand, be careful with the introduction of bigger technical changes, like for example Swift and SwiftUI. Start learning these new technologies so you are prepared to use them, but don't adapt them too early in production.

On Windows, WPF and .NET still is the right choice for developing Desktop applications. There is no way around customizing a lot of controls yourself. There's a market for third-party Window UI controls, but in our experience you are better off writing your own.

Extract as much logic as possible into core modules and share this code between platforms. Alternatively, make a good plan to document and exchange specifications about features and use the same code architecture on all platforms as much as possible.

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!