Peer Pressure for Rails 3

Blazing Cloud is working on a new iPhone application, called Peer Pressure.  The idea is that you get your friends to help you achieve your goals.  We’re beta testing it and it is at the point where I feel ready to try a public goal.

I’ve have been working on updating my class curriculum for the Rails class that starts on Sept 26.  A lot of people have asked me about how to get started with Rails 3 if they already know Rails, so I thought I would write up a few notes along the way.  So my goal is to create some short “Cliff Notes” on Rails 3.

The idea is that I set up these milestones and check them off each day. I’ve made these to happen daily, but they could happen on a schedule where some milestones take more time.  (You can do quantitative goals too which chart with a line graph.) Here are my goals ready to be checked off:

I’ll be able to add a note and photo if I want when I complete a milestone.  I can preview my progress, which currently looks like this:

SVG Scripting with JavaScript Part 1: Simple Circle

I recently embarked on the task of converting an interactive Flash widget to SVG (Scalable Vector Graphics) and DHTML. The incentive for this project is primarily to make this widget work on the iPad which does not support the Flash player. SVG has been supported in all major browsers except for IE including mobile browsers for a long time. And now that IE 9 will include native support for SVG (finally!), this technology will soon actually be a viable option for cross-browser graphics support.

There are two ways to include SVG graphics in a web page. One is to create an SVG document using the SVG DOM. This type of document has a different MIME type and supports a different tag set than a standard HTML document. In this way you can declare your SVG elements using markup just as you would your normal HTML elements . This mechanism is appropriate if your entire document will be composed of SVG elements. You can script this type of document just as you can a standard HTML document.

The second method is to create SVG elements inside of a regular HTML document using JavaScript. This method is appropriate if you want to enhance an HTML page with some fancy graphical elements, but you still want the basic HTML support. Creating SVG elements in this way using JavaScript is fairly straightforward but there is not a lot of info out there describing how to do it. I will attempt to remedy this with a series of posts (this being the first) explaining how to create and add various SVG elements to an HTML document. I will try to cover the basics to get you started, and also any tricky stuff that I run into as I progress through my project.

Given the increasing use of mobile devices to browse the web, I will limit the scope of what I cover to only the subset of SVG that is included in the SVG Tiny spec, which is the set of SVG supported by Mobile Safari.

I will assume you have a basic knowledge of JavaScript, CSS and the DOM as I present this material. For a primer on DOM scripting see the W3C’s JavaScript and HTML DOM Reference.

OK, here we go. I will start off with a simple example that creates the base SVG document and draws some circles in it. Start with a simple HTML document like this:

<html>
	<head>
		<title>SVG Circles</title>
        <style>
            #svgContainer {
                width:600px;
                height:200px;
                background-color:#EEEEEE;
            }
        </style>
        <script>
            window.onload = function() {
            }
        </script>
	</head>
	<body>
	    <div id="svgContainer"></div>
	</body>
</html>

This document includes a div with id “svgContainer” that will hold your SVG graphics. It also includes a window.onload handler where your script will go.

To create an SVG graphic you need to start with the base “svg” element, which acts as a container for your graphics. In an SVG document this would be the outermost DOM element in the tree. Inside your onload handler add the following code:

        var container = document.getElementById("svgContainer");
        var mySvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        mySvg.setAttribute("version", "1.2");
        mySvg.setAttribute("baseProfile", "tiny");
        container.appendChild(mySvg);

This creates the base SVG element to which you will add your circle elements. Note that you need to use the DOM method “document.createElementNS” rather than the standard “createElement” because the “svg” element is part of the SVG DOM rather than the HTML DOM. For a complete specification of the valid attributes of an svg element see the W3C SVG Tiny Spec Section on the SVG Element

Now add a circle to your SVG element with the following javascript:

var c1 = document.createElementNS("http://www.w3.org/2000/svg", "circle");
c1.setAttribute("cx", "100");
c1.setAttribute("cy", "100");
c1.setAttribute("r", "60");
c1.setAttribute("fill", "#336699");
mySvg.appendChild(c1);

the cx and cy properties are the x and y coordinate of the center of the circle, and r is the radius. Fill determines which color will fill the circle.

You can also add a stroke to the circle like so:

var c2 = document.createElementNS("http://www.w3.org/2000/svg", "circle");
c2.setAttribute("cx", "250");
c2.setAttribute("cy", "100");
c2.setAttribute("r", "60");
c2.setAttribute("fill", "#996699");
c2.setAttribute("stroke", "#AA99FF");
c2.setAttribute("stroke-width", "7");
mySvg.appendChild(c2);

