Friday, May 20, 2016

Integrity?

Some years ago, the elder ex-teen (now the mother of two) and I spent some time in Professor Carter’s book integrity, which goes into various areas: intent, due diligence and so on. In other words, integrity means more than simply not telling lies. When put that way it seems obvious, though I don’t usually pay so much attention.

The question of integrity came to mind recently when a friend (I’ll call him “Dieter”) told me about an incident at work. Dieter’s a software guy, like me, and his company’s website (I’ll call the company “JCN”—not the real name) describes a project they did internally. In the article is a statement of why they did this project. The statement is not true; JCN actually did it for a completely different reason than their website says.

JCN’s stated corporate values include words about ethics and integrity, and they have an email “hotline” for that, so Dieter sent them a note pointing out that, paraphrasing, “Our website says the project was ‘first and foremost’ about doing X better, which everybody knows is not true.”

In fact, when the project went “live” at JCN, X was much worse. Dieter admits that today, X is not that much worse than it was before the project. That said, the project really wasn’t about improving X; it was done for a completely different reason.

Dieter acknowledges that this false statement isn’t critical to the company. They’re not promising something their products can’t deliver; nobody’s going to sue JCN or cancel a purchase order because of this statement. But as Dieter told the “integrity” people at his company,

When we make a statement about why we did something, and that statement is not true, that is what makes it a lie.
Please remind me not to get into arguments with Dieter.

JCN’s “integrity” people didn’t see it that way. Dieter was quite bugged by this; he even considered leaving JCN for another employer. But then remembered a couple of things.

  • He’s an American; he knows that his government has killed people in other countries and overthrown democratically-elected governments. But he’s not thinking to become a citizen elsewhere.
  • The prophet Daniel worked for a cruel and arbitrary boss, King Nebuchadnezzar. But would Daniel have quit, given the chance? Probably most bosses at the time were pretty similar, and maybe incompetent to boot. The same thing is probably true of American corporations.
Dieter came to understand that when the company says “integrity,” what they mean is, “Don’t do anything illegal, anything embarrassing, anything that will alienate a customer.” He wasn't happy with that conclusion, but anyway it was a conclusion.

Something else happened that I thought very interesting. After concluding his dialogue with JCN’s “integrity” folks, he told me, “my back stopped hurting!” His back has been complaining (yeah, he’s old enough for that) for some months. The pain hadn’t been debilitating, but he says that was the first afternoon when his back didn’t hurt at all.

What brought relief to Dieter’s back? Was it his acceptance of his employer's Newspeak, like the 5th stage of death and dying, that did the trick?

And what’s the moral of this story? Dieter doesn’t know. Neither do I

Tuesday, May 17, 2016

Confession: taking one for the team

Last week, I sent out a confession at work. I'd read an encouragement to do things like that, and…well, it's pretty self-explanatory. Here's a lightly edited version:
   From: collin <email.address@here>
     To: <recipient-list here>
   Date: Last Tuesday
Subject: Confession

Short version: I did something dumb and confess it.
Busy people can stop reading here, though I hope you read this at some point--maybe while waiting for one of your tests to complete. Details follow.
I picked up a free copy of The Soft Edge when they were being handed out at the cafeteria some weeks back. In it was an encouragement to celebrate successes and also to confess mistakes--especially big successes and big mistakes (cf. “Asoh Defense”).

I saw the power of this a while back when a colleague told me about a mistake, looking somewhat sheepish. “We’ve all done that,” I said. Just to make sure, I added, “I’ve done it myself.”

Well, I’m not the most empathic guy but I felt the weight lift off their shoulders. “You’ve done it?” they asked, incredulous. Yep. It was probably about 20 years ago, but I’ve done stupider things before. And since.

Fast forward to the present. There have been lots of failures in <test case name here>. Some of them happen only when nobody is watching, and have defied analysis. But one of them should have been fixed (by me) right away: burt987303.

