My Campaign to Stop Bad Rails Code

Posted about 3 hours back at Envy Labs

Those of us in the consulting business have all been there.  We receive a lead for a new client with an existing Rails codebase that stinks to high heaven.  Its controllers are fat, tests are non-existant, and the database.yml is checked into source control with the production passwords in plain sight.  This quote is taken right out of a Code Review done by Envy Labs:

“The high point of this application is the rails scaffold generated code”

I wish I was kidding.  Bottom line is there are still a lot of beginner Rails developers out there.  I don’t know the complete solution to the problem, but I know one thing you can do … right now.  Help spread the word about the Code School Free Weekend.  This weekend CloudSpokes wants to buy you a free weekend to play through the courses on Code School.

Two said courses you could play include:

Rails Best Practices – This course contains some of the most useful patterns and techniques to keep your code clean and maintainable.  These aren’t just screencasts, you actually have to CODE and practice these techniques to get to the next level.  I know companies that require their new hires to play this course before they touch client code.

Rails Testing for Zombies – This course walks you through all the basics of testing your Rails applications, from Test::Unit to Mocha, Shoulda, Capybara, FactoryGirl, and more.  Only thing it doesn’t cover is RSpec (that course is next month).

Those two are the most important to play through to stop bad rails code, but it also wouldn’t hurt to learn some CoffeeScript, Backbone.js, or maybe learn some CSS best practices that would make your designer friends happy.  We even have CodeTV screencasts on using jQuery Mobile, Knockout.js, jRuby on Rails, Pry, and using Guard and Spork.

“OMG Gregg are you saying Code School is 100% the answer?”

No, and here’s where things get really awesome.  When you finish Rails Testing for Zombies you’re going to get a free month of Destroy All Software screencasts by Gary Bernhardt.  Dray, a senior developer at Envy Labs, watched 50 of these in the span of a 3 days because they were so eye-opening and he tells me “This is where you go to learn how to write testable code”.

When you finish Rails Best Practices you’re going to get free peepcode screencast.  You can use this credit to maybe grab a VIM, cucumber, RSpec, or play by play screencast produced by Geoffrey Grosenbach.  You can even watch Rails & Ruby committer Aaron Patterson himself build a Rails app in his play by play cast.

If you play through Rails for Zombies 2 (even if you skip the videos) you’ll get a free month of Railscasts.com Pro Subscription.  Ryan Bates has an amazing library of screencasts covering so many topics to keep your Rails skills at the top of their game.

Using your knowledge from Code School and continuing on to these websites will certainly set you on the path to Rails expert.

Your Mission if you Choose to Accept it

So do me a favor.. well, two favors in the interest of stopping bad Rails code:

  1. If there’s any part of your brain that wonders if you could be a better Rails developer, start this weekend polishing your skills for free on Code School by signing up for free access this weekend.
  2. If you know any Rails developers who need to improve their skills, let them know about our free weekend.

Thanks!

The trouble with light boxes

Posted about 5 hours back at mir.aculo.us - Home

These days (actually more like for the last five years), when you’re designing a site and have preview thumbnails/photos/screenshots of things, you’re probably using one of the millions of light box scripts/plugins out there. Light boxes are the new funny mouse trails.

Chances are you’re completely breaking your sites for mobile users.

If you don’t have a mobile site

In case you’re serving the same site to both desktop and mobile users (which for most sites is preferable anyway, Apple does it!), use a light box script that calculates the “center of screen” position once when you open the image. Make sure the button to close the zoomed-in image is always visible.

Don’t use any scripts that recalculate the position on scrolling or window size changes. Users on mobile devices will hate you for it. A lot.

In general, don’t try to be too clever.

If you have a mobile site

The trick is to link to the bigger version of the image directly.

Why? First off, it loads really fast, as only the image has to be transferred and you won’t need any JavaScript at all. Secondly, the user can use gestures to zoom in on the image and by default it’s shown as full-screen as possible. Afterwards the user can just hit the back button to go back to your main content. There’s no need to implement fancy zoom scripts and complicated UI controls; the user already knows how to zoom images on the device.