See the W3C SVG Tiny Spec section on the Circle Element for the complete list of attributes you can apply to a circle. Here is the result of the above code:

So there you have a simple example of how to include SVG graphics in your web page using JavaScript. I will follow up with more examples regularly, so check back soon!

guidlines for open source

Evan Phoenix (@evanphx), lead developer for Rubinius, spoke today at the Golden Gate Ruby Conference about how to effectively run or contribute to an open source project. Awesome talk.  Great information that is pretty slow to figure out by osmosis.

Evan presented 4 guidelines:

  1. Contributors are a privilege: sometimes they feel like a burden.  They are providing you with a service you couldn’t get on your own.
  2. “No” is a respectable answer
  3. Responsibility is power
  4. Communicate.  A lot.  Open source projects live and die by how much they can communicate within the project and outside of it.

Be Nice. Sometimes contributors can be demanding and push your buttons.  Remember the contributors are doing you a favor by being there.

Case Study: the unwanted feature

  • I added the ability to avoid flushing the toilet!
  • You think “what an idiot!”
  • Deep breathe.  Apply the laws.  Think of this as an invitation.

“Great!  I don’t think we’re ready for that.” … start a conversation: “Why do you want this feature?” explain why you don’t.  If you aren’t ready for them, what should they do.  When should you as a contributor or committer push for a fork.

What about Forking?
Fork for the right reasons.  Fork for love, not for hate.  Fork in public.
Pay attention to the fork.  Be a friend to the fork.  Talk to them.  Understand what they are doing.  See if you can move forward together.

Process?
avoid complicated setup and workflow
premature process is the root of all frustration
“These patches overlap with stuff we already wrote”
and they introduce 5 new dependencies, different test framework, different coding style… note:  this is a teachable
discuss - how for them to contribute more often so they don’t get out of date, how can you educate them about the architecture — docs are hard, but even the conversation is documentation, communicate that they need to adhere to the style
worst case: “I’m not willing to change for you”

answer: “sorry to hear that, have a nice life” (doesn’t need to be a big deal)

more typical is the best case scenario: “No problem, thanks, I’ll get right on that.”

Best way to start is with Easy Wins… just like TDD.  The simplest thing that could possibly work.  Simple goals and easy tasks.  Run this command and fix whatever is broken.  In Rubinous, a simple command will print every Ruby command that doesn’t pass.

“Easy wins are the gateway drug.”  Evan suggests that you should have no “core team.” By pushing out the idea that anyone    Trust is transformative.  Rubinious borrowed an ideas from Pugs: if you submit one patch you get commit privileges.  Responsibility is greater than privilege.  If someone fixes an error in the readme, give them the power (and responsibility) to fix any error in that area.  (Conflicts with saying “no?” If you communicate that is mitigated.  Advocate forks/branches for new features.)

As a committer. Don’t take it personally.  This project is just not ready for your awesome.

Closing notes:

  • OSS is not about software — it is a social contract.
  • Contributors want to succeed.
  • Give respect <-> Get respect.
  • We all just want to be loved.

Q: What communication channels work?

A: IRC is terrible, but it often the best answer.  Phone calls are great — offer to talk to them on the phone, people will feel honored and take you up on it.  Screen sharing/ facetime — whatever has the lowest latency.

Training Hackers for an Awesome Job Market

I hear that the economy still sucks and lots of people are out of work, and I believe it. At the same time, I hear managers complain that they can’t find good engineers who know the tools and languages to create mobile and web software. Nick Saint published an insightful article today, “Why It’s So Darn Hard To Hire A Decent Engineer – Even In This HORRIBLE Job Market” (via @johnwoodell).  I enjoyed his comment that “the media was more concerned with the largely make-believe narrative that programming jobs were all being outsourced to India.” It is true a lot of jobs are outsourced, but it seems like there is still significant demand here. A while back I wrote about an alternate approach, I call insourcing, but that’s just part of the story.

Saint also notes that college students are unaware of how lucrative the opportunities are for programmers.  That problem is compounded by the fact that most people have no idea what a programmer does.  Unlike medicine or law, which you learn about in grade school, kids (and most adults) have little exposure to software development. Many entrepreneurs are discovering; however, that most businesses today require (or at least benefit from) an on-line presence that often requires some software development.  Even non-technical business owners and managers need to know something about software development.  The knowledge and skill gap goes beyond a lack of professional programmers.

What can be done?

