Monday, January 23, 2017

A Hacker's Guide To The Dip

While searching around for an old post, I discovered this draft I originally composed on 6/26/2007. Nearly everything written below I still agree with. I can't imagine why I didn't publish this back in 2007.

Seth Godin's latest book, The Dip is a must read. In it, he describes the typical flow of a project: things start off fun and exciting, and overtime, become difficult. The fun goes away and all that's left is the work. This stage of the project is called The Dip. Seth's book explores this concept and makes valuable recommendations for dealing with it.

It occurred to me that most large programming projects fit this model to a tee. If you take on a complicated enough project, whether it's for business or pleasure, you're going to hit a stage where it's simply not much fun anymore. Here are some of my preferred ways to deal with this fact of life. I'd love to add yours to the list, so mention them in the comments. Thanks!

A Hacker's Guide To the Dip

  • Expect It. This is a key point in Seth's book: projects are going to have a dip associated with them, so decide up front if you are ready to go through it or not. If not, quit while your ahead.
  • Embrace It. This was a fairly surprising idea that Seth presented: The Dip is actually a very good thing. Long story short, it will keep out all your competitors. If you are struggling like heck to get a cross platform UI to work, then, the good news is, so are your competitors. Pick a tricky problem and nail it. If you've got a big dip, then you've got plenty of protection against other hackers.
  • Have Fun. I admit it, I like to program in Scheme because it's fun. That's not the only reason I do it, but when facing the fact that I've got plenty of hours of programming ahead of me, it's nice to start off with something that's just plain fun. Chuck Moore, the inventor of Forth has even advocated a fun-down approach to programming (see chapter 3 of Thinking Forth).
  • Little Victories. Rather than facing the huge goal of a finished and shipped project, setup small victories that you can accomplish. These may be things as simple as saying: I'm getting Tomcat setup today. Fight The Dip by making itty bitty dips that you regularly beat.
  • Write Only Mode. What to do when you're working on some tricky aspect of a project and more requirements start flooding in? This only makes The Dip larger. For this, I typically create a Wiki and start documenting each request. I don't think, evaluate or prioritize them - I just record them and continue on with what I'm working on. When I've gotten to my next victory and am ready to face more of The Dip, I can go back to the list.
  • Demand Flow. Flow is that intoxicating state where time seemingly stops and work just gets done. It's glorious. The Dip disappears during flow. Make sure you setup an environment which is conducive to flow - this means no interruptions and a long stretch of time program. Not every programming session can be like this, but you should plan for a significant number of these.
  • Tune Your Dev Environment. No serious project can get accomplished until the environment is there - this means a trivial code-compile-test loop, source control, deployment is automated, and lots of other details. If there's any roadblocks to basic development, The Dip will get you big time.
  • Share Your War Stories. When the going gets tough, and it will, it's handy to have a community you can share your frustrations with. By sharing your progress and getting ideas, you'll be reminded why the heck you started this crazy project in the first place. It will help you get and stay motivated.
  • Sharpen Your Tools. When The Dip starts really getting steep consider taking a step back and optimizing your tools. Sure, you've got the basic environment there, but are there things you're doing with 4 key strokes you could do with one? Are you adding the same header to every file, so why not get your editor to do that work? An improvement in your tool set will help increase your momentum and take away yet another roadblock to your success.
  • Program Yourself Out Of It. When things get arduous ask yourself why that is? Perhaps you're writing class after class which looks more or less the same. Time to break out the code generation tools. By taking a step back and looking at the problems behind your problems, you can have a big impact on making the development fun again.
  • Visualize A Solution. When I have a bit of free time, I'll often work visualize in my head how I'm going to program a solution to some problem. I'll run through in my head which classes I'm going to create and how they'll connect. If I'm lucky, I'll actually discover a problem and re-work the design before I even write a line of code. By having the solution in your head before you even sit down, the programming session goes much smoother and The Dip is held at bay.
  • Don't Force It. I can recall my first big project I worked on. I needed to free up some memory, so I traced through hundreds of lines of code adding in various calls to free(). It felt wrong at the time, but I just pushed through it. The next I realized I could have changed a single point in the source code instead of the hundreds that I did by moving up the stack one level. I learned my lesson - if it doesn't feel right, don't do it. The solution will come to you, don't rush it.
  • Eat. Sleep. I find that my outlook on life is dramatically effected by the amount of sleep I've had and my blood sugar. Every night of bad sleep I have in a row makes my outlook on life just a bit dimmer. And then, when I finally do get a good night sleep, poof, everything is great again. Know your body, and know when you should and shouldn't be doing battle against The Dip.
  • Run. For me, there's nothing that clears my head like a jog. I find that I can work out problems while huffing and puffing that stumped me in front of a computer. This works for me, find out what activities work for you, and give your brain a chance to process.
  • Stick With It. There's no secret to this - just keep programming like mad. And before you know it, you'll be through The Dip and onto the good stuff.

