A letter to ATI/AMD

October 11th, 2008

Dear Ati and Ati’s daddy AMD,

A week ago, i needed to replace my graphics card and so after being an Nvidia customer for several years, i decided to go with an Ati card this time to support the company for choosing to open source their graphic drivers. I am a GNU/Linux user, and although Nvidia has worked great on this platform in the past, it has not kept up with the times and still chooses to withhold specs from the free software community trying to help them implement open source drivers for their cards.

Now, i realize that the open source driver for your cards is still not ready, and that’s ok. Just making the jump is a great effort on your part. However, your 



proprietary
driver sucks. And hence, under Linux, your cards suck too.

You want some details? Here goes.

- The “Catalyst Control Center” is a joke. I mean i used to write interfaces like that too…when i first started programming… Ok, so maybe aesthetics in interfaces is not your thing(although you do manufacture graphics cards!), even in terms of functionality it hardly works. Trying to change any configuration using the control center produces an xorg file that messes everything up. I had to manually re-write it myself. Either implement a proper “control center”, or ask the community for help.

- Switching between virtual terminals produces transient weird graphic artifacts using driver 8.53.4. Using an earlier driver, X just locks up.

- Hibernating or suspending the computer causes X to also lockup. This seems to still be a problem even in the latest driver(8.53.4).

- Performance wise, the driver is terrible. I mean absolutely horrible. World of Warcraft runs with 10-15 fps on this thing. Definitely not what i would expect from a midrange sub-$200 card(i actually paid $160). Luckily, i still dual boot for when a windows VM does not do the job and under windows xp sp2, the performance is pretty good. So please, please fix your driver. I do not wish to change platforms just to get your stuff to work.

- The Ati bugzilla appears to be abandoned with tens(hundreds?) of unanswered bug reports. That is simply not acceptable, even if it is an unofficial bug database. You either want the community to help you, or you don’t. This just looks like you’re taking advantage of us.

- Oh, and this one is for Sahpire. Have you ever actually used one of
your products? It sounds like you’re sitting next to a blender…

I have a lot more, but i think you got my point. I want to support you, i want to give you my hard earned dollars. But you’re making it very difficult. So please start acting like a good citizen or ask for help. Spend more time on your products, and less time on pretty PowerPoint presentations. Those do not impress us.

Firemote project is finally public

September 10th, 2008

A couple of months ago, we started working on a project, code named firemote, to help in the detection and prevention of forest fires in Lebanon. I didn’t say anything about it because i was waiting for it to be announced, and the announcement was finally done a few days ago. The press coverage(in english) is at The Daily Star - Politics - AUB team invents new tool to help battle forest fires

Sadly, the coverage doesn’t really do justice to the project and its potential impact on the devastating forest fires that eat up a substantial amount of forests each year. But i think this will be addressed when the pilot is under way and we have some results to show.

The project was a collaboration between the American University of Beirut (AUB) and the Association for Forests, Development&Conversation(AFDC). I was one of the researchers at AUB.

On Producitivity and running your own business

September 8th, 2008

It just occurred to me today. Running your own business, you try to optimize the hell out of everything to make as much use of your time as possible. Employees on the other hand, wish to be as unproductive as possible.

But i have to say, I still don’t understand how people think. Its one thing to have a lazy day, but to turn laziness into a habit is just plain wrong. Recently, I’ve been observing this behavior and wondering why do the employees act as if they don’t care anymore. And it just dawned on me. Its very simple; They never did care.

When your compensation is relative to how much time you spend sitting in a chair looking busy instead of how much units of “output” you generate, for whatever output means in your situation, then its obvious that the loophole is to just stretch everything out. The task that is supposed to take 5 mins now takes 15. The task that should take a week now takes a minimum of 3. Why? “Oh, because its how we do things around here.”

Instead of trying to analyze the hell out of the situation, I’ll instead ask a few questions. What ever happened to people doing their jobs to make a difference? What ever happened to taking pride in your work? When did it become alright for people to stop caring? When did it become unusual if you wanted to make a difference in this world?

I used to have a low tolerate rate towards lazy people. Now i have none.

