Re:Giving Mono Souper Powers
by gwbas1c on Friday December 07, 2018 @11:38AM
(#18629079)
Syncplicity, a desktop file synchronization application, uses Mono on MAc.
The UI is native: WPF on Windows, Objective C on Mac. The core synchronization logic is shared C# code. (Objective C and C# co-exist via Pinvokes and function pointers.)
We started with Mono in 2010 before a lot of the modern tools, libraries, ect. At the time mono was very buggy. Now, Mono is a lot more stable.
As far as insights go:
We originally had, on Mac, a C# UI built with a (now obsolete) framework called MonObjC. The problem with MonObjC was that the only way to understand it was to be an Objective C expert; and it didn't always wrap the APIs in ways we needed. Thus, when we had some lawyer come and tell us that they didn't like the license, we just rewrote everything to PInvoke into shim C functions that call into Objective C. Thus, IMO, when in doubt, PInvoke into native code instead of fighting a compatibility layer.
Our Mac app packaging is all homegrown, primarily because our application predates the more modern mono packaging. I haven't tried the newer app packaging that comes with Visual Studio on Mac. IMO, make sure you understand app packaging.
Quite frankly, we've always had trouble with live debugging. (This might be due to our older packaging scheme.)
Ultimately, you need to understand the cost of writing something twice. When you work with Mono, or any cross platform framework / language / ect, you won't "write once." Instead, you will write once, debug on all platforms, and then add a bunch of special cases. Then, the developers who work on platform X will make a change that breaks platform Y because it wasn't covered in a unit test. Sometimes the cost of writing something twice really is worth it compared to the tradeoffs. (This certainly is the case with our UI, where we want a 100% native UI.)
Edit: We use dependency injection. (Via code, not a framework.) We have a lot of base classes in common code, and then platform-specific subclasses to handle special cases.
The UI is native: WPF on Windows, Objective C on Mac. The core synchronization logic is shared C# code. (Objective C and C# co-exist via Pinvokes and function pointers.)
We started with Mono in 2010 before a lot of the modern tools, libraries, ect. At the time mono was very buggy. Now, Mono is a lot more stable.
As far as insights go:
We originally had, on Mac, a C# UI built with a (now obsolete) framework called MonObjC. The problem with MonObjC was that the only way to understand it was to be an Objective C expert; and it didn't always wrap the APIs in ways we needed. Thus, when we had some lawyer come and tell us that they didn't like the license, we just rewrote everything to PInvoke into shim C functions that call into Objective C. Thus, IMO, when in doubt, PInvoke into native code instead of fighting a compatibility layer.
Our Mac app packaging is all homegrown, primarily because our application predates the more modern mono packaging. I haven't tried the newer app packaging that comes with Visual Studio on Mac. IMO, make sure you understand app packaging.
Quite frankly, we've always had trouble with live debugging. (This might be due to our older packaging scheme.)
Ultimately, you need to understand the cost of writing something twice. When you work with Mono, or any cross platform framework / language / ect, you won't "write once." Instead, you will write once, debug on all platforms, and then add a bunch of special cases. Then, the developers who work on platform X will make a change that breaks platform Y because it wasn't covered in a unit test. Sometimes the cost of writing something twice really is worth it compared to the tradeoffs. (This certainly is the case with our UI, where we want a 100% native UI.)
Edit: We use dependency injection. (Via code, not a framework.) We have a lot of base classes in common code, and then platform-specific subclasses to handle special cases.