Over a year ago, Sarah Mei and I found ourselves in the middle of a surprising dearth of women in the San Francisco Ruby community (~3%).  We decided to fix it by simply teaching women Ruby on Rails in weekend workshops.  Over a year later, we have significantly changed the gender balance in the community, but more importantly the workshops created a fundamental shift in the ecosystem, furthering some of the natural effects of open source.  In the past year there have been more study groups and open hack sessions for all genders.

Seeing a demand, Blazing Cloud started teaching classes, which have grown to include Javascript and HTML, as well as Ruby and Rails.  In addition to teaching a range of web technologies, we also have broadened the offering to meet the demand for classes for people who have no prior programming experience.  People are thirsty for this knowledge.  The students are professionals who are driven to work nights and weekends to hone their skills.  Some are unemployed; some are looking to switch jobs; there are always a few entrepreneurs and some who have just always wanted to learn to program and never found a way in.

Additionally, we started a cross-training program in collaboration with Captain Recruiter.  This innovative program started with Honk.com, a forward-thinking company who signed up for the first session.  Ali Crocket, an engineer with no web development experience, paired with Jen-Mei Wu, a Blazing Cloud senior Rubyist, on-site with the Honk team.  After 12 weeks, Ali was up-to-speed and hired as a full-time employee.  We are in the midst of a second session with Scribd and have already started interviewing for a new fall session.

It is a strange artifact of the ever-changing software industry that experienced engineers can find themselves with obsolete skills and unemployable, but the problem also seems eminently fixable for the folks who are willing to dive back in.  The core skill is problem-solving, but it must be combined with the ability to learn quickly and communicate well for true success in this field.

The good news is that lots of organizations and individuals see the same problems and are offering solutions.  In San Francisco, there is NoiseBridge, with Hacker Dojo on the peninsula.  Women2 Labs offers a real-life experience for not just hackers, but for designers and marketing folks.  Other cities have different programs with a similar spirit and I’m sure there are a dozen SF resources that I’m neglecting to mention.  There’s a meetup every night of the week if you want to start something or learn something.  Change is happening.  I don’t think this kind of change is inevitable, but I do believe that a whole lot of people want it and are working very hard to make it happen.

Radiant WYSIWYG Editor Comparison

Radiant is a popular content management system written in Rails. It is very simple and lightweight out of the box, and customizing it is fast and easy. Several of our current projects use Radiant and we’ve been searching for a more intuitive editor than Markdown or Textile - both of which come packaged with Radiant but require a learning curve to use.

Radiant doesn’t have a ‘What You See Is What You Get’ editor as a core feature. Several third party extensions exist. We installed and evaluated three editor extensions: Fckeditor, WYMeditor & Tinymce editor.

Fckeditor
We started off with the Fckeditor. The installation process was easy with just two terminal commands:

  • git clone git://github.com/djcp/radiant-fckeditor.git vendor/extensions/fckeditor
  • rake radiant:extensions:fckeditor:update

The interface is available in the dropdown list of filters for each page. The Fckeditor extension works well immediately after install, but we weren’t impressed with its cluttered UI. We hoped that we could find an alternative editor with a more elegant UI design.

WYMediter
Next we installed WYMeditor which considers itself a ‘What You See Is What You Mean’ editor. WYSIWYM focuses on the structure of the document instead of the design of the document. Here is a bit more information about it:

According to the documentation:

WYMeditor’s main concept is to leave details of the document’s visual layout, and to concentrate on its structure and meaning, while trying to give the user as much comfort as possible (at least as WYSIWYG editors).

WYMeditor has been created to generate perfectly structured XHTML strict code, to conform to the W3C XHTML specifications and to facilitate further processing by modern applications.

According to Wikipedia:

In a WYSIWYM editor, the user writes the contents in a structured way, marking the content according to its meaning, its significance in the document, instead of designing its appearance. For example, in a WYSIWYM document the user might mark text as the title of the document, the name of a section, or the name of an author.

We were impressed with WYMeditors’ user interface. It is simple, uncluttered with a modern look and feel.

The only problem we encountered occured during install because the documentation didn’t specify the name of the destination folder for the git clone command.

The git clone command (from the root directory) should look like this to avoid NameError issues:
git clone git://github.com/jomz/radiant-wym-editor-filter-extension.git vendor/extensions/WymEditorFilter

This should be followed by these rake commands:

rake radiant:extensions:wym_editor_filter:install

rake radiant:extensions:wym_editor_filter:update

