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 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.

Wednesday, June 24, 2015

Cheating via Lookup Table

One of the assignments in college was to write a binary-to-decimal converter in MIPS assembly, of all things. The goal was, given a 32-bit unsigned number like 0xdecafbad, print out “three seven three seven eight four four six five three”. Or “six four” for 0x40.

So the professor got 150 submissions like

print_digit:
  cmp #0
  beq print_zero
... nine more digits ...
print_zero:
  (load address of "zero" string)
  (call library function to actually print)
  rts
... nine more digits ...

I almost coded mine the same way, but I asked myself, “I don't want to write the same code for ten cases. How would a real hacker solve this?” So I made a lookup table of pointers to each string, and my function was more like:

print_digit:
  (load value from "string_addrs + digit")
  (call library function to actually print)
  rts

Of course, I’m just showing snippets of the core function; everyone had to write their own complete program.

The prof had apparently never seen my approach, because he asked if I had even run it to see if it worked. In shock, I said something like, “Yeah, why? Didn’t it work for you?” and he replied, “Um well yes. I just thought you maybe cheated.”

Haha, no. I’m just awesome.

Thursday, May 28, 2015

Apache, FastCGI, and the Authorization header

I couldn’t find much about why Apache (up to and including 2.4.x) doesn’t pass the HTTP Authorization header to FastCGI by searching the Internet, so I fished through their source code.

There’s a function that sets up the default variables to pass to CGI programs, called ap_add_common_vars. This function expects that other users on the server can see these variables with ps -e, so to hide usernames and passwords from appearing in there, it specifically avoids passing Authorization through to CGI.

FastCGI uses the same ap_add_common_vars function, and mod_proxy_fcgi doesn’t take any special care to put the Authorization back in for requests that are sent over a socket. Thus, by default, no FastCGI requests will receive usernames and passwords.

The standard workaround is to use mod_rewrite to set an environment flag if the request has authorization. Because nothing unsets the Authorization—ap_add_common_vars simply skips setting a default—that explicitly-set environment variable will be included in the FastCGI request.

RewriteCond %{HTTP:Authorization} .
RewriteRule / - [E:HTTP_AUTHORIZATION=%{HTTP:Authorization}]

That’s fine if you’re already using mod_rewrite. Can it be done without that module? I haven’t benchmarked the difference, but mod_setenvif can do it via the rule:

SetEnvIf Authorization (.+) HTTP_AUTHORIZATION=$1

tl;dr: Authorization isn’t passed to FastCGI because of the default protection from exposing passwords with slow CGI. It can safely be passed to a FastCGI server (requests are sent over a socket, not through world-readable process attributes) but it must be explicitly passed.

Updated 28 Jul 2015: I finally tested the SetEnvIf rule. I also mentioned what Apache line I'm working with.

Monday, April 20, 2015

Hacking my Habits: screen vim → gvim

I spend much of my time using the screen command inside a VM, opening vim in a new window by running screen vim.  When I'm on bare metal, then, sometimes I accidentally start a whole screen for a quick edit, and I don't realize it until I exit vim and it says, [screen is terminating].

So I built a little function into my ~/.bash_aliases (sourced from the default .bashrc) on the host machine:
# if I run `screen vim` outside of screen, invoke gvim instead.
screen() {
 if [[ $1 = vim && -z $STY ]] ; then
  shift
  gvim ${1+"$@"}
 else
  command screen ${1+"$@"}
 fi
}

Now "screen <anything but vim>" will run screen, and "screen vim" will invoke gvim.  The latter may surprise me, but it'll be what I actually want.

Update: I put similar code inside the VM to convert "gvim" into "screen vim" or regular "vim", as appropriate. Now I abuse this all the time to save three keystrokes ("gvim" vs "scr<TAB>vim").

Monday, March 23, 2015

Timezone Fail

Okay.  Who messed up timezone handling so badly that it's “not safe” to rely on the system?  If it’s actually unsafe, how is date_default_timezone_set() or an equivalent ini_set any safer?  You could just as easily set an Evil Attack™ Timezone with them.

(And who formatted this message so poorly?)

Tuesday, February 24, 2015

Broadband Asymmetry

Someone, somewhere on the intertubes, recently asked: “Why are we seeing 10:1 speed asymmetry?”

I’m pretty sure the speed asymmetry started for good technical reasons: through some signal magic, companies could deliver 48+ Kbps down and 33 Kbps up. ADSL took advantage of the technological landscape of the time (browsing and email were asymmetric) to deliver faster speeds where the customers cared, and indeed, my first DSL services were (if memory serves) in the 1.5/0.38 Mbps area, only a 4:1 asymmetry. My current service is ADSL at 9.3:1 (7.0/0.75), which is both notably closer to 10:1, and hasn’t qualified as broadband since the 4/1 Mbps definition went into effect.

Even though YouTube made video hit the web in a big way—they were there at the crossover point between better codecs and better bandwidth, plus some cleverness* on their part—most traffic was still downstream. The video being delivered was much larger than the return traffic that acknowledged receipt of the video.

The restricted upload rates are thus firmly grounded in historical reality, and they persist today because, I suspect, of two reasons.

One, there’s obviously a chicken-and-egg problem where uploads are less frequent because upload rates are low, and the rates are lower because uploads are less frequent. There’s a natural tendency for uploads to be less frequent anyway (how many funny cat pictures do you look at per picture you upload?) but low upload rates discourage actual upload usage in and of themselves.

