Playing With Pain

For the past year, I have been fighting a running battle with my body. The battlefields have been my wrists and back. By and large, my body has been winning.

When sports commentators talk about a player “playing with pain” I think it’s natural to think about the pain in the moment – that play, that sprint, that quick turn on the grass, the game on the line. What doesn’t get talked about is the psychological effect of the pain, day after day, on the player. At practice, at home, at rest. How it changes their relationship to the game.

Playing With Pain

They love the game. Clearly. It’s what they’ve spent their whole life perfecting. But now, every interaction with it is colored by the overlay of pain. Do your warm-ups, work through that early pain, now feel the pain on each play. Good play or bad, it doesn’t matter. It hurts to do the thing.

No matter how much you love something, if you are given a negative stimulus every time you do it, you’ll stop liking it so much. This isn’t psychological weakness, it’s just conditioning. It’s how we train pets; how we try to stop smoking.

I used to take up my work every morning with enthusiasm. Now I take it up because I must, my enthusiasm is very attenuated. And I cannot figure it out for sure: am I not liking the work, is my ennui related to the actual tasks; or have I been conditioned, slowly but surely, to not like it? It’s very hard to tease those apart, because the conditioning works so very deep down in the stack of consciousness, and I’ve been playing with the pain for what feels like forever. I can’t remember what it was like before, anymore.

Anyways, I have a good chair. I’ve gotten a better keyboard and mouse. I ice my wrists every night. Sometimes things are better, sometimes they are worse, but drip, drip, drip, the reinforcement is mostly negative.

I’m only 300 words in, and it hurts.

I’ll stop now. Experience with repetitive strain, magic solutions? Hit the comments. Unfortunately, the only thing that has worked for me so far is not using computers.

LNG eDrive is a Massive Subsidy

Update: Commenter cpnet notes that in EAO documents the proponent estimated a plant power usage of 1,500,000 MWh / year, which is three times larger than my guesstimate. The EAO document notes it is a very conservative (large) estimate, but at the outside it would imply a subsidy three times larger – about $45,000,000 per year compared to the old LNG power pricing deal. It’s probably somewhere between.

The British Columbia government’s new “eDrive” rate for LNG producers is going to be creating new jobs at an ongoing cost of $138,000 per job at the electrically powered Woodfibre LNG plant in Squamish.

LNG eDrive is a Massive Subsidy

Let’s do the math, shall we? Here’s the input data:

Now the math:

  • 2,100,000 tonnes of LNG times
  • 230 kWh of electricty is
  • 483,000,000 kWh per year of useage. Which can also be stated as
  • 483,000 MWh per year. Times
  • $28.68 per MWh in eDrive subsidy equals
  • $13,852,440 per year in foregone revenue for BC Hydro, which for
  • 100 permanent jobs is
  • $138,524 per job

If we want to create 100 new government-funded jobs:

  • Why are we paying $138,524 for each of them; and,
  • Why are they freezing methane, and not teaching kids or building transit or training new engineers.

Government is about choices, and this government is making some batshit crazy choices.

CloudBC: All your clouds are belong to us...

The CloudBC initiative to “facilitate the successful adoption of cloud computing services in the British Columbia public sector” is now a little over a year old, and is up to no good.

CloudBC: All your clouds are belong to us...

Like any good spawn of enterprise IT culture, CloudBC’s first impulse has been to set themselves up as the arbiter of cloud vendors in BC, with a dedicated revenue stream for themselves to ensure their ongoing hegemony.

The eligibility request currently online1 for CloudBC is a master-work of institutional over-reach:

  • Only CloudBC approved services2 can be sold to the BC public sector.
  • Approved services will add an ‘administration fee’ to all their billing3 to the BC public sector and remit that fee to CloudBC.
  • The fee4 will be 2%.

And in exchange for that 2% of all cloud services, CloudBC will provide what in return?

Well, they’ll set the eligibility list, so the BC public sector will be literally paying for someone to tell them “no”. Setting the list will include a few useful services like FOIPPA reviews and making the vendors cough up promises to follow various international standards that nobody reads and few people audit. So that’s something. But mostly just more reasons to say “no”.

I misspent some hours reviewing the agendas [Part-1, Part-2] of CloudBC for the its first year in operation, and among the interesting tidbits are:

  • The request to vendors was supposed to be released in October 2015, but was actually released in fall of 2016.
  • Negotiations with Microsoft for Office 365 and what was dubbed the “Microsoft opportunity” were started in summer of 2016, but shut down in spring of 2016: “decision to communicate that CCIO5 will not pursue the deal as presented by Microsoft”
  • Taking the website live was targeted for June 2016, but as of writing it remains “under construction”.
  • Spring 2016 plans include contracting with a vendor for a “CloudBC digital platform”, so we’ll at least have an expensive under-utilized web presence “soon” (no RFP exists on BC Bid).
  • CloudBC was budgeted $1.6M for year one, and managed to under-spend by about 20%. Getting almost nothing done has it’s benefits!
  • An office and several staff have been seconded, so from an institutional existence point-of-view, CloudBC is off to a roaring start.

When I first heard about CloudBC, I was pretty excited. I naïvely thought that the mandate might include promoting, for example, cloud infrastructure inside BC.

Our FOIPPA Act requires that personal information of BC citizens not be stored outside the jurisdiction or by foreign-controlled corporations. That makes using cloud services (usually hosted outside BC, usually owned by foreign corporations) a hard lift for government agencies.

Wouldn’t it be nice if someone did something about that? Yes it would. cough

