Jeff Lembeck learns a code or two

Serious code business!

Design Book Recommendations

I sent this tweet out the other day -

I’m making it a point this year to read more about design, the principles behind it, and the science of it - I would like some book recs

https://twitter.com/jefflembeck/status/426028933868302336

and also asked in the Filament Group chat room and have received some pretty good responses so far:

Edward Tufte's Visual Display of Quantitative Information

Design of Everyday Things

Stop Stealing Sheep and Find Out How Type Works

The Elements of Typographic Style

Pantone Guide to Communicating With Color

A Pocket Guide to Colour Accessibility

Interaction of Color: Revised Edition

Meggs History of Graphic Design

O'Reilly's Information Architecture for the World Wide Web

Thinking with Type

Universal Principles of Design

Don't Make Me Think

How Buildings Learn

Everywhere

Yell at me on twitter (@jefflembeck) if you have any others you'd like to contribute.

Workspiration

Hey neat,

Somebody thought it was a good idea to interview me on the type of site where they interview people who, for the most part, are those I look to for inspiration in my work. Cleverly enough, it's called Workspiration and you can see me ramble on about my work setups and making websites work in the third world over there.

Jeff Lembeck: Web Developer | Workspiration

Quick Servers in Different Languages

So, I've mentioned simplehttpserver before here, a quick rack script that will allow you to start up a server in your current directory, but there is a way better way in Ruby.

ruby -run -e httpd . -p 9090

If you're a fan of things like dotfiles, check this out: https://github.com/jlembeck/dotfiles/blob/master/.functions#L115

For PHP, you can run

php -S localhost:4000

or, something like this can be added to your dotfiles: https://github.com/jlembeck/dotfiles/blob/master/.functions#L108

How Do I Release My Own Grunt Plugin?

Background

By this time, if you work with JavaScript at all, you've likely heard about Grunt. Grunt has become the go to "build tool" and task runner for JS projects. It's used for projects backend and frontend alike and has a plethora of useful plugins that are easy to install and use. They cover everything from deleting files to compiling your sass files; you can even find something that can replace your icon solution by doing some awesome SVG magic.

Come up with a thing you need

If you're anything like me, doing anything twice is excruciating. Automation is wonderful and is forever, so let's take advantage of it. Maybe you've got a part of your build system where you want to use pngcrush to compress those image files down to the smallest they can be, and you're perfectly ok writing a node wrapper for the binary. Awesome. Let's turn this thing into a Grunt plugin.

Scaffolding

Death Star

For scaffolding the best (only?) tool out there is grunt-init

Grunt Init Page

To get grunt-init running, it's as easy as using npm install

npm install -g grunt-init

Grunt Init running in terminal

Then you just need to make folder for your grunt-init templates. You can do this by going to your home directory, and creating a hidden folder called .grunt-init.

$ mkdir .grunt-init

You then just need to clone the templates you want to use into that folder. The most commonly used templates are available here.

They even have instructions on the template pages for this.

Instructions for how to install grunt-init node

You want the Gruntfile one though, so you can run this to install (on Unix systems): git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile

Now, you can make that project!

$ mkdir grunt-pngcrush
$ cd !$
$ grunt-init gruntplugin

Grunt-init will ask you a set of questions about the project, for naming/testing/publishing purposes. You can just hit enter if you want take the suggested answer.

Gif of running the code to create the scaffolded project

Now, let's make sure it worked!

$ npm install
$ grunt

Passing tests in the terminal

Looks great!

Git To It

$ git init
$ git add .gitignore
$ git ci -m "Initial commit"
$ git add --all
$ git ci -m "Scaffolding!"

Using git to keep track of your things during this whole process is important. I suggest making your first commit your .gitignore file. That way, if you messed something up during scaffolding, you can revert everything going back to the .gitignore. Believe me, this is recommended.

Testing!

Let's talk about tests. I used to tell new developers at a company I once worked that handing over code without attached tests is like telling them to screw off and that your time is more important than theirs. I'm obviously into testing things. Your plugin should be no exception. Here's the thing though, you likely won't be writing a lot of small and easy to maintain functions for your task. It will likely be a glued together set of a few testable functions that are part of a library where you've already written said tests.

For this circumstance, I tend to use a couple of integration tests posed at unit tests. Luckily, the gruntplugin scaffolding already gave us some examples! Pop into the tests to check it out.

When you have looked those over, figure out what you're going to do, and maybe written a test or two because TDD is amazing, hack away! In my case, the file where the magic is happening is in "tasks/pngcrush.js." Yours should be somewhere similar.

Once you have your tests written and everything working swimmingly, go ahead and test the package by creating a fake project in another folder, then running npm install on this folder.

$ cd ..
$ mkdir test-grunt-pngcrush
$ cd !$
$ npm install ../grunt-pngcrush/

If this installs for you and runs from your other directory, it's time to publish this thing to NPM!

Publishing to NPM!

First thing's first, create an account at https://npmjs.org.

Next up, set up the account on your machine.

$ npm adduser

Now follow the prompts.

Time to publish!

$ npm publish

And you're done! Tell everybody about it! Freak out a little bit! Your code is on the internet! You can find more details for publishing here.

WHO DELETED THAT FILE?

So, there you are, working on a huge project that has 50+ devs on it because #enterprise and you realize that some files are missing. How long have they been missing? WHO DELETED THAT? WHY (most important question here, really)?Crap.

TO THE GIT-MOBILE

$ git log --diff-filter=D --summary

That will give you every commit where a file was deleted, but you don't have time to look through these, and you remember where these files were, right? So you go to use grep, that's a handy thing.

$ git log --diff-filter=D --summary | grep DeletedFile.js

Huh, but it gives you a print out that is useless. Let's see if we can't make our initial output a little better.