Let me share a little story with you. Once i was in the hospital for some medical exam. And i needed to have it approved for coverage by the insurance company. No biggie, they have an office there for such cases. So in i went with my usually nice attitude and a hearty “Good Morning”. Only to find the insurance guy angry and yelling at everybody. So i asked him why he was angry. He said that he has been working since 8am. Hospital shifts start at 8 and end at 5, so i really couldn’t quite reply with anything except “So am I”. I couldn’t really tell him that it was his job to work from 8 till 5. I couldn’t tell him that since he works directly with people, he should at least remain civil if not nice. I couldn’t tell him that i work for 16 hours a day. I also couldn’t tell him that if he minds working from 8 till 5, to quit and let any of the thousands of other qualified but unemployed graduates take his place. I usually don’t hold back, but he had “the power to push a button”. And i needed that button pushed.

Don’t understand what this blog post is about? Don’t worry, I’ll explain more later.

On being funny

August 28th, 2008

I just heard about a project that uses WhatsUp, which is sort of an uptime server or network monitoring service. I couldn’t help but imagine how the SMS alerts would go.
“You wanna know what’s up? Not your server that’s what’s up.”

Weak, i know…Some more meaty posts on the way.

On NDAs and My NDA Policy

July 6th, 2008

My NDA Policy ~ I have decided to starting signing them! : Texas Startup Blog discusses Non-Disclosure Agreements and how the author has decided to react to it.

I think it is brilliant.

Also of interest are the other linked articles such as To NDA or Not to NDA? That is the question.

My stance on NDAs is that i only sign specific ones that actually relate to confidential information. And i only do that to make newer clients feel more at ease. Frankly, i have turned down some projects before because of this.

Honestly, if the strength of your business idea relies on the assumption that people won’t find out about it. Then I don’t think you have much of an idea. Certainly not one to base a business on.

I often brought in Gary Hoover, founder of Hoovers, BookStop, and TravelFest as well as author of Hoover’s Vision as a guest speaker. He says he talks to so many businesses and students that when someone asks him to sign an NDA he proceeds to ask them ‘Why?’ and immediately wonders about the viaObility of the concept.

This quote from the linked article shows that i am not the only one who thinks this way. And this quote comes from a serial entrepreneur!

One designer i was working with, after telling him that the project is funded by an angel investor, expressed interest in meeting the investor to tell him about all his “great ideas.” He pitched his greatest idea to me, and it was neither original nor did it have any revenue model(or even a future one). I do agree with the “1% inspiration and 99% perspiration” saying, and it is often the case that people who choose not to do the 99% part are the ones with the most “great ideas.”

Now, i didn’t even talk about the legal aspects of an NDA. But even with those issues aside, NDAs are no protection whatsoever. They are just plain stupid(using Linus’s term). I won’t go as far as saying “ideas are worthless,” but i will say that an idea without a proper implementation plan is.

Recently, a new client decided against using an NDA after i expressed that i am uncomfortable with generic NDAs. Certainly, a smart decision. I am very fortunate to have such clients.

Bomb Maker Gnome Applet Released

June 20th, 2008

I finally got around to releasing the BombMaker Gnome applet that i blogged about. I’ll share with you a little secret, I’ve actually been using it for the past 6 months or so. I even learned to package debian packages just so that i can release it.(manually installing gnome applets is a bit too much)

There were a couple of snags along the way, mainly in the packaging part and specifically in using autotools for that. I didn’t use autotools because i think they’re way too complex for something that should be relatively simple. Sadly, the complexity is necessary for autotools because it has to work on some many systems. Whether that complexity is still needed today, especially that the whole world has converged on a few key systems, is a question that is asked often.

So, I’ll blog about it sometime. But for now, you can visit the project page on the main site here. And as always, if anybody would like to work with me on this project, I’m just an email away.

Quietly working on my Bomb Maker

June 20th, 2008

Strange title, isn’t? I don’t actually make bombs :) although during the last war, a lot of people probably thought i did.

