Month: December 2013

Keep it light. Keep it simple.

Unknown

I tend to cook like I code. Hopefully it tastes better than Javascript.

Pan grilled the shrimp in a very small amount of olive oil. Threw some basic seasoning on there along with some red pepper flakes for kick and color. Lay that on a bed of fresh spring mix, corn, and peas for added protein. Bam!

Advertisements

Air Plant Installation

Air Plant Installation

The time I spend in Seattle has landed me in the land of terrariums and found objects. While hiking I often come across some really nice tree stumps, branches, etc that just beg me to bring them home so…

This piece is a mix of found objects and store purchased air plants (Tillandsias), stones, and moss. These plants have no root system and take all of their nutrients and moisture through leaves so you can just stick them onto things and they’ll live.

While I soak the plants once a week, I also spray the entire piece to keep it living. There’s natural moss on the stump that I’m trying to keep without taking over the wood.

Thank you, GRACE MA, for getting me into air plants.

JS Tests in Jasmine

Test driven development has been a welcome standard and a pain for a few of the team projects that I’ve been on. Since I tend to live on the client side I haven’t had to worry much about writing tests. Well, that’s over because the age of javascript applications is here.

Jasmine makes it super easy to test individual methods in your Javascript code. Let’s take a look at a simple code snippet.

currentFlo = 0;
currentTime = new Date().getTime();

Flos = {
    
    helloWorld : function(){
        return ("Hello world!");
    },
    detectFlo : function(time,startDate,cycle){
        var myTime = new Date(time).getTime();
        var myDate = new Date(startDate).getTime();
        var status = ( secToDays(myTime) - secToDays(myDate) ) % (cycle);
        return status;
    }
}

Lines 1-2 declare a couple of globals that we’ll use throughout the app. They contain no security risks or personal data.

Lines 4-7 create a basic “Hello world” response. I use this as a case positive to make sure that the framework is working at all. When this method stops working then something is definitely wrong. It serves no other purpose and likely will be ripped out on a production build.

Lines 9-14 makes the only real method in this example. It creates two variables with date strings that have been passed into it. Takes those two dates, converts them an actual number of days using a helper method, then runs some simple math on them. It returns an integer.

Ok, let’s examine the tests for these. Lines 1-5 will test the “Hello world!” method. I try to always put this test first since it’s really testing the framework. It’s made up of three distinct parts; describe(), it(), and expect(). The describe() function passes a simple text string to the test suite just so you have something human readable to describe the test. There’s no relation between the value and the actual method being tested. The it() function also passes a simple text string in the case of passing. Again, there’s no real relation other than the one in your mind as the coder. It should make sense to you and to anyone looking at the tests as to what this thing is supposed to be doing. Lastly, the expect() function is actually doing something.

It takes the real name of the method being tested and runs whatever comparison you desire against the result passed back by that method. The the case of Flos.helloWorld we’ll need to see if the string passed back is equal to “Hello world!”.

describe("Hello world", function() {
         it("says hello", function() {
            expect(Flos.helloWorld()).toEqual("Hello world!");
            });
         });

Now that we have a basic understanding and expectation of the framework we can start doing some actual tests. This nest snippet tests to see if those globals that we require through the app’s lifecycle have been instantiated. Do they exist at all?

We expect() them toBeDefined(). In the case of the currentFlo var we also expect it toEqual an integer value of zero. If I wanted to be really fancy I could also see if currentTime is within a certain number of milliseconds of ‘new Date()’ but let’s not go there.

describe("Checks if global currentFlo and currentTime exist", function() {
         it("currentFlo = 0 & currentTime exist", function() {
            expect(currentFlo).toBeDefined();
            expect(currentFlo).toEqual(0);
            
            var myTime = new Date().getTime();
            expect(currentTime).toBeDefined();
            });
         });

As you can see, these are just functions! Easy peasy, right? That means we can do pretty much anything we’d do in a custom method; declare variables, return methods as values, etc. The last snippet makes three primitives  and passes them to the detectFlo() method and then expects a value of zero to be returned. I try to use primitives because they are static over time. I know that these values worked when I wrote the test and they should always return zero no matter what the date is.

describe("Detect Flo", function() {
         it("returns 0", function() {
            var time = 1388135645554;
            var startDate = "2013-12-27";
            var cycle = 30;
            expect(Flos.detectFlo(time,startDate,cycle)).toEqual(0);
            });
         });

