It's the little things (Chrome OS - Cr48)

Summary: While the Cr48 is a great device, a few small issues prove to be nearly fatal flaws.

In my last post, I mentioned that a couple little issues really ruined the Cr48 experience.  It may seem overly dramatic to say one little thing made something unusable. But, it's the little things that do matter.

Chrome OS/Cr48 gets so many big things right:
  • The multi-user security is fantastic.  It's great to be able to share the Cr48 with Corinne and not have to log out of gmail, twitter, facebook, etc so she can.
  • The size is nearly perfect: small and easy to carry around without the cramped feeling of a netbook.
  • The idea of a laptop that is a portal to the internet is amazing -- may not be perfect for me (and other developers) but for many people this is exactly what they need.
  • The security (not having to worry about viruses) is great
  • Ditching the caps lock button and F keys is smart
  • Integrated 3G is great
  • Chrome sync / extensions / popup gTalk -- all fantastic

Even with all those things done right, a couple little things can really harm the user experience.  

The trackpad on the Cr48 is bad.  Not just a little "this doesn't feel quite right" bad, but bad enough to distract from so many of the good points.  Enough to make me notice it every time I have to click on a link or scroll up and down a page.

The performance is another disappointed.  Even Google's own "20 things I learned about the web (http://www.20thingsilearned.com/)" doesn't run smoothly.  For some browsing the performance isn't an issue, but hope that Google further optimizes web browsing performance.

Finally, the startup time doesn't cut it.  With "regular" laptops getting close to 20 second starups, a 10-15 second start time for a web only device is quite disappointing.  

My point is this: by screwing up a couple little things Google nearly ruins the whole Chrome OS experience. This idea is too good to mess up! I hope Google refines the Cr48, even the prototypes, so that they provide a great user experience and a winning device. 

 

 

Last, first thoughts on Chrome OS / cr48

Good concept, but poor execution.  I like having an instant on internet device that boots straight into my favorite browser and syncs with my other computers that I can install great extensions on.  I like being able to play music through Rdio while browsing Hacker News.

But... it's not really "instant on" -- an iPad is instant on.  The cr48 take just long enough to turn on and log in that I get annoyed waiting for it.  This makes me reach for my phone or iPad when I need really quick access to the internet.

It's performance is sub par.  Opening multiple tabs and loading sites is noticeably slower than my two year old Dell laptop.  Combine this with the questionable text rendering and I'm reaching for a real laptop when I need to do some serious web browsing / research.

If the cr48 isn't fast enough for quick access to the internet and not powerful enough when I'm going to use it for a longer period of time... when would I use it?

 

Warden Authentication with Rails 3

Warden is a general authentication framework for Rack applications.  Using it with Rails 3 is simple, but requires a few steps.  I pullled some of this from https://github.com/HP/rails_warden_mongoid_example, but had to massage it a little to get it working with my application.

Assumptions

  1. You have a User model with a static authenticate method
  2. Your User is authenticated by email and password
  3. Your User model has an id property
  4. Your User model can be loaded with User.find(id)
  5. You will handle user creation separately
  6. You have a Users controller with a Show action (so we can call redirect_to @user)

1) Install Warden and rails_warden using your Gemfile

Add the following lines to your Gemfile and run "bundler install"

gem 'warden'

gem 'rails_warden'

2) Configure rails_warden in /config/application.rb

Add the line: config.gem "rails_warden"

3) Create a warden.rb initializer in /config/initializers/warden.rb

Note: You may need to change params["session"]["email"] to match your application

Note: If you are not using ActiveRecord, you may need to change the call to User.find(key)

Note: If your signin/signout controller isn't named "SignoutController" you will need to change that

4) Modify an ApplicationController to include some helpers

You can use require_user and require_no_user to define which controllers/actions require the user to be authenticated

Note: "current_user" is provided by rails_warden and will be the User model of the current user.  

Note: "new_session_url" assumes we are using the "SessionsController" with a "New" action to sign in

5) Create a SessionsController

Fairly simple -- notice the calls to "authenticate!" and "logout": these are provided by rails_warden.  

6) Routes for the SessionsController (/config/routes.rb)

(bonus) New session view (sign in)

First thoughts on Rails with Windows

I've decided to learn a second platform and am going for RoR (I use C# / .NET at work), so far so good.  railstutorial.org is a nice (if slow) introduction. 

First Thoughts

1) The lack of IDE/good editor on Windows bothers me (I use e-texteditor)

2) The performance (starting Rails environment, running specs) on Windows is really bad

3) I love RSpec and how easy it is to write integration tests

4) I'm confused about the love of static methods, are these OK in the Ruby world? Time will tell...

Configuring 2wire router in "bridge" mode -- aka how to use a Netgear router with a 2wire

My 2wire modem/router (the real cost of my 24mbps internet) was giving us trouble again.  The wifi network was fading in and out causing @cgthomas and my no end of trouble.

The "logical" solution for a couple technology lovers like us was to buy a fantastic new Netgear router (a WNDR3700, to be exact).  This thing has it all: gigabit ethernet, dual radio a/b/g/n wifi, attached USB storage, aaand a CPU faster than my first several computers.

