Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How It Is

Making philosophy about the why behind technical things.

  • Name Collisions

    Name Collisions

    Many many years ago I played MUSHes. One of the games was PernMUSH (which apparently is inactive now). PernMUSH took place on the world of Pern, and you had the chance to be a dragon rider. Which was kind of the Thing to Be ™. One of the ‘quirks’ of the game was that every character had to have a unique name, and so did each dragon. When I started playing, I didn’t really understand this. Today I know that it’s because of name collisions.

    A “name collision” is a problem not solely endemic to computers, but it comes up there an awful lot, whereby you must have a unique identifier to know what each ‘thing’ is. For example, in WordPress every post has two unique identifiers. It has a post ID, which is a number given to the post when it’s stored in the database. If you use ‘ugly’ permalinks, you’ll see this as example.com/?p=123 – that 123 is the post ID. But if you use pretty permalinks (like I do here — example.com/my-cool-post/) then you have to have only one ‘post’ with that name.

    You, literally, cannot have two posts with the same ID or name. Makes sense, right?

    On PernMUSH we had everything have a unique ID as well as a unique ‘nice’ name. But then when dragons were introduced, you had to give them unique names as well. This was not for frivolous reasons nor pretty special snowflake ones. While it was perfectly understandable to have a hundred rooms named “Bedroom,” the code for the dragons allowed them to all talk to each other and send private messages. They were, basically, our cell phones. Dragon Ath had to be able to talk to dragon Bth, and in order to ensure that worked properly without everyone having to type dtu #12724=message we had to have the code written such that someone could type dtu bth=message and that meant each name had to be unique.

    This would have been fine and dandy as it was except for one small problem. PernMUSH wasn’t the only MUSH based on Pern. There was also a game called SouCon, which took place on the Southern Continent. And transfers between the games were allowed. This added in a wrinkle that now PernMUSH and SouCon had to be sure that everyone on both games had a unique name and dragon name.

    It was quickly determined that they wouldn’t bother with human names. If J’cob on SouCon came to visit PernMUSH, which already had a J’cob, then SouCon’s J’cob would use a different name like Jy’cob. But for whatever reason it was decided that the dragon names on both games were going to be unique. Thus the “All The Weyrs List” was created. That list (which still exists at dragons.pernmu.com ) was a mostly honor system site where you would email in your ‘hatching records’ with who’d impressed and to what dragon and what color and who were the parents. The list would be updated. Then the next time anyone had a hatching, they’d search that page for the dragon names they wanted to use. If the name was there, then then couldn’t use it. Done.

    Of course this wasn’t perfect. Anything based on the honor system is bound to have a few bad eggs. After 10, 15, 20 years, the ability to give people the name they ‘want’ starts to chaff against the tacit agreement not to repeat a name. At some point, I know some games gave up and let people have whatever name they wanted, and transfers could cope.

    What does all this have to do with anything?

    On the WordPress.org servers, where we list all the plugins approved by the team, each plugin has a unique slug that cannot be changed. I have a plugin called Impostercide, which has the slug of impostercide and it’s the only one. No one else can submit a plugin with that name. For the most part, this worked fine. If someone else wanted to make a plugin with that name, they were free to do so but it just wouldn’t be on WordPress.org and that was okay.

    Then we shot ourselves in the spirit of making life easier. Today WordPress updates your plugins and themes by using an API that calls back to the wordpress.org servers. That API check sees if Impostercide on your install of WordPress is older than the one on wordpress.org and, if so, alerts you to update. You press a button and your plugin is updated. It’s magic. It’s gold. It’s great. If you’re that person who wrote your own plugin, not on wordpress.org, you can hook into the update code and have it update from other servers. It’s brilliant.

    Except what if you’re that person who has their own plugin named Impostercide? The obvious answer is that you can just rename your folder and off you go. That doesn’t fix the thousands of people who just upgraded themselves to my version, though. They’re having a bad day. Also what if someone submits a plugin called impostercide-two? Now you have the same problem all over again. Other people will tell you to bump the version to something the real Impostercide will never use. But again, that doesn’t hold up since what if Impostercide does?

    The actual fix is to tell WordPress not to check for updates for that specific plugin.

    The awesome Mark Jaquith posted about this in 2009. You can code a plugin to tell WordPress to not check for updates for it. This does put the onus on people who are writing the plugins not hosted on wordpress.org though, which is and isn’t fair. There’s a movement to allow a new plugin header to prevent these things in trac ticket 32101, which boils down to the idea that if those non-org hosted plugins can flag themselves as ‘I’m not from .org’ then the API stops trying to update them.

    I think that it would be a good idea to have an easy way for people to flag their plugins as not being hosted. The alternative would be an honor system method, where everyone registers their plugin slugs and all submissions to wordpress.org is checked against that. But that falls apart quickly the day one person forgets to do it. With a way to easily kill the API check, we can allow non-org hosted plugins to very simply protect themselves, and their users, from being stomped on.

    As for the risk that someone might edit their own locally installed copy of Jetpack to have that header because they’re tired of updates, well, we can’t stop you from shooting yourself. I just hope people are smart enough to understand that you don’t edit core and you don’t edit plugins and you don’t edit themes. You make child themes, you use other plugins, and you use filters and hooks.

  • Bad Code

    Bad Code

    You can pick your friends and you can pick your code, but you can’t pick your friends code.

    I said that to Michelle as we were walking from WordCamp Minneapolis, kind of as a joke, but then she looked at me and said how appropriate that was.

    Sometimes the people we like and rely on code things in ways we think are a little insane. Here are the things that make me sigh a lot when I look at the code. They’re not always bad, but they do make me wonder what people were thinking.

    Hidden

    Someone wrote a plugin where the options were called via a base64_decode() from a compressed storage:

    #default settings code
    $options = '1VtPj-smEP8qKz2pt0qJs5vs7ju29_bQS08WtolD1zYp4M3mPfW7F2yDwWAPPK0q9erMj_nDzDAzEPSaHbLX7_x1n73-9HdPxdeK8GuD7nlDazp--cpfd9OP5sPz9EFR5T1r1in3O5v0Ripx2SDe28QXTOqLiKWWUuSXaoP6caYmXR4huV7-jN5JSTuA-mn6wgUp3-4x6z-HEdtanAIgyKohRqBx9ZcO3_Irw2fyEcFBETeowE1O3zFjpMIRG6JAgrT4ihmhMTuIOtTcpS48L-kmB_2l7...';
    

    At the risk of sounding like the US government, there’s no reason to hide your public code. Knock it off. It’s public. Hide the service code if you must. Keep your serviceware code on your own data. But hiding code someone can download and decrypt? No, you’re shady.

    Nesting

    The plugin basically was one thing: add_filter('show_admin_bar', '__return_false');

    But the plugin setup was /hide-admin-bar/hide-admin-bar.php which included a file /lib/bar-settings.php which in turn included /lib/false.php

    Three files. One line of code. Why? Why!?

    Inconsistant

    I don’t mean tabs vs spaces. I mean with names. Like having add_menu_myplugin() and myplugin_settings() and then sanitize_myplugin_value() and finally double_check_myplugin() — Sure they all have ‘myplugin’ in there, but they don’t have any rhyme or reason to the names.

    Names should be consistent and descriptive. A good function name should tell you what the function does.

    Echo

    I see this one a lot. People using ‘echo’ on every line in a function call in order to output their results.

    $my_count = $whatever->my_count;
    
    echo '<h2>Hello World</h2>';
    echo '<p>This is a cool thing!</p>';
    echo '<p>This is even more cool. This is '.$my_count.' times cool</p>';
    echo '<p>Ain\'t this cool too? But I have to escape my apostrophes.</p>';
    

    Besides the fact that it looks ugly, it’s created more ‘data’ in your code. There are easier ways around this and ones that are more readable.

    What Do You Think Is Bad?

    And remember, we’re not talking about code that’s outright wrong, we’re talking about the things that work and are right, but make you cry “Why!?!” like Nancy Kerrigan.

  • Rant: Gmail Contacts

    Rant: Gmail Contacts

    It’s been a while since I’ve gotten to have a good ol’ rant in on tech!

    I use Gmail in the browser, like my friend James. It’s meant to be used there. I’ll use it there. But I often get emailed new contact information, and I want to add it to Google Contacts. Here’s the workflow.

    I open the email and click on the ‘add contact’ button.

    Google - Add vcf to contacts

    There’s often no response at this point. The page sits there and I don’t see anything telling me to go to another page. Eventually the browser takes me to a new page in the same screen where I now have a new contact group with the name “Imported DATE” and one user (or possibly two if I clicked, saw no response, and clicked again):

    My new google contact group and my new user(s)

    At this point, I have to click the find and merge to get them back down to one. Then I click what groups I want the new user to be in. Of note, you must press the “Apply” button:

    I have to press Apply to add Obenland to WP

    No ajax here.

    Yay! Obenland is in WP!

    But what about that group?

    I have to delete the group

    Now some of this I can do from the list user screen, but I still have to go to contacts, mess with it, and then delete the temp group. No ajax. No way to add just from within mail. No way to open in a new window.

    It’s just crap.

  • Make or Break Yourself

    Make or Break Yourself

    How you react to adverse situations is what makes or breaks your business, not the fact that you had one in the first place.

    Taylor Swift recently penned an open letter to Apple Music. To Apple, Love Taylor lets us all in on a fact of the new Apple Music (their streaming service, coming soon for free for 3 months) that a lot of us didn’t know.

    I’m sure you are aware that Apple Music will be offering a free 3 month trial to anyone who signs up for the service. I’m not sure you know that Apple Music will not be paying writers, producers, or artists for those three months. I find it to be shocking, disappointing, and completely unlike this historically progressive and generous company.

    Three months where we get free music is great, but the cost of that free music was astronomical. As Taylor points out, it doesn’t hurt her, she has money. But the indie people will be terribly hurt by this, to the point that many of my indie friends pulled out of the trial too.

    Apple kowtowed in under 24 hours from that post. Eddie Cue (who’s the Apple mogul in charge of this project) replied on Twitter:

    I see a lot of people take criticism in some pretty appalling ways. I’ve been threatened with legal action for not deleting a one-star review of a plugin on WordPress.org. I’ve been vilified, called a Nazi or worse, and had my reputation blasted because I stood up for a user who didn’t like a product and left a bad review. I get insulted daily because I tell people “If someone misunderstood what your documentation said, you need to review your docs and consider updating them.”

    I’m glad I have a thick skin, because some days the things people say and accuse me of would make me cry. Sometimes they do, and those are the days I walk away and let someone else handle that person, or just take a break.

    In general, I believe in the inherent capability of goodness in humanity. I assume good faith. I presume that people who are leaving reviews aren’t generally doing it to attack me personally, but because they’re having a terrible day. Maybe they’re having the worst day of their life. And I, as an experienced support tech, know that they’re pretty much always going to be irrational.

    That’s the thing. People aren’t usually intentionally misleading, nor do they plan to make my life miserable. They’re having a bad day and it’s perceived to be my fault, so I’m sorry, but let me try to understand things better. How I reply to them depends on how they come to me with their issues, though. If they say ‘it’s broken!” (a common complaint, right?), I tell them I’m sorry and ask them if they can explain what, exactly, is broken. I may spend time clarifying with them “Do you mean X?” and I may ask “Why are you trying to do Y?” so I can understand the big picture.

    And then… those people who come at me and say “This person is lying and gave me a bad review!” I’m often inclined to side with the users, since a bad review is something that makes people overreact. But that doesn’t mean I dismiss the complaint out of hand. I check if the reviewer is a fake account (we have ways), and I check their history and their information and validate they’re real people before I reply. If they’re fake, I remove the reviews. If they’re not, I leave them be.

    Leaving them be is where most (if not all) of the hate comes from. You see, leaving them be is hurting businesses and ruining reputations.

    No. No they’re not.

    What ruins your reputation is how you reply to them. If you accuse them of being spammers or harassers, you make yourself look bad. If you lay into them because you disagree with their review, you make a fool of yourself. A review is a ‘how I feel’ from a user, and even though you may not agree with their conclusions, that doesn’t make their experience invalid. It means there was a breakdown in communication somewhere between you and them.

    This is why I tell people to check their documentation. If they’re getting a lot of bad reviews that are plain wrong, and they’re wasting a lot of time talking to people and correcting them, then the issue has to be, in part, the information they’ve presented up front. If its not there, add it. If it’s there, point them to it. “Actually I answered this in the FAQ where it says this plugin is Multisite only.” True story, I have to use that a lot.

    But when that question comes up time and again, I may ask “The FAQ covers this here LINK. Do you think there’s a better place I can put that? Where were you looking so I can make it more obvious for the next guy?”

    Maybe they never reply and fix that one-star review, but when people go and look at the reviews and see a one-star, and read it, they’ll see my mature, reasonable, honest reply. And that will do far more for my reputation than anything else.

  • Mailbag: Why Don’t You Tell People How To Contact You?

    Mailbag: Why Don’t You Tell People How To Contact You?

    My contact form scares off people. It’s supposed to. So this was asked of me at GeekGirlCon:

    Your card doesn’t have your email. Why do you make it so hard to contact you?

    It’s not that I don’t want to have people ask me for more information about my site, or a class I gave. I love that. I’m happy to answer those. I tell people ‘Go to halfelf.org and use the contact form.’ Sometimes I’ll reply personally, sometimes I post on the blog, sometimes both. But yes, if we’ve met in person and you have a question, it’s okay to ping me.

    But I hide my contact form behind a couple ‘are you sure?’ layers because people are weird and unreasonable.

    People contact me for the one thing I don’t offer, and that’s consultant work.

    People want to get free help on very complex problems.

    People want to be friends.

    Okay that last one is nice, but if I meet you once, we’re going to be acquaintances unless we hit it off like gangbusters… And at that point, I probably gave you my email and phone number and said “When you come to X, we have to do coffee!” It happens!

    But if you’re trying to ask a long question about how to write code to do a very complex thing, consider this. Would you otherwise pay someone to do it? Would you, if you were asked by someone, ask for payment? If yes, don’t just drop me a ‘hey can you help?’ Don’t drop anyone that question. Shoot them a polite message, asking if they can help you with a project. Offer to pay. And ask if they’re busy, can they please direct you somewhere?

    And do check out [https://halfelf.org/get/help] – Because yes, I keep a list.

  • Varnish Cache and Cache-Control

    Varnish Cache and Cache-Control

    In our quest for speed, making websites faster relies on telling browsers when content is new and when it’s not, allowing them to only download the new stuff. At their heart, Cache Headers are what tell the browser how long to cache content. There’s a special header called Cache-Control which allows each resource to decide it’s own policy, such as who can cache the response, when, where, and for how long. By default, they time we set for the cache to expire is how old a visitor’s copy can be before it needs a refresh.

    A lot of the time, I see people setting Cache-Control to none and wondering why their site is slow.

    Since I spend a lot of time working on DreamPress, which uses Varnish, I do a lot of diagnostics on people with slow sites. One of my internal scripts checks for Cache-Control so I can explain to people that setting it to none will tell Varnish (and browsers) literally not to cache the content.

    The way it works is that they actually set things to ‘no-cache’ or ‘no-store.’ The first one says that the content can actually be cached, but it’s going to check and make sure the resources haven’t changed. It’s not really ‘no-cache’ but ‘check-cache.’ If nothing’s changed, there’s no new download of content, which is good, but it’s still not caching.

    On the other hand, ‘no-store’ is really what we think about when we say not to cache. That tells the browser and all intermediate caches that every time someone wants this resource, download it from the server. Each. Time.

    What does this have to do with Varnish? Well here’s the Varnish doc on Cache-Control:

    no-store: The response body must not be stored by any cache mechanism;

    no-cache: Authorizes a cache mechanism to store the response in its cache but it must not reuse it without validating it with the origin server first. In order to avoid any confusion with this argument think of it as a “store-but-do-no-serve-from-cache-without-revalidation” instruction.

    Since Cache-Control always overrides Expires, setting things not to cache or store means you’re slowing down your site. Related to this, if you set your Max-Age to 0, then you’re telling visitors that the page’s cache is only valid for 0 seconds…

    And some of you just said “Oh.”

    Out of the box, WordPress actually doesn’t set these things poorly. That generally means if your site kicks out those horrible messages, it’s a plugin or a theme or, worst of all, a rogue Javascript that’s doing it. The last one is nigh-impossible to sort out. I’ve only been able to do it when I disable plugins and narrow down what does it. The problem is that just searching for ‘Cache-control’ can come up short when things are stashed in Javascript.

    But there’s some kind of cool news. You can tell Wordpress to override and not send those headers. I’ve not had great success with using this when it’s a script being an idiot, but it works well for most plugins and themes that seem to think not caching is the way to go.

    From StackExchange:

    function varnish_safe_http_headers() {
        header( 'X-UA-Compatible: IE=edge,chrome=1' );
        session_cache_limiter('');
        header("Cache-Control: public, s-maxage=120");
      if( !session_id() )
      {
        session_start();
      }
    }
    add_action( 'send_headers', 'varnish_safe_http_headers' );
    

    And yes, it works on DreamPress.