5 ms·
Well, let's think about the sources of bloat. I'd argue that the primary source of bloat in software today is when there's a mismatch between what developers n
by mike_hearn 2y ago
Well, let's think about the sources of bloat.
I'd argue that the primary source of bloat in software today is when there's a mismatch between what developers need and what the underlying platform provides. The most extreme case of this can be found in desktop operating systems where relatively few apps now use the underlying platform at all, largely because nobody wants to write GUI code multiple times. What developers want and what the underlying operating systems provide are almost entirely different so everyone ships a giant runtime to replace what's the OS comes with. Modern mobile platforms have a similar problem, where things like Swift UI or jetpack tend to be bundled with the app or at least were historically up until recently, and that yields bloated packages too.
In contrast people get the vapors if a web app is more than 5 MB of download and this happens because the web platform is significantly more responsive to what developers really want even though it has poor technical foundations. Where bloat does occur in web apps, it's because the browser makers have not responded quickly enough or at all to growing mismatches, for example the vdom diffing algorithm react uses could be implemented in the browser itself, but isn't, so lots of apps ship it bundled.
Apps for Windows 95 didn't seem bloated, but that's because they relied so heavily on what already came with the computer when you bought it. People just had a suck up the fact that the underlying API was pretty bad, because they couldn't afford to ship anything better and till the CD era came along and then you did start to see apps leave behind the underlying platform and get more bloated.
A truly next-gen operating system would make it very difficult to talk precisely about bloat, I think, because if you really went beyond the Unix or NT designs your operating system would download and manage code modules automatically, a little bit like browsers did before the introduction of cache partitioning. How bloated an app appears to be then would depend entirely on what you had previously used and downloaded, and thus to some extent would be in the eye of the beholder. After all, if you measured all of the code paged in by running a native Mac app, or even something like delphi, versus the amount of code paged in by an electron app, it probably wouldn't be that different. It's just that the Mac app is accessing code that is shared with other operating system utilities.
- mwcampbell 2y agoThanks for steering the discussion in a more constructive direction than where I was going. There are C++ UI toolkits wrapping Win32, Cocoa, etc., and sometimes such toolkits are statically linked into the executable, meaning that dead code elimination should be able to minimize the executable size. I'm thinking in particular of wxWidgets. But even with C++ and static linking, it's easy for a library to be designed in such a way that you end up paying for stuff you don't use. The last time I did a project in C++ with wx, 10+ years ago, my program itself was quite trivial, and it only used very basic widgets, but the statically linked Win32 executable still ended up being ~2.5 MB. I didn't get very deep into why, but my understanding is that code for a bunch of features (printing, drag and drop, etc.) got linked in, even though my application wasn't using it, because the window procedure had to handle messages related to those features regardless. I guess, to optimize for minimal executable size, the API would have to be designed to require the application developer to explicitly initialize only the features they need, and in this case, the message handler would have to be more dynamic. Sometime I'd like to design a new toolkit inspired by wx and SWT, in either Rust or Java. In the latter case, I'd use the new Foreign Function and Memory API to call the native APIs. I'd be interested to see how much GraalVM Native Image could optimize an application written with such a toolkit; I recall you've said good things about how much Native Image can optimize program initialization in particular. There seems to be a broad consensus, though, that Win32 in particular isn't suitable for "modern" desktop apps, and so, by extension, neither are wx and SWT. Certainly in the Rust GUI space, all the popular toolkits are drawing their own widgets, and even reimplementing lower layers of the stack like text rendering, thus contributing to the trend you talked about where applications bring along their own runtime. I assume there are actual deficiencies in OS-supplied APIs that are leading to this, though a sufficiently jaded person might argue that developers are in fact wasting their time on unnecessary things for one reason or another. Anyway, if the classic Win32 widgets are still good enough for some parts of the OS itself (although, admittedly, fewer and fewer with each release), then presumably they're good enough for some subset of applications as well, and if the developers of those applications had a convenient and lightweight abstraction layer over those classic widgets, then we could start to reduce bloat.
- mike_hearn 2y agoYeah, static DCE is a limited optimization. I've personally given up on it. It's not useless, but it's a big lift for developers and the app size will keep growing anyway. These days I'm more interested in dynamic code paging systems as a way forward, but, at the moment I'm not able to work on that right now. Think about how "bloated" an app like Google Maps or Search is, yet it still feels fast because it downloads what it needs on demand. Everything should work that way. The Conveyor installer is a native Win32 app written in C++. It's pretty trivial, it mostly just invokes some Windows APIs, works around bugs in those and ties the results to a progress bar. It's a classic app that uses HWNDs, window messages and the like. The bulk of the logic is in one file. Despite that it's about a 500kb EXE. Where do the bytes come from? Partly, it's C++. Native code is verbose and template instantiation creates a lot of it. You don't need to instantiate many std::vectors before suddenly binary size has crept up on you. The widespread adoption of C++ increased binary sizes significantly over C, because suddenly you were using value typed containers everywhere instead of a single shared linked list utility library. GraalVM native executables start extremely fast, but they aren't small. Partly this is the mismatch problem again: operating systems don't provide stuff like built in garbage collectors, even though GC is a fundamental service nearly every app needs, so, programs ship their own. Partly it's because GraalVM makes apps start fast by pre-initializing the app, so the binaries come with a heap image that it just mmaps and starts using. But then you have to download and store the initial heap instead of recomputing it at startup. It's a disk space/startup time tradeoff. And partly it's because a static analysis must be inherently conservative. Anything that could potentially run has to be included, even if in reality it never does (think exception handlers, assert messages...) So IMO the right fix is to just assume an always-on internet connection and then stream code in as it's needed, with pre-emptive paging in the background to get apps into a state where you can disconnect. The system would aggressively deduplicate data to avoid redownloading stuff you already have. A smarter version of what browsers do. This lets you have apps that are hundreds of gigabytes in size but they still start fast and sip resources on the client side where you're most constrained. I think modern languages ignore Win32 partly because it sucks and partly because virtually no working developers have ever used it. Many modern devs won't even realize it's there. How many devs that slung window messages in the 90s are still coding? I think a lot have retired or moved into management roles, or were hired to work on Chrome. There are Microsoft security engineers, working on Edge, who announced in a blog post that they had no idea how to use COM and had to rely on AI to write the needed code for them! [1] And a lot of devs aren't developing on Windows, they're probably writing these Rust toolkits on macOS or Linux. Anyway, Win32 UI is something I'd not recommend using. It's been unmaintained for decades. Conveyor uses it because, well, it's an installer that downloads the rest of the app, so size matters more than anything else, and the UI needs are simple. The moment you want table stakes stuff like High DPI support, responsive layout, dark mode, vector icon support, data binding etc, you end up needing big frameworks that sit on top and/or you end up in a nightmare of twisty barely documented APIs. [1] https://microsoftedge.github.io/edgevr/posts/Escaping-the-sandbox-A-bug-that-speaks-for-itself/ https://microsoftedge.github.io/edgevr/posts/Escaping-the-sa...