<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Blake Harley]]></title><description><![CDATA[The ramblings and thoughts of a crazed web developer.]]></description><link>https://www.blakeharley.com/</link><generator>Ghost 0.6</generator><lastBuildDate>Mon, 12 Sep 2016 01:32:59 GMT</lastBuildDate><atom:link href="https://www.blakeharley.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[My Thoughts on CoffeeScript]]></title><description><![CDATA[<h2 id="thehoneymoon">The Honeymoon</h2>

<p>When I first got my hands on CoffeeScript, I fell in love. It abstracted away a <strong>ton</strong> of boilerplate JavaScript code and handled a large number of common JavaScript "idioms." Naturally, I began to replace all of my JavaScript usage with CoffeeScript&mdash;and life was good.</p>

<p><strong>Annoyingly</strong></p>]]></description><link>https://www.blakeharley.com/my-thoughts-on-coffeescript/</link><guid isPermaLink="false">432d0cec-a686-4914-93fb-594f65617608</guid><category><![CDATA[programming]]></category><category><![CDATA[rants]]></category><dc:creator><![CDATA[Blake Harley]]></dc:creator><pubDate>Tue, 05 May 2015 02:31:51 GMT</pubDate><content:encoded><![CDATA[<h2 id="thehoneymoon">The Honeymoon</h2>

<p>When I first got my hands on CoffeeScript, I fell in love. It abstracted away a <strong>ton</strong> of boilerplate JavaScript code and handled a large number of common JavaScript "idioms." Naturally, I began to replace all of my JavaScript usage with CoffeeScript&mdash;and life was good.</p>

<p><strong>Annoyingly trivial example</strong></p>

<pre><code class="language-javascript">if (str &amp;&amp; str.slice(-1) === '?') {  
    // Handle the question
}
</code></pre>

<p>becomes</p>

<pre><code class="language-coffeescript">if str?[-1..] is '?'  
    # Handle the question
</code></pre>

<h2 id="thefallingout">The Falling Out</h2>

<p>CoffeeScript made my JavaScript life simple for a time, and it was good. I wasn't undertaking any major JavaScript projects, so my CoffeeScript usage was replacing very basic JavaScript. Fast-forward a year or so: my employer saddles me with a rather large application that I ended up building using AngularJS and CoffeeScript. As the controllers and services began to grow, product requirements morphed and designs changes, I found myself longing for help with refactoring. I did a lot of jumping around between files to refresh my memory on inputs to functions, and refactoring resulted in some unsavory regular expressions.</p>

<p>This is when I came to appreciate TypeScript. I would have cut down on the number of tests, saved myself time debugging stupid errors, made refactoring much simpler and <code>&lt;insert 7,000 other reasons for choosing to leverage static type checking&gt;</code> had I started this project in TypeScript.</p>

<h2 id="thetakeaway">The Takeaway</h2>

<p>I'm sure this sounds like a love song to static typing (of which I am generally a huge fan), but I do find that static typing will save you a lot of headaches at the cost of writing some slightly more verbose code. I miss a number of the nice shortcuts CoffeeScript provides now that I have picked up TypeScript, but saving myself a few keystrokes now is not worth having to go through the hoops when a projects gets enormous. That's not to say I have ditched CoffeeScript though; it still has a place in my tool belt. I still default to CoffeeScript on small, quick scripts where the gains from static typing would be questionable at best.</p>

<p>Now don't get me started on Ruby...</p>]]></content:encoded></item><item><title><![CDATA[Checking for Uniqueness in Doctrine]]></title><description><![CDATA[<p>Doctrine allows you to add unique constraints to tables, but what happens when you try to flush a change that would result in a collision? Doctrine introduced an exception type in 2.5 that will allow you to catch and handle problems maintaining your uniqueness constraint: <code>Doctrine\DBAL\Exception\UniqueConstraintViolationException</code></p>]]></description><link>https://www.blakeharley.com/checking-for-uniqueness-in-doctrine/</link><guid isPermaLink="false">bab80b15-9490-4d67-8259-31cc7bd714f9</guid><category><![CDATA[php]]></category><category><![CDATA[how to]]></category><dc:creator><![CDATA[Blake Harley]]></dc:creator><pubDate>Sat, 07 Mar 2015 21:04:00 GMT</pubDate><content:encoded><![CDATA[<p>Doctrine allows you to add unique constraints to tables, but what happens when you try to flush a change that would result in a collision? Doctrine introduced an exception type in 2.5 that will allow you to catch and handle problems maintaining your uniqueness constraint: <code>Doctrine\DBAL\Exception\UniqueConstraintViolationException</code>.</p>