Now the problem: how to get it to cooperate with my ATT u-verse router.  In the past this wouldn't have been an issue as previous firmware versions allows you to configure the 2wire as a bridge.  With the latest firmware this option is gone.

However, there is a work-around:

  1. Connect your computer to your new router (the Netgear, in my case) and use its LAN Settings to assign IP addresses in the 192.168.2.1 range.
  2. Set your new router to get its WAN IP address via DHCP.
  3. Connect your new router to your 2wire modem/router.
  4. Connect your computer directly to your 2wire
  5. Go to 192.168.1.254 / Settings / Firewall / Applications, Pinholes, DMZ
  6. Use the link to choose your new router
  7. Check the box that says "Allow all applications (DMZplus mode)" and "Save"
  8. Disconnect your computer from the 2wire and connect to the new router
  9. Success!

In this configuration your new router is handing out addresses in the 192.168.2.x range while the 2wire is handing out addresses in the 192.168.1.x range.  When you are connected to the new router you can access:

  1. The internet
  2. The new router (go to 192.168.2.1)
  3. AND the old router (go to 192.168.1.254)

It also routes all external traffic to the new router so you can use it to configure static routes/etc without dealing with the 2wire.

Hope this helps!

Test / Demo Data Generation in C#

We recently needed to regularly generate a significant amount of data for a demo environment.  Standard sort of data: users, inventory, transactions, fulfillments, associated history, etc.  Our solution was a scriptable data generator application that has so far worked out extremely well. 

Our past data generation tool was used only to create one specific data set (a specific type of inventory and transactions) it was configured using a "traditional" XML configuration file that controlled how much and what type of inventory was created and how many transactions were associated with that inventory.

The tool would not meet our new needs since:

  1. We needed more flexibility in terms of what data was created
  2. We needed to be able to create a larger array of types data (not just inventory and transactions)
  3. It used some direct database updates that caused some data to be created that violated our internal business rules (specifically the data generated looked correct in one of our applications but there was no guarantee that it would work with all the applications)
  4. It lived outside our primary build/test process so it "aged" and had to be tweaked to keep up with modifications/refactorings to the main application

I developed a new tool that overcame these limitations by following a few guiding principals.

Key aspects of this new tool:

  • Uses our full domain/service stack so that the resulting data is realistic and doesn't violate any internal logic
  • Scriptable via a DSL like language so that we can easily generate different data sets
  • Multi-threaded so that demo data can be generated quickly and testing new scripts is less painful
  • Integrated the application into our primary/production build/test process so that it grows along side our application

Use Full Domain / Service Stack

The new tool uses our standard domain/service stack.  It processes data just as if requests were coming in through a web application.  Since our application is fairly well factored, this really simplified most processes.

Scriptable

The biggest enhancement was to make this tool totally scriptable.  We wanted to be able to have one script to generate data for a demo environment, another to generate one specific data set for a QA environment, and others for individual developer use.  

My first thought was to write a DSL.  

Thankfully I quickly regained sanity and decided that there must be a better way. (As an aside, DSLs can be great, but this tool needed to be built in days in my spare time. A real DSL may have been more elegant, but our solution worked and worked with a minimum amount of effort.)  Instead of building a whole DSL, I used the Microsoft.CSharp.* classes to dynamically compile a c# script.

The basic idea is this:

1) Create a base class that exposes all the needed operations 

2) Create helper methods that make common operations simpler

3) Create scripts that use those to generate the data

4) Magically compile and execute the script

And by "magically", I mean:

  • Read the script file, append a header and footer to it so that the entire script becomes a method inside a class that derives from my base class
  • Add a list of standard "usings"
  • Create a dynamic compilation unit using the Microsoft.CSharp namespace
  • Add needed references
  • Compile into an in-memory assembly 
  • Execute via reflection

This isn't nearly as hard as it sounds, the basic idea is outlined in this article: http://stackoverflow.com/questions/53844/how-can-i-evaluate-a-c-expression-dynamically

Multi-threaded

Since the scripts use our custom "Each" and "Times" methods we get multi-threaded code execution for "free".  In my ever so unscientific tests this gave us a 4x increase in performance.

Conclusion

By leveraging some neat features in C# (dynamic compilation, extension methods, Parallel.* methods) and our existing, well factored domain services I was able to write this application in my spare time in a single week.  

MacBook Pro 13in: irrelevant?

Apple's new MacBook Air is pretty great.  It follows the iPad in being surprisingly inexpensive (at least in compare to the original Air). 

The new Air creates a nice niche -- the "affordable" luxury mini laptop.  It also puts pressure on one existing MacBook: the 13in MacBook Pro.

If you upgrade a 13in MBP to a 128GB SSD and 4GB ram it comes to $1549.  A similar Air costs $1399. 

The MBP includes a faster processer (alibet with less L2 cache), slightly longer battery life, and more ports.

The Air includes a higher resolution screen and weights almost 2lbs less.

I know that I would choose the Air.