Friday, January 20, 2017

Weekly Discoveries: The Giving Tree, a bit of jazz and a most remarkable violinist

This week in music I stumble on a bit of jazz, and a remarkable guitar street performance. But the most unusual find has to be Lindsey Stirling's work.

Lindsey's video that I linked to has 4 million views - so it's not as if she's an undiscovered talent, it's just that I've been apparently living under a rock.

Lindsey's schtick is that she's a violinist. And dancer. And singer. And, she chooses to use her talents to make the most non-traditional violin, dancing and singing work possible. I can't say that I love her music, but I do love what she's accomplished. I can just imagine her telling her friends, yeah, I'm going to be a rock star solo violinist. Sure you are Lindsey, sure you. And that's what she is. Good for her!

In the non-music videos, there's a sweet bottle opener build, and proof that you can cook over tea light candles.

Happy inauguration day! When you've had enough political coverage, give these tunes a listen!

Thursday, January 19, 2017

Web Based Protocol Handlers: The fastest user experience in the shortest amount of dev time

Firefox's Web Based Protocol Handler support has to be one of its hidden gems. Once a handler is registered, you gain especially quick access to specific content on the web. For 3shrink, this means quick access to the URL behind the 3 letter codes the site produces.

For example, to visit the URL behind the code PQW I need only type the following in my browser bar:


The protocol handler serves as the complement to the 1 click bookmarket, insuring that both growing and shrinking a URL is as streamlined as can be.

Best of all, implementing a Web Based handler couldn't be simpler. You need only make a call to: navigator.registerProtocolHandler. Here's the code that powers the register protocol handler link on 3shrink:

 * A PHP file for rendering the code needed to install a web
 * based protocol handler.