It happened in February, then again 8am on May 2. The symptom was a timeout on a “d-volume-create” zapi. “Hey,” I thought, “if the simulator (in this case) can’t come back within 100 seconds, then maybe it died. I could look more, but since it won’t happen again for another 2 months, how much time should I spend on this?”

The answer was: Just a few minutes more--long enough to RTFM and adjust the timeout. You see, it happened again May 4th. You can read <internal document name here>, but the short version is that zsmcli has a “timeout” parameter: I coulda just set that in the command to extend the default 100s timeout.

I’m happy to tell you that I checked in a fix, and that said fix prevented another failure on 5/7 (in <log file name here>, there’s a 118-second d-volume-create execution).

To be clear, the issue was in a test script; the issue wasn’t in the product. I’ve introduced, or incorrectly fixed, product defects before, but this particular issue is in a test case, not in any product sold by my employer.

Is there a moral to the story? Well, the obvious one is to rtfm. Or the help message, as the case may be.

The second is, if you’ve done something like this (it could be more or less dumb; we’re not being precise), don’t feel too bad about it. Performance reviews are over; you could tell somebody. If you’re more senior--or just old--you could tell someone younger; it’ll probably help them feel better. And that in turn might help them think more clearly, too.

cheers,

Why did I say that telling a younger person about your mistake might help them think more clearly? Because when we reduce the pressure they feel to appear perfect (even if the pressure originated inside their own head), they’ll have less anxiety—less stress. Less anxiety, clearer thinking.

It also makes you appear more human, more real. And we need more of that—more live, human connections (as distinct from mere contractural, transactional connections) in the workplace. Out of the workplace too.

Wednesday, May 04, 2016

Too Thorough? part deux

In part 1, I tried to make the point that when a VP or Director calls someone “too thorough,” s/he may mean
“You're giving me too much detail (which I don’t want/need to know); let's get to the high-level information (which I do need to know).”
In other words, sometimes our presentation doesn't match the audience. I resemble this remark, I hope progressively less so as the years have passed.

Another way we're sometimes “too thorough” is that sometimes we spend too much time delving into details that have no bearing on the problem we're trying to address. By the way, I sincerely do mean “we,” as this post attests. About 3/4 of the way through that post, I wrote, “In other words, I was done.” I could have stopped there. Arguably I should have, since I demonstrated that my explanation fit all the facts, and that my code change banished the symptom.

That last sentence is the key. We are not FreeBSD maintainers; we are FreeBSD users. As such, once we know enough to plausibly assert we know what's going on, and to demonstrate that we can make the symptom vanish, we know enough, period.

So why did I continue there? No doubt some of it is a kind of engineering curiosity, not altogether a bad thing. It was exactly that engineering curiosity that drove me to ask my colleague to configure a virtual machine with a disk that could take coredumps, and to find the uninitialized struct component. That is, a certain amount of engineering curiosity is required if we're to make progress. I'll claim it's worse to have too little curiosity than too much, though the truth is probably more nuanced than that.

Early in my career, my manager wrote on a review that I tended to work fast and rely upon experiment. This was a nice way of saying that I sometimes rushed in with an answer without fully assessing the situation. He was right, of course. Back in those days, I would never have written that blog post, because the experimental result would have fully satisfied me; I'd be on to the next thing.

Is it just curiosity then? I guess there's some sort of pride in there, too—the desire for mastery. I love it when I have a complete explanation for how something happened—when I've mastered it. Of course that's not what my employers pay me for; they pay me for solutions to problems that they choose.

The next question for an engineer is: What problems are worth my attention, my curiosity? Senior people are supposed to just know; if something looks odd, is that something worth looking at today, or can it be safely ignored until it becomes a real problem? Is the "obvious answer" truly the answer, or does it simply make the "root cause" harder to find?

Well, we don't know. We need to look far enough to feel confident enough to make a decision, and we need to be lucky enough to not get blindsided too much.