Tinymce editor
Last, and um…least, we have Tinymce. We struggled to find a git repo of the Tinymce Radiant filter. We found several places with instructions for SVN and eventually found instructions for Git as well. The SVN instructions didn’t use the standard Radiant extension rake task installation which was a turn off. We followed two (here and here) different Github repo’s README instructions and neither of them worked for us. Neither version displayed WYSIWYG icons when the filter was selected and the second repo added extra ‘body’ and ‘extended’ tabs.

We would not recommend this extension.

Conclusion

Our favorite WYSIWYG editor ended up being a WYSIWYM editor. The WYMeditor was clean and modern with a simple interface, yet seems to have all of the features we need.

Thanks to Rachel Myers for her help with researching & writing this post.

Making DSLs with Ruby

My favorite Ruby Kaigi talk was by Yasuko Ohba (@nay3) of Everyleaf Corporation in Japan. Despite the fact that the talk was in Japanese, with nice code examples on the slides and key translations over IRC, I was able to follow the presentation and learn some tricks. The coding techniques are really quite straight-forward, just not necessarily intuitive to invent. She reviews a variety of techniques along with real and imaginary examples of each.

Blazing Cloud Sign

We have a new sign for our office. Check it out next time you visit:

jQTouch slide transition fix for Android 2.0

A client of Blazing Cloud recently wanted to support animated screen transitions in their mobile platform and came to us for help. We decided to integrate the latest jQTouch (version 1, beta 2) into their framework since we had heard good things about it. Unfortunately, many animated transitions in Android don’t work very well. Worst is that slide transitions don’t work at all on Android 2.0 devices.

After poking around a bit, it seemed that the @-webkit-keyframes styles in jqtouch.css defined for the sliding transitions were being applied in parallel when running in Android 2.0. For example, a slide-in-from-right link  has these webkit animated styles applied to it:

.in, .out {
    -webkit-animation-timing-function: ease-in-out;
    -webkit-animation-duration: 350ms;
}
.slide.in {
    -webkit-animation-name: slideinfromright;
}
@-webkit-keyframes slideinfromright {
    from { -webkit-transform: translateX(100%); }
    to { -webkit-transform: translateX(0); }
}

On  iPhone and Android 1.0 devices,  a slide-in-from-right screen slides in correctly from 100% to 0 in about 350ms. But on Android 2.0 devices,  the screen appears immediately as if no animation occurred.

To work around this problem,  you have to manually set the start position first, then the end position and animation style. That is, instead of letting the @-webkit-keyframes do the work, you have to manually position the screen at 100%, then set the animation and final position style after a small time interval. For example, the key portion of the code to consider  is:

toPage.css("webkitTransform", "translate3d(100%,0px,0px)");
setTimeout(function() {
    toPage.css({webkitTransitionDuration: "350ms",
    webkitTransitionTimingFunction: "ease-in-out"});
    toPage.css("webkitTransform", "translate3d(0px,0px,0px)");
}, 5);

Note that we first set the starting position then wait about 5 milliseconds before applying the animated style (webkitTransitionDuration and webkitTransitionTimingFunction). After the transition completes, I clear the style from the page:

toPage.css({webkitTransitionDuration: null,
            webkitTransitionTimingFunction: null})

The sliding animation is handled in the animatePages function. Here’s the code with workaround (my changes in bold):