Zappos does it, so you can too.

Addtionally, don’t bother having “retina” versions and “normal” versions. Just provide one single hi-res image.

It’s better to spend your time on seeing what level of JPEG compression works best for the image you use (if you’re curious, Zappos uses 92 for this particular image—one way to find out is to use identify -verbose filename.jpg | grep "Quality" if you have ImageMagick installed).

Plus, have good toolchain to minimize your images without quality loss, I can’t recommend the ImageOptim tool highly enough for that. I was able to shave off a cool 6% of the file size of the image used on Zappos. Your users will love you for the faster loading images!

Want to learn how to master JavaScript? Grab a seat at the JavaScript Master Class, a two half-day live online class with Amy Hoy and yours truly! (Next date: June 14/15, 2012!)

Presentation: Pallet - DevOps for the JVM

Posted about 8 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Antoni Batchelli introduces Pallet, a devops platform for the JVM for provisioning and configuring servers, configuring clustered services, deploying and managing software, servers and services. By Antoni Batchelli

Web Intents: What They Are and Their Current Implementation Status

Posted about 9 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

This article shortly explains what Web Intents are and why they are useful. Google has enabled Web Intents in Chrome 19, the implementation being available to Safari via WebKit, and Mozilla is also working on it. By Abel Avram

Presentation: Quantum, Virtual Networks for OpenStack

Posted about 9 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Salvatore Orlando introduces OpenStack and Quantum, a project intended to provide network connectivity as a service, covering the current state and expected developments in the future. By Salvatore Orlando

jQuery find function

Posted about 11 hours back at Jay Fields Thoughts

I've recently been using Tilava Table on a few different projects. At one point I ran into a situation where I wanted to change all of the visible rows as well as the template, but the row template was no longer found when using a traditional jQuery selection. The solution to my problem was a combination of holding on to the template as well and using jQuery find to select the td elements I was interested in altering.

In Tilava Table you create a template, but that template row isn't displayed within the table. We could use that as an example, but it seems easier to simplify the example to the following code:

<script src="http://code.jquery.com/jquery-1.7.2.min.js">
</script>
<label><input type="checkbox" id="hideMoreData"/>hide more data</label>
<table id="myTable" style="border:1px solid black">
  <tr class="template">
    <td>row data</td><td class="additional-field">more data</td>
  </tr>
</table>
<button id="addButton">Add</button>
<script>
$(document).ready(function () {
  function addRow(template) {
    $('#myTable').append(template.clone().removeClass('template'));
  }
  var template = $(".template");
  $('#myTable').html("");
  $("#addButton").click(function () {
    addRow(template);
  });
  $("#hideMoreData").click(function () {
    $(".additional-field").toggle(!$('#hideMoreData').is(':checked'));
  });
  addRow(template);
  addRow(template);
});
</script>
The executing version of that code can be found below.

<script src="http://code.jquery.com/jquery-1.7.2.min.js"> </script>
row datamore data
<script> $(document).ready(function () { function addRow(template) { $('#myTable').append(template.clone().removeClass('template')); } var template = $(".template"); $('#myTable').html(""); $("#addButton").click(function () { addRow(template); }); $("#hideMoreData").click(function () { $(".additional-field").toggle(!$('#hideMoreData').is(':checked')); }); addRow(template); addRow(template); }); </script>

In the above example we have a table in which we can dynamically add rows by clicking the 'Add' button. We also have a checkbox that determines whether or not the additional data is displayed in our table. Click the add button a few times and show and hide the additional data, just to make sure everything is working as you'd expect.

You may have noticed (either by reading the code, or by playing with the example) that when you hide the additional data it hides what is already in the table; however, if you add additional rows the additional data for the new rows will be shown. This is due to the fact that when you select all td elements with the class 'additional-field' the template is not included in the results. Even though the template is not returned in our 'additional-field' selection, it does still exist and is accessible as the var 'template'. When we clone the template var the cloned row will contain the additional-field td, but it will not be 'correctly' toggled.

