Monthly Archives: February 2016

How am I supposed to do my cargo cult encapsulation in AngularJS?

A computer science degree and years of engineering best practices have given me a very specific anxiety disorder. Whenever I see a public member variable, I feel intense distress. Something like:

public class Coordinate {
    double x;
    double y;
}

makes me physically ill. You know that study where the MIT Professor asked people to do mean things to Furbies?

...in a small experiment conducted for the radio show Radiolab in 2011, Freedom Baird of MIT asked children to hold upside down a Barbie doll, a hamster and a Furby robot for as long as they felt comfortable. While the children held the doll upside down until their arms got tired, they soon stopped torturing the wriggling hamster, and after a little while, the Furby too. They were old enough to know the Furby was a toy, but couldn’t stand the way it was programmed to cry and say “Me scared”.

-- Would you murder a robot?

That's how I feel about making things public that can be made private. Stop doing that to that poor class! Stop it!

Most of my work now is in AngularJS. If you're not familiar, the 101 of it is that if you want to display something, or have a form, you use a special syntax in a template and all the changes will be magically wired together and appear.

<div ng-controller="MadeUpCtrl">
 <form>
   <input type="text" ng-model="MadeUpCtrl.text">
 </form>
 <div>
   {{MadeUpCtrl.text}}
 </div>
</div>

When you type things in the form, they display in the div below without any real effort. You do have to have a variable named text in the controller, even if it has no value. (You can do {{text}} but there a lot of reasons not that I find too boring to explain now).

But wait, you conveniently ask, isn't that mucking around with some other object's internal variables? Yes, yes it is. "text" is a public member variable and we are doing terrible, terrible things to it.

The problem is that there's no real way around this. The usual getText() setText() monstrosity won't work -- it has to be a value, not a function that returns a value. How does Angular know getText() will return something different? Well, you'd have to tell it.

That creates a disaster like this. Template:

<div ng-controller="MadeUpCtrl2">
 <form>
   <input type="text" ng-model="MadeUpCtrl2.exportText">
 </form>
 <div>
   {{MadeUpCtrl2.exportText}}
 </div>
</div>

Controller:

MadeUpCtrl2 = function($scope) {
  this.text_ = "";
  this.exportText = "";
  var self = this;
  // this fires when exportText changes
  $scope.$watch(this.exportText, function(exportText) {
    self.setText(exportText);
  });
}
 
MadeUpCtrl2.prototype.setText(text) {
  this.text_ = text;
}
 
MadeUpCtrl.prototype.getText() {
  return this.text_;
}

The problem is that this is awful. If you want to do anything interesting in setText, let's say escape some html, you're going to have to push it back to exportText to make it visible, and then that's going to trigger another $watch...

Looks like I just have to live with it.

Three years to build a ship, three hundred to build a tradition

 

I

As a shut-in who hates sunlight, I am a big user of Amazon Prime. Most things I order from Amazon are things I should not order from Amazon. They are things I should get for myself, but do not, because I really am too goddam lazy to just walk five goddam minutes to the store.

Unfortunately for my laziness, Amazon has started its own shipping service. It is not very good at delivering packages to my door. It is, in fact, quite bad. Google "AMZL_US", it's a world darker than "Untied Airlines."

So far I am 0 for 2 on packages delivered via them actually showing up — Joseph K. logged into his Amazon account to see that two nothings had been delivered to his doorstep. Phone service was very helpful, as soon as they realized the orders were sent via Amazon's own shipping service they offered to send replacement orders for free. "No need to bother asking if he's looked for it," the nice woman in the North Carolina phone bank thinks to herself. "We know there's nothing there. We've never successfully delivered a package."

II

I live in an apartment complex. My address looks something like this:

XXX Streetname
Apt YYY

If you live in an apartment complex, I would like you to conduct a little experiment. Go to the unit where XXX and YYY are the same, something like

123 Streetname
Apt 123

If your complex is anything like mine, they will have posted signs everywhere. The first will seem reasonable — "Please check Apt number on package" — and then you'll see another, more aggressive, it's strokes rushed — "Do not deliver unless Apt # is 123, this is only for Apt 123" — and then another, gashed into the its canvas in a frenzied hand, its ink a dark red that makes you wonder where it came from — "ONLY APT 123 DELIVERIES YOU HAVE BEEN WARNED TURN BACK"