$ git log --diff-filter=D --pretty=format:"%h: %ae %an" --name-only

Well now we have all of our deletion commits coming out as

CommitHash: AuthorEmail AuthorName

file deleted

file deleted

...

We're closer, but not quite there.

Let's go back to using some grep; did you know that grep can also search backwards from your line? Oh, you didn't? We hereeee we go

$ git log --diff-filter=D --pretty=format:"%h: %ae %an" --name-only | grep -B 1 DeletedFile.js

Output looks like this now

CommitHash: AuthorEmail AuthorName

file deleted

For your specific file!

Woo!

Now, before you go asking questions, it's probably best to run a git show on that commit hash.

Case Sensitivity, Git, OSX, and You.

So, as a developer, there's a really good chance you build your websites using OSX, and that's great. I do it too and I really enjoy it. That being said, there's a little ... feature ... in the OSX filesystem of case-insensitivity on your files. This makes a lot of things easier for you when you're testing sites locally, but when you deploy to that, say, CentOS box and are reaching for your JS file that is named camelcase.js which it should be named camelCase.js, you're in big trouble.

So, because of that case insensitivity, if you rename the file in git, it's not going to notice, to the level that git mv just as a standard won't work. So, force it.

git mv -f camelcase.js camelCase.js

And check that sucker in. Solution found.

JavaScript function name(param) vs. var name = function(param)

Bloated title for this, I know, and likely a subject that will return more Google hits than one can possible imagine, but what's another lesson in how JS works?

There are two well-known ways to write a function in JS:

function foo( param ){
  console.log( param );
}

and

var foo = function( param ){
  console.log( param );
};

For most situations, what you're dealing with here is all one and the same. After this code runs, you can call foo(2) and it will, in turn, call console.log( 2 ). Seems simple enough. But what if somebody calls the function before it is defined on the page? Seems like a prime spot for an error, right?

foo(2);
var foo = function( param ){
  console.log( param );
}

Go ahead and write that into a file and run it. The result should be: "TypeError: undefined is not a function." This makes some level of sense. Due to hoisting in JS, you are calling the equivalent code of:

var foo;
foo(2);
foo = function( param ){
  console.log( param );
};

Clearly, at this point, foo is undefined when it is called.

Now, let's try the other way:

foo(2);
function foo( param ){
  console.log( param );
}

You’d expect the same result, correct? Of course not. This actually will print “2” out to the console.

Why?

Because functions created in this manner are not just hoisted at the name level, but also at the implementation level, so writing code like that is actually read like this:

function foo(param){
  console.log( param );
}
foo(2);

despite how you wrote it.

Big deal, you say. Who cares if every function I write has its implementation hoisted?

Let’s look at another example.

var foo;
if( true ){
  foo = function(){
    console.log( "true" );
  };
} else {
  foo = function(){
    console.log( "false" );
  };
}
foo();

Well, while this example is contrived, the output should be “true”, and it is.

What about if we changed the way we write functions?

if( true ){
  function foo(){
    console.log( "true" );
  }
} else {
  function foo(){
    console.log( "false" );
  }
}
foo();

Any guess out the output? It’s “false.”

Due to the hoisting of implementation, for the level of scope in which these functions exist, the lowest foo defined on the page, no matter where it exists in the flow, will win out.

This can be absolutely damaging if you’re, say, creating a callback based upon info being passed. So, be careful out there when creating functions.

My Git Workflow

Ya know what I hate?

[Project/dev] Merge branch 'dev' of github.com:filamentgroup/Project into dev - Jeff Lembeck

being all up in my commit logs.

So, I've changed up my git workflow a little bit to fix this:

Say I get a new feature to build on project "Project".

Normally, we work in the dev branch, and then push that thing into master after it's all tested and what not.

So

~/code/Project (dev) $ git co -b feature

This feature has 5 or 6 little code pieces to get it going.

~/code/Project (feature) $ git aa && git ci

SIDENOTE: I have some aliases up in my ~/.gitconfig file. aa = add --all ci = commit -i co = checkout

Make my comment, repeat a few times for every little thing I do.

$ git co dev $ git pull origin dev $ git co feature $ git rebase -i dev

Squash all of my commits down into one fantastic feature commit.

$ git co dev $ git merge feature

Pow. 1 commit added to our dev commit logs for this entire feature. Easy to navigate and easy to read.

OpenSSL and Gemfiles

Ever have this happen?

$ bundle install

Fetching source index from https://rubygems.org/ Could not verify the SSL certificate for https://rubygems.org/. There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn't have the CA certificates needed for verification. For information about OpenSSL certificates, see bit.ly/ssl-certs. To connect without using SSL, edit your Gemfile sources and change 'https' to 'http'.

According to this comment, there is nothing to be gained from using https with rubygems - https://github.com/rails/rails/pull/4684#issuecomment-3670624

But, since this is the default for Rails, let's fix this by installing OpenSSL.

$ rvm pkg install openssl

Now, you'll have to install any ruby that you have in order to get this to work. Oof.

rvm reinstall all --force

Using Ruby 2.0? Does this STILL not work? Your certificates are probably outdated.

Luckily, <a href="raggi has given us something to update the certs on our machines - https://github.com/raggi/openssl-osx-ca

brew tap raggi/ale brew install openssl-osx-ca

Hopefully that fixes your problem like it did for me.

Edit: From what I've read out there on the internet, you can just install Ruby 2.0 like this:

rvm install 2.0.0 \ --with-openssl-dir=$HOME/.rvm/usr

instead and this problem will never arise in the first place.

Good times.

Presto Change-o

Yeah, I did that.

Opera is changing from the Presto engine to the Webkit engine. Actual story here: 300 Million Users Move to Webkit.