<p>Let's assume you have the following entity:</p>

<pre><code class="language-php">&lt;?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(
 *     uniqueConstraints={
 *         @ORM\UniqueConstraint(columns={"email"})
 *     }
 * )
 */
class User  
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    public $id;

    /**
     * @var string
     * @ORM\Column(type="string", nullable=false)
     */
    public $name;

    /**
     * @var string
     * @ORM\Column(type="string", nullable=false)
     */
    public $email;
}
</code></pre>

<p>and we try to create a new user:</p>

<pre><code class="language-php">$user = new User;
$user-&gt;name = 'Nick';
$user-&gt;email = 'dronepilot@example.com';

$em-&gt;persist($user);

try {  
    $em-&gt;flush();
} catch (Doctrine\DBAL\Exception\UniqueConstraintViolationException $e) {
    echo 'That email address has already been taken.';
    exit;
}
</code></pre>

<p>Now whenever a user tries to create an account with the same email address, they will trip our <code>try/catch</code> block instead. There's a problem with this approach though: what happens when you have multiple unique constraints and you want to know which one failed? Unfortunately this doesn't have a "simple" answer. Maybe the exception has some clue. Let's take a look at the exception's message:</p>

<pre><code class="language-sql">SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'dronepilot@example.com' for key 'UNIQ_2DA17977E7927C74'  
</code></pre>

<p>Hmm... that doesn't really help. How can we improve this? Maybe if we give the constraint column a name, we'll have something to look for later. Assuming we have made the following changes to our entity:</p>

<pre><code class="language-php">&lt;?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(
 *     uniqueConstraints={
 *         @ORM\UniqueConstraint(name="unique_email", columns={"email"}),
 *         @ORM\UniqueConstraint(name="unique_username", columns={"username"})
 *     }
 * )
 */
class User  
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    public $id;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    public $name;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    public $email;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    public $username;
}
</code></pre>

<p>we should now get en exception message that looks like:</p>

<pre><code class="language-sql">SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'dronepilot@example.com' for key 'unique_email'  
</code></pre>

<p>Writing a regular expression to parse out the relevent column should be pretty trivial at this point:</p>

<pre><code class="language-php">preg_match('#\'unique_([^\']+)\'$#i', $e-&gt;getMessage(), $matches);  
</code></pre>

<p>The solution isn't ideal, but it works. <strong>Note</strong> that you cannot use the <code>unique</code> property on the <code>@Column</code> annotation with this as it does not allow you to specify a column name.</p>]]></content:encoded></item><item><title><![CDATA[SoundBlock: A Review]]></title><description><![CDATA[<p>I have always wanted a Bluetooth speaker for bathroom and gym use (<em>don't worry, I use the gym in my apartment complex that no one else uses</em>), but I have never seriously looked for one.</p>

<p>On a whim, I purchased a <a href="http://www.amazon.com/gp/product/B00HHDLMEQ/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B00HHDLMEQ&amp;linkCode=as2&amp;tag=blakharl-20&amp;linkId=MVHL77WAWGGFWPC6">SoundBlock Bluetooth Speaker</a> in black. The price was okay,</p>]]></description><link>https://www.blakeharley.com/soundblock-a-review/</link><guid isPermaLink="false">15b95242-0f25-4b31-b4e7-3ee8b04bfea2</guid><dc:creator><![CDATA[Blake Harley]]></dc:creator><pubDate>Mon, 23 Feb 2015 05:00:00 GMT</pubDate><media:content url="https://www.blakeharley.com/content/images/2015/05/soundblock.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.blakeharley.com/content/images/2015/05/soundblock.jpg" alt="SoundBlock: A Review"><p>I have always wanted a Bluetooth speaker for bathroom and gym use (<em>don't worry, I use the gym in my apartment complex that no one else uses</em>), but I have never seriously looked for one.</p>

<p>On a whim, I purchased a <a href="http://www.amazon.com/gp/product/B00HHDLMEQ/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B00HHDLMEQ&amp;linkCode=as2&amp;tag=blakharl-20&amp;linkId=MVHL77WAWGGFWPC6">SoundBlock Bluetooth Speaker</a> in black. The price was okay, and the reviews on Amazon were solid.</p>

<p>I was not expecting to get much out of a small speaker like this. In my experience, speakers in this form factor tend to sound like music coming from the bottom of a toilet. I am glad to say that I was pleasantly surprised when I finally received my little guy.</p>

<p>The SoundBlock gets decently loud, sounds good, and&mdash;best of all&mdash;it has bass. Granted, this thing probably won't drive your next outdoor BBQ, rattle your neighbor's walls or prevent an audiophile from clawing at his or her ears, but if you want anything like that from this form factor: you need to adjust your expectations.</p>