One solution would be to append the row and rerun the toggle code, but that wouldn't be as efficient - and, jQuery gives us a better solution anyway: find
find: Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
The simple solution is to add the following line in the #hideMoreData click handler.
template.find(".additional-field").toggle(!$('#hideMoreData').is(':checked'));
The finished code is below in it's entirety, and the working version of the code can also be found at the bottom.
<label><input type="checkbox" id="hideMoreData2"/>hide more data</label>
<table id="myTable2" style="border:1px solid black">
  <tr class="template2">
    <td>row data</td><td class="additional-field2">more data</td>
  </tr>
</table>
<button id="addButton2">Add</button>
<script>
$(document).ready(function () {
  function addRow(template) {
    $('#myTable2').append(template.clone().removeClass('template2'));
  }
  var template = $(".template2");
  $('#myTable2').html("");
  $("#addButton2").click(function () {
    addRow(template);
  });
  $("#hideMoreData2").click(function () {
    $(".additional-field2").toggle(!$('#hideMoreData2').is(':checked'));
    template.find(".additional-field2").toggle(!$('#hideMoreData2').is(':checked'));
  });
  addRow(template);
  addRow(template);
});
</script>
row datamore data
<script> $(document).ready(function () { function addRow(template) { $('#myTable2').append(template.clone().removeClass('template2')); } var template = $(".template2"); $('#myTable2').html(""); $("#addButton2").click(function () { addRow(template); }); $("#hideMoreData2").click(function () { $(".additional-field2").toggle(!$('#hideMoreData2').is(':checked')); template.find(".additional-field2").toggle(!$('#hideMoreData2').is(':checked')); }); addRow(template); addRow(template); }); </script>

Article: Distributed Version Control Systems in the Enterprise

Posted about 13 hours back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Every major Open Source project worldwide has already embraced Distributed Version Control Systems (DVCS), will enterprises be next? By Pablo Santos

The Plight of Pinocchio: JavaScript's quest to become a real language

Posted about 22 hours back at blah blah woof woof articles

Brandon Keepers at JSDay:

JavaScript is no longer a toy language. Many of our applications can’t function without it. If we are going to use JavaScript to do real things, we need to treat it like a real language, adopting the same practices we use with real languages.

I’ll admit that I still write a lot of JavaScript in toy-like style. Brandon’s presentation is both motivating and informative for anyone wanting to improve their use of JavaScript.

Permalink

How I Open Source

Posted 1 day back at Jay Fields Thoughts

It's been recently brought to my attention that I don't view open-source the way that many of my friends do. My attitude has always been:

Here's some code that works well for what I want. If it works well for what you want, great! If not, I'm willing to make changes that improve the library; however, I'm also going to reject any code that causes the library to bloat. Lastly, the library will likely be 'done' in the next few years - at which time I expect it will be mature enough that a stable final release will be possible, or someone will (re)write a superior version. I don't expect an open-source project will ever define what I accomplish in our industry.
It finally occurred to me that others don't think this way when they began telling me that they don't open-source due to -
  • the code isn't mature enough
  • they don't want to write documentation
  • they don't want their time monopolized by feature request emails
I can understand each point of view, but events have occurred in my career that have shaped my (differing) opinion.

I still remember my first open-source project: I didn't tell a soul about it until I had used it in production for over a year and was very confident that I'd addressed the majority of common use cases. It was a .net object relational mapper called NORM, and it was released in 2005. No, you haven't ever heard of it. I polished it for months, and no one cared. After that I never waited to release anything. I now believe that it's highly unlikely that whatever I create will ever gain any traction, so I might as well get it out there, fail quickly, and move on.

No one writes documentation for themselves, they write it for people who they hope will use their software - and very few people people ever gain anything from someone else using their open-source software. That simple equation makes documentation scarce; however, scarce documentation doesn't mean you can't open-source your software, it just means adoption rates will very likely be slowed.