If you're feeling particularly adventurous, tape up a box, put on your best UPS Browns, and knock on their door. Listen to the tears of the children, "Daddy! Make it stop!" Look at the mother comforting the children, "Daddy will make the bad men stop!" Look into the mad eyes of the man holding the double barreled shotgun. Do what the man tells you. Read off the Apt number on the box, nice and slow.

I probably should have mentioned this earlier — write "Apt 123" on the box.

III

You know how your friends are stupid morons who take forever to find your apartment even though you gave them the address and directions? You know how you spend fifteen minutes trying to get to a restaurant, because the streets don't make any sense here, dammit, but you know you're real close?

My parents house is on a corner. It has two driveways that open to two different streets. One is fairly simple. If I am in the car, I will insist you use that one. If you come from the main street without me, you will see the other approach, a nice big driveway to turn into, made for cars. "Hey, I'm driving a car!," you think to yourself. "Let's turn into that driveway," you say in your best teen-in-a-horror-move-voice, "what's the worst that could happen?"

It is a trap. Do not go in there. It is a twenty foot curved stretch of asphalt with with steep ten foot drops to either side. Better drivers than you have tried to back out and had a to call a tow truck to pull them out of the ditch. Most had to call another, more expensive tow truck that can hall semis, because the regular tow truck is unable to help a car that falls down there. That's how fucked up this driveway is.

Listen to me. I was born on this driveway, molded by it. I didn't back up a straight driveway on flat ground until until I was twenty two. I am the baddest fucking sherpa on this shitty little Everest. Hand me your keys.

IV

Your mail always winds up where it's supposed to be. The USPS mail carrier on your route figured out all the little stuff the first few weeks on the job. The family at Apt 123 caught them as they were delivering one day, had a short conversation, and now they get only their mail and wave every time it's delivered. Nice bunch of people.

Every new person and new organization has to start from scratch. The Amazon couriers haven't done this before. If their annual turnover is only in the high double digits I would be surprised. Guess what? Every new guy has to figure that out, and they mess up a lot.

I think this is why the older people I know are so wistful for the good old days where the person at the store really knew who you were and really knew what they were doing and all that Leave it to Beaver stuff. That experience is unfathomable to me. Of course the clerk has no idea what they're doing. Of course you have to Google around and do everything yourself. Of course sometimes you get the wrong thing and no one will help you and you will be out of luck. That's how it works.

V

There are two basic facts at play here.

  1. The employer wants employees to be as fungible as possible to keep costs down.
  2. Doing the job well requires extensive domain knowledge only applicable to this one situation. There's no way to scale it.

They don't really play well together. Some ways to resolve this:

Compile all collective wisdom in a Great Wiki

Imagine if you wrote down everything you did at your job as you did it. Almost all of the ways things actually get done aren't written down, you just sort of found them out from somebody else who learned from someone else. Well, now they're written down. Now they can look it up in the Great Wiki.

To equal what someone would know after years on the job delivering packages in a neighborhood, the Great Wiki would have an entry on every house in the region. The first few days on the job would consist of the new hire studying all these facts. Some of them will be out of date when they get there, which will cause some mixups. Mis-delivered packages aren't great, but there are much worse disasters an organization can creation with this level of effort. Imagine:

"Yes, ma'am, we need your signature on every package. Why? Uh, well you know, so they don't get stolen," the delivery person says. "The system says code 131, 'probable family member with an addiction.'"

"Ellen's been clean three years. How do you know — no. What!? No."

"Let me just make a note of that in the system —"

"Why are you writing this down!?"

"You don't want me to make a note of that?"

"Why do you have this!? Stop writing! Get rid of it!!"

"The record is inaccurate. Do you want me to update it or delete it?"

"Delete it! Delete everything!"

"Okay."

"How do you know all about this!? How do you know all of this!? Where's Julio!?"

"Julio retired, that's what I'm here. I've read all about you, Mrs. Wallace, nice to finally meet you."

Contract out everything to the same local guys

