Ancestors

Written by Matt Campbell on 2025-01-19 at 12:55

A comment in an article about prototyping in Rust [1] led me to this ~11 year old article by a programmer who decided to use Java for all non-throwaway programming: https://www.teamten.com/lawrence/writings/java-for-everything.html

I think java isn't as dominant now as it was when that article was written, but the article's arguments for prioritizing programming in the large resonate with me. But I want my default language to be Rust, because of its added guardrails for safety and correctness.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:19

I made a conscious decision at some point in my early 30s that I would refuse to become set in my ways when it came to programming language and tech stack in general, that I would never stop learning new things and trying to choose the best tool for every job, not just the one I was comfortable with. At that point, my default language had been Python for a bit over a decade, but I was already aware of its limitations for desktop apps, particularly in terms of package size.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:22

I had already paid a price for that limitation in 2007-2008 by rewriting a substantial Python codebase in Lua, only to discover that, at scale, the same fundamental limitation applies; to really optimize total package size, one needs static analysis and fine-grained dead code elimination, which are intractable in dynamic languages like Python or Lua. Not that there was necessarily a better choice in 2008; doing the whole thing in C++ was off the table, and Native Image for Java didn't yet exist.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:27

And by the early 2010s, when I was in my early 30s, the future was supposedly going to be all about native mobile and/or client-heavy web apps, where small size and closeness to the platform are important. For a while I did iOS (and Mac) apps in Lua, using a two-way Lua/ObjC bridge called Wax. But at some point I decided I needed to make the jump to static languages. I wasn't going to become limited as a generalist developer because I was too wedded to Python or dynamic languages in general.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:32

My first major project developed under this new mindset was a client-side web app I did in the first half of 2013. I wrote it in JavaScript, but I used the Google Closure Compiler in advanced mode, with type annotations (in doc comments, ugh), all the optimizations that compiler could do, and the Closure Library. Aside from that library, I ported one third-party dependency to Closure-flavored JS and wrote the rest myself. The final bundle size was ~250K uncompressed. I considered this a triumph.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:35

Of course, I was short-sighted, over-optimizing for one dimension (runtime efficiency). Even while I continued to maintain that application over the next few years, I rarely updated the Closure compiler or library. And, in the decade plus since, the JS community at large has gone in a different direction.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:41

One of my projects in the latter half of 2013 was an Android app written directly in Java, and by late 2014, I was looking at various ways to write cross-platform code in one language and compile it to native code on iOS and JVM/Dalvik bytecode on Android. The top two contenders for me were J2ObjC, another Google internal tool that they had open-sourced, and an obscure proprietary compiler called RemObjects Elements. Remember, I wanted to optimize for small size and closeness to the platform.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:46

In 2015, the biggest project that I shipped that year was a desktop app (some of my blind followers can probably guess which one). I wanted it to have as native a UI as possible, only using web views for document content. As I was trying to choose the best tool for the job and not just the most comfortable one, I was going to use the SWT GUI toolkit for Java, which had good accessibility on both Windows and macOS. I was determined to have a no-compromise UX while sharing code across platforms.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:49

So I figured I'd write the whole app in Java, using a lightweight third-party JVM implementation called Avian, that could even compile JVM bytecode ahead of time to a stand-alone executable. I was finally going to have it all, even in a desktop app: native-feeling UI, small size, and instant startup time, across platforms. Yes, I'd have to write in painfully verbose Java, but it would be so worth it. That was the plan, anyway.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:51

But I couldn't make myself push through it. The first sign of trouble was when I found myself having to either adapt an existing JNI binding for the libcurl HTTP client, or write my own (I don't remember which), so I could have an HTTP client while keeping executable size down. And I knew I was going to have to write bindings for more native stuff. I had already done plenty of that for Lua in 2007-08, and I didn't want to do more JNI glue code. I missed good old Python and ctypes.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:53

I also had some existing Python code, which ran on the server in a previous implementation of the product I was rewriting, but now I wanted to run it on the user's desktop so that functionality could be available offline. And I was just all around more comfortable with Python and its ecosystem than I was with the JVM ecosystem.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:56

So I basically restarted the project, in Python. It felt good to be using Twisted, requests, and other familiar Python libraries again, not to mention my own existing Python code. But I was determined to still use SWT for the UI. So this app was a mongrel; I embedded the Avian JVM via a Python package called pyjnius, and used that just to bring in SWT. Yes, it was a mess. But I managed to deliver the native-feeling UI across Windows and Mac, with minimal platform-specific code.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 13:59

But that project felt to me like a shameful retreat from the full set of goals I had set for it, goals that, in retrospect, I realize didn't really matter to anyone else, not just users, but the others at my company. Still, I felt that my plan B using Python was a capitulation to the requirement to unblock my productivity and get the thing out quickly. I don't think I stopped to reconsider the priorities that had led me to try doing the whole thing in Java.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 14:02

BTW, that desktop app went into beta in June 2015, a month or so after I had started over in Python. The Windows package size for the latest version of that app is ~44 MB uncompressed, or ~12 MB compressed with 7-Zip. That's not as bad as an Electron app today, but it was still shameful to me at the time.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 14:09

Like I said, I hadn't really reconsidered my priorities or pondered what lessons to take from the failure of my original approach to that project. For my big 2016 project, a consumer app spanning desktop, mobile, TV set-top boxes (initially the newly accessible Apple TV), and, we assumed, eventually a client-side web version for Chromebooks, I was going to double down on runtime efficiency (especially small size), closeness to the platforms, and no-compromise native UI.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 14:15

So I decided to write the cross-platform non-UI code in Java. That would be native to Android, for the Apple platforms I'd use J2ObjC, for Windows I'd use IKVM.NET (a JVM implementation on top of .NET), for the eventual web port (which never happened), I was planning to use Google Web Toolkit or maybe Google's new j2cl if it was ready in time. For the UI, I would use the native language and toolkit of each platform, or maybe SWT again on Windows and Mac.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 14:19

What I actually did for the UI was reuse a bunch of code from the previous platform-specific versions of this app that I was trying to unify. The previous Android version was pure Java (that was the late 2013 project from earlier in the thread). The rest was compromises on my pure vision: Lua and wax for the iOS, Mac, and Apple TV versions (see earlier), and for Windows, a mongrel of .NET and Windows Forms (I had started on that in 2014) plus some of the Lua code from 2007-08.

=> More informations about this toot | More toots from matt@toot.cafe

Written by Matt Campbell on 2025-01-19 at 14:21

I did actually get to reuse some non-UI code across platforms, including the audio player and some code for managing downloaded content and synchronizing the user's playback position with the server. But another compromise, the big one, was this: the Ui was a hybrid between native and server-rendered web views. There was just no other way I was going to ship the damn thing. And a few features remained exclusive to the Windows version (the original).

=> More informations about this toot | More toots from matt@toot.cafe

Toot

Written by Matt Campbell on 2025-01-19 at 14:23

And still, after the compromises of this 2016 project and the one before, I hadn't learned my lesson: the inevitability of tradeoffs and the importance of picking the right ones. I think I saw the compromises of both projects as simply a failure to be perfectly productive.

=> More informations about this toot | More toots from matt@toot.cafe

Descendants

Proxy Information
Original URL
gemini://mastogem.picasoft.net/thread/113855471329989518
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
404.424751 milliseconds
Gemini-to-HTML Time
4.722797 milliseconds

This content has been proxied by September (ba2dc).