Two years ago I open-sourced expectations with zero documentation, and documentation stayed at zero for at least a year. In that year very few people paid any attention to expectations; however, expectations does fit a sweet spot for some people, and some adoption did occur. Eventually, new adopters began to send pull requests with documentation, and their contributions inspired me to write some documentation of my own. It can be hard to get motivated about providing documentation to theoretical adopters; however, I got my code out there and adoption began, and the motivation came along with those (no longer theoretical) adopters.

If you end up lucky enough to create a project that is widely used, there's no doubt that you'll start getting swamped with email. In the beginning I expect everyone will be overjoyed with their success, and the added workload will be no big deal. However, I imagine over time it begins to feel like a second full-time job, and for what? Developer-fame doesn't get you closer to retirement any faster than watching grass-grow. However, I don't believe that should deter you from putting your work out there. Additionally, I think GitHub has changed the game with respect to moving on. If your project is on GitHub and you decide to call it quits tonight, there will probably be plenty of forks that are more than happy to take your place.

I have no qualms with walking away from projects, as I expect that if the idea is valuable, someone else will be happy to step up and take my place; furthermore, it's more likely that several people will step up and the strongest will survive - which is best for everyone. The best example I've ever seen of this behavior was Capistrano. Jamis Buck famously walked away from Cap in 2009, yet I still know plenty of people using it today without any issue. I firmly believe that if an idea is good, it'll live on even if you've decided you're ready to do something else.

It occurs to me that I might be a bad open-source citizen - releasing way too early and walking away too early as well. If that's the case, then I expect well deserved criticism, but that's just not how I see the world at this point...

Presentation: Grid Gain vs. Hadoop. Why Elephants Can't Fly

Posted 1 day back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Dmitriy Setrakyan introduces GridGain, comparing it and outlining the cases where it is a better fit than Hadoop, accompanied by a live demo showing how to set up a GridGain job. By Dmitriy Setrakyan

Presentation: Games for the Masses - How DevOps Affects Architecture Design

Posted 1 day back at InfoQ Personalized Feed for unregistered user - Register to upgrade!

Jesper Richter-Reichhelm presents the DevOps integration at Wooga, and how their system architecture has evolved over the years in order to cope with the increasing number of players. By Jesper Richter-Reichhelm

The Plight of Pinocchio: JavaScript's quest to become a real language

Posted 1 day back at opensoul.org - Home

JavaScript is no longer a toy language. Many of our applications can’t function without it. If we are going to use JavaScript to do real things, we need to treat it like a real language, adopting the same practices we use with real languages.

This framework agnostic talk takes a serious look at how we develop JavaScript applications. Despite its prototypical nature, good object-oriented programming principles are still relevant. The design patterns that we’ve grown to know and love work just as well in JavaScript as they do any other language. Test driven development forces us to write modular, decoupled code.

Here are the slides for my JSDay talk.

<script async="" class="speakerdeck-embed" data-id="4fa986b3a117fc00220012ed" data-ratio="1.3333333333333333" src="//speakerdeck.com/assets/embed.js"></script>

#350 REST API Versioning

Posted 1 day back at Railscasts

APIs should be consistent, but it is difficult to do this when returning a JSON response along side the HTML interface. Here I show how to add a versioned, RESTful API. The version can be determined from either the URL or HTTP headers.

BOSH: What, How, When

Posted 1 day back at Dr Nic

I’m still very bullish on BOSH. I’ve been experimenting with it internally at work, looking to see how it could duplicate or improve upon our current infrastructure, automation and release management. I’ve also watched the commits that have come out in the last month and I’m excited by the project velocity and direction.

A few weeks ago I was fortunate to be invited to LinkedIn to the SV Forum group to give an introduction to BOSH. What it is, why it was created, how to use it and when you might use it.

If you’re interested in BOSH or even CloudFoundry itself, this talk also includes cutaways to Vadim Spivak from the Cloud Foundry core team, who has many very interesting things to say about BOSH and the future of BOSH.

<iframe src="http://player.vimeo.com/video/42248020" width="600" height="337" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

BOSH: What, How, When from Dr Nic on Vimeo.