<p>Pairing your Bluetooth device with this speaker is a breeze. It has no pairing codes or button combinations&mdash;just turn it on and connect your device to it. That does come with a small security concern though: anyone within range of the speaker can connect to it and use it. Normally this should not be a problem, but it is something to be aware of. If Bluetooth is not quite your speed, the SoundBlock also accepts your standard 3.5mm audio cable.</p>

<p>Unfortunately, I have not had a chance to stress the battery to verify the claimed lifespan. I have only used the SoundBlock while getting reading in the morning and during my gym time. I charge it between uses, so it does not have a chance to get very low. Charging is done with a micro-USB cable. I have a lot of these lying around, but it includes one if you don't. It doesn't, however, come with an adapter to plug it into the wall, so you will need to use a computer to recharge the speaker if you do not have any of these.</p>

<p>Beyond functionality, I also have to comment on the SoundBlock's aesthetics. The packaging is okay. At first glance the packaging is nice, but the product image on the outside did not match the color of the device I received. The plastic tray holding the device inside of the box also felt cheap&mdash;betraying the quality of the box. Thankfully the ordeal was free of that frustrating plastic clamshell nonsense.</p>

<p>The device itself looks nice: the plastic has a very nice feel, the buttons are solid and the speaker grill has a nice ripple to it. It also feels like a solid device. Not solid enough to take too much of a beating, but enough to shrug off that cheap plasticy feeling that plagues too many devices these days.</p>

<p>If you are in the market for a speaker like this, I strongly suggest giving this one your consideration. I am surprised by how much I ended up enjoying this little device.</p>]]></content:encoded></item><item><title><![CDATA[Little SASS Tip]]></title><description><![CDATA[<p>As I was working in SASS the other day, I found out that you can join list variables with a comma:</p>

<pre><code class="language-stylus">$baseFont:    Helvetica, Arial, sans-serif;
$readingFont: 'Helvetica Neue', $baseFont;
</code></pre>

<p>Probably not news to many people, but it helped me.</p>]]></description><link>https://www.blakeharley.com/little-sass-tip/</link><guid isPermaLink="false">8cc54ed1-048d-496f-8559-5f3124a95c33</guid><dc:creator><![CDATA[Blake Harley]]></dc:creator><pubDate>Mon, 23 Feb 2015 04:03:00 GMT</pubDate><content:encoded><![CDATA[<p>As I was working in SASS the other day, I found out that you can join list variables with a comma:</p>

<pre><code class="language-stylus">$baseFont:    Helvetica, Arial, sans-serif;
$readingFont: 'Helvetica Neue', $baseFont;
</code></pre>

<p>Probably not news to many people, but it helped me.</p>]]></content:encoded></item><item><title><![CDATA[Markdown Mediawiki Extension]]></title><description><![CDATA[<p>When it came time to get a wiki running at work to document several projects, Mediawiki was the “obvious choice.” Unfortunately, the state of extensions over there is a very sad state. Numerous extensions have not been updated in years and most are poorly documented.</p>

<p>Most notably, there was a</p>]]></description><link>https://www.blakeharley.com/markdown-mediawiki-extension/</link><guid isPermaLink="false">c82f5d44-756a-4d2a-8bb9-a3d490112fcb</guid><dc:creator><![CDATA[Blake Harley]]></dc:creator><pubDate>Sat, 30 Aug 2014 04:07:00 GMT</pubDate><content:encoded><![CDATA[<p>When it came time to get a wiki running at work to document several projects, Mediawiki was the “obvious choice.” Unfortunately, the state of extensions over there is a very sad state. Numerous extensions have not been updated in years and most are poorly documented.</p>

<p>Most notably, there was a distinct lack of Markdown syntax support. You’d figure with Markdown being all the rave these days, <strong>someone</strong> would have made an extension for this. The only thing I could find was <a href="http://www.mediawiki.org/wiki/Extension:MarkdownSyntax">this extension</a>. To my surprise, the extension didn’t work.</p>

<p>To get things running around here, I quickly threw together a Markdown extension for Mediawiki: <a href="https://github.com/bharley/mw-markdown">Markdown</a>.</p>

<p>It’s a little rough around the edges, and there are a few <a href="https://github.com/bharley/mw-markdown/issues/1">usability issues</a>. Feel free to use it though.</p>

<p><strong>Bonus</strong> I also made a <a href="https://github.com/bharley/mw-hidesubpageparents">HideSubpageParents</a> plugin. Enjoy!</p>]]></content:encoded></item></channel></rss>