Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: development

  • PHP Spaceship

    PHP Spaceship

    It’s no Jefferson Starship, but in PHP 7 there’s an awesome new comparison operator called ‘Spaceship.’

    Dragon Fly

    Operators are those things we use to tell PHP what ‘operations’ to perform on variables and values. Comparison operators are used to compare two values (like a number or string). And Spaceship — <=> — is a cool new one.

    It’s a combined comparison operator and returns:

    • 0 if values on either side are equal
    • 1 if value on the left is greater
    • -1 if the value on the right is greater

    Red Octopus

    So why would anyone use it?

    Let’s say you have an array of characters with lists of when they died. But the characters are ordered alphabetically. Sara Lance comes after Lexa, even though Sara died first. And let’s say you want to take the list of all the characters who died and put them in the order of death, not their names.

    To do this in PHP, you would use usort or uasort to ‘user sort’ the array. The A in the sort is if you have an associative array, and you want to keep ‘name’ and ‘date of death’ connected when you sort. Which you do.

    Spitfire

    In PHP 5, the sort would look like this:

    uasort( $death_list_array, function($a, $b) {
    	$return = '0';
    	if ( $a['died'] &lt; $b['died'] ) $return = '-1';
    	if ( $a['died'] &gt; $b['died'] ) $return = '1';
    	return $return;
    }
    

    Which isn’t bad, but it’s messy right?

    Earth

    In PHP 7, the sort would look like this:

    uasort( $death_list_array, function($a, $b) {
    	$return = $a['died'] &lt;=&gt; $b['died'];
    	return $return;
    }
    

    Way nicer, and faster, isn’t it?

    Freedom at Point Zero

    Why not use it all the time? Because it’s PHP 7+ only, and for some reason not all servers have PHP 7 as the command line version of PHP. Which means if you use it, sometimes wp-cli commands don’t run.

    However. If you have PHP 7 all across the board, then use the starship and save yourself some flying time.

  • Dynamic Amazon Associates

    Dynamic Amazon Associates

    I preface this with a note that there are actually a lot of WordPress plugins that purport to do this.

    Stable, Topical, Content

    Sometimes a blog is just a blog, and you write what you write. Other times you have a site that covers an ever expanding, diverse plethora of topics. When you have topical content that can be easily identified and codified, the game changes. You no longer are forced to rely on generic ads, you can pick and chose what works best for your specific content.

    There are two general ways to achieve this. The first way is adding a specific ad to each page, manually, and the second is figuring out how to automate it.

    Using an API

    Amazon has a Product Advertising API which gives developers access to the entire product catalog, which can let you programmatically determine what links to call and when. Like a lot of Amazon APIs, it’s not exactly written in low-geek levels of usage. This is my constant complaint about Amazon and their services: they were not written to be easily understood.

    Thankfully, unlike my experience with making a custom Alexa skill, I did not actually have to invent the wheel. This time there is a fully functional, if poorly documented, Amazon Product Adverstising Library based on PHP REST and SOAP using the Product Advertising API..

    A ‘Simple’ Application

    The API is best installed via composer, which isn’t my favorite method. Nothing against composer, it’s great to pull down a library and it’s dependancies. My issues with it are that people don’t properly flag their archives so even if you use --prefer-dist on your build, you still get all the tests and documentation and that annoys me.

    Anyway. Use composer, get the files, and then you can use it to call Amazon searches and build links:

    <?php
    include_once( 'vendor/autoload.php' );
    
    use ApaiIO\Configuration\GenericConfiguration;
    use ApaiIO\Operations\Search;
    use ApaiIO\ApaiIO;
    
    $conf = new GenericConfiguration();
    $client = new \GuzzleHttp\Client();
    $request = new \ApaiIO\Request\GuzzleRequest($client);
    
    $conf
        ->setCountry( 'com' )
        ->setAccessKey( AWS_API_KEY )
        ->setSecretKey( AWS_API_SECRET_KEY )
        ->setAssociateTag( AWS_ASSOCIATE_TAG )
        ->setRequest( $request );
    $apaiIO = new ApaiIO( $conf );
    
    $search = new Search();
    $search->setCategory( 'DVD' );
    $search->setActor( 'Lucy Lawless' );
    $search->setKeywords( 'Xena' );
    
    $formattedResponse = $apaiIO->runOperation( $search );
    
    var_dump( $formattedResponse );
    

    Obviously you don’t ‘var_dump’ for real, but it’s a good way to get an idea of what kind of data you’ll be getting back. You can also reformat the output by changing the response transformer. For example, if you want an array, you can add this to your $conf setting:

      ->setResponseTransformer( new \ApaiIO\ResponseTransformer\XmlToArray() )
    

    Customizing Keywords

    Of course not everyone wants every search result to be about a warrior princess. Pity, but that’s the world for you. These three aspects are the ones most people will care about:

    $search->setCategory( 'DVD' );
    $search->setActor( 'Lucy Lawless' );
    $search->setKeywords( 'Xena' );
    

    All of that data was actually saved in the post, so I wrote my code to extract it. That is the actual magic, though. On pages for characters, we had their actors. On pages for shows, we had the show title and genre. Using that, we were able to logically extract the information to generate the appropriate ads.

    Why Not a Plugin?

    I did mention there were plugins that do this. The problem was that I needed to mess with that customization so much. I had to hand code in the logic (which was not perfect) to show the ‘right’ links on the right pages. No plugin met all my needs nor permitted enough customization in the right ways.

  • The Curious Case of a Comatose Cloud

    The Curious Case of a Comatose Cloud

    The summary here is that remotely hosting SVGs caused a massive slowdown.

    Isn’t the Cloud Magic?

    Nope. Well. No. It is totally magic, in that they’re great for large files and are an inexpensive storage alternative. But the cloud is, at the end of the day, just another server out there in the world, holding your data. Unless that cloud server is behind a CDN, you may not see a great deal of speed improvements on your site.

    And in my case, it didn’t.

    Diagnosing the Problem

    In building out a dev site with Tracy (LilJimmi), we noticed certain pages were really slow to load. 35 seconds slow. That’s unacceptable. I compared it to the live site, and it was faster, but some specific pages were still incredibly slow. What pages? The L Word for the most part. And as we inched closer to being done, I said “I’m going to fix this speed stuff before the weekend!” because you can’t go-live on a slow site. You just can’t.

    Once I was home, I fired up a local site, installed Query Monitor, and had a serious sit down with everything.

    It Wasn’t What I Thought

    My initial thought, the one I ruminated on during my bike ride home, was that it was the database queries. Most shows have one or two queer characters, but The L Word has 60 right now. While I may joke about wanting nine more, it’s a weird situation where I need to get the number of characters on the show without knowing the number of characters on the show. My assumption was that it was my calculation loop that caused the issue. That I was querying the queers too many times.

    Turned out it wasn’t (just) the number of characters, it was the number of tags.

    How It Got So Slow

    Most of the issue is my fault. Every single tag has a custom image associated with it. These images are stored remotely, in the cloud, and called as part of the design. The issue was that when calling the images I ran a check “Is the service available?” and if not, it would stop. When you make one or two calls, it’s no big deal. When you make a couple hundred, it adds up.

    The L Word had 2 icons per 60 characters, and then 15 tags, and then 30 more icons.

    Remote Get Is Slow

    I used wp_remote_get to process my images, and it was taking between .1 and .4 seconds per image. That adds up. At first I simplified my check-if-exists routine and more than halved the time to load from 35 to 15 seconds. But in order to drop the page back to 1 second-ish load times, I had to put the images local again. No matter what I did, if I loaded them remotely the best I could get was a 13 second page page load.

    Sometimes, local is better.

    What’s the moral?

    Obviously the moral is test before you rollout. Which we certainly did! By using Query Monitor, I was able to narrow down the speed for the database queries as well as the speed for all the HTTP requests. In doing so, I lost a CDN but gained speed. I’m trying to figure out how to speed up the CDN, maybe by finding a different front-end proxy, but right now I’ll keep using it for the large files like videos rather than the hundred small ones.

    I think it it’s worth it.

  • Git: Combining Your Messy Commits

    Git: Combining Your Messy Commits

    Sometimes I end up making a lot of commits while I’m working on a branch in order to get the code right. It mostly happens when I’m going back and forth between my new branch and the old (live) one to double check some code that I think got lost. It happens when changing theme structures.

    However. This left me with a conundrum. I had about 100 commits and really it was going to be the messiest pull request ever. Which I didn’t want.

    One Branch to Rule Them All

    In order to fix this, finished up all my errant commits, as messy as they were, and then I went back and checked out the clean development branch (named development). Since everything was up to date, I went and made a new branch.

    That gave me three branches:

    1. development – The actual dev branch
    2. messy-dev – My super messy branch
    3. clean-dev – My clean branch

    Of course, nothing of mine was actually in that clean branch.

    One Branch to Find Them

    Once I switched to my new branch ( git checkout clean-dev ) I imported my old branch with this: git merge --squash messy-dev

    Yep, that was it. I then went though all my regular checks, made sure the code was working, did a few more fiddly changes, and then I ran a git commit to run the last pull.

    This gave me a commit message filled with … well … this:

        Merge branch 'development' into messy-dev
    
    commit 6c7534b9f7eabb5db59a85880bbf42ff2b982d84
    Author: Mika Ipstenu Epstein <ipstenu@ipstenu.org>
    Date:   Sat Sep 23 19:47:27 2017 -0700
    
        Cards again
    
    commit 9fe21f380a1befcbbe34a79937399b679c31c06f
    Merge: 0362bb5 14b4fab
    Author: Mika Ipstenu Epstein <ipstenu@ipstenu.org>
    Date:   Sun Sep 24 18:08:18 2017 -0700
    
        I hate Sara Lance so much!
    
    commit 0362bb5a289e2694bd4872137ad470091529021d
    Author: Mika Ipstenu Epstein <ipstenu@ipstenu.org>
    Date:   Sun Sep 24 17:57:33 2017 -0700
    

    One Branch to Bring Them All

    Don’t worry. I didn’t keep that. In fact, I’d been writing a log of the entire work, listing out what was changed, fixed, added, deleted, etc. So I deleted that entire commit message and pasted mine in it’s stead.

    Well written inline documentation is one thing, but a good commit message saves lives. Since I planned to submit this as a pull request, I knew I had to have a good, simple, commit that listed things that had changed.

    But there also had to be more…

    And In The Pull Request Bind Them

    I’m rather pedantic about all that and wrote about 500 words to explain what all the code was in that Pull Request. Since I’m working with other people, and I’m not the lead developer on this project, I know not to commit my changes to the dev server right away.

    Instead, I made a pull request with a repeat of data in my commit, but also a different and more detailed explanation. A pull request has to explain why the work was done and why the pull is needed.

  • Admins Are Humans Too

    Admins Are Humans Too

    This conversation happens often enough that I've ceased to be mind boggled by it. A developer will submit code, I review it, and I'll tell them to please sanitize the input. Instead of just using the functions, they'll come back and ask why? Invariably they'll point out that they're using nonces to make sure only authorized actions can happen (no cross site scripting), and they're checking user permissions too, limiting access to only admins. So why am I being pedantic? My default reply:
    Admins are humans. Humans make mistakes. Computers do exactly what they're told to do. 

    Admins Are Humans

    I'm often a broken record, telling people to sanitize, validate, and escape. When people ask me which sanitize function to use in WordPress, I play Socrates and walk them through the logic process. What kind of data are you saving? What will it look like? Okay, now what of these looks the most appropriate based on their descriptions? Sanitizing data is contextual. By this I mean we sanitize for what the saved data should be. If you're saving an email address, make sure you sanitize for email and so on. This has a side benefit of helping validate your data as well. If you check that the email address entry actually is an email, you're both sanitizing and validating. Now you've prevented someone from putting in a domain instead of an email!

    Humans Make Mistakes

    The details of 'best practices' for coding change often, as we learn about how to make code safer and smarter. That said, the ultimate best practices have nothing to do with the language you're writing in, the app you're writing for, or even the platform!
    • Restrict access to only the people who need it
    • Sanitize and validate the data you're given
    • Provide helpful error messages
    • Test your code with good and bad data
    • Document what the code does and what the errors mean
    Those practices transcend every single minutia of programing. If you do those five steps, your code will be robust, sane, and safe. Because you will have taken the steps to ensure that humans can make as few mistakes as possible. You don't save 'Dog' when true/false is the only valid answer.

    Computers Do What We Tell Them To Do

    The real problem is that AI doesn't exist.
    Source: CommitStrip.com
    Computers can't think for themselves, and humans have a tendency to stop thinking at weird moments (or just go on auto-pilot) which means nothing can destroy work faster than a human. And since a computer does what it's told, the most dangerous computer tool is the one that doesn't account for how big a mistake a human can make.

    Sanitize, Validate, Escape

    Especially when it's an admin.
  • But Seriously…

    But Seriously…

    In reviewing people’s code for WordPress, I’m constantly struck by the lack of foresight people put in to their success. When a developer makes it clear they intend to run a business or have some modicum of popularity, one would expect them to put a bit of effort into it. Instead, I’ve watched people make the same mistakes over and over. And they complain to me about why their plugin is failing to become “the one” to use.

    The answer always seems to surprise them. People don’t take them seriously because they are unprofessional.

    WordPress Basics

    First of all, no one magically knows all this when they start. So it’s alright not to know. However. If you’re going to go into business based around anything, you need to learn the rules of the road. Take the time to learn that it’s WordPress with a capital P, that there’s a foundation, a trademark, and, yes, that you cannot use WordPress in your domain name.

    If you were going into business with PayPal or CitiBank, that’s all legwork you are expected to do beforehand. This is a business, and when you don’t take WordPress seriously, you won’t be taken seriously by WordPress.

    SEO Basics

    Pick a good domain name for your business site. Make sure you’re not violating a trademark or copyright. Pick a good name for your product. For the love of all things whiskey, don’t name your slider plugin “Slider” and stop using “Mega” as a prefix for anything. Remember, the name of your product cannot infringe on anyone’s trademark. So while “Shoppable Cookie Cutters” is not trademarked, “Shoppable” is. And yes, you’ll get a C&D for being similar.

    Write good copy for your website. Have a clear mission statement, a human about page, and some semblance of being real people. This extends to your documentation. Write it. Write it good. Write a readme that tl;dr pitches your product, explains why someone needs it, and details out what kind of services it uses (if any). Remember that most of your SEO comes from humans. Write for them.

    Community Basics

    The OpenSource community in general will help anyone who asks politely. So be polite. Be respectful. Be courteous. Be generous. If people are helping you for free (and most of them are) then thank them and ask how to pay it forward. Offering services, answering generic questions, educating users, or even just publicly thanking volunteers helps.

    The community also includes your users. Respect them. Especially when they’ve gone off the deep end and accuse you of wild impropriety. Your plugin hacked their site? Probably not, but treat them with respect and kindness. It goes a long way to inspiring the volunteers to back you up. But also don’t spam your users with a million in-product reminders to review your product, give it five stars, or otherwise distract them from actually using your plugin.

    Universal Basics

    Do your research. There is nothing on this earth that is a get-rich-quick, so study what you’re getting into. Don’t jump in blindly. Make sure the community is one you can work with, that they have ethics similar to yours. And if not, make absolutely sure you really are comfortable with going for the money.

    Set your expectations realistically, and be willing to have them reset. Take your work seriously, don’t make excuses like “someone else did this first!” Own up to any mistakes or missteps you make. Remember, you absolutely will screw something up along the way. The measure of success can be found in how you handle it.