This talk is one hour. If you only have 10 minutes, there is a good introduction upfront.

I’ve rewatched this talk. Given all the things I’ve learnt about using it and living it, for the most part I still agree with myself and what I said. That’s handy.

It was two days after RedHat had released OpenShift, so I had a few bonus comments to make about OpenShift towards the end of the talk. I’m also some what liberal with making jokes about any other technology that comes into my mind at the time. A politically correct person might have said different things.

At the time of the talk, I was not able to give a live demo of BOSH. I think such a demo would be valuable to get a complete “what is BOSH?” understanding, since it was a 5 minute demo that sold me on it.

Thanks to LinkedIn for recording the talk and for letting me share the video, and to LinkedIn’s Dan Lujan for doing the great post-production work. It’s a great room they have there for giving talks, and with all the cameras in the room they got some great shots of Vadim answering questions.

Related posts:

  1. Creating a BOSH from scratch on AWS A lot of devops projects revolve around managing instances/VMs...

Running the Tizen SDK Simulator on non-Ubuntu Linux

Posted 2 days back at townx - tech

This explains the steps you need to get the Tizen SDK Simulator working standalone on Linux. Also shown is a small example of how to exercise some of the HTML5 APIs in Tizen to demonstrate how the Simulator does its stuff.

The aim here is to get a working Tizen dev environment, without having to download and run the full Tizen SDK (a 1Gb download), and on platforms which aren't officially supported (only Windows and Ubuntu are supported, but I use Fedora). It's not the recommended or official way to use the Tizen SDK (see https://developer.tizen.org/sdk for that), but it is a way to use a bit of it. I also can't vouch for whether it's a sensible thing to do as I've only tested one toy application with it so far. But it is fun.

The Simulator is actually a fairly small (5Mb) Chrome extension, which is based on a fork of Ripple:

"Ripple is a multi-platform mobile environment emulator that runs in a web browser and is custom-tailored to HTML5 mobile application testing." (http://ripple.tinyhippos.com/ ; NB the company that developed it has been acquired by RIM).

The Tizen simulator extends Ripple with stubs for the APIs which are specific to Tizen, but not necessarily present in other HTML5 environments (e.g. sensor and messaging capabilities). This enables you to build applications which use those APIs if you don't have access to Tizen hardware. (The other alternative is to use the full Tizen SDK, which provides an emulator that runs "real" versions of the APIs; however, this is a big install and only works on Ubuntu and Windows.)

The steps:

1. Go to https://www.tizen.org/user/register and register for a Tizen account. This is free to anyone.

2. Register your public ssh key for Tizen Gerrit, at https://review.tizen.org/gerrit (Gerrit is the code review tool used by the Tizen project). You can then use ssh to checkout Tizen source (I couldn't check out directly from source.tizen.org and kept getting timeouts, but did manage a checkout via Gerrit). All this is explained on the platform developer orientation pages.

3. Clone the part of the SDK we're interested in: the webapp plugins for Eclipse:

git clone ssh://<your tizen.org username>@review.tizen.org:29418/sdk/ide/webapp-eplugin.git

4. Now you have the source code for the Tizen SDK Simulator plugin for Eclipse (as well as a lot of other plugins). We're just going to use a part of this to set the simulator up to work with Chrome.

The piece we need is in this location (relative to the directory you made the clone from):

./webapp-eplugin/org.tizen.web.simulator/pkg/web

So copy those files somewhere else to make them easier to get at:

$ mkdir ~/tizen-simulator
$ cp -a ./webapp-eplugin/org.tizen.web.simulator/pkg/web/* ~/tizen-simulator/

Take a look to check you have the right files:

$ cd ~/tizen-simulator
$ ls
beep.wav  cache.manifest  images  index.html  package.json  ripple.css  ripple.js  themes

That's all the code you need for the Simulator.

5. Open up Google Chrome (a recent version; I'm using 20.0.1132.3 dev) and type the URI for the Simulator in the address bar, i.e.:

file:///home/user/tizen-simulator/index.html

(replace "user" with your Linux account username)

You should see the Simulator UI with a blank "phone" in it.

6. You need a project to test against, so make one like this:

$ mkdir ~/tizen-messaging-test

Then add two files to this directory.

~/tizen-messaging-test/index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0,
                   maximum-scale=1.0, user-scalable=0, target-densityDpi=device-dpi">
    <meta name="description" content="Tizen web app"/>
    <title>messaging test</title>
</head>

<body>
  <p>Tizen SDK Simulator running on Linux.</p>
  &lt;script src="main.js"&gt;&lt;/script&gt;
</body>
</html>

(you need to use real script tags, but I can't put them in here as the Drupal editor removes them...)

and ~/tizen-messaging-test/main.js:

window.onload = function () {
  var errorCb = function (err) {
    console.error(err);
  };

  var successCb = function (services) {
    if (services.length === 0) {
      console.error('could not get email service');
      return;
    }

    var service = services[0];

    // listen for message changes; NB when the message is sent below,
    // it appears in the OUTBOX folder and a notification is logged
    var messagesChangedListener = {
      messagesadded: function (messages) {
        console.log(messages[0].folderId);
      },
      messagesupdated: function (messages) {},
      messagesremoved: function (messages) {}
    };

    service.messageStorage.addMessagesChangeListener(messagesChangedListener);

    // send a message
    var msg = new tizen.Message("messaging.email", {
      'to': ['bingo.barry@bogus.com'],
      'subject': 'hello email from Tizen web app',
      'plainBody': 'hello'
    });

    service.sendMessage(
      msg,
      function (recipients) { console.log(recipients); },
      errorCb
    );
  };

  tizen.messaging.getMessageServices("messaging.email", successCb, errorCb);
};

See the Tizen developer docs for more information about the APIs supported. Also note that I'm not suggesting this as a sane pattern for structuring an application.

7. Open the Simulator at your new project by entering the address in Chrome:

<notextile>file:///home/user/tizen-simulator/index.html?url=file:///home/user/tizen-messaging-test/index.html</notextile>

(replace "user" with your Linux username)

Note that the URL of the project is passed as a url=xxx parameter to the Tizen simulator.

Also note that things don't work so nicely if you run the Simulator and the application on different domains (you get cross domain errors), even if the Simulator is a Chrome extension with permissions set to allow requests to any domain (I tried). The easiest thing to do is run both from file:// URIs.

You should see the index.html page in the "phone" with the message:

"Tizen SDK Simulator running on Linux."

Like this:

Next, Ctrl+Shift+j to see the console output. You should see something like:

Ripple :: Environment Warming Up (Tea. Earl Gray. Hot.)   ripple.js:27588
TIZEN :: Initialization Finished (Make it so.)            ripple.js:27588
OUTBOX                                                    main.js:11
["bingo.barry@bogus.com"]                                 main.js:28

"OUTBOX" is the name of the folder containing the sent message (i.e. it's queued and ready to go); ["bingo.barry@bogus.com"] is an array of the recipient names to whom the message was successfully sent. This proves that the Simulator's API stubs are working correctly.

One other thing you might notice is that if you click the refresh button inside the simulator to reload the project, you get this in the console:

Uncaught ReferenceError: tizen is not defined                                 main.js:41
TIZEN :: -----------------------------------------------------------          ripple.js:27588
TIZEN :: Pay no attention to that man behind the curtain.                     ripple.js:27588
TIZEN :: Environment Warning up again (Set main batteries to auto-fire cycle) ripple.js:27588
TIZEN :: Initialization Finished (Make it so.) ripple.js:27588
Uncaught TypeError: Cannot call method 'log' of undefined                     main.js:11
["bingo.barry@bogus.com"]

At first I thought this was a bug caused by me hacking the simulator out of the SDK. But when I checked, the same bug happens in the Simulator when run from the SDK installed on Windows. So it's either an SDK bug or I'm doing something wrong in my code (needs further investigation), but at least it isn't an artefact of the simulator being disemboweled.

That's it. You can continue developing your application with whatever JavaScript libraries take your fancy.