Flojugger Jasmine TestsWhen this is all done and ready to test you can just load the test suite into any JS browser. When all the tests pass you get something like this. It’s remarkably fast, simple, and reliable.

SFAF.org

SFAF

Established in 1982, our mission is the radical reduction of new infections in San Francisco because we refuse to accept HIV as inevitable.

The San Francsco AIDS Foundation came to me with a handful of Photoshop files from a designer and instructions to “make it work in any content publishing system”. No problem! We created a custom JS navigation system that had a single dependency, JQuery. The CSS was also custom which allowed us to escape the “everything looks like bootstrap” issue. These two decisions made for an amazingly lightweight and extensible end product. What would I do differently? While the home page is built to work across content contexts, a responsive design throughout was not in the cards for the project. The designer delivered desktop only context layouts. I would LOVE to go back and make the existing look and feel more responsive to mobile and alternative platforms like televisions.

There’s a cheaper alternative to Github

Github is great if you want all of your code to be public. Open source is all about being available to everyone all the time. That’s a good thing. The thing is, when you’re looking for a place to store your not so public code Github’s pricing plans can get a bit steep.

Let’s say that you have 50 projects that you want code storage for. These are personal projects or client projects that you don’t want the world forking and making their own versions of. On Github that’ll cost $50/mo. Now let’s say that you want someone else to also have access to this repo. Just went up to $100/mo. That’s a lot of scratch for some fairly inactive code.

Codeplan private Git storage

Unlimited repos, unlimited users, 2GB storage cap for $9/mo.

I recently came across an upstart Git service called Codeplan. They offer unlimited private repos for $9/mo with one restriction, 2GB total limit. That’s a lot of space! No limit on the number of users, either.

So if you’re looking for no-frills, very affordable, and reliable private Git hosting… the math speaks for itself.

Simple model is best!

Flojuggler for IOS on Github

So I’m sitting there looking at my model class for the Flojuggler app and wondering at how simple it is. Instinctually I worried that it was too simple and needed some data exchanging panache but then I remembered that a good model should be simple.

var Model = {

 openDB : function () {
 if (window.openDatabase) {
 db = window.openDatabase("flos","1.0","Local database of flos", 1024*1000);
 db.transaction(function(tx) {
 tx.executeSql("CREATE TABLE IF NOT EXISTS Flos (id INTEGER PRIMARY KEY, name TEXT, cycle INTEGER, long INTEGER, startDate DATE, thumbnail TEXT)", []);
 });
 } else {
 console.log("No browser support for DB");
 }
 },

 addFlo : function(e) {
 e = $.parseJSON(e);

 db.transaction(
 function(tx) {
 tx.executeSql("INSERT INTO Flos (name,cycle,long,startDate,thumbnail) VALUES (?,?,?,?,?)", [e.name,e.cycle,e.long,e.startDate,e.thumbnail], displayInsertResult);
 },

 function(err) {
 console.log("Error: " + err.message);
 }
 );
 },

 updateFlo : function(e) {
 e = $.parseJSON(e);

 db.transaction(
 function(tx) {
 tx.executeSql("UPDATE Flos SET name=?,cycle=?,long=?,startDate=?,thumbnail=? WHERE id = " + currentFlo, [e.name,e.cycle,e.long,e.startDate,e.thumbnail]);
 },

 function(err) {
 console.log("Error: " + err.message);
 }
 );

 },

 deleteFlo : function(id) {
 db.transaction(
 function(tx) {
 tx.executeSql("DELETE FROM Flos WHERE id = ?", [id], displayDeleteResult);
 },

 function(err) {
 console.log("Error: " + err.message);
 }
 );

 },

 getFlos : function() {
 db.transaction(
 function(tx) {
 tx.executeSql("SELECT * FROM Flos", [], initFlos);
 });
 },

 getFlo : function(id) {
 db.transaction(
 function(tx) {
 tx.executeSql("SELECT * FROM Flos WHERE id = ?", [id], populateEditPage);
 });
 },

 clearTable: function() {
 db.transaction(function (tx) {
 tx.executeSql("DROP TABLE Flos");
 });
 }
} //end model

In retrospect it seems like the getFlo method is unnecessary so I’m refactoring to remove it. There’s no need to do another database read if I already pulled the set with the getFlos method.

The clearTable method is more of  helper function than anything else. It’ll likely be removed before I ship this.