In this situation and UPS and AMZL_US and FedEx all subcontract out to local people who stay around longer and can build up the knowledge to actually do things well. Maybe UPS doesn't like their current subcontractor, they can probably make do with their business from FedEx. If it really fails, and goes out of business, the other subcontractors will probably need to hire people who have been working the area.

I don't know how much UPS and FedEx contract out vs do in house, but I think there's a mix. The issue is that someone always wants to be The Emperor of All Things, and that requires having your own little army rather than borrowing someone else's.

Do a bad job, but cheaply

Pretty much what happens. Hope my packages get delivered the second time.

DIRECTORY_HAUNTED_DO_NOT_OPEN = true;

Many years ago I did not read the documentation for PostgreSQL.

To make my database "more parallel" I started up multiple database servers aimed at the same hapless directory. This does not work. What's worse, it doesn't work, but only after appearing to work for a while.

The multiple PostgreSQLs will start up and one will get the lock on the directory necessary to actually operate it as a database. The others will answer your requests and make a bunch of tiny little files for the database transaction in a tmp folder that I presume it cleans up when it gets a lock. In retrospect, I'm kind of amazed I managed to wreck something this badly, the one that got the network port must not have been the one that got the database lock.

This insanity happened for a day under reasonably heavy load before I came to our senses and undid this. The problem is that PostgreSQL tries to run all these transactions back when it reboots, and is unable to say their names.

For example:

C34D699D0DFFA570A520B92B7C69426646A10C12B2F4DE5DFC530C0B872BECA5
616225FCA474CA481CBA75021AEC46D5F77B47C130DE3F48308CCD9B920F12CE6
8961C9A446FF60B4B2BB4751703DEE879D062984315D576F1755E62BFD6EE7C694
6646A10C12021AEC46D5F77B47C481CBA7502F60B4B2BB47F60B4B2BB47308CC1

Would not be an unusual filename for one file. And there were millions of these. The files themselves were much smaller than their unique names. Something inside the code was doing a wildcard, and trying to read in millions of unique names into memory would hit the memory max very quickly and throw the server into swap hell.

A simple

  $: ls *

would load the millions of unique names into memory hit the memory max and throw the server into swap hell. Guess what

  $: rm -rf *

does? That's right, it expands the wildcard and tries to load the gigs and gigs of names of files into memory until it hits swap hell, but recursively.

I know now the right answer involves find with arcane flags, but I didn't know how to do it then. Deleting it was impossible, but I could move it — mv doesn't need to know about the children. The junk folder lies until the end of time at /var/ryleh, where dead Cthulu waits dreaming.

Capitalism

Preach, Eevee, preach

That’s all great, except (a) I’m writing a 2D tile game in Python and really don’t care if my video card is only at 99% efficiency, (b) I don’t control the original code and am not really positioned to learn the entirety of OpenGL so I can port someone else’s entire library to a thing that half their target audience doesn’t support, (c) fuck you.

We have always been at war with UI

How the Sausageable is made

It is a fact universally acknowledged that a program accessing a resource must be in need of an abstraction. In a lot of situations once you add one abstraction you need to add another just to deal with that. What's the point of having a Sausageable if you have to buy and butcher the Butcherable inherits Buyable yourself? Thus the SausageableFactory.

That's a pretty easy problem to spot, since the product and the result are so close to each other. It feels like work to do kill the animal all by yourself. The real problem starts when you get more abstract than reality. Let's take this interface here:

1
2
3
4
5
6
7
8
9
Name ::= <string>
DataObject ::= <boolean> | 
               <number> |
               <string> | 
               <Name> | 
               <Array<DataObject>> |
               <Map<Name,DataObject>> |
               <Array<byte>> |
               <null>

Let's say most of the work in a program happens on big lists of DataObjects, which could be any of a half dozen different types. This is fine. You can do a lot with this, you can nest them and it makes a good wire format. Then you start to see a lot of functions like this:

  print(DataObject[] obs);
  syncWithAdobeMiddleware(DataObject[] obs);
  infectYourComputerOnLoad(DataObject[] obs);

Yup, this is the PDF format. The api is more abstract than we are; we only care about PDFs. This spec can do a lot more than will ever be done with it. It's a close cousin of the millions of Java ThingDoer.java interfaces that only have one friend in the whole world, ThingDoerImpl.java. These interfaces aren't decoupled, they're just pretending to be.