I mean this in the same sense as “XML was created to solve the interoperability problem.”
The container craze is about the interoperability problem across environments. By vendoring the entire distribution and communicating only over the network, they essentially provide isolation for all the dependencies of a service. Maybe that part is the same, in essence, as the nix package manager.
But then containers have one more trick: they run anywhere with a “Linux syscall interface” underneath. Any environment with Docker support can run Docker containers, anywhere. (As long as the binaries run on the host, at least.) It’s not entirely simple—orchestration is an issue, and Docker is working on that, too—but the containers themselves become highly portable, since they’re shipped as black boxes. They don’t depend on code outside themselves, and as such, that outside code cannot break them so easily.
And maybe, by so fully entwining a Linux distro to our app, we’re forgetting how to be cross-distro or cross-platform. And the old coder in me wants to grump about that. Yet, that’s also a kind of freedom. Not everyone has to learn how to write cross-platform code if the container environment defines exactly one platform to run on.
Maybe we’re losing something, but we’re also gaining ease-of-use and accessibility in the deal.
Showing posts with label cross-platform. Show all posts
Showing posts with label cross-platform. Show all posts
Thursday, August 1, 2019
Friday, July 10, 2015
Letting Go of Go
The things that originally attracted me to Go were the concurrency model, the interface system, and the speed. I was kind of meh about static typing (and definitely meh about the
But it hasn’t really turned out that way. I still like the concept of having no locks exposed to the user (safely hidden in the channel internals) à la Erlang or Clojure. But I’m not going to pay for it with
Seriously, all of the synchronization choices of Go seem to come down to, “Use another channel.” Keeping track of so many channels among a few stages of processing is a whole new layer of heavy work. That would be pretty much unnecessary if channels could be “closed with error,” which could then be collected by the UI end.
Then there is the whole problem of generics. The runtime clearly has them: basically, anything creatable through
You can pretend to hack around it with
To get the purported advantages of static typing, the data has to be fit to the types that are already there.
I’d almost say it doesn’t matter to my code, but it seems to be a big deal for libraries. How they choose their data layout has effects on callers and integration with other libraries. I don’t want to write a tall stack of dull code to transform between one and the other.
The static types thing, I’m kind of ambivalent about. If the compiler can use the types to optimize the generated code, so much the better. But it radically slows down prototyping by forcing decisions earlier. On the balance, it doesn’t seem like a win or a loss.
Especially with all the performance optimization work centering on dynamic languages, refined in Java (to a certain extent), C#, and JRuby, now flowing into JavaScript. It’s getting crazy out there. I don’t know if static typing is going to hold onto its edge.
I think that brings us back around to
Go isn’t supposed to have exceptions, but if you can deal with the limitations of it,
I forgot about the mess that is vendoring and
But am I wrong? What about the “go is the language of the cloud” thing that Docker, Packer, and friends have started? I don’t think Go is “natively cloud” because that’s meaningless. I think a few devs just happened to independently pick Go when they wanted to experiment, and their experiments became popular.
It surely helps that Go makes it easy to cross-compile machine-code binaries that will run anywhere without stupid glibc versioning issues, but you know what else is highly portable amongst systems? Anything that doesn’t compile to machine code. For instance, the AWS CLI is written in Python… while their Go SDK is still in alpha.
interface{}
escape hatch) but figured the benefits might be worth the price?But it hasn’t really turned out that way. I still like the concept of having no locks exposed to the user (safely hidden in the channel internals) à la Erlang or Clojure. But I’m not going to pay for it with
err
everywhere, static types, a profusion of channels, and a lack of generics.Seriously, all of the synchronization choices of Go seem to come down to, “Use another channel.” Keeping track of so many channels among a few stages of processing is a whole new layer of heavy work. That would be pretty much unnecessary if channels could be “closed with error,” which could then be collected by the UI end.
Then there is the whole problem of generics. The runtime clearly has them: basically, anything creatable through
make()
is generic. But there’s no way for Go code to define new types that make
can create generically. There’s no way for Go code to accept a type name and act on it as a type, either.You can pretend to hack around it with
interface{}
and runtime type assertions, but you lose all of the static checking. The compiler itself knows that a map[string]int
uses strings as keys and can only store integers, but an interface{}
based pseudomap won’t fail until runtime.To get the purported advantages of static typing, the data has to be fit to the types that are already there.
I’d almost say it doesn’t matter to my code, but it seems to be a big deal for libraries. How they choose their data layout has effects on callers and integration with other libraries. I don’t want to write a tall stack of dull code to transform between one and the other.
The static types thing, I’m kind of ambivalent about. If the compiler can use the types to optimize the generated code, so much the better. But it radically slows down prototyping by forcing decisions earlier. On the balance, it doesn’t seem like a win or a loss.
Especially with all the performance optimization work centering on dynamic languages, refined in Java (to a certain extent), C#, and JRuby, now flowing into JavaScript. It’s getting crazy out there. I don’t know if static typing is going to hold onto its edge.
I think that brings us back around to
err
. Everywhere. I really want lisp’s condition system instead. It seems like a waste to define a new runtime, with new managed stacks, that doesn’t have restarts and handlers. With the approach they’ve chosen, half of go code is solving the problem, and the other half is checking and rethrowing err
codes.Go isn’t supposed to have exceptions, but if you can deal with the limitations of it,
recover
is a thing. (But it’s still not Lisp’s condition system, and by convention, panic/recover isn’t supposed to leak across module boundaries.)I forgot about the mess that is vendoring and
go get
ruining everything, but I guess they’re working on fixing that. It’s a transient pain that’ll be gone in a couple more years, too late for my weary soul.But am I wrong? What about the “go is the language of the cloud” thing that Docker, Packer, and friends have started? I don’t think Go is “natively cloud” because that’s meaningless. I think a few devs just happened to independently pick Go when they wanted to experiment, and their experiments became popular.
It surely helps that Go makes it easy to cross-compile machine-code binaries that will run anywhere without stupid glibc versioning issues, but you know what else is highly portable amongst systems? Anything that doesn’t compile to machine code. For instance, the AWS CLI is written in Python… while their Go SDK is still in alpha.
tl;dr
I find the limitations more troublesome than the good parts, on the balance. I recently realized I do not care about Go anymore, and haven’t written any serious code in it since 1.1 at the latest. It’s not interesting on all sides in the way Clojure is.Saturday, February 11, 2012
Layer Juggling
Consider:
I get layers 2 and 3 mixed up so frequently that I typically only have tabs open in vim for a wide-ranging interface change inside my code, where I need to update model, validation, and view/controller all at once. Each of those scopes gets a tab, and the tab is split into windows for each affected file of that particular scope. If I have to muck around in more than two different layers at once, it gets extremely error-prone.
I think this is the reason people try to do everything inside emacs: if it’s run within a single frame, which I boldly claim is the common case, it combines layers 1 through 4 into a common framework, and leaves only layer 6 as important on the desktop. You don’t need workspaces to tame a sprawling collection of windows anymore, because most of them are inside emacs.
Subscribe to my feed for the firehose, or check @sapphirepaw_org on twitter for stuff I deem important enough to bother telling the world about.
- vim windows (Ctrl+W{w, W, h, j, k, l, ...})
- vim tabs (gt, gT, :tab, ...)
- screen session (Ctrl+Z ...) [because I liked Ctrl+A as beginning-of-line]
- terminal window tabs (Ctrl+{PageUp, PageDown, Shift+PageUp, Shift+PageDown, ...})
- application windows, e.g. other terminals (Alt+`, Alt+Shift+`) [a distinction newly required in Unity and Gnome-Shell’s defaults]
- other applications (Alt+Tab, Alt+Shift+Tab) [may include all workspaces]
- other workspaces (Ctrl+Alt+{↑, ↓} for gnome-shell and Unity, additionally Ctrl+Alt+{←, →} for Unity; also with Shift to drag a window with you)
I get layers 2 and 3 mixed up so frequently that I typically only have tabs open in vim for a wide-ranging interface change inside my code, where I need to update model, validation, and view/controller all at once. Each of those scopes gets a tab, and the tab is split into windows for each affected file of that particular scope. If I have to muck around in more than two different layers at once, it gets extremely error-prone.
I think this is the reason people try to do everything inside emacs: if it’s run within a single frame, which I boldly claim is the common case, it combines layers 1 through 4 into a common framework, and leaves only layer 6 as important on the desktop. You don’t need workspaces to tame a sprawling collection of windows anymore, because most of them are inside emacs.
Subscribe to my feed for the firehose, or check @sapphirepaw_org on twitter for stuff I deem important enough to bother telling the world about.
Sunday, August 22, 2010
Quickie: The Cross Platform Quandry
When an app runs on multiple platforms, it seems like there are two basic designs that they can choose to follow. Either they try to integrate with each platform, or they try to appear the same on each platform.
It's not clear to me that either of these ways are correct. Obviously, in the case where the differences between the platforms are hidden to the greatest degree possible, the app doesn't match the look and feel of platform-native applications. This is the situation with old Mozilla builds that drew virtually all the UI themselves: the chosen GTK+ theme had no effect on Linux. An app that looks "the same everywhere" can look like it belongs with at most one platform.
Meanwhile, since Mac users in particular are vocal about their dislike for using non-Mac-like apps, most modern cross-platform apps have switched to trying to integrate with each platform. Firefox has a different theme and adjusts its button order on the various platforms; likewise, GIMP for Windows switches its button order to match the Windows custom of putting Cancel in the corner instead of OK.
As a habitual user of Firefox, Gimp, and Pidgin on both Linux and Windows, this second approach turns out to be less-than-ideal for people who frequently switch platforms. In this case, the "same" app behaves differently on the different platforms, and I have to remember which platform I'm on so that I can hit the correct buttons. Of course, this doesn't always happen, so frequently in Windows Gimp, I spend a couple of minutes selecting the perfect color, only to hit Cancel by mistake. Another frequent source of mistakes is the way that Pidgin's tray icon toggles the buddy list with a double-click on Windows, but a single-click on Linux. I'm frequently opening-then-closing Linux Pidgin with a double-click.
One last problem with writing a cross-platform app for Linux/BSD specifically is that these are not all-in-one platforms. An app like Firefox that's written in GTK and follows the Gnome HIG is still going to fail to integrate with the KDE desktop on the points where their respective conventions differ.
Given these difficulties, it's not surprising that most apps aren't cross-platform. The ones which are face the choice of whether they should integrate with platforms and appear different in the details to people who work on multiple platforms, or whether they should look the same everywhere and look alien or second-class on each platform.
It's not clear to me that either of these ways are correct. Obviously, in the case where the differences between the platforms are hidden to the greatest degree possible, the app doesn't match the look and feel of platform-native applications. This is the situation with old Mozilla builds that drew virtually all the UI themselves: the chosen GTK+ theme had no effect on Linux. An app that looks "the same everywhere" can look like it belongs with at most one platform.
Meanwhile, since Mac users in particular are vocal about their dislike for using non-Mac-like apps, most modern cross-platform apps have switched to trying to integrate with each platform. Firefox has a different theme and adjusts its button order on the various platforms; likewise, GIMP for Windows switches its button order to match the Windows custom of putting Cancel in the corner instead of OK.
As a habitual user of Firefox, Gimp, and Pidgin on both Linux and Windows, this second approach turns out to be less-than-ideal for people who frequently switch platforms. In this case, the "same" app behaves differently on the different platforms, and I have to remember which platform I'm on so that I can hit the correct buttons. Of course, this doesn't always happen, so frequently in Windows Gimp, I spend a couple of minutes selecting the perfect color, only to hit Cancel by mistake. Another frequent source of mistakes is the way that Pidgin's tray icon toggles the buddy list with a double-click on Windows, but a single-click on Linux. I'm frequently opening-then-closing Linux Pidgin with a double-click.
One last problem with writing a cross-platform app for Linux/BSD specifically is that these are not all-in-one platforms. An app like Firefox that's written in GTK and follows the Gnome HIG is still going to fail to integrate with the KDE desktop on the points where their respective conventions differ.
Given these difficulties, it's not surprising that most apps aren't cross-platform. The ones which are face the choice of whether they should integrate with platforms and appear different in the details to people who work on multiple platforms, or whether they should look the same everywhere and look alien or second-class on each platform.
Subscribe to:
Posts (Atom)