Mi-Fi 1.1 in AppStore Now and what I learned along the way... 3
During 360idev (Sept 27-30) I wrote a small app to check the battery and connectivity level of my Mifi Card. I didn’t think many people would have an iPhone and a Mifi card. The iPhone is already 3g, but effectively there is not tethering allowed and the AT&T network is crapy. Nevertheless I thought my Mi-Fi App could be useful to others and along the way I would learn what it takes to submit an app to the AppStore.
I submitted the app on September 29th (during 360idev) and it was approved on October 12th. I submitted two other version since and last Monday I started collecting details of my experience of the AppStore, thoughts on the process, and various tibits around the web regarding this app and started writing this blog entry, but didn’t finished it as it was getting too late. Then last week I stumbled upon this article of Rogue Amoeba which detailed their experience with the store. I could relate on the feeling of waiting to know if you apps goes through or not, but fortunately the process took only two weeks for the first release. However I only had a Verizon card and was so eager to submit my app that I didn’t wait to find someone with a Sprint card. And of course the first version didn’t work with the Sprint card. Around the time the first version was approved I wrote a fix to support the Sprint cards and submitted that fix as version 1.1. Thanks to @2busy2blog and pdsphil for helping supporting the Sprint version. Then before it got approved Verizon put out a firmware update for their Mi-Fi card which of course broke version 1.1 (and 1.0). So I updated my Mi-Fi card and wrote a new version which additionally added support for the GSM version of the Mi-Fi card thanks to @jkkmobile. That’s when I made a mistake…I wasn’t sure how to submit a new version when there is one waiting for approval so I just replaced the binary. What I didn’t know is that updating the binary puts you to the back of the queue. And I submitted version 1.1 two weeks before, and it took two more weeks to approve this “new” version 1.1 which was fortunately approved. Now I am not sure how they tested my app as it requires a piece of hardware. So maybe part of the two weeks is to find an approver that had a mifi card.
So all this approval process was new to me and indeed very frustrating when you are used to deploy several times a day fixes to your application in a “web” world. Now this is just a different paradigm and wether you like it or not thats’ the rules you need to play with (for the moment). That means several things. First your application must be tested way better before submitting and be more resilient to different scenarios. If you really have a bug that “Kills” you are just out of luck. It’s similar to developers writing games for the Nintendo DS…once you ship it…tough luck. Note the situation is slightly better, but if you have a fatal bug then people may never give it a second look, not time to cover up issues in a timely fashion. So Apple must find a way to allow fixes to be submitted and approved in a shorter time frame. Maybe two queues for approvals? Now I must admit the Rogue Amoeba guys had a different issue and they had to cripple their application just to have it approved and that for reasons that don’t make sense. Again this was an update to an application that was previously approved, so the wait time has to be way shorter and then again there needs to be some sort of “appeal” process where developers can justify why the app really should be approved.
Now you may argue why an approval process at all, why don’t let the user decide what to install. You may certainly not agree with me, but I like the fact that I can install apps and know they won’t reck my iPhone. I don’t think with an OS and an SDK like the iphone that this could be automated. Maybe an automation build where the apps are compiled by Apples and the compiler could check for any api call infringements? That would be fair, no? I don’t think no approval process is viable for the Apple as this would open the door to malware applications and even though many more savvy users would avoid bad apps the majority of users could end up just downloading any thing, would have issues, and that would be a bigger nightmare than facing the unhappy users. So in the mean time the iPhone development ecosystem is what it is and the platform is too cool to ignore. I’ll be working on several more iPhone apps over the next few months.
But will it make me rich?
Well, that was not the intend of the Mi-Fi app and I sold it for $0 and I can assume that I won’t make it up in numbers. So what are the numbers?
As of today a little more than 2000 downloads which includes 695 upgrades. Wouhao, AT&T must really suck to have that many people that may potentially have an iPhone and a Mi-Fi card. Note these number are ridiculous compared to certain apps that get downloaded thousands a time a day, but hey, it’s all about learning here for me :-)
The interesting thing is that when Andy Ihnatko tweeted about it and Robert Scoble re-tweeted it the downloads made a nice bump:
“This is a must-have iPhone app for MiFi users: shows complete status of device. http://j.mp/2HBsso—big thanks to @2busy2blog – Andy Ihnatko”
And it shows of the iPhone community is active as many iPhone blogs picked on it, here are a few reviews:
- http://www.macsparky.com/2009/10/23/mifi-iphone-application
- http://www.gadgetreview.com/2009/10/mi-fi-iphone-app-monitors-your-mifis-battery-connections-and-more.html
- http://jkontherun.com/2009/10/23/iphone-app-monitors-mifi-3g-usage/
- http://www.gottabemobile.com/2009/10/23/do-you-use-mifi-with-your-iphoneipod-touch-theres-an-app-for-that
- http://www.iphonefreak.com/2009/11/mi-fi-app-for-the-iphone-ipod-touch-gets-an-update.html
- http://www.appstorehq.com/mi-fi-iphone-78445/app
- http://appsearch.justanotheriphoneblog.com/mi-fi-iphone-78445/app
- http://iphoneblips.dailyradar.com/story/iphone-app-monitors-mifi-3g-usage/
- http://www.zatznotfunny.com/2009-10/the-mifi-updates/
- http://technews.am/conversations/gottabemobile.com/iphone_mifi_app_needs_still_needs_some_work
- http://gearshrine.com/iPhone/opinion:iphone-app-monitors-mifi-3g-usage/
So this was a good first learning experience and hopefully there will be more.
Enjoy! Daniel
Amazon RDS: Amazon Relational Database Service or MySQL in the Cloud for Ruby On Rails. 2
For watchthatsite.com (not public yet) I have an instance on EC2 with Rails and MySQL but was looking for a more solid hosting solution for MySQL. And how fortunate, Amazon came out with the solution I need this week. Basically with two command line instructions you can start a new server with mysql configured, tuned, and secured. In this blog entry I will go through the steps that perform to move my sql database to Amazon RDS.
You can find more information on Amazon Relational Database Service (API Version 2009-10-16) here.
Prerequisite: you need to signup for an account on aws.amazon.com, it can be used for EC2, S3, SimpleDb and all the other services AWS provides.
1) Install the Command Line Toolkit
First thing, go download the command line toolkit and read the README.TXT on how to install it. In short you unzip the files, I did put mine at /Developer/aws/RDSCli-1.0.001. Then you create a credential file which contains your AWS access key id and secret key. Then I configured my ~/.bash_profile as follows:
export AWS_RDS_HOME=/Developer/aws/RDSCli-1.0.001
export AWS_CREDENTIAL_FILE=$AWS_RDS_HOME/credential-file-path.conf
export JAVA_HOME=/Library/Java/Home
export PATH=$AWS_RDS_HOME/bin:$PATHto see that the command line toolkit is setup correctly type $rds—help
You will need the command line tool to execute several commands described here after.
2) Create an Instance
Let’s create a MySQL Server instance. RDS offers the following 5 server instance classes:
- db.m1.small (1.7 GB of RAM, $0.11 per hour)
- db.m1.large (7.5 GB of RAM, $0.44 per hour)
- db.m1.xlarge (15 GB of RAM, $0.88 per hour)
- db.m2.2xlarge (34 GB of RAM, $1.55 per hour)
- db.m2.4xlarge (68 GB of RAM, $3.10 per hour)
I will choose a small instance which I will call dbserver1 with a database name db1 and allocate 5g of database space. I also set the master username as admin and password as secret.
$ rds-create-db-instance --db-instance-identifier db1 --allocated-storage 5 --db-instance-class db.m1.small --engine MySQL5.1 --master-username admin --master-user-password secret --db-name db1 --headersThe output is the following:
DBINSTANCE DBInstanceId Class Engine Storage Master Username Status Backup Retention
DBINSTANCE db1 db.m1.small mysql5.1 5 admin creating 1
SECGROUP Name Status
SECGROUP default active
PARAMGRP Group Name Apply Status
PARAMGRP default.mysql5.1 in-syncNow you have a server running and you are being billed $0.11 per hour, that’s like $80 a month without bandwidth but with backup…and it took only 2 minutes to get going. Can’t beat that.
To see all the instances you have you can issue the
rds-describe-db-instances --headers3) Grant Network Access
So I will grant access from my notebook, assuming the ip address is 24.19.0.48 (you can also specify ranges i.e. 24.19.0.0/50). (Note that access was revoked by AWS, not sure why??)
rds-authorize-db-security-group-ingress default --cidr-ip 24.19.0.48 --headersI also have an ec2 instance which I want to grant access to
rds-authorize-db-security-group-ingress default --ec2-security-group-name watchthatsite --ec2-security-group-owner-id 526541544691Note the ec2-security-group-owner-id is your Amazon AWS account number, you can find it for example on you account activity page. To see your security configuration issue the following command: rds-describe-db-security-groups default—headers
4) Using the Database
To use your database you first need to find out the endpoint address of your new server. So describe you instances:
rds-describe-db-instances --headers commandDBINSTANCE DBInstanceId Created Class Engine Storage Master Username Status Endpoint Address Port AZ Backup Retention
DBINSTANCE db1 2009-10-28T22:53:31.666Z db.m1.small mysql5.1 5 admin available db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com 3306 us-east-1b 1
SECGROUP Name Status
SECGROUP default active
PARAMGRP Group Name Apply Status
PARAMGRP default.mysql5.1 in-syncYou find out your endpoint address, for me db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com
So now you can connect to your database:
mysql -h db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com -P 3306 -u admin -p db1Let’s configure my Rails application to point to that database and run a migration:
So I change my config/database.yml to point to the above database
development:
adapter: mysql
host: db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com
reconnect: false
database: db1
username: admin
password: secret rake db:migrateLet connect to the mysql console and do a show tables;
+-------------------+ | Tables_in_db1 | +-------------------+ | schema_migrations | | users | | watches | +-------------------+
Yep, all there.
Now I still have to move my old production database to the new one, so let’s dump the data from my old database:
mysqldump watchthatsite_development -u admin > wts.sqland reload that data in the new database:
mysql -h db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com -P 3306 -u admin -p db1 < wts.sqlRestarting my Rails server…That’s all!
Enjoy, Daniel.
You Mifi card status iPhone App on the Available on the AppStore now. 2
360iDev is next week in Denver...and it's nearly sold out! 2
360iDev is around the corner and if you know the organizers or have been to 360flex then you know Denver is the place to be starting next Sunday if you are or wanna be an iPhone developer. The conference starts with a day of tutorials on Sunday then kicks in full gear Monday through Wednesday with three tracks of 80 minute sessions covering all angles of iPhone development from some of the best authorities in the fields.
You can find the schedule as ical or download a pdf
Here is my schedule:
On Sunday I’ll attend the “Hands-On with the Appcelerator platform.” session.
Monday

