Entries from April 2009 ↓
April 27th, 2009 — Planet

While I know the title is both asking for trouble (because of the now anecdotal original article with a similar title) and flamebaity, please read on - my goal is not to get some great stats but rather to know your opinion about the situation and discuss the possible solutions of the problem.
How it all started…
I would not like to re-iterate what has been said on several blogs, just to summarize: Matt Aimonetti, member of the Rails Activists, gave a presentation at GoGaRuCo which contained sexually explicit images (according to some - I am not here to judge whether that’s true, and it doesn’t matter anyway, as you’ll see in the rest of the post).
I am not really discussing whether it’s appropriate to have images of nude chicks in your presentation at a Ruby conference (I think it’s not, it’s unprofessional etc. - but that would be a matter of a different post Update: Someone summed this up in the article’s reddit thread nicely: If you’re a Rails programmer, or a Ruby programmer, and you don’t decry this sort of thing, you have no business calling yourself a professional. It doesn’t matter how large your website is, how easy it was to write, how much better it is over PHP or ASP.NET or J2EE; by definition, you do not belong to a professional community. That’s all there is to it.
It’s incumbent on every Ruby programmer to either reject this sort of misogynistic sewage, or accept that you’re never going to advance the promotion of Rails in the public perception because members of the community still think it’s edgy or cool to put pictures of strippers in their public presentations.
And here’s a hint: if your decided reaction is to talk about how unimportant this is, how much it doesn’t matter, or how much it doesn’t offend you personally, you probably don’t understand professionalism at all.) because sadly, I think there are far bigger problems here than that - shedding light on them is the real purpose of the article, not talking about pr0n at GoGaRuCo again.
Would You Walk Into a Hindu Temple with Your Shoes on?
I have been living in India for 2 months last summer, working on a Rails startup. Maybe I am odd or something, but I knew that I had to remove my shoes when entering a Hindu temple, and no one had to convince me (what’s more, I didn’t even think about it for a second) wether this is the right thing to do, why is it so, whether I should do otherwise etc. This is a similar situation - I just don’t do X when speaking at a conference, if I suspect that X makes feel even one person in the room uncomfortable, whether because of his gender, race, nationality, Ruby/Rails skills, penis size or what have you - regardless whether I think it’s fine for me, my wife, for other members of the community and/or the majority of the room.
The trick is, how does a hindu feel when I enter a temple in footwear (even if that is perfectly acceptable in my country, culture, family, friends) - it’s perfectly irrelevant how do I feel in the given situation. Using the previous paragraph, try to apply this to a Ruby/Rails conference.
Shit happens…
Until this point in the story, I see no problem at all, and could even agree with the guys asking “what’s wrong with you, don’t make a fuss out of nothing” - the pictures Matt used are non-problematic in my book, and he had no idea they are problematic in anyone’s book - theoretically it could have worked, but the point is, it did not. Some members of the Ruby community got offended, and here our story begins.
…and hits the fan
One of the real problems is that after this has been pointed out, Matt still keeps answering “As mentioned many times earlier, I don’t think my presentation is inappropriate.”. As I mentioned two paragraph above, it doesn’t matter what do you think, unless of course, you don’t care about offending some members of the community. In that case you should not try to apologize at all. However, if you are trying, reciting “I don’t think my presentation is inappropriate” will not put and end to the discussion. It just doesn’t work. Why can’t you just simply apologize, admitting that this was a bad move (because it offended some, not because porn, sexual images or whatever in presentations are bad, per se) and finish the discussion?
Rails is Still a Ghetto
However, in my opinion that’s still not the worst part of the story, or to put it differently, some members of the Rails community still found a way to make things worse, by applauding to all this:
OK, you say, we are all used to DHH’s style, this is just how the guy is. That’s (kind of) cool, but I heard that most of the Rails core team (and obviously Matt himself) has the same opinion - and that’s a much more serious problem, because it means that a Rails activist, backed by DHH and other Rails core members finds all this OK, despite of the fact that numerous people in the community voiced their opinion otherwise.
This is not about being a closed-minded prude, shouting for police and suing everyone using sexually explicit images in a presentation. This is not even about women, as I have seen both males and females on either side of the fence. This is about mutual respect - I don’t agree with you, but respect your feelings. Or not, as demonstrated in this case.
So Rails continues to be the most socially unacceptable framework - associated with arrogance, elitism and whatnot in the past - now add pr0n images in presentations. Thankfully RailsConf is held in Las Vegas, and that should calm down all the people who associate Rails with all this crap :-). The real problem is that people associate you with the tools you are using - think Cobol, PHP, Java… or Rails. By being part of the Rails community people associate me with Railsy stereotypes automatically, which aren’t nice at all right now.
I hear you, dear creme-de-la-creme Rails (core) member, I know you don’t give a shit, and you think this is all prude babbling - because your hourly rate is more than some of us earn in a day, and you’ll be sought after even if Rails will have a much worse image than it has now. But 99.9% of us are not in the ‘circle of trust’ and would be happier if Rails would not be constantly associated with a ghetto.
MINASWUBN
In case you are wondering what does the acronym stand for, it’s “Matz is Nice And So We Used to Be Nice”. Unfortunately, the stuff I don’t like about the Rails community is sneaking into Ruby too, it seems, as the above case demonstrates. Besides this, the count of aggressive comments and reactions on various blog posts is really disturbing to me. Please (at least Rubyists) try to avoid being contaminated by all this shit and stop thinking you are cool because you can swear on a forum (always in anonymity). You don’t have to be a douchebag just because you are a Rubyist / Rails coder, as surprising as this might sound to some.
Conclusion
I think “incidents” like this and getting more and more antisocial members are inevitable by-products of growth in a community. The questions is, whether, and if, how, do we stop them. The problem is that it seems to me the Rails “top management” doesn’t want to stop them (what’s more, even encourages them) in the first place (please prove me otherwise - maybe I don’t see the full story - I’ll be the happiest to admit that I am talking bullshit).
I have to admit I have no clue what would be the right move - burying our heads in the sand and pretending everything is fine is not. Please leave a comment if you have an idea or anything to add.
April 23rd, 2009 — Planet, Uncategorized
Slovak Ruby and Ruby on Rails fans will meet in Bratislava on April 25, 2009. For more details see the Slovak Ruby on Rails site or directly the post about the meeting [all in Slovak].
April 14th, 2009 — Planet
Another training's over. Very different but equally challenging.
Seems that Ruby's been making headway to corporate world as most of the participants this time were there on their employers' budget. When I compare it with our first RoR trainings around 2 years ago with Rails 1.0 just out and more than 30% of the things still on a wish list and the only way to learn RoR was Agile Web Development With Rails...this time it was much more business-like. There's like 20 books out, including a (bit obsolete) video from Linda.Com and pretty much everybody knows about rails.
Another aspect that has changed is Rails versions. With Rails 2.3 and Ruby 1.9 out there's a lot of changes and incompatibilities that complicate the learning. Most of the books and reference materials use Rails 2.0 or early versions of 2.2. This makes it little bit difficult to have training on 2.3 as most of the "further" reading is incompatible. While the incompatibilities may seem easy to solve for experienced developers they can be quite exasperating for a newbies. On the other hand, people are quite reluctant to start learning something that is already obsolete.
Similar is true for Ruby 1.9, even though after burning they're fingers several times until it got finally compatible with Rails most people would still prefer to use 1.8.6 or 1.8.7.
April 13th, 2009 — Planet
I just had another unproductive afternoon. Another thing I would expect to work out of the box that turned out to be not that easy. It was not the first time I needed dynamic number of columns in the grid but until now I was always able to find a workaround. Fortunately, today I couldn't go around and had to solve the problem once and for all.
What I needed was a column model dynamically adjusting depending on the data received from data store (i.e. JSON provided by server). Something like the following:
Where each site has a different set of dimensions (rows) and different set of auditors (columns).
It turned out that the problem was actually two-fold - first dynamically change the columns and then display the editable checkboxes instead of true/false values.
To change the columns I used metaData attribute in my JSON. Including metaData attribute causes Ext.data.JsonReader to be adjusted to the new set of fields and other config parameters and fire metachange event. Here's an example of the JSON with metaData:
{
"results": 3,
"auditors": [
{"dimension_name": "Audits and Reviews", "auditor_3": false, "dimension_id"
: 10, "id": 10, "auditor_4": false, "auditor_18": false},
{"dimension_name": "Emergency Management & Fire Safety", "auditor_3": false, "dimension_id": 8, "id": 8, "auditor_4": false, "auditor_18": false}
.
.
.
],
"metaData": {
"fields": [
{"name": "id"},
{"type": "string", "mapping": "dimension_name", "name": "auditor[dimension]"},
{"type": "int", "mapping": "dimension_id", "name": "auditor[dimension_id]"},
{"type": "bool", "name": "auditor_3", "header": "Dasha Alexo"},
{"type": "bool", "name": "auditor_18", "header": "Tester 3"},
{"type": "bool", "name": "auditor_4", "header": "Zobak Zobakovic"}],
"root": "auditors",
"totalProperty": "results",
"id": "id"
}
}
In this case it's the number of auditors (and their names) that's changing. My data types are booleans but displaying any other data type would look pretty much the same.
Next I needed to update the column model based on the new meta data. I did that by adding metachange listener to my store
auditors_store.addListener("metachange", function(store, meta){
var grid = Ext.getCmp('auditors-grid');
var columns = [
{header: 'Dimension', dataIndex: 'auditor[dimension_id]', hidden: true},
{header: 'Dimension', dataIndex: 'auditor[dimension]', width: 200}
];
for (var i = 3; i < meta.fields.length; i++ ) {
var plugin = new Ext.grid.CheckColumn({
header: meta.fields[i].header,
dataIndex: meta.fields[i].name,
grid: grid,
width: 120
});
columns.push(plugin);
plugin.init(grid);
//use columns.push( { header: meta.fields[i].header, dataIndex: meta.fields[i].name, type: meta.fields[i].type }); for fields that don't require plugins
}
grid.reconfigure(auditors_store, new Ext.grid.ColumnModel(columns));
});
I had to create and initialize the plugin for each new column as I needed editable checkboxes. For normal fields just use the usual column config object { header: meta.fields[i].header, dataIndex: meta.fields[i].name, type: meta.fields[i].type }.
The actual magic happens is in the last line. Grid has an obscure method
reconfigure( Ext.data.Store store, Ext.grid.ColumnModel colModel ) that allows to switch the store and column model (the columns displayed) on the fly.
My next problem was to make the checkboxes editable. To do that I had to put a small fix to the CheckColumn plugin (see
the plugin) as the original plugin assumes that the grid is not rendered when initializing, however, when dynamically adding columns the grid is already rendered so I had to change the following:
init : function(grid){
this.grid = grid;
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
},
to the following:
init : function(grid){
this.grid = grid;
if (this.grid.rendered) {
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
} else {
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
}
},
And that's all - nice and simple. If only there were more books on Ext :-(
April 8th, 2009 — Planet
A lot has been said said about agile development and agile principles like content delivery over contract negotiation, flexibility of contracts and no upfront specification. We've been loving and doing that for some years now. One thing I was not able to wrap my head around for the longest time, though, was how to manage (traditional) employees in this kind of a non-traditional arrangement. Most of the agile books spend only very limited time on this topic pretty much always retorting to anecdotal evidence of "self motivated teams rising to the occasion and living happily ever after"
When dealing with clients, both parties are bound by the contract (however agile and flexible) and there are clear and simple business rules to be followed. In our case it comes down to if client doesn't like what they're getting they don't pay. The payment happens after every iteration so both parties have a tangible motivation/interest to get things done. Both parties enter the contract without previous baggage and maintain pretty much equal status.
Not at all as simple with (traditional) employees. They usually start with limited knowledge and require extensive training. In our company it takes several months and even after they've mastered the technical skills they still need months and months of experience to grasp various aspects of different domains and business processes we deal with every day. We use commission from closed iterations and collected payments as a motivation. Main portion of the money, however, still comes in the form of monthly salary. Given high level of stress, steep learning curve of ever changing technology, demanding customers, even more demanding bosses it's only matter of time when the initial motivation wears out and everyday routine kicks in. In many of my ex-employees, this was accompanied with a feeling that they've learned more than they'd ever thought they would and their price on the market has soared indefinitely. Sarcasm aside, after reaching this level, people start to be more relaxed and try to find motivation/amusement in experimentation with latest gadgets, obscure technologies or start working on they're own version of Rails or other frameworks. What's worse, it slowly starts to affect the delivery of project(s).
Now let's switch to our shoes. We spent the money on training and non-productive period of the employee. We see that the results are diminishing and we see that the employee is even starting to abuse others requiring help and claiming that he is a slow programmer and that it's not his domain knowledge, etc. Problems in delivery cause delayed payments and smaller and less frequent commission for the employee. No matter how little employee produces (and this can quickly become negative value when the quality reaches throw away and rework levels) his salary is still guaranteed to him by employment act. If we let him go we lost all our investment in training and we will incur extra costs replacing him mid-project. During all this time there is absolutely nothing we can do to protect our side. Yes, we can motivate, but if that doesn't work we've got nothing.
Agile development contracts seem to be calling for agile employment contracts.
April 7th, 2009 — Planet
Around a half a year ago I started slowly switching my servers to Apache mod_rails. I wasn't very keen after my first test around September on one of my Slicehost servers. Without any application running apache, ruby and postgresql processes tookup around 500MB of memory - around 100MB per processes. When I experimented with my other servers I found out this happens on 64bit architecture - 32bit servers took up less than half of that memory. I am still running performance tests to compare the performance and behavior of mod_rails vs Lighttpd - I'll be writing about it soon.
For now here's the installation for Hardy Heron (I assume you have the build-essential, ruby and so on already installed):
sudo apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert apache2-prefork-dev
sudo gem install passenger
sudo passenger-install-apache2-module
Now add the 3 generated lines (almost last on the screen) to config file:
sudo vim /etc/apache2/apache2.conf
Right now it looks something like the following -
BUT THE VERSION NUMBERS WILL CHANGE SO COPY THE LINES FROM THE PREVIOUS PROCESS
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-2.1.2/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.1.2
PassengerRuby /usr/local/bin/ruby
In the same config file add the server name and NameVirtualHost otherwise the server will complain at restart:
ServerName XYZ
NameVirtualHost *:80
save the config file and continue - we'll need to enable modrewrite and disable default site:
sudo a2enmod rewrite
sudo a2dissite default
now just configure your application by adding your_app_name to /etc/apache2/sites-available/ with the following content:
sudo vim /etc/apache2/sites-available/your_app_name
<VirtualHost *:80>
ServerName abc.def.com
ServerAlias xyz.com
DocumentRoot /home/bohm/rails/access/current/public
</VirtualHost>
where abc.def.com and xyz.com are the URLs of your application and DocumentRoot points to the public folder of your application.
To enable the application run
sudo a2ensite your_app_name
sudo /etc/init.d/apache2 reload
To disable it run
sudo a2dissite your_app_name
sudo /etc/init.d/apache2 reload
And you're done :-)
April 7th, 2009 — Blog
Všetkým priaznivcom Ruby či Ruby on Rails na známosť sa dáva, že v sobotu 25. apríla 2009 sa uskutoční stretnutie nás, nadšencov tohto jazyka a všetkého okolo toho.
Mesto: Bratislava
Ozval sa aj niekto z Košíc. Žiaľ, zatiaľ je viac ľudí z Bratislavy. Čo tak ďalšie stretnutie v Košiciach?
Miesto: Family Caffee, Blagoevova 18, Petržalka
palacinkáreň s palacinkami :), kofolou (.5l za 1€), nefajčiar, wi-fi - prvých 30 minút zadarmo, potom 1 hodina za 1€
View Ruby on Rails stretnutie 25. apríla in a larger map
Dátum: sobota 25. apríla 2009 približne od 14:00 do odhadom 16:00 - 18:00.
Kontakt: po zaslaní e-mailu na forum zavinac rubyonrails bodka sk zašlem moje telefónne číslo.
Obsah:
- stretnúť a vidieť sa :)
- porozprávať o skúsenostiach
- výmena kontaktov
- komerčné, nekomerčné a akademické použitie Ruby a Ruby on Rails
- komunita Ruby a Ruby on Rails na Slovensku
Poznámky, postrehy a možno i fotografie zo stretnutia sa objavia na tomto blogu.
Prípadná diskusia je na fóre.
Všetci sú srdečne vítaní.
April 7th, 2009 — Planet
While I really like Ext and the component model behind it, some simple things seems to be missing - an example would be multiline nodes in TreePanel. After some searching I managed to find a
MultilineTreeNodeUI plugin.
Here's how to use it:
new Ext.tree.TreePanel({
//renderTo:'treecontainer',
id: 'upcoming_events',
loader: new Ext.tree.TreeLoader({
dataUrl:'/datasource/upcoming_events_json',
baseParams: {},
baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI}
}),
root: new Ext.tree.AsyncTreeNode({
expanded: true
}),
rootVisible: false,
collapsed: false
})
Just include the MultilineTreeNodeUI.js in the page and create a usual TreePanel. The only difference is to include
baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI} in your loader. Multilne tree requires the data in the following format:
{
text: '09 April 2009',
iconCls: 'calendar',
details: ['Program for the day...'],
uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
children:[
{
text: '9:30',
iconCls: 'time',
details: ['Win $1M', 'Sure win...'],
uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
leaf: true
},
{
text: '11:30',
iconCls: 'time',
details: ['Buy private jet', 'Or something'],
uiProvider: Ext.ux.tree.MultilineTreeNodeUI,
leaf: true
}
]
}
Where the additional lines are provided by
details attribute. It's an array - one item per line - maybe not an ideal solution but still workable - worst case you just split the longer line by number of characters. The
uiProvider will generate the multiple lines. Your controller doesn't have to do anything about it as it will be added automatically by the
baseAttrs: {uiProvider: Ext.ux.tree.MultilineTreeNodeUI} we added in the loader.
And here's the outcome:
April 5th, 2009 — Planet
Last time I wrote about sending SMS using online tools. The main problem there remains 2 way communication. Luckily, there's a simple solution to receiving problem. Since the start of 3Gmobile internet, GSM modems became quite ubiqitous and reasonably cheap. Just like the SMS software. I used
Smstools that proved to be a snap to install and use.
wget http://smstools3.kekekasvi.com/packages/smstools3-3.1.3.tar.gz
tar -xzf smstools3-3.1.3.tar.gz
cd smstools3
sudo ./install.sh
I am using Huawei Mobile Modem E270 and E170 from Starhub. The only change I had to make now is update the config file. Here's my config file /etc/smstools.conf
devices = GSM1
logfile = /var/log/smsd.log
loglevel = 7
[GSM1]
device = /dev/tty.HUAWEIMobile-Modem
incoming = yes
#pin = 1111
init = AT+CNMI=2,0,0,2,1
After that just start/restart the smsd daemon
sudo killall smsd; sudo smsd;
Sending of SMS is now as simple as
sudo sendsms +6584199983 'Your SMS message....'
or just put SMS File to /var/spool/sms/outgoing/
To: 491721234567
Hello, this is the sms.
More info about the structure of the file is
here.
As for receiving, all the received messages will be downloaded to /var/spool/sms/incoming/ so all you have to do is create a cronjob to check this folder for new messages and then forward the message to your application.
April 5th, 2009 — Planet
When I tried to integrate one of our applications with SMS messages (both incoming and outgoing) several years ago we didn't manage to find not even one SMS gateway provider that would be able to pass our simple criteria. Allow sending (da :-) and receiving of messages with some reasonable notification of received messages (simple webservice / forward to email, anything). The replies should preferably be handled by a local number and sending/forwarding should be within reasonable price range :-) Is it too much to ask?
There is a number of online portals for sending (some support also receiving) SMSes like Clickatel, SMSZilla, SMSCountry. Their pricing per message varies from SGD0.05 - 0.1 which is quite reasonable and some provide nice and easy API for sending (when you think about it how complicated can it get to write a form handler with 3 or 4 fields) - some ask you to pay for API extra. For better or worse they would accomplish the sending but the receiving was either very painful or expensive or both. On top of that sending a hundred messages to and Indian or US number shows on your bill so we had to find something better.
For systems that require only sending we mostly used Singtel Ideas or Starhub Gee. Both are just a little short of and actual webservice, nevertheless worked quite well. Here's an example how to send message using StarHub Gee (12345678 is your phone number)
require 'rubygems'
require 'mechanize'
mech = WWW::Mechanize.new
page = mech.get('http://groupsms.starhubgee.com.sg/VCRLS/login.cgi?cb=http%3A%2F%2Fgroupsms.starhubgee.com.sg%2Fcgi-bin%2Fs.pl')
#login first
form = page.form('loginform')
form.action = "https://login.starhubgee.com.sg/eam/login"
form['cb'] = 'http://groupsms.starhubgee.com.sg/cgi-bin/s.pl'
form['vcid'] = 'groupsms'
form['pudn'] = 'starhubgee'
form['domain'] = 'starhubgee'
form['fake_uid'] = '12345678'
form['uid'] = '12345678@starhubgee'
form['password'] = 'password'
page = mech.submit(form)
page = mech.get("http://groupsms.starhubgee.com.sg/cgi-bin/s.pl")
form = page.form('compose')
form['to']='comma separated recipients numbers'
form['message']= "Your message...."
page = mech.submit(form)This would take care of sending with much lower cost as it utilizes bundled SMSes in the package (400 - 1000 messages) with nothing else required. The problem, however, was still receiving. A little glimpse of hope was SMS+ introduced by SingTel last year, which allows you to auto forward your received messages to email address. This would have been ideal - if not for a small glitch - it only works with messages sent from SingTel numbers. OH MY GOOOOOD!!!!!!!! I almost cried when I found out that.
Lately I found a nice and simple Singaporean provider www.gsmexchange.com able to handle 2 way communication. Nothing to say about sending - just send a http request with username, password, phone numbers and message and you will receive message ID that you can use for tracking. Replies are slightly more complicated as I didn't find any API for reading replies - nevertheless - there is a list page that you can parse with mechanize to get the responses. There is an option to forward messages to email but for 5c per message it's a bit too expensive. Actually, also pricing for sending of the messages is on the higher end 10c per message which makes it much less attractive for our customers.
Luckily I managed to find a much cheaper solution - running my own SMS server :-) See the next post...