$domain = item_domain();
$code = <<<EOF
(function() {
  var proto = prompt("Protocol? (ex: grow)");
                                    "$domain Handler");

$code = esc_attr($code);
<a href="javascript:<?= $code ?>">Install Firefox Protocol Handler</a>
(<a href="">Huh?</a>)

Note how the code above prompts the user to enter the protocol name. That way, you could have personal and business and point them to two different 3shrink domains.

When you click to register a protocol, you'll a sort of pop-up bar message thingy:

The first time you use the protocol (that is, enter: grow:...) you'll be prompted to select the handler. While you're at it, select the checkbox so you're not nagged about this again:

One gotcha: attempting to access a protocol containing only numbers fails. For example:


Will take you to: - not what I wanted. The fix for 3shrink is to use any letter prefix. So you can type:


I'm amazed I haven't found more uses for web based protocol handlers. For advanced users, you can offer a terrifically fast user experience at almost no cost in terms of development time.

Wednesday, January 18, 2017

Adventures in Landscaping

For the past few years, as I've hired someone to cut our lawn, I've wondered aloud to Shira what it would take to have some "real" landscaping done to our property. What if we brought in a pro, instead of just hiring someone to cut the grass. This year, I finally got off my butt and decided I'd try to get this answer. My first stop: I searched for landscapers on Yelp and sent out a few contact-us requests.

And this is where I learned my first lesson: there's a difference between someone who does landscaping and a landscape designer. Despite what I thought was a clear request ("hey, can you draw me up a design / recommendation for our property?") every person I contacted showed up ready to give me a price to cut my grass. Yeah, that's not really what I wanted.

Just as I was beginning to think that my request only made sense if you owned a 7 acre estate, I got a lead to an individual over at Merrifield Garden Center. I poured out my story about our tiny lawn, and how I'd been curious about what a professional would do to improve the property. Turns out, I was talking to the right gal. She explained to me that she'd be glad to assess our property, sketch up a plan, and of course, put together a proposal to get work done. There was a nominal fee to have her come out and write up the plans, which I was actually glad to hear about: I wanted to pay someone to think this through, versus showing up to my property and recommending their first impression.

A few weeks later, I had the plan in my hand I was so curious about. It called for quite a bit of hardscaping in the back yard, due to the amount of shade we get back there. It also had a clever selection of plants that would look good throughout the year, be low maintenance and be sized to our property. Heck, she even included an especially fragrant plant to cover an additional sense. In other words, she did things all the things a classic landscaper designer is supposed to do.

I now had my plan and a proposal to implement it. As I considered what to do with it, Shira stepped in and took control. Turns out, we could save a few bucks doing the work in the winter time. And before I knew it, we had a crew of folks demo'ing our front walkway. In the span of 2 weeks, I watched as our entire property was overhauled from blah to looking great.

I have to say, Merrifield did a top notch job. The designer who worked on the plans was at the site every day, tuning things as need be. Any concerns Shira or I had were quickly addressed. Overall, I couldn't be more impressed.

Want the name of our landscape designer? I'd love to provide it. Just hit me up at: and ask.

Tuesday, January 17, 2017

Gotcha of the Day: iOS Cordova App running in iSimulator Hangs on Splashscreen

I recently submitted Cordova iOS to iTunes, only to have it rejected because the app was hanging on startup. Turns out, the app worked fine on a real device, but on a simulator, the app's splashscreen wouldn't ever be hidden.

On the simulator, I did notice that if I returned 'home' and relaunched the app, it did function. It was all very confusing.

I was already working around this quirk in the splashscreen plugin:

The config.xml file's AutoHideSplashScreen setting must be false. To delay hiding the splash screen for two seconds, add a timer such as the following in the deviceready event handler

After further debugging, I learned that:


was being called, yet, it wasn't having any effect.

To add insult to injury, the IO Simulator's console log wasn't showing the output of JavaScript's console.log(...) messages. The 'debugging' above involved using old school alert statements.

I solved the mystery of the missing console.log statements by following the instructions here. I'd totally forgotten that you can remotely monitor a web instance from within Safari. Frankly, it's sweet functionality, even if a bit non-intuitive.

  1. On your real iDevice or in iOS simulator go to Settings > Safari > Advanced and turn on Web Inspector.
  2. Desktop Safari: Safari > Preferences > Advanced and select the Show develop menu in menu bar checkbox.
  3. Now that you have either iOS Simulator open or your iDevice connected to your mac start using web inspector on your website: On your mac, open Safari and go to Develop

Along with my new found console.log statements, I saw the following message being repeatedly blurted out:

Refused to load gap://ready because it appears in neither the child-src directive nor the default-src directive of the Content Security Policy.

Eager to fix *something*, even if it's not the splashscreen bug, I Googled for this message. I found this discussion, which as the message itself suggests, shows that the Content-Security-Policy meta tag needs to be updated.

To shut the app up, I went ahead and updated my CSP to be:

<meta http-equiv="Content-Security-Policy" 
   content="default-src * 'self'; style-src * 'self' 'unsafe-inline'; script-src * 'self' 'unsafe-inline' 'unsafe-eval'">

I relaunched the app, and not only did the message disappear, but the call to navigator.splashscreen.hide() worked!

And of course, this all makes sense now: the call to hide the splashscreen was failing due to a lack of permission by the page. I added the permissions and things were back to working.

Why this was failing in the simulator and not a device, I can't really say. But I'm just glad it's working.

Monday, January 16, 2017

Weekly Discoveries: Israeli Rap, WOGN, Van Hacking and a Sweet Alchol Stove Design

So yeah, I meant to post this last Friday, but the week got away from me. Better late than never.

Among other finds: some sweet tunes, an remarkable van transformation and a novel stove design that requires little more than a tea candle, pop can and scissors to build.


Friday, January 13, 2017

3shrink: adventures in one click shrinking

While I'm pleased with the core functionality of 3shrink, it definitely needed a faster interface. That is, a way to effortlessly encode and decode 3shrink URLs, as well as bits of text. For now I've only solved half the problem, the shrinking side of things. The solution was straightforward: create a couple of bookmarklets. Here they are in action.

With these bookmarklets in place, I'm only one click away from a 3shrink code.

The implementation of the bookmarklets is nearly trivial. Here's the PHP snippet that powers them both:

 * A PHP file for generating a URL shrinking bookmarklet
$code = <<<EOF
  window.location = 
    'http://{$_SERVER['SERVER_NAME']}/shrink?i=' + encodeURIComponent($src)
$code = esc_attr($code);
<a href="javascript:<?= $code ?>">3shrink <?= $label ?></a>

And here's the calling code that renders the bookmarklets in the footer:

<div class="footer">
  <a href="/">Home</a> | <a href="">Built By Ben</a> |
  [<?= snippet('bookmarklet',
       ['label' => "URL", 'src' => 'window.location']) ?>]
  [<?= snippet('bookmarklet', 
       ['label' => "TXT", 'src' => "prompt('Text to Shrink')"]) ?>]

Installing the bookmarklets is as simple as browsing to your preferred instance of 3shrink, say and dragging the appropriate links from the footer into your bookmark toolbar.

You'll want to note that the bookmarklet's a domain specific. That is, the bookmarklets in the footer of the site register URLs with a different context than

With the shrinking side of things streamlined, the next area to focus on is how to quickly expand 3shrink codes. Stay tuned for that solution.

Wednesday, January 11, 2017 In Pursuit of Paper Friendly URLs

But Why?

Recall that my paper based TODO list had two challenges to overcome. First, I needed a backup/archiving mechanism, second I needed an easy bridge from the paper to the digital world.

The former issue, backups, was easy solved: every morning I splay out the various index cards I'm tracking tasks on (with each card representing a single project) and snap a photo of them. If I lose, or corrupt any of the cards (read: spill tea all over them), I've got a photo I can use to recover my lost work.

The latter issue I solved by use of a jerry-rigged URL shortner. Essentially, I can turn any entity associated with a URL (an e-mail message, bug report, Google Doc) into a 3 letter code. I've found that even with my crappy handwriting I can manage to neatly print 3 characters.

Here's a card for a hypothetical Project X:

Using the URL Shortner, I can jump to the resource associated with the first task using the code CLW.

This all works, and works surprisingly well.

However, it was nagging at me that my URL Shortner solution depended on a now defunct Google Apps Lab Project. While this works for me now, nothing stops Google from pulling the plug on this project tomorrow and I'd be left hanging. Also, I figured if I was getting benefit from these super short URL codes, maybe other folks would, too.

Introducing 3Shrink

I therefore give you: 3shrink is yet another URL Shortner, but unlike others out there, it focuses on making extra short, text friendly URLs. (OK, it does feel a bit like 7 minute abs, but bear with me here.) I quickly coded 3shrink, and you're welcome to grab the source code here to play with it. Or, just head over to to give it a try.

To make 3shrink truly useful I need to implement a corresponding bookmarklet and protocol handler. Stay tuned for those bits of code, but for now 3shrink does have some value.

For one thing, you can control the namespace associated with your 3 digit codes by changing the URL. The above codes, CLW, DEY and L48 were created in the instance. So visiting takes you to a valid link, whereas visiting will most likely give you a 404 page. You can even point (CNAME) your own domain, say, to the 3shrink server, and it will use that as the corresponding name space. It's all very mailinator like.

And like mailinator, there's effectively no security. There's no obvious way to get a list of all URLs associated with an instance, but if you spent enough time poking at you could figure out all the URLs associated with it. So be smart. You can also use a more difficult to guess submdomain if you want a bit more security.

Throw &geek=1 on any 3shrink URL, and you gain access to a trivial text based API that Tasker, curl and friends can easily plug into. See:

$ little=`curl -G -s \
  --data-urlencode i= -d geek=1 `
$ big=`curl -G -s -d i=$little -d geek=1 `
$ echo $big
$ echo $little

And finally, 3shrink isn't limited to encoding and decoding URLs. It's happy to shrink any text that's 1024 characters or smaller. This lets you turn an address, latitude and longitude or a Tweet into a handy 3 character code. Like the following:


So there you have it, Go and put it to use. Where will your 3 letter URLs take you today?

Tuesday, January 10, 2017

My BestBuy Criticism Explained

A couple weeks back I stopped by Best Buy to purchase a new lens. The clerk who helped me was nice, but powerless: while the lens was on display, I wouldn't be able to actually try it out in the store. For one thing, all the lenses were locked to the camera bodies, and for another, all the camera batteries were dead. I told the clerk I would go ahead and buy the lens, but then I muttered something customer experience and talking to his manager.

I doubt the clerk understood what I was talking about, so here is my criticism, in detail.

For nearly everything I buy today, I first turn to Amazon. The prices are reasonable, the ordering process streamlined (1 click, baby!) and the customer service quite solid.

However, for certain expensive electronics, I've found a better option: buying them at the local Best Buy. Best Buy price matches Amazon without a fuss, and being able to pick up the item versus wait a few days is a nice bonus. Best Buy has a free rewards program that earns me back a few bucks on big purchase, which I can in turn, put forward toward my next tech splurge. Best of all is the return policy: I can easily walk into a Best Buy and return anything, versus having to repackage and potentially pay for shipping.

For something like a Canon EOS Lens, Best Buy was the ideal solution.

But the camera setup at Best Buy is clearly lacking. How on Earth can then expect to sell expensive tech like cameras without allowing folks to actually use them? That's like trying to sell TVs without allowing folks to turn them on. The obvious answer is, they don't really care about selling DSLRs. And that's OK; that's their prerogative.

However, Best Buy should know that it's earning my business because of their actions, and it's these same actions that can lose it. All it wouldn't take is for a photography obsessed clerk at Staples, two doors down, to go to his manager and push for a better photography setup. She would explain that not only should we have functioning cameras customers can experiment with, but we should have a short term rental program. Want to try out this $9,000 500mm lens? Sure, let us take your driver's license and here, have a good time. The process works for car dealers, so why can't it work for camera sales?

Oh sure, the process would take effort. And it may not earn a whole lot of new business. But I'd be there. And my days of stopping by Best Buy to pick something up would be over.

It's fine when a business choses not to offer a service or particular experience. Where things fail is in the blind spots: when a business doesn't even realize they're offering a cruddy service or experience. Choices are good, blind spots are bad.

Update: After hitting publish on this post, I figured I'd hit and drop them a Contact Us message with this link. Unfortunately, I couldn't find any intelligent way to leave this feedback. Alas, this seems typical for a big company on web. Perhaps another blind spot?

Friday, January 06, 2017

Weekly Music Discoveries - New Year's Edition

These days, I find myself gravitating to YouTube for my music needs. In general, YouTube's on the fly 'mixes' are a serviceable way to pick a song and stream tunes, all with control of jumping to a totally different song when the mood strikes. The only issue I find after a few intensive days of doing this is that all my playlists tend to converge. While it blows my mind that a song can have *billions* of views (or listens?), and I'm willing to admit I enjoy popular music as much as the next guy, I did find myself craving something totally fresh.

At one point I tripped over Vevo's New Indie Videos and was pretty much blown away: for 70+ songs in a row I listened to band after band I'd never heard of. Sure not a lot of it was great, but just to 'discover' a new heap of songs and artists was a pleasure.

And so in that vein, I give you my weekly Music Discoveries for the very first week of 2017. Some of these songs struck me as winners the very first time I heard them, others took a couple of listenings before I realized I liked them. There's even a homage to the recorder if you play close enough attention!

So press play, sit back and enjoy.

Listen to Ben's Music Discoveries


Related Posts with Thumbnails