Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

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

  • Updating Bower with Grunt

    Updating Bower with Grunt

    The goal of automation is to make the annoying stuff I don’t want to have to remember to do easier to do. Bower is useful for updating things. Grunt is useful for running a series of commands. Using them together makes life easier.

    In my little world, everything lives in a folder called ‘assets’ and its very simple.

    Add a Package to Bower and call it in Grunt

    First I have a .bowerrc file which very simply says this:

    {
       "directory": "vendor"
    }
    

    That tells Bower where to install things. So when I run bower install jquery-backstretch --save in my asset folder, it saves backstretch to the vendor folder.

    In my gruntfile.js, I have this to pull in my backstretch arguments and the main file into one file, uncompressed, a folder level up:

    		concat: {
    			// Combine all the JS into one
    		    backstretch: {
    		    		src: ['js/backstretch.args.js', 'vendor/jquery-backstretch/jquery.backstretch.min.js'],
    				dest: '../js/backstretch.js',
    		    },
    		},
    

    Just like magic.

    Tell Grunt to Update Bower

    But while Bower pulled in the packages, I don’t want to have to tell Bower ‘Hey, make sure everything’s up to date!’ every few days. I want to make sure I’m on the latest version of a branch most of the time, for security reasons at the very least. That means I have this in my bower.json file:

      "dependencies": {
        "bourbon": "~4.2.3",
        "neat": "~1.7.2",
        "jquery-backstretch": "~2.0.4"
      }
    

    So if I run bower update I would get this:

    bower jquery-backstretch#~2.0.4 cached git://github.com/srobbin/jquery-backstretch.git#2.0.4
    bower jquery-backstretch#~2.0.4         validate 2.0.4 against git://github.com/srobbin/jquery-backstretch.git#~2.0.4
    bower bourbon#~4.2.3                      cached git://github.com/thoughtbot/bourbon.git#4.2.3
    bower bourbon#~4.2.3                    validate 4.2.3 against git://github.com/thoughtbot/bourbon.git#~4.2.3
    bower neat#~1.7.2                         cached git://github.com/thoughtbot/neat.git#1.7.2
    bower neat#~1.7.2                       validate 1.7.2 against git://github.com/thoughtbot/neat.git#~1.7.2
    bower jquery#~1.9.1                       cached git://github.com/jquery/jquery.git#1.9.1
    bower jquery#~1.9.1                     validate 1.9.1 against git://github.com/jquery/jquery.git#~1.9.1
    bower neat#~1.7.2                        install neat#1.7.2
    bower bourbon#~4.2.3                     install bourbon#4.2.3
    
    neat#1.7.2 vendor/neat
    └── bourbon#4.2.3
    

    Cool. But who wants to run that every day?

    Instead, I ran npm install grunt-bower-update --save-dev to install a new Grunt tool, Bower Update. With that code added to my gruntfile.js, every time I run my grunt update command, it first updates my libraries and then runs the processes.

    There is a downside to this. I use git to keep track of my work and either track the vendor packages in my repo (which can make it a little large) or I can remember to install the packages. There are other ways around this, like using grunt-bower-task to set up things to install if not found, update if they are found. I went with including them in my repos, which makes the git pull a bit large (it added about 6000 files), but since I properly delete my assets folder when I deploy from git, it won’t impact the size of my server’s package.

    Register a New Bower Package

    Randomly, when I initially tried to install backstretch, I forgot it was named ‘jquery-backstretch’ and did this:

    $ bower install backstretch --save
    bower                        ENOTFOUND Package backstretch not found
    

    Obviously the right fix is to use the right repo name (and bower has a great search tool to help me to that). But what if I did want to package it up as backstrech? Or if I wanted to add my own repo? Well I would have to register that package first. And that’s pretty easy:

    bower register backstretch git://github.com/srobbin/jquery-backstretch.git
    

    Your Tricks?

    Do you have Bower tricks?

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

  • Uniqueness Matters

    Uniqueness Matters

    This email gets sent a lot to plugin devs lately:

    All plugins should have unique function names, defines, and classnames. This will prevent your plugin from conflicting with other plugins or themes.

    For example, if your plugin is called “Easy Custom Post Types”, then you might prefix your functions with ecpt_{your function name here}. Similarly a define of LICENSE would be better done as ECPT_LICENSE.

    Please update your plugin to use more unique names.

    And once in a while someone asks why we care so much.

    There are 38,308 active plugins in the WordPress.org repository. If every one of them uses a global define of IS_PLUGIN_SETUP then they will all conflict with each other. If half use a script handle of plugincss then all those plugins will stomp over each other when it comes to enqueuing the CSS.

    It’s literally a numbers game.

    Every day we get at least 30 new plugin submissions to WordPress.org. That means every day at least 30 new potential conflicts show up. And it’s not just plugins. In WordPress 4.2, a new function was added: get_avatar_url()

    This was a great idea that saved people countless hours of work. Unless they logged in to see the error Fatal error: Cannot redeclare get_avatar_url() prance across their screen.

    Now in this case, theme authors had previously been told to include/make themselves, but was later added to core. All theme devs hosting on WordPress.org were notified and it was posted on the change blogs. But not everyone remembers to check those. And not everyone updates their themes right away. In a way, this probably could have been communicated better, but had the themes called their function mythemename_get_avatar_url() then this wouldn’t have been a problem.

    Prefix everything. Make it unique to your plugin or theme. WordPress is ‘home free’ and shouldn’t have to, but you should.

  • Mailbag: Multisite Subdomains Live Where?

    Mailbag: Multisite Subdomains Live Where?

    Heather is confused, and I don’t blame her:

    I am want to use subdomains in my multisite. 1. Install WordPress in the subfolder and set it up to run from root before you create your subsites. 2. You should not use www in your URL ….. Where exactly do need to change this? Settings/ General ( that’s how i saw it in your book) or in my file manager, having to change it in many different files…. ( saw and read this from other internet sources).

    Let’s take this by the numbers.

    1. Install WordPress in the subfolder and set it up to run from root before you create your subsites.

    If (and that’s a big if) you want to install WordPress at example.com/wordpress but have the URL look like example.com then you must do this before you activate Multisite. Can it be done after? Yes. But you will go insane.

    1. You should not use www in your URL

    If you’re using subdomains, just don’t. The issue where WordPress breaks if you use the www here is not to do with WordPress so much as the variant hosts out there and how they handle the www/non-www redirects. Save yourself a headache. Don’t use www. You don’t use www. Yes, I know Google does. They don’t care so long as you’re consistent.

    In both cases, on your single site install of Wordpress, you go to the General panel. The value for Site Address (URL) is what you want people to see when they visit your site. The one for WordPress Address (URL) is where WordPress is installed.

    Make sure they both match in terms of schema and www. Then change the Site Address from http://example.com/folder to http://example.com and save it.

    The official directions are on the codex – Giving WordPress it’s own Directory. There’s a bit more when it comes to moving a couple files, but really that’s it. Once it’s done and working, go ahead and activate Multisite.

    By the way, I always get the WordPress Address and Site Address confused. It’s not just you.