Two, I think ISPs are rewarded if they keep upload rates low. Settlement-free peering has traditionally required each side to send “about equal” traffic as the other. If an ISP strongly encourages downloads through 10:1 or more asymmetry, then they will never come close to sending “about equal” traffic out of their network... and they can demand payment from anyone who wants access to their customers, such as Netflix.

I still believe that ISPs should be charging their own customers enough to support their own customers’ data requests including adequate network investment, but that doesn’t invalidate the reality.

As for 10:1 specifically, I can only speculate. It may be, that’s simply the size where sending email and uploading to Facebook “doesn’t seem to take too long” for users. And if more people sent more video to Facebook, then ISPs may reshuffle their plans to provide more upstream “so you can Facebook.” Regardless, in the absence of an obvious technical reason, I must assume it serves a specific marketing purpose.

* At one time, they showed 320-pixel video in a 425-pixel player. Although scaling technically hurts quality, it crossed the gap between “small” and “nicely sized,” looking much better on 1000-pixel browsers.

Monday, February 23, 2015

Perl is Dying

I like Perl. It's been a part of my life for over 14 years, since I had 5.6.0 on Red Hat 7.0. (Funny how Red Hat Enterprise is now 7.0, and the desktop project hasn't borne the name for over twenty releases.)

But, I'm getting the distinct impression that the language is losing its community. It seems to be getting too small to keep up with the nice things.

Case in point: AWS. Trawl metacpan.org, and there's no coherent set of packages for using Amazon services. There are some Net::Amazon modules, some Amazon modules, some AWS modules, and SimpleDB::Client doesn't even have Amazon in the name. UPDATE (2020-08-08): This update has been a long time coming, but I discovered and switched to Paws sometime in 2018. On the other hand, Paws::S3 (S3!!!) issues a warning on load that it's not finished. Yea, unto this very day.

Then there are the duplicate packages like Net::Amazon::DynamoDB and Amazon::DynamoDB, which are worlds apart. The former supports practically the original DynamoDB API, using signature version 2, and accepting numbers, strings, and sets of those types as data types. Not even binary types. Amazon::DynamoDB uses the version 4 signature and an updated data model, along with an async client built on IO::Async. Yes, seriously, in 2014 someone didn't use AnyEvent.

This wouldn't be so much of a problem if I didn't sail straight into RT#93107 while using it. The most insidious thing is that fds only get closed sometimes, so it mostly seems to work. Until it doesn't. But there's a patch... That's been open without comment for many months.

This is not unlike another patch, for AnyEvent::Connection, open even longer. I can understand if the maintainer thinks it's unimportant because it's "only a deprecation" or because an updated common::sense avoids the issue on affected Perl versions. But to not even comment? The package is apparently dead.

I recently ran into a little trouble finding any OAuth 2.0 server modules. I didn’t see anything general, nor anything for Dancer to be an OAuth server. We have plenty of clients and client-integrations to providers, though, and it didn’t take my boss long to find a PHP library that he wanted to use.

But enough about CPAN. Let’s talk Perl core.

Perl has been adding numerous ‘experimental’ features over the years. Since 5.16, the current status of all of these has been gathered in the perlexperiment documentation. Though 5.20.1 has now been released, there are items on that list introduced in 5.10.0.

An experimental feature that is neither accepted nor rejected is dead weight. Authors are discouraged from using them, so they’re not benefitting the majority of users, yet they require ongoing maintenance and care by the perl5-porters. An experimental feature that stays experimental for far, far longer than the deprecation cycle is the worst possible outcome.

Just imagine being excited about Perl and having conversations about, “Can it do «cool thing»?” or “Have they fixed «wart» yet?” and having to respond “Well, it’s experimental, so technically yes, but you shouldn’t use it.”

Eventually, that conversation is going to come down to “Why don’t you use «Ruby|JavaScript|PHP» instead? They have more cool stuff, and only one object system.”

Even if Perl made a major push to accept experimental features in “the next release,” there’s anywhere from months to years before that release is widely deployed as a baseline. Unless one wants to build their own Perl every week for their fresh cloud images, which is a whole other can of worms.

Meanwhile, the more unique stuff about Perl—regex syntax, contexts, sigils and their associated namespaces—aren’t exactly banner features anymore. Other languages have been absorbing regex syntax, and the rest of it tends to create bugs, even by authors who understand it all. That’s especially problematic when I change languages frequently, because the Perl-unique stuff takes longer to reload in my head than the rest of the language.

Overall, I’m thankful for what Perl has been for me. However, it seems like it has lost all its momentum, and it doesn’t have anything particularly unique to offer anymore. Certain parts of it like @_ and the choose-your-own-adventure object system feel particularly archaic, and I have to interact with them all the time.

Overall, it seems like basic stuff (IO::Poll working with SSL, please?) and easy fixes aren’t being taken care of, while new code isn’t showing up or isn’t high quality. If CPAN can’t keep up with the web, and the web is eating everything, then Perl will be eaten.

You are in a twisty little maze of event backends, all different.
Most of which can use most of the other backends as its own provider.

It pains me to write this. I don’t want to sound like a “BSD is dying” troll. I know I’m throwing a lot of criticism in the face of people who have put much more into Perl (and making Perl awesome) than I have. Miyagawa is perhaps singlehandedly responsible for why our API server started its life in Perl. But he can’t do everything, so the present signs are that no new Perl will be added to our codebase… because doing so would burden our future.