In my KDE days, i used to make a lot of use of an applet called KTeaTime(http://docs.kde.org/stable/en/kdetoys/kteatime/introduction.html#whats-kteatime). Its a nice little applet that tells you when your tea is ready after you select what type of tea you want. So if you select extra black tea for example, it will remind you that your tea is done after 10 mins for example. I used this when i wanted to make some hot drink for my coding sessions. So i would setup the drink and i will let it cool and use that to remind me when it would be done. Or when i would run a long compilation process that takes several minutes to finish, i just put it on another workspace and set this to remind me after a few minutes.

Bomb Maker is a gnome applet that tries to clone this with a twist. It is a reminder applet in which you choose a certain bomb type and it goes off after its time period elapses. You can also choose to manufacture a custom bomb type which has a custom time period till explosion and includes a custom message. Did you ever tell yourself that you will attend to a certain task in 10 mins and then forgot? Well, try this….

ScreenShot of Bomb Maker Gnome Applet

Some features include:
-Multiple notifications
-Multiple Time Periods
-Custom Message for Custom Bomb Type
-Custom Time for Custom Bomb Type
-Unlimited persistence of notifications until you dismiss them

The code is not yet ready for release, this is just to wet your appetite. As you can see from the screenshot, some paths still reference my machine and so it is not yet ready for distribution. But i will soon release it for debian based systems as a deb package.

Update: I released the applet, and you can get it here.

Working with Hadoop: My first MapReduce App

May 7th, 2008

Most Hadoop tutorials use the wordcount application as a demo application. And while this might be a good demo application, it is not particularly helpful. So i wanted to think of an idea for a more useful application to use on a cluster.

My first thought was trying to implement the famous Sieve of Eratosthenes. But it turned out that this might not be a good first application because i think there needs to be a shared state between map tasks. So its better left for another time.

So instead, i opted for the methods mentioned in Primality Test. And went with the first naive approach as an example. So i tested numbers by checking if any number perceeding them divides them.(again,no optimization)

This might seem like a simple application to do, since you can basically change a couple of things in the wordcount demo application. But you see, the first thing that i noticed while reading up on Hadoop is that most apps focus on the same file-based approaches. Which makes sense when you consider the project’s roots in indexing. And that is a limitation if you consider the possible projects that can and do make use of distributed computing such as medical research, cryptography work, and so on…

Well, while Hadoop does have built-in classes to deal easily with file based input, you can easily make it deal with any other kind of input you want. So while most apps don’t actually go deep enough to tell you how to do this, I will. Although i am still scratching the surface, i hope this would be useful to somebody out there.

So, if you just finished reading about the wordcount application, you’d think that you can the prime test by writing all the numbers that you want to check into a file and then just use that file as input to your MapReduce app. While this would work, why do the extra step of writing all the numbers to a file and then reading from that file again. We’re already have to generate the numbers, so just hand out those numbers to the Map tasks.

From this point on, I assume that you’ve already read the tutorial that comes with Hadoop, so I won’t go into details on anything basic.

In a nutshell, to make the mapping tasks acccept generated input, you have to define a new type of input format. You do that by develping a class that implements InputFormat. With that, you also have to implement a RecordReader and an InputSplit.

In the end, you will have the following files:

  • PrimeTest.java: Contains the MapReduce procedures.
  • PrimeTestInputFormat.java: Defines the input format and provides the input splits for the map tasks and also defines the record reader.
  • PrimeInputSplit.java: Defines a split in the input data for each map task.
  • PrimeRecordReader.java: Responsible for returning <Key, Value> records from bye-based input splits.

This application will use a record <K,V> of <long, long> type with both the key and value being the prime number to test. And the intermediate record <K’, V’> from the map tasks will be of types <boolean, <Long….>> with the key being a true/false primality result. The result record <K”, V”> from the reduce tasks will be of type <boolean, Long> and is again the number keyed by primality result. Not really the best of use for records, but for out specific example, that’s all we need.

Starting with the main file, In PrimeTest.java, we define the map/reduce procedures.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import java.io.IOException;
import java.util.*;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class PrimeTest
{
    private static final Log LOG = LogFactory.getLog("PrimeTest");

    public static class Map extends MapReduceBase implements Mapper<LongWritable, LongWritable, BooleanWritable, LongWritable>
    {
        private final static BooleanWritable truePrime = new BooleanWritable(true);
        private final static BooleanWritable falsePrime = new BooleanWritable(false);

        public void map(LongWritable key, LongWritable value, OutputCollector<BooleanWritable, LongWritable> output, Reporter reporter) throws IOException
        {
            long suspectPrimeValue = value.get();
            boolean isComposite = false;

            for(long i = 2; i < suspectPrimeValue - 1 ; i++)
            {
                if(suspectPrimeValue % i == 0)
                {
                    output.collect(falsePrime, value);
                    isComposite = true;
                    break;
                }
            }

            if(!isComposite)
            {
                output.collect(truePrime, value);
            }
            System.out.println(suspectPrimeValue);
        }
    }

    public static class Reduce extends MapReduceBase implements Reducer<BooleanWritable, LongWritable, BooleanWritable, LongWritable>
    {
        public void reduce(BooleanWritable key, Iterator<LongWritable> values, OutputCollector<BooleanWritable, LongWritable> output, Reporter reporter) throws IOException
        {
            while(values.hasNext())
            {
                LongWritable vCheck = values.next();
                output.collect(key, vCheck);
            }

        }

    }

    public static void main(String[] args) throws Exception
    {
        JobConf conf = new JobConf(PrimeTest.class);
        conf.setJobName("primetest");

        conf.setOutputKeyClass(BooleanWritable.class);
        conf.setOutputValueClass(LongWritable.class);

        conf.setMapperClass(Map.class);
        conf.setCombinerClass(Reduce.class);
        conf.setReducerClass(Reduce.class);

        conf.setInputFormat(PrimeTestInputFormat.class);
        conf.setOutputFormat(TextOutputFormat.class);

        conf.setOutputPath(new Path(args[0]));

        JobClient.runJob(conf);
    }
}

The map procedure is a direct implementation of the prime test algorithm. And so is quite straightforward. So is our reduce procedure; just placing the values in the output collector.

You’ll notice that we define our own input format and that we do not need to define an input path since our input is generated.

Now we need to implement the input format class. And it would look like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.util.ArrayList;

import org.apache.hadoop.mapred.InputFormat;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.mapred.InputSplit;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.RecordReader;

public class PrimeTestInputFormat implements InputFormat<LongWritable, LongWritable>
{
    public RecordReader<LongWritable, LongWritable> getRecordReader(InputSplit split, JobConf job, Reporter reporter)
    {
        return new PrimeRecordReader((PrimeInputSplit)split);
    }

    public InputSplit[] getSplits(JobConf job, int numSplits)
    {
        long startingNumber = 2; //from 
        long endingNumber = 265; // to, exclusive

        long numbersInSplit = (long)Math.floor((endingNumber - startingNumber)/numSplits);
        long startingNumberInSplit = startingNumber;
        long endingNumberInSplit = startingNumberInSplit + numbersInSplit;
        long remainderInLastSplit = (endingNumber - startingNumber) - numSplits*numbersInSplit;

        ArrayList<PrimeInputSplit> splits = new ArrayList<PrimeInputSplit>(numSplits);

        for(int i = 0; i < numSplits - 1; i++)
        {
            splits.add(new PrimeInputSplit(startingNumberInSplit, endingNumberInSplit));
            startingNumberInSplit = endingNumberInSplit;
            endingNumberInSplit = startingNumberInSplit + numbersInSplit;
        }

        //add last split, with remainder if any
        splits.add(new PrimeInputSplit(startingNumberInSplit, endingNumberInSplit + remainderInLastSplit));

        return splits.toArray(new PrimeInputSplit[splits.size()]);
    }

    public void validateInput(JobConf conf)
    {
        //valid input since we are generating it
    }

}

The only interesting part in this class is the getSplits() method which splits the input data to feed the map tasks. One thing to note here is that the “from “and “to” numbers are hardcoded while it would have been better to place them as properties and retrieve them via the JobConf. Also, the input generation is a naive one and has many assumptions.

Looking at the PrimeTestInputFormat class, you’ll also notice that we’re referncing a PrimeInputSplit class and a PrimeRecordReader. So we also need to implement those.

As mentioned earlier, the PrimeInputSplit class represents a byte view to a particular data split. In our case, this class will hold the starting and ending numbers for each split. So it could like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.io.IOException;
import java.io.DataInput;
import java.io.DataOutput;

import org.apache.hadoop.mapred.InputSplit;

public class PrimeInputSplit implements InputSplit
{
    private long m_StartNum;
    private long m_EndNum;

    PrimeInputSplit(){}

    public PrimeInputSplit(long p_Start, long p_End)
    {
        this.m_StartNum = p_Start;
        this.m_EndNum = p_End;
    }

    public long getLength()
    {
        return (this.m_EndNum - this.m_StartNum) * 8;
    }

    public String[] getLocations() throws IOException
    {
        return new String[]{};
    }

    public void readFields(DataInput in) throws IOException
    {
        this.m_StartNum = in.readLong();
        this.m_EndNum = in.readLong();
    }

    public void write(DataOutput out) throws IOException
    {
        out.writeLong(this.m_StartNum);
        out.writeLong(this.m_EndNum);
    }

    public long getStartNum()
    {
        return this.m_StartNum;
    }

    public long getEndNum()
    {
        return this.m_EndNum;
    }

}

Next, we implement the record reader which translates the byte view input split into a record for the map task.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapred.RecordReader;

public class PrimeRecordReader implements RecordReader<LongWritable, LongWritable>
{
    private long m_End;
    private long m_Index;
    private long m_Start;

    public PrimeRecordReader(PrimeInputSplit split)
    {
        this.m_End = split.getEndNum();
        this.m_Index = split.getStartNum(); //index at starting number of split
        this.m_Start = split.getStartNum();
    }

    public LongWritable createKey()
    {
        return new LongWritable();
    }

    public LongWritable createValue()
    {
        return new LongWritable();
    }

    public void close(){}

    public float getProgress()
    {
        if(this.m_Index  == this.m_End)
        {
            return 0.0f;
        }
        else
        {
            return Math.min(1.0f, (this.m_Index - this.m_Start) / (float)(this.m_End - this.m_Start));
        }
    }

    public long getPos()
    {
        return this.m_End - this.m_Index;
    }

    public boolean next(LongWritable key, LongWritable value)
    {
        if(this.m_Index < this.m_End)
        {
            key.set(this.m_Index);
            value.set(this.m_Index);
            this.m_Index++;

            return true;
        }
        else
        {
            return false;
        }
    }
}

And that’s about it. Just jar up the application and deploy it on Hadoop.

There are a couple of interesting things to try here. First up would be to implement some optimizations to the prime testing function. Another thing would be to implement a better way to generate input splits to accommodate sparse data for example. Another interesting thing that I’d like to try sometime is do a multi-threaded application with the same functionality and then compare its performance to a small non-uniform cluster. Ofcourse the overhead of Hadoop on a single node cluster would mean that the local app would be faster so i am interested in observing how much this overhead affects performance so spreading it out over a couple of machines should balance things out. At least in theory…so we’ll see.

The source files are available here.(you can also directly deploy this jar)

Comments, feedback are welcome.

Working with Hadoop

May 6th, 2008

My last twitter was “Its after midnight and i just finished my first MapReduce application. Next up, blogging about it.”

Well now its time to blog about it. And share some code…won’t that be fun?

So I’ve always wanted to do some distributed programming or parallel programming(technically not the same, but aim at solving similar problems), but the barrier of entry was always too high and the learning curve a bit steep. At least for a hobby. I remember getting a demo account on my university’s cluster when i was still a student after attending a workshop but i never had the time to try it out and it silently expired.

Well, I’ve been reading about hadoop for quite some time and i finally decided to dedicate some time to learn how to use it. I was pleasantly surprised. I gotta say, that’s one well written application. Doug Cutting is one exceptional programmer; Not that he’s waiting for my recognition. The project wouldn’t be where it is without the Hadoop community, so kudos to all.

The whole experience only took a couple of hours. That included reading the documentation, setting up hadoop as a single node cluster and writing my first application.

Hadoop can certainly make use of some more tutorials. The documentation is very good, but at first view might look a little overwhelming. Let’s hope that more people will use it and share their experience.

Next up, my first app, the problems i faced and my comments.

On getting Ruby-fied and its aftereffects

April 8th, 2008

As a follow-up on I am getting Ruby-fied, Ruby’s not ready - glyphobet • ???????? • ???????? does a much better job at going over Ruby’s faults. Ruby on Rails is not discussed except to say that it and Pylons are very similar, but i tend to agree that a lot of the different web frameworks out there are quite similar because they all include what is needed of a modern framework.

The author has had more experience in Ruby(and Ruby on Rails) than i did obviously, so i won’t try to go into the things he did. I also can’t validate all his concerns, but i can validate most and agree with most. So i can’t go as deep as he could in the discussion because as expected, the RoR project has been stalled for the past month or so. But let me review my previous assumptions and determine what was and wasn’t true. Note that i will refrain from commenting on the things that i can not yet validate to keep things objective.

Ruby seems like en easy to learn language. A lot of the language syntax and Ruby-way-doing-things(yes, that’s one word) is meant as a productivity boost.

That is definitely true. But the many quirks in there make it really difficult to learn the language in any deep manner. I mean to_s ? Come on. Really? to_str i might understand(which does another thing all together) but to_s? And that’s just saying one thing that i find highly annoying, take a look at the linked article and be amazed.

Ruby is not a new language, it is as old as Python and Java.

Definitely true. Although, Python and Java being old has worked to their advantage. Both languages have evolved in a generally useful direction. Ruby on the other hand seems to be this toy language that suddenly got immensly popular and is now struggling to become a modern language.

Python and Ruby have similar principles. The most interesting perhaps is that code should be easy to read and some would say beautiful to look at.(should be true of any language, but depends on the programmer i guess)

Hmmmm…. I am not sure about this one. Ruby is very lax in its syntax and that makes it terrible to read and definitly not beautiful. In fact, this whole flexibility has turned me off the language completely.

It was meant to solve a general problem and is not meant as an end-all-be-all type of solution.

That’s true. If you turn off the noise generated by the fan boys then you would find some wise people telling you not to use Ruby for things it wasn’t designed for.

I come from a c background so i had trouble getting used to languages that don’t follow the C syntax(and its older parents). Earlier on in my career, i decided that i shouldn’t let something like different syntax stop me from learning what might be a truly great technology. I followed this approach with Python and was quite successful and will do the same with Ruby.

I did follow that approach on leanring Ruby and well, i think that with proper coding standards, Ruby code can be quite elegant. My only problem is fan boys turning turning Ruby into php.

I think that a lot of the features in Ruby 1.9 should really have been in earlier versions. I don’t know why is that the case though, maybe there’s a good reason.

Also true. In fact, my suspicions were quite correct here in that the language doesn’t have a very clear path. But again, this seems to be a subjective issue.

I don’t appreciate the Ruby community believing that the Ruby language is the best thing since sliced bread. It is possible that it is an excellent language but definitely not the answer to everything. Passion is always good, but zealotry is not. I believe that good programmers should choose the best tool for the job. I wouldn’t advocate Python for every kind of problem out there.

Well, there’s nothing i can do about that expcept advise my clients(and anybody else who asks) about the proper technology.

A lot of people also complain about some of the conventions used in RoR and how dreadful they are. That is somewhat scary, but then again, all frameworks have some of those. It would be possible to create a framework that doesn’t, but then it would be too complex to learn. A compromise is always needed. I don’t yet know enough to comment on this, I’ll report back.

Well, this wasn’t very accurate. I wasn’t intimidated by the convention in RoR, and actually think they’re quite reasonable. The conventions and quirks in Ruby however were a PITA. In an RoR project however, you would be more worried about developing within RoR rather than worrying about Ruby’s idiosyncricities.

People always rave on about the great toolset that RoR has. In particular, capistrano and rake. I think those are definitely good tools but there are several different alternatives for different techs as well.

I haven’t worked with capistrano yet, but Rake is cool. I like the way migrations work with some minor comments(should be fixed in RoR 2.1 i think) and i also like the way unit and integration tests are considered to be part of the project development as opposed to “extra development”. I hate the way JS using prototype is dealt with in RoR and prefer Django’s “use whatever you like” atitude and for good reason. Scaffolding is nice at first look, but nobody actually sticks with it except for very small applications. The book i was reading didn’t describe static scaffolding, that seems to be a nice approach to it. And so on….

I went with Django earlier last year because of the excellent way the framework developed. It has very good documentation and a healthy development environment. At the time, i couldn’t see that in RoR.

Things have definitely changed with RoR. I still prefer Django immensly because of the general atitude of its developers, but…..

RoR and consequently Ruby got its fame largely from the efforts of one company. 37Signals may be great, but i wouldn’t trust the development of a general purpose framework to one small company.

True at first, but RoR is its own beast now. There are still some existing problems, but then again, there always is.

Django seems like field-produced framework. Initially, it constituted the guts of a CMS and was later extracted and made in a general framework. I find that it particularly adept at solving problems that you would encounter when writing a data driven web application which a CMS is an extreme example of.

This is definitly also true of RoR. So the comment is valid, but it doesn’t apply correclty to RoR. RoR was extracted from a 37Signals application(backpack was it?) and so is also a field-produced framework.

So in summary, i still wouldn’t use either Ruby or RoR if i had the choice. But depending on its couterpart in comparsion, they might just win.