Tuesday

Wednesday

If you are not signed up yet…you better hurry.
I hope I’ll see you there!
Daniel
RMagick (from source) on Snow Leopard 39
After the release of 10.5, I published an article about building RMagick from source on Leopard. I won’t rehash the why, you can read the original article for that. My clean install necessitated updating the RMagick script, so here’s what worked for me to install from source on Snow Leopard! For the impatient, here’s the download link: rmagick-build.sh
First, we start with installing wget, as it seems to be a bit more clever than curl about dealing with mirrors, etc. Then, we compile and install each prerequisite package. Finally, we install the gem.
All the links in the script worked for me, but, depending on your location, network, conditions, etc, your mileage may vary. Enjoy!
#!/bin/sh
# install wget, which is cleverer than curl
curl -O http://ftp.gnu.org/gnu/wget/wget-1.11.tar.gz
tar zxvf wget-1.11.tar.gz
cd wget-1.11
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src
# prerequisite packages
wget http://nongnu.askapache.com/freetype/freetype-2.3.9.tar.gz
tar zxvf freetype-2.3.9.tar.gz
cd freetype-2.3.9
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src
wget http://superb-west.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.39.tar.gz
tar zxvf libpng-1.2.39.tar.gz
cd libpng-1.2.39
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src
wget ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
tar xzvf jpegsrc.v6b.tar.gz
cd jpeg-6b
ln -s `which glibtool` ./libtool
export MACOSX_DEPLOYMENT_TARGET=10.6
./configure --enable-shared --prefix=/usr/local
make
sudo make install
cd /usr/local/src
wget ftp://ftp.remotesensing.org/libtiff/tiff-3.9.1.tar.gz
tar xzvf tiff-3.9.1.tar.gz
cd tiff-3.9.1
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src
wget http://superb-west.dl.sourceforge.net/sourceforge/wvware/libwmf-0.2.8.4.tar.gz
tar xzvf libwmf-0.2.8.4.tar.gz
cd libwmf-0.2.8.4
make clean
./configure
make
sudo make install
cd /usr/local/src
wget http://www.littlecms.com/lcms-1.17.tar.gz
tar xzvf lcms-1.17.tar.gz
cd lcms-1.17
make clean
./configure
make
sudo make install
cd /usr/local/src
wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/gs870/ghostscript-8.70.tar.gz
tar zxvf ghostscript-8.70.tar.gz
cd ghostscript-8.70
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src
wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/gs860/ghostscript-fonts-std-8.11.tar.gz
tar zxvf ghostscript-fonts-std-8.11.tar.gz
sudo mv fonts /usr/local/share/ghostscript
# Image Magick
wget ftp://ftp.fifi.org/pub/ImageMagick/ImageMagick.tar.gz
tar xzvf ImageMagick.tar.gz
cd `ls | grep ImageMagick-`
export CPPFLAGS=-I/usr/local/include
export LDFLAGS=-L/usr/local/lib
./configure --prefix=/usr/local --disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8 --with-gs-font-dir=/usr/local/share/ghostscript/fonts --disable-openmp
make
sudo make install
cd /usr/local/src
# RMagick
sudo gem install rmagickUPDATE There is a bug with libgomp that breaks the convert utility (See comments below). the --disable-openmp configure option has been added to the script to fix this.
UPDATE 2 A new patchlevel of ImageMagick has been released that supersedes the original one referenced in this script, and the original has been removed from the server. Thanks to Sebastian for this update that will grab the latest release.
Introducing Hashdown 4
If your database is normalized, you will almost always end up with small tables (often referred to as reference data or lookup tables) which provide a set of possible values for a particular attribute. (e.g. Currency, Category, etc.) A common pattern that emerges in many applications is accessing these records by a symbolic name (as opposed to by id) for purposes of clarity when reading the code. In C (and friends), the database ids can be mapped to the positions of an enum datatype. I recently released the hashdown plugin that provides hash-like access for reference data records, and also adds some dropdown option list generation support, since this data is often used to populate select list in forms.
As an example of what hashdown does, suppose we have the following model:
class CardType < ActiveRecord::Base
endwith the following data:
+----+-------+------------------+
| id | code | name |
+====+=======+==================+
| 1 | visa | Visa |
| 2 | mc | MasterCard |
| 3 | disc | Discover |
| 4 | amex | American Express |
+----+-------+------------------+By adding the following line to the model:
class CardType < ActiveRecord::Base
finder :code
endYou get the functionality of a hash-like square-bracket accessor for the model that will let you do something like:
@order.card_type = CardType[:visa]The underlying implementation is similar to:
def CardType < ActiveRecord::Base
def self.[](value)
find_by_code(value)
end
end...except it adds a caching layer to boost performance by preventing repeated database access.
Adding the following directive:
def CardType < ActiveRecord::Base
selectable
endto the model gives you a class method called select_options that can be used to populate a select list like this:
<%= form.select :card_type_id, CardType.select_options %>produces:
<input type="select" name="order[card_type_id]" id="order_card_type_id">
<option value="1">Visa</option>
<option value="2">MasterCard</option>
<option value="3">Discover</option>
<option value="4">American Express</option>
</input>By default, this will use the id attribute as the submitted value of the option and call a display_name method (if it exists) for the displayed value of the option, falling back to the name method/attribute. Each of these can be overridden by passing a symbol attribute / method name, or a lambda that will be executed to generate the value. For (a contrived) example:
<%= form.select :card_type_id, CardType.select_options(:key => :code, :value => lambda{|card_type| card_type.name.reverse }) %>produces:
<input type="select" name="order[card_type_id]" id="order_card_type_id">
<option value="visa">asiV</option>
<option value="mc">draCretsaM</option>
<option value="disc">revocsiD</option>
<option value="amex">sserpxE naciremA</option>
</input>Again, the select_option results are cached for better performance.
This is a pretty small plugin that I’m using to DRY up some code in a current project I’m working on. Let me know if you have feature requests (or fork and patch it on GitHub!)
Behind the scene: Quiltivate.com a beautiful Flex on Rails website.
Behind the scene: Quiltivate.com a beautiful Flex on Rails website. from daniel wanja.
Check out quiltivate.com for a video on how to really use the Quilt Builder and go try it out. As it's fresh out of the gates their may be a little quirks here and there, so please let me know what you find. So thank you Kacie and Phil for getting me on this project, it was really fun! Enjoy, Daniel.Screencast: Testing Flex Apps with Cucumber - Take 2 1
Screencast: Testing Flex Apps with Cucumber - Take 2 from daniel wanja.
To run this code you need to have all the gems installed. So config your Rails to run Cucumber with FunFx (in config/environments/test.rb):
config.gem "rspec", :lib => false, :version => ">= 1.2.7"
config.gem "rspec-rails", :lib => false, :version => ">= 1.2.7"
config.gem "webrat", :lib => false, :version => ">= 0.4.4"
config.gem "cucumber", :lib => false
config.gem "funfx"
config.gem "safariwatir" require 'funfx'
require 'funfx/browser/safariwatir'
browser = Watir::Safari.new
browser.goto("http://localhost:3000")
Before do
@flex = browser.flex_app('flashContent', 'flashContent')
end
at_exit do
browser.close
end Cucumber::Rails.use_transactional_fixtures <flex-config>
<compiler>
<include-libraries append="true">
<library>../../lib/funfx-0.2.2.swc</library>
<library>../../lib/automation.swc</library>
<library>../../lib/automation_agent.swc</library>
<library>../../lib/automation_dmv.swc</library>
<library>../../lib/automation_agent_rb.swc</library>
</include-libraries>
</compiler>
</flex-config> Screencast: Testing Flex Apps with Cucumber 7
Testing Flex Apps with Cucumber from daniel wanja
The source code can be found on github
Enjoy!
Daniel
UPDATE: An updated version (and slightly) different version of the screencast can be found here.
RailsConf 2009 Day Two 1
Day Two got off to a good start. Engine Yard did a promotional pitch—the speakers could have been a bit more polished, but it was interesting stuff about their one-button-deployment, and overall not bad for an advertisement.
Next up was Chris Wanstrath. He started with a lead in regarding how to become a famous Rails developer—focusing on yourself, your blog readership numbers, your twitter follower count, etc. Later, he talked about how he went from being an unemployed college dropout to co-founder of the very successful GitHub, due to sharing code. His point was that in his eyes, it’s better to focus more on the community: share code, contribute to open source projects, even write documentation for existing projects. Being a good developer trumps being a famous developer. The complete text of the talk is online here .
For the first session of the day, it was a tough call between Rack/Sinatra and Metric Fu. I finally went with:
Using metric_fu to Make Your Rails Code Better – Jake Scruggs
The central theme of this talk was how to use automated code analysis to direct you on where to spend your refactoring cycles. He used Carlin’s law (Anyone going slower than me is stupid; anyone going faster than me is crazy), but applied to programming. As your programming skills change over time, you see the same code differently.
He touched on coverage as a baseline that you should be doing as a part of your code analysis, then went on to complexity analysis, reviewing two tools available to analyze the “complexity” of your code: Flog and Saikuro. Flog examines your code (flog -g app for a Rails app) and gives you a (somewhat arbitrary) numeric range measuring the relative complexity of your code. Basically, 0-10 is awesome (and practically unatainable), 11-20 is okay for real world methods, and it goes downhill from there. If you have 200+ complexity scores, refactor immediately! Flog is somewhat opinionated about what is good/bad or more/less complex, but generally does a good job in helping you avoid the “icebergs”.
Saikuro gives a more concrete result—the “score” is the number of branches through a method, including tertiary operators, foo if/unless bar, etc. This is a plus over Flog, and usually indicates about how many tests you should have (one per branch). The downside to Saikuro is that it does not pick up on dynamically defined methods, where Flog does.
Next, we walked through a refactoring example, where Jake showed using high Flog scores as a hit list of where to refactor next. He also mentioned that better readability trumps lower complexity scores, one thing to keep in mind—as being generated by automated tools, the scores should be taken as a guide, not a law. A good point was brought up during Q&A: there is currently no way to “flag” a high-scoring method as acceptable, so if you have a justifiably complex method that you choose to live with (e.g. for readability), then you’ll have to live with the flogging you will receive. I’m sure patches would be welcome if someone wanted to fix this!
On to code smell and Reek and Roodi, tools to identify smells (overly large methods, etc.) Reek tends to warn over smaller issues than Roodi, and can indicate false positives. Roodi generally tends to have fewer complaints—if it warns about something, it should probably be fixed!
Next up was Flay, which detects non-DRY-ness in code, anything from strict copy-n-paste to functionally identical blocks with different variable names to do..end blocks matching curly-brace blocks.
Also covered was a way to track source control churn. At this point, you’re probably thinking “How can I keep up with all this?” Luckily, there’s metric_fu, a way to wrap all this up into one package and get all this code analysis goodness in your project. Install the gem, then run rake metrics:all. For more info, installation instructions, etc., see: http://metric-fu.rubyforge.org/ Looking forward to adding this bag of tricks to our CI toolset.
Rails 3: Step off of the Golden Path – Matt Aimonetti
Matt started off with a history of programming languages and how Ruby came to be, including some of Matz’ core philosophies embodied in the language. Moving along to Rails, he talked about the growth of Rails and the desire for increased performance and options that led to the split between Rails and Merb. This led us in to the discussion of the current and future state of affairs for Rails 3.
Currently, as DHH mentioned in the opening keynote, there is no official release for Rails 3. However, much work has been done, and a direction / ideas are emerging that will be implemented once an official release is ready. These include:- improved performance
- increased modularity
- agnosticism
- public api
- mountable apps
Matt emphasized that there will be no drastic changes, and by default, rails app will generate a very similar application to what you would get today under 2.x. However, there will no longer be the idea of “the one true Rails way” of building an app—the framework will be less opinionated. However, you should go through a process of justification to see if you really need something different than the default stack.
- JavaScript frameworks, including jQuery, YUI, ExtJS, MooTools, Prototype, or the ability to write your own, and plug it in.
- Different templating engines: HAML, ERb (this is already doable in Rails)
- Different ORMs: ActiveRecord, DataMapper, SEQUEL, Hibernate, non-RDBMS stores like CouchDB, Tokyo Cabinet, etc.
- DataMapper re-uses existing Ruby object for both sides of a
has_many/belongs_torelationship. In other words, if I load parent and child records from the database, and look atparent.object_idas compared tochild.parent.object_id, under DataMapper, these will point to the same object automatically, while with ActiveRecord, these will be separate objects. (Note that inverse_of was recently checked into rails, which enables this in ActiveRecord as well ) - DataMapper does automatic lazy loading as well as strategic eager loading, so in this scenario:
@parent = Parent.find(12345)
@parent.children.each do |child|
puts child.name
end:include => :children) to be added to the original query to avoid the N+1 iteration problem, where DataMapper is clever enough to figure that out and generate 2 SQL queries for you automatically.
- The ability to have multiple repositories (which looks like it means databases), and a
copymethod on models to clone data from one database to another—one use case would be an automatic archive or backup process that copies data generated within the last week to a backup database. - Query Path, allowing more flexibility in SQL condition generation (WHERE name LIKE ‘foo‘)
- one potential gotcha that was mentioned: DataMapper does not support STI and Polymorphic associations as well as ActiveRecord does
- file structure
- router DSL
- request handling But he voiced the opinion that the vast majority of Rails apps will not need anything like this—make sure your need justifies coloring outside the lines.
All in all a good presentation, maybe a bit much focus on DataMapper specifically. However, I personally enjoyed the DataMapper bits, and might have to try it out on a project, if it’s a fit.
Art of the Ruby Proxy for Scale, Performance, and Monitoring – Ilya Grigorik
I skipped out on the afternoon sessions, so my next talk was Ilya’s—never disappointing. Ilya spoke about EM-Proxy, his event machine based proxy. He gave good example code of how EM proxy could be used to implement transparent and intercepting proxies.
It started with an itch at PostRank, Ilya’s blog aggregation solution. An effective staging environment should closely resemble the production environment—the problem was that their production environment spanned nearly 80 (virtual) servers on EC2’s cloud. Spinning up that many servers just as a staging environment was an expensive proposition. Also, simulating production traffic then becomes a challenge, as you end up trying to store production logs and “replay” them into the staging environment. The way that they chose to solve the problem was to separate a group of the servers into a staging app server pool, set up a proxy that would transparently (to the end user) intercept incoming requests, send them to both the production and staging pools simultaneously, then return only the production response to the user, using the staging response internally for benchmarking, testing output, etc. With this strategy, the more static parts of the system (web servers, load balancers, etc.) can be shared across environments, and the staging environment is testing the part that actually changes (the application servers).
The first example code was a transparent proxy that simply forwarded a request from one port to another. Ilya built on this to show how you could dynamically alter request/response data on the fly. Finally, he built up to the original scenario: duplexing a single request across two (or multiple) backend servers, but returning only a specific response. As he mentioned in the talk, one strategy for servicing a specific request as fast as possible might be to send the request to all machines in your pool, then respond with whichever request completed first.
These examples were centered around HTTP requests, but he went on to show some other examples of how this is not protocol-specific: you are just dealing with data over a socket connection, so as long as you understand the underlying protocol, EM-Proxy could be useful. His examples showed SMTP proxies for accepting/rejecting incoming mail by email address and implementing a spam filter by forwarding the incoming mail to Defensio before passing it along to your real SMTP server. The final example was pretty clever: an implementation of EM-Proxy to reduce the memory overhead of beanstalkd by selectively delaying queue inserts based on the scheduled execution time—basically buffering far future jobs into the database instead of immediately inserting into the work queue.
Slides are available here: http://bit.ly/ruby-proxy
Another packed day at RailsConf 09, one more to go!