function animatePages(fromPage, toPage, animation, backwards) {
    // Error check for target page
    if(toPage.length === 0){
        $.fn.unselect();
        console.error('Target element is missing.');
        return false;
    }
    // Collapse the keyboard
    $(':focus').blur();
    // Make sure we are scrolled up to hide location bar
    scrollTo(0, 0);
    // Define callback to run after animation completes
    var callback = function(event){
        if (animation)
        {
            if (animation.name == "slide") {
                var css = {webkitTransitionDuration: null,
                    webkitTransitionTimingFunction: null};
                toPage.css(css);
                fromPage.css(css);
            }
            toPage.removeClass('in reverse ' + animation.name);
            fromPage.removeClass('current out reverse ' + animation.name);
        }
        else
        {
            fromPage.removeClass('current');
        }
        toPage.trigger('pageAnimationEnd', { direction: 'in' });
        fromPage.trigger('pageAnimationEnd', { direction: 'out' });
        clearInterval(dumbLoop);
        currentPage = toPage;
        location.hash = currentPage.attr('id');
        dumbLoopStart();
        var $originallink = toPage.data('referrer');
        if ($originallink) {
            $originallink.unselect();
        }
        lastAnimationTime = (new Date()).getTime();
        tapReady = true;
    }
    fromPage.trigger('pageAnimationStart', { direction: 'out' });
    toPage.trigger('pageAnimationStart', { direction: 'in' });
    if ($.support.WebKitAnimationEvent &&
        animation &&
        jQTSettings.useAnimations) {
        tapReady = false;
        if (animation.name == "slide") {
            toPage.one('webkitTransitionEnd', callback);
            toPage.addClass('in current');
            fromPage.addClass('out');
            toPage.css("webkitTransform",
                       "translate3d(" + (backwards ? "-100%" : "100%") + ",0px,0px)");
            fromPage.css("webkitTransform",
                         "translate3d(0px,0px,0px)");
            setTimeout(function() {
                var css = {webkitTransitionDuration: "350ms",
                    webkitTransitionTimingFunction: "ease-in-out"};
                toPage.css(css);
                fromPage.css(css);
                toPage.css("webkitTransform",
                           "translate3d(0px,0px,0px)");
                fromPage.css("webkitTransform",
                             "translate3d(" + (backwards ? "100%" : "-100%") + ",0px,0px)");
            }, 5);
        } else {
            toPage.one('webkitAnimationEnd', callback);
            toPage.addClass(animation.name + ' in current ' + (backwards ? ' reverse' : ''));
            fromPage.addClass(animation.name + ' out' + (backwards ? ' reverse' : ''));
        }
    } else {
        toPage.addClass('current');
        callback();
    }
    return true;
}

Note that jQTouch sets $.support.WebKitAnimationEvent to false for Android 2.0 devices even though it does support WebKit animation. Make sure you set that to true. Replace the animatePage function in your jQtouch with the function in this post and now  you should be golden with iPhone and Android!

What's weird about floats in objective-c?

Aright, what’s up with this? This code using a double works just fine:

double myDouble = 2.2;
NSLog(@"myDouble %f", myDouble);
[self testDouble:myDouble];
- (void) testDouble:(double)myDouble {
    NSLog(@"testDouble %f", myDouble);
}

This code prints:
myDouble 2.200000
testDouble 2.200000

No surprises there. But the same code using a float behaves very strangely:

float myFloat = 3.3;
NSLog(@"myFloat %f", myFloat);
[self testFloat:myFloat];
- (void) testFloat:(float)myFloat {
    NSLog(@"testFloat %f", myFloat);
}

This code prints
myFloat 3.300000
testFloat 36893488147419103232.000000

So what happens to the float that is passed to the testFloat method? According to this Techtopia article about Objective-C 2.0 Data Types when you create a float like this:

float myFloat = 3.3;

It is internally stored as a double, which has greater precision. If you actually want to store something as a float you need to append an “f” to the number like this:

float myFloat = 3.3f;

So I thought perhaps that was the problem - that internally it was represented as a double, so when passed in to a method expecting a float there was a conversion error. But when I modified the code above to include the “f” I get the same result.

I also get the same result when I pass the float in directly to the method like this:

[self testFloat:3.3f];

So what the heck is going on here? Why can’t I pass a float to a method? What am I missing? I’ll follow up with a comment when I figure it out, but does anybody know why this is happening?

What’s weird about floats in objective-c?

Aright, what’s up with this? This code using a double works just fine:

double myDouble = 2.2;
NSLog(@"myDouble %f", myDouble);
[self testDouble:myDouble];
- (void) testDouble:(double)myDouble {
    NSLog(@"testDouble %f", myDouble);
}

This code prints:
myDouble 2.200000
testDouble 2.200000

No surprises there. But the same code using a float behaves very strangely:

float myFloat = 3.3;
NSLog(@"myFloat %f", myFloat);
[self testFloat:myFloat];
- (void) testFloat:(float)myFloat {
    NSLog(@"testFloat %f", myFloat);
}

This code prints
myFloat 3.300000
testFloat 36893488147419103232.000000

So what happens to the float that is passed to the testFloat method? According to this Techtopia article about Objective-C 2.0 Data Types when you create a float like this:

float myFloat = 3.3;

It is internally stored as a double, which has greater precision. If you actually want to store something as a float you need to append an “f” to the number like this:

float myFloat = 3.3f;

So I thought perhaps that was the problem - that internally it was represented as a double, so when passed in to a method expecting a float there was a conversion error. But when I modified the code above to include the “f” I get the same result.

I also get the same result when I pass the float in directly to the method like this:

[self testFloat:3.3f];

So what the heck is going on here? Why can’t I pass a float to a method? What am I missing? I’ll follow up with a comment when I figure it out, but does anybody know why this is happening?