While setting up “private cloud” infrastructure is anathema (it’s very hard to find success stories, and all signs point to public cloud as the final best solution) in BC there are some strong incentives to take the risk of supporting made-in-Canada clouds:

  • Thanks to FOIPPA, the alternative to made-in-BC cloud is no almost no cloud at all. Only apps with no personal information in them can go on the US-owned public clouds, which is a sad subset of what government runs.
  • There are other jurisdictions and other technology domains that need non-US sourced cloud infrastructure. Seeding a Canadian-owned-and-operated PaaS/IaaS cloud industry would open the door to that marketplace.

“Just” getting the FOIPPA Act changed would be the cheapest, “simplest” solution (ignoring the humungous, intense, non-negotiable, insuperable political issues). Since that’s unlikely to occur, the alternative is DIY. I thought CloudBC might be that initiative, but turns out it’s just another enterprise IT control-freak play.

  1. Search for ON-002797
  2. “As only Eligible Customers with a written agreement in effect with the Province will be permitted to use the procurement vehicle established by this Invitation, including the CloudBC Marketplace, the Province intends to establish and maintain a list of Eligible Customers on the CloudBC Marketplace for use by Eligible Cloud Providers.”
  3. “CloudBC Framework Agreements will appoint and require the Eligible Cloud Provider to collect and remit as agent an incremental Administration Fee to be paid by Eligible Customers with Contracts in order to fund the CloudBC operations administered by the Province.”
  4. “An amount equal to 2% of the fees for all services provided”
  5. BC Council of Chief Information Officers (CCIO)
  6. All your base are belong to us

Geomatiqué 2016 Keynote

This week I had the pleasure of presenting the morning keynote at Geomatiqué 2016 in Montreal. I’ve been thinking a lot recently about symbiosis of technology and culture: how new technology is generating new norms to go along with it. We humans are enormously adaptable, so princples that were sacrosanct to one generation become unknown to the next, and back again.

Geomatiqué 2016 Keynote

On the chopping block for our generation: privacy.

Not that privacy is any human absolute. I doubt a hunter gatherer had a lot of personal space and privacy: the smaller the group, the more fevered the gossip-mill. On the other hand, the abolition of privacy within the context of an industrial-sized polity will truly be something new under the sun. It could be fine, in its way; it could also be Nineteen Eighty-Four realized.

Anyways, the talk is mostly a survey of technology trends, with some philosophizing at the end. Unfortunately, no video at this event, but if you’d like me to deliver this talk to your organization, drop me a line.

PgSQL Indexes and "LIKE"

Do you write queries like this:

SELECT * FROM users 
WHERE name LIKE 'G%'

Are your queries unexpectedly slow in PostgreSQL? Is the index not doing what you expect? Surprise! You’ve just discovered a PostgreSQL quirk.

TL;DR: If you are running a locale other than “C” (show LC_COLLATE to check) you need to create a special index to support pattern searching with the LIKE operator: CREATE INDEX myindex ON mytable (mytextcolumn text_pattern_ops). Note the specification of the text_pattern_ops operator class after the column name.

As a beginner SQL student, you might have asked “will the index make my ‘like’ query fast” and been answered “as long as the wildcard character is at the end of the string, it will.”

PgSQL Indexes and "LIKE"

That statement is only true in general if your database is initialized using the “C” locale (the North America/English-friendly UNIX default). Running with “C” used to be extremely common, but is less and less so, as modern operating systems automagically choose appropriate regional locales to provide approriate time and formatting for end users.

For example, I run Mac OSX and I live in British Columbia, an English-speaking chunk of North America. I could use “C” just fine, but when I check my database locale (via my collation), I see this:

pramsey=# show LC_COLLATE;
(1 row)

It’s a good choice, it’s where I live, it supports lots of characters via UTF-8. However, it’s not “C”, so there are some quirks.

I have a big table of data linked to postal codes, this is what the table looks like:

              Table "gis.postal_segments"
      Column       |     Type     | Modifiers 
 postal_code       | text         | not null
 segment           | character(4) | 
    "postal_segments_pkey" PRIMARY KEY, btree (postal_code)

Note the index on the postal code, a standard btree.

I want to search rows based on a postal code prefix string, so I run:

SELECT * FROM postal_segments 
WHERE postal_code LIKE 'V8V1X%';
                                              QUERY PLAN                                              
 Seq Scan on postal_segments  (cost=0.00..2496.85 rows=10 width=68) (actual time=30.320..34.219 rows=4 loops=1)
   Filter: (postal_code ~~ 'V8V1X%'::text)
   Rows Removed by Filter: 100144
 Planning time: 0.250 ms
 Execution time: 34.263 ms
(5 rows)

Ruh roh!

I have an index on the postal code, so why am I getting a sequence scan?!?! Because my index is no good for doing pattern matching in any collation other than “C”. I need a special index for that, which I create like this.

CREATE INDEX postal_segments_text_x 
  ON postal_segments (postal_code text_pattern_ops);

The magic part is at the end, invoking text_pattern_ops as the opclass for this index. Now my query works as expected:

SELECT * FROM postal_segments 
WHERE postal_code LIKE 'V8V1X%';
                                                           QUERY PLAN                                                           
 Index Scan using postal_segments_text_x on postal_segments  (cost=0.29..8.31 rows=10 width=68) (actual time=0.067..0.073 rows=4 loops=1)
   Index Cond: ((postal_code ~>=~ 'V8V1X'::text) AND (postal_code ~<~ 'V8V1Y'::text))
   Filter: (postal_code ~~ 'V8V1X%'::text)
 Planning time: 0.532 ms
 Execution time: 0.117 ms
(5 rows)

I have gotten so used to PostgreSQL doing exactly the right thing automatically that it took quite a long time to track down this quirk when I ran into it. I hope this page helps others save some time!