So what's my plan? I'd like to say that the next time I'm hot on the trail of something, I'll stop and think, "Do I truly need to be investigating this?" and make a sober assessment of whether I'm being compulsive, vs. just exercising due diligence.

Maybe that's like saying, "The next time I'm about to say something stoopid, I'll bite my tongue." Does that sound totally useless? Well, if I can remind myself that I have this tendency, or limitation, that's the first step, right? As the engineering guru Clint Eastwood said, "A man's got to know his limitations." Or weaknesses. And of course women do, too.


Well, that was a lame ending. That's because I don't really have this one figured out. Maybe you have some ideas? Leave me a comment :)

Monday, April 25, 2016

Citizens?* Or mere taxpayers?
[* I don't mean Citizens United]

In a recent Harper’s, Marilynne Robinson remarked that whereas our society used to have citizens (who may have a sense of identity based on their country, maybe even pride in or aspirations for their country), we now speak mainly about taxpayers. Both the citizen and the taxpayer are creations of political rhetoric, she wrote, pointing out the power of words to shape our thinking.

But I want to write about paying taxes. As a taxpayer, I’m pleased that my federal and state income taxes are lower than they might be. As a citizen, however, I think it’s outrageous that marginal tax rate is so low for someone with my income.

Back in the 1970s, the top marginal tax rate was about 70% for single taxpayers and about 55% for married couples filing jointly. But ever since the Reagan administration, the top marginal tax rate has been something like 39.6%. I’ve paid this rate. My income hasn’t decreased since that time, but my marginal tax rate for 2015 was 28%. Which is nuts!

Why is the national debt ballooning? Why don’t we have enough money to repair roads and bridges, and to pay our teachers a decent wage? Yes, I know that teachers are paid with state and local taxes, but the federal government also contributed to education funding; these federal subsidies have decreased dramatically since the 1980s.

I also know that we’ve wasted a lot of money fighting wars that we never should have started, and that we have furthermore wasted billions on “security theatre” at the nation’s airports. But if you say, “I’ll support higher tax rates when the government stops wasting money,” you’ll wait forever.

Those are problems I can't solve, but there is an issue I'm considering. I had solar panels installed on my roof last year, and consequently I'm eligible for a tax credit. The question is: Should I ask the federal government (read: "my fellow citizens") to pay for part of my solar panels?

Because tax credits—and, to a lesser degree, tax deductions—are expenditures. A dollar not collected because of tax deductions or tax credits is a dollar not available to fix a road or a bridge; alternately, it's a dollar that can't be used to pay a park ranger, or a dollar we've got to borrow...

Why should I ask my fellow citizens to pay for [part of] my solar panels? I understand the offer is there, and that it's permissible for me to receive it, and as a taxpayer I "should" take it, as I'm entitled to.

But as a citizen, do I really have an obligation to? Following Kant, do I want my fellow citizens to take every legal tax credit and deduction available? As a taxpayer, all I'd care about is myself, but as a citizen...

So there's my quandary.

Sunday, April 24, 2016

Alaska Airlines to Hawaii?

Some folks say that Hawaiian and Alaska are the two best airlines to take to Honolulu. What with Dad's passing last year, I've been making quite a few trips, usually on Alaska; Carol and I just got back from a trip on Hawaiian. Here are a few opinions.
 AlaskaHawaiian
gate experience outbound checkin at San Jose terminal B; your gate may be in terminal A checkin at HNL Hawaiian terminal (can you spell c-r-o-w-d-s?); your gate is in main terminal and may involve quite a hike
Food A wide variety of paid options; usual complimentary beverages; water offered throughout the flight Complimentary meal and glass of wine. Snacks available for purchase; usual complimentary beverages; water offered throughout the flight
in-flight amenities Power outlet at every seat. I saw no power outlets on any leg of this past trip. Safety video (seen on both CA↔HI legs) was particularly entertaining.
baggage Bags come out I think within 20 minutes of landing. Carol's checked bag appeared 30 minutes after we were at the gate at SJC. widebody jet (A330, 2+4+2 seating) means more passengers, hence more bags

Postfix SMTP authentication update

The lovely Carol's blog got hacked, so I updated the password on our ISP account. Mostly this was a matter of changing the passwords on mail clients (Mail.app, thunderbird) but that didn't do it for cron(8)-driven commands that sent mail; for that I needed to update the passwords in old-school files. So now I'm telling you about it, where one of you is my future self :)

On the Mac Mini, the file is sasl_passwd, which I updated using vi(1). After that I had to root around a bit to find out how to update the map, which turned out to be quite simple, once I knew how.

bash-3.2# postmap hash:sasl_passwd
bash-3.2# ls -ot|head
total 440
-rw-------  1 root  16384 Apr 24 10:05 sasl_passwd.db
-rw-------  1 root    XXX Apr 24 10:01 sasl_passwd
-rw-r--r--  2 root  27097 Nov  1 14:32 main.cf
-rw-r--r--  2 root  27097 Nov  1 14:32 main.cf+sasl
-rw-r--r--  1 root  26615 Sep  9  2014 main.cf~orig
-rw-r--r--  1 root     44 Sep  9  2014 custom_header_checks
-rw-r--r--  1 root  26147 Sep  9  2014 main.cf.default
-rw-r--r--  1 root   7443 Sep  9  2014 master.cf
-rw-r--r--  1 root   7443 Sep  9  2014 master.cf.default
bash-3.2# exit
The hint came from http://www.postfix.org/SASL_README.html, particularly this:
  • Use the postmap command whenever you change the /etc/postfix/sasl_passwd file.

And on Debian Wheezy

For some reason the layout is a bit different.
root@p64:/etc/postfix# cd sasl
root@p64:/etc/postfix/sasl# postmap hash:passwd
root@p64:/etc/postfix/sasl# ls -ot
total 16
-rw------- 1 root 12288 Apr 24 10:09 passwd.db
-rw------- 1 root   XXX Apr 24 10:09 passwd
root@p64:/etc/postfix/sasl# exit
collin@p64:~$ echo how about this from p64? | mail -s well? MY.OTHER@EMAIL.ADDRESS
The message was received at my other email address, and I didn't get a bounce.

So apparently I got all this done in under ten minutes. How often does that happen??

Sunday, April 17, 2016

Recovering posts from a toasted wordpress site

The lovely Carol had her wordpress site hacked. Not knowing squat about wordpress except this, I naively thought it would be a Good Idea to pull the posts and the media off the site, blow it away, create a new site on top of it, and put the content back. It wasn't a problem finding the media; I tar(1)ed it up, gzip-ed (in vain) like this:
$ tar -tzf ~/uploaded-images.tgz
wp-content/uploads/
wp-content/uploads/2013/
wp-content/uploads/2013/01/
wp-content/uploads/2013/01/masthead_web.jpg
wp-content/uploads/2013/01/masthead_web-150x150.jpg
wp-content/uploads/2013/01/masthead_web-300x112.jpg
wp-content/uploads/2013/01/masthead_web-1000x288.jpg
wp-content/uploads/2013/01/masthead_web-500x187.jpg
…
But what about the text? I asked the lovely Carol, who said there was no need to capture the comments and a bunch of other stuff. She did, however, want her subscribers.

Following the method shown in that other posting, I went to the database and said

mysql> show tables;             
+--------------------------+
| Tables_in_REDACTED       |
+--------------------------+
| wp_commentmeta           |
| wp_comments              |
| wp_links                 |     
| wp_options               |
| wp_postmeta              |
| wp_posts                 |
| wp_subscribe2            |
| wp_term_relationships    |
| wp_term_taxonomy         |
| wp_termmeta              |
| wp_terms                 |
| wp_usermeta              |
| wp_users                 |       
+--------------------------+
I saved the subscribers off by typing mysql> select * from wp_subscribe2; which will do, because we don't have bazillions of them; a little scripting will get all the email addresses set up as subscribers for the new site.

She doesn't care about saving the old options, or comments, so all I need to do is save the posts and pages. We'll ask the designer who did the original design to please re-do it, once I can give her access.

So, what about saving the posts? It turns out that wp_posts has both the posts and something wordpress calls "pages." My first thought was to save everything into a nice file, like this:

SELECT * INTO OUTFILE '/$HOME/posts-outfile' CHARACTER SET utf8 FROM wp_posts;
which didn't work, because I don't have FILE privilege. Dang.

This worked fine though:

echo -e "use REDACTED\nSELECT post_type, post_date, \
    post_modified, post_title, post_content \
    FROM wp_posts where post_status = 'publish'; " \
 | mysql -h REDACTED -u REDACTED -p | tee $HOME/tempfile
So now I had her posts and "pages"

I then moved everything in the "root" directory of her domain into a subdirectory where nobody will look. By "nobody will look" I mean "nobody has permission." And by "nobody has permission" I mean 0700.

Now getting the data out of the aforementioned temp file was harder than I thought. My first naive thought was to do something like

sed -n 5p TEMPFILE
and just snarf'n'barf the rather long line I got. Bad idea. It almost worked, except for a few things:
  1. a bunch of newline characters, which were represented as "\n"; of course, HTML doesn't care about "\n" and just renders it like that....
  2. Some unwelcome <CR> (aka '\015' or '^M' or '\r') characters, which do a "carriage-return," putting the cursor back at the left margin but without scrolling the window. These caused a jumble of nonsense, but it was over toward the right, where you wouldn't see it without reading the whole thing through
  3. characters with the high-order bit set. These are things in the range 0x91—0x97, which are translated in this chart
I couldn't quite do all this with a shell one-liner, but I tried this:
grep '^page' published-posts-pages.out |sed -n 1p | tr -d '^M' | \
   sed 's/\\n\\n/<p>/g'
which was mostly okay. the bold blue ^M was entered by using <ctrl-V><ctrl-M> I think.

For the "page"s I think I just did the funky characters by hand, addressing (mostly) #1 and #2 in the one-liner. To take care of #3 (the "posts" had a lot more of these than the "pages") I wrote a little Python.

#!/usr/bin/python2.7 -utt
# vim:et:sw=4
import sys

the_line = sys.stdin.read()
sub_table = [
    [ 0x91, '&lsquo;' ],
    [ 0x92, '&rsquo;' ],
    [ 0x93, '&ldquo;' ],
    [ 0x94, '&rdquo;' ],
    [ 0x96, '&ndash;' ],
    [ 0x97, '&mdash;' ],

]
for old_thing, new_thing in sub_table:
    the_line = the_line.replace(chr(old_thing), new_thing)

sys.stdout.write(the_line)
sys.exit(0)
I stuck this into $HOME/bin/chars.py and then, to handle a typical post, said:
$ LANG=C; grep '^post    ' published-posts-pages.out | tr -d '^M' \
   | sed 's/\\n\\n/<p>/g' | sed 's/\\n/<br>/g' | sed -n 12p \
   | ~/bin/chars.py | pbcopy
A few things about this:
  • LANG=C was because I had been trying some other character sets. They didn't work.
  • after translating all the "\n\n"s into "<p>", there were some single "\n"s left, which I translated into "<br>"
  • chars.py of course was to do the right thing with those odd characters
  • I used the Mac OS utility "pbcopy" because the terminal emulator renders unknown characters as '?'. Of course, now that I have chars.py in the pipeline, this was probably superfluous. Well, I could just CMD-v in the wordpress window to add a new post.
That's about it. The site is now ready for the lovely Carol to fine-tune. The .htaccess file currently will allow access only to the IP address of this particular house. When it's ready to publish, we'll remove the IP address restriction.