Archive for the ‘Software’ Category

Mythical Great Developer

Monday, May 26th, 2008

Nowadays a lot of guys are curious how to find “Great Developer” but, do not specify what do they mean by this words. How can we find something if we do not know what we are looking for? Let us at first find out is this instance exists. Probably, you are looking for a guy, who is:

  1. Knows everything on technologies she/he supposed to work with during her/his job at your company;
  2. Can create perfect easy-to-understand, scalable, maintainable architecture/code;
  3. Team player;
  4. Has nice leadership skills.

If you do, I can surely tell you that you are on the wrong way. Let me explain why.

  1. Usually, a regular human can not know every detail of every technology. Good professionals know key points and some details, not all. It means that it could make no sense to ask person for a particular details of that particular technology. Professionals usually know how to find this detail quickly, not all the details.
  2. I pointed my attention that roughly speaking all people could be divided into 3 categories:
    1. people with good memory but bad analytical skills and
    2. people who have good analytical skills and not very good memory
    3. people who have perfect analytical skills, perfect memory but do not care of your business, since whey could be perfect chess players and think about chess all the day instead of working on you
  3. On 2 I would say that usually code either easy to understand or scalable/maintainable, not both. So there are people, who writes first or second types of code.
  4. Next bad news is that usually person either hacker or team player. I knew 1 hacker on 1 project was so negative that it would be better that this guy just never participated at the project at all;
  5. And at the end leader persons are rarely good developers themselves;
  6. And now imagine of 2 hackers on the team hating each other!

We usually do not think about it when building our perfect team, yeah?

And there is even a theory called socionics that explains all types of characters and intertype relations.

Roughly speaking it tells us the next:

  • Person is either thinker of feeler, meaning either good abstract thinker or good team player;
  • Person is either sensing or intuitive type, meaning either stable worker and leader or gifted hacker, who can learn in seconds and do job better an faster than others;
  • Person either perceiving or judging meaning either strategist or tactician.

More of that, even hacker performs better if works with “bad worker” of appropriate type. And the whole team performs better if all members has non conflicting intertype relations. It is what Tom DeMarco and Timothy Lister were talking about in their peopleware than they told us about “unproductive” people on successful teams and on successful teams participating in selection of their colleagues. Does your team do it?

Even more, the Joel’s method of finding “Great Developers” on conferences could fail for Introverts, which would prefer writing code and learning new technology to participating on some conference.

But everything is not so bad. Some people advance their skills in areas they are not best in. So there is a chance you can find appropriate person or Guru. Don’t forget to ask person what area she or he is the best, what is easy and what she/he is working on.

Good luck in building your team!

Problems with outsourcing in software development

Sunday, May 25th, 2008

I actually was on the both sides. So I know how it looks like from inside and outside. I’m going to describe several problems, which you can, probably, face to, starting to work with some software development outsourcing.

1. Guys there think another way. They, probably, did not read peopleware and other books, you’ve read. They could be surprised by schedule you provide them or have in mind, but they could say nothing. Some that guys think that as they are pay hourly, it is not their problems to correct your schedule. You are lucky if have experienced team lead/PM on site to let you know about project risks. The usual rule applies: more expensive teams/companies/developers could cost you less overall.
Actually the main problem here is integration. Let me tell you about 2 projects I worked for. One from outsourcing side, and another from US side. On both projects US side wrote business logic and remote team wrote UI. If you do things this way you can be already in trouble of bad integration.

2. Remote guys sleep when on site team works and vice versa. If you are lucky, you can, probably, have an hour or two of overlapping time. It means that if one of the teams have a bug it will be fixed next day only, causing huge problems to another team. In worse case they could loose whole day.

3. If teams do not have common source repository it is another big issue. If some team do some refactoring it affects another team - other team’s code become uncompilable. Even bigger evil here is integration. On the second project I participated that way we had 2 guys on US side constantly working on integration tasks only, stating from second week of development, when we tried to integrate our code (!). On the similar project before we had only 3 guys on site doing UI, before the same task was transferred to outsourcing team. Can you imagine that? 3 guys did job here and after switching to outsourcing it were 2 guys doing integration tasks! On the first project bugs in business logic prevented UI developers from testing their code.

Okay, it is not always so bad, and sure, it make sense to have outsourcing in many cases.

Here is what you can do to have successful outsourcing:

1. If it is possible, let outsourcing do all parts of the job. That will save you from integration evil. Remember, that if you can’t let outsourcing do all parts of the task, integration is your biggest risk here;

2. Even if you were lucky with 1., make all your teams to write unit tests and run continuous integration everyday or even more often in all teams. It will at least help your teams to prevent most of integration issues, and help them to find their bugs earlier;

3. If it is possible, all teams should store their code in the same source control system. This will help teams to do successful refactoring, even changing other team’s code. To let it work better all teams should try to commit code before end of day, to let remote team successfully refactor. If it is not possible, new code from remote team should be committed to local repository daily;

4. Make business logic team to write all interfaces and mockups before writing actual code. The actual code could take much time, since interfaces and mockups are easy. It will also help your teams to write unit tests and to set up continuous integration tasks early.

Hope it will help you to choose right way and good luck with outsourcing if you are going to use it!

Bushido of Software Development

Sunday, April 27th, 2008

12 Must Have in Software Development 

Just a minimal simple set or rules and approaches, which, I believe, help projects to succeed. Most of software developers will say that it is something like ”must have” on your project and, of course, it is not complete set. Since each complete set is a process and you can always chose the most suitable process for you.

  1. Unit and integration testing full or most code coverage (of course, you don’t have to test your DTOs or VOs if they don’t have any business logic inside);
  2. Continuous integration. Running integration testing at least daily;
  3. All developers (of all sub-teams) on the project can communicate with each other directly (not only though representative person);
  4. Adequate number of developers on the project (not too small and not too much);
  5. Adequate volume of design documentation (again not too small and not too much);
  6. Design documentation must be readable, illustrative, brief, well-structured and clear; 
  7. Developers must have adequate hardware and software to develop software;
  8. Team must have at least one development server to have development version of software, DB, continuous integration there;
  9. Team must have mock-ups (separate DB) for continuous integration;
  10. Team must use source-control system, all sub-teams of the team must integrate with code in the source control at least daily;
  11. Team must have development infrastructure. Such as wiki, project management and bug-tracking software, etc.;
  12. Automate everything you can.

Unit and integration testing full or most code coverage

It will let developers be sure that their code is functioning OK. More of that, it let them to to check if some part is OK without re-testing whole application.

Continuous integration

Imagine, some developer changed behavior of her/his module and updated his unit tests. Her/his unit tests works fine, but some other, dependent part could be broken.
Continuous integration allows developers to know if there are hidden problems in their application.

All developers on the project can communicate with each other directly

Don’t let absence of communication to become bottleneck of your process. If one developer has question and/or misunderstanding regarding some part of other developer’s work, communicating though contact person could delay delivery date of your project. Or even worse: communication person could transfer information incorrectly.

Adequate number of developers on the project

No need to tell you what happens if there not enough developers on the project. The surprising problem could happen if you took too many developers:
they will face all integration issues. Sometimes small teams could perform better than big ones. The one more issue about big teams is non-uniformity of the application
design. Not all developers have the same level and not all people have the same approaches.

Adequate volume of design documentation

It is simple. Nobody will read bad-structured huge design documents. On the other hands something should stay in-written to reflect common parts, possible misunderstandings,
etc.

Design documentation must be readable, illustrative, brief, well-structured and clear

If it not readable obviously nobody will read it. Non-illustrative documentation hard to process and developers could miss something. Why should it be brief is discussed in
previous section. In badly structured document hard to find information you need, so such documents become useless.

Developers must have adequate hardware and software to develop software

Just not fast enough hardware will simply delay your project. Do you need it? Usually the biggest expense is developers themselves. So it is very improvidently to spend
their time for waiting while program is compiled. The same idea is about software. Just let your developers work more effectively.

Team must have at least one development server to have development version of software, DB, continuous integration there

By word “server” you can understand some computer. They are not so expensive nowadays.

Team must have mock-ups (separate DB) for continuous integration

Don’t let changes in your development DB break your unit-testing. It is not such a big deal to maintain 1 more DB for testing.
Just let your developers play in development DB (or DB on their PCs) and put only what you need for testing to test DB.
Your continuous integration will hardly work well without it.

Team must use source-control system, all sub-teams of the team must integrate with code in the source control at least daily

I can’t imagine a project without source control. I’m sure everyone does the same. The issue can be, for example, if you have one team in
closed proprietary network (say, writing business logic) and one outside (say for presentation layer development). Sometimes both teams
can’t use the same source-control for various reasons, but at least in one of teams should integrate with others frequently (they can put
other team’s code in their source control. Even this process can usually be automated.).

Team must have development infrastructure. Such as wiki, project management and bug-tracking software, etc.

Don’t make your developers search their emails for some important information. Just set up wiki. Your developers are still write
their tasks on pieces of paper? How do you plan to manage it? Use software to develop software.

Automate everything you can

Compilation, deployment, integration with other source controls, sometimes even code-generation, etc. Usually you already have to do much for continuous integration. You can even chose dedicated person for this task if your team is big enough. Save costy time of your developers.

Misunderstanding of Agile development

Saturday, April 26th, 2008

Agile development is NOT:

  1. A mess-style development;
  2. Agile does not mean that you can write programs without any design documentation;
  3. When your developers have no access to business and business do not take part in the communication with the development team;
  4. Separating development sub-teams;
  5. Absence of continuous integration;
  6. Absence of unit-testing at all or even just some unit-testing instead of full coverage;

Unfortunately, sometimes you have to be negative to distinguish misinterpretations.

Break and continue statements will stop exception flow

Monday, March 24th, 2008

As it is said in The Java Language Specification (http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.15):
The preceding descriptions say “attempts to transfer control” rather than just “transfers control” because if there are any try statements within the break target whose try blocks contain the break statement, then any finally clauses of those try statements are executed, in order, innermost to outermost, before control is transferred to the break target. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a break statement.
Let’s look into next example:

public class Test {
	private static void test() throws Exception {
		for (int i = 0; i < 3; i++) {
			try {
				throw new Exception("Exception text");
			} finally {
				System.out.println("Finally exception " + i);
				continue;
			}
		}
		System.out.println("Impossible");
	}  

	public static void main(String[] args) throws Exception {
		test();
		System.out.println("Impossible 2");
	}
}

will produce output:

Finally exception 0
Finally exception 1
Finally exception 2
Impossible
Impossible 2

So, be extremely careful with your breaks!

How to access overridden methods of superclass of a superclass in Java?

Monday, March 24th, 2008

Let us consider an example:

public class Test2 {
  static class TestClass1 {
      int x = 1;
      String test() {
          return "1";
      }
  }    

  static class TestClass2 extends TestClass1 {
      int x = 2;
      String test() {
          return "2";
      }
  }    

  static class TestClass3 extends TestClass2 {
      int x = 3;
      int testX() {
          return ((TestClass1)this).x;
      }
      String test() {
          return super.test();
      }
  }    

  public static void main(String[] args) {
      TestClass3 obj = new TestClass3();
      System.out.println(obj.testX());
      System.out.println(obj.test());
  }
}

It produces expected output

1
2

The point is that there is no way to call test() method of the TestClass1 class!

super.super.test()

won’t compile but

((TestClass1)this).test()

will produce java.lang.StackOverflowError.

Despite that we can access superclass members of any level by casting this to appropriate class (see The Java Language Specification at http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.11.2), polymorphism allows us to access immediate superclass only, not overridden methods of higher levels (see The Java Language Specification at http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.9).

Some approach for writing equials() and hashCode()

Monday, March 24th, 2008

The problem described in details in http://www.hibernate.org/109.html
The problem is that if we implement equals()/hashCode() as comparison and hashCode() of entity’s ids (see http://djeang.blogspot.com/2005/08/override-equals-and-hashcode-methods.html) then the hashCode() (and, possibly, equals()) will change after saving entities if ids are generated by DB.
To solve this issue I can suggest to use inner classes with equals()/hashCode(). It will not affect Hibernate’s internal collections taskflow, but will allow you to use ids in equals()/hashCode() after entities are persisted. On other hand hashCode() and equals() will not change in your persistent objects after you have saved it.

public class Test3 {
   static class SomeEntity {
       private Integer id;   

       private String data;   

       public SomeEntity() {
           super();
       }   

       public SomeEntity(Integer id, String data) {
           super();
           this.id = id;
           this.data = data;
       }   

       public Integer getId() {
           return id;
       }   

       public void setId(Integer id) {
           this.id = id;
       }   

       public String getData() {
           return data;
       }   

       public void setData(String data) {
           this.data = data;
       }   

       public class SomeEntityId {
           private SomeEntity link = null;   

           public SomeEntityId(SomeEntity link) {
               super();
               this.link = link;
           }   

           @Override
           public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if ((obj == null) || (obj.getClass() != this.getClass()))
   return false;
  if (this.link.getClass() != ((SomeEntityId) obj).getLink().getClass())
   return false;   

               Integer thisId = link.getId();
               Integer otherId = ((SomeEntityId) obj).getLink().getId();
               if ((thisId == null) || (otherId == null))
                   throw new RuntimeException("Id not defined!");   

               return thisId.equals(otherId);
           }   

           @Override
           public int hashCode() {
               Integer thisId = link.getId();
               if (thisId == null)
                   throw new RuntimeException("Id not defined!");   

               return thisId.hashCode();
           }   

           public SomeEntity getLink() {
               return link;
           }
       };   

       public SomeEntityId getDTO() {
           return new SomeEntityId(this);
       }
   }   

   public static void main(String[] args) {
       SomeEntity e0 = new SomeEntity(null, "no id");
       SomeEntity e1 = new SomeEntity(1, "e1");
       SomeEntity e2 = new SomeEntity(2, "e2");
       SomeEntity e3 = new SomeEntity(3, "e3");
       SomeEntity e33 = new SomeEntity(3, "e33");   

       Set aSet = new HashSet();
       // aSet.add(e0.getDTO());
       aSet.add(e1.getDTO());
       aSet.add(e2.getDTO());
       aSet.add(e3.getDTO());
       aSet.add(e33.getDTO());   

       System.out.println(”set size: ” + aSet.size());
       System.out.println(”set:”);
       for (SomeEntity.SomeEntityId seId : aSet) {
           SomeEntity se = seId.getLink();
           System.out.println(”entity: ” + se.getData());
       }
   }
}

I even could suggest you to add it to entities code generation in such tools as Hibernate Tools.
I would also like to mention also that SomeEntityId object could be stored in transient field of an entity.
Comments are welcome.

Algorithm for generating serialVersionUID for java entities

Monday, March 24th, 2008

Here is some way of generating serialVersionUID for java entities.
It is stable in sense that it depends only on your schema, not JVM/time or date of creation.
On the other hand it depends on all fields in entity.
If we have next n fields:
typeName_1 fieldName_1;
typeName_2 fieldName_2;

typeName_n fieldName_n;
we could calculate
serialVersionUID =
(fieldName_1.hashCode() XOR typeName_1.hashCode()) * 31^0+
(fieldName_2.hashCode() XOR typeName_2.hashCode()) * 31^1 + … +
(fieldName_n.hashCode() XOR typeName_n.hashCode()) * 31^n
where fieldName_i.hashCode() is hashCode() of fieldName_i string
(for int id; it will be “id”.hashCode())
and typeName_i.hashCode() is hashCode() of typeName_i string
(for int id; it will be “int”.hashCode())
so, we will be independent from
1) JVM
2) time/date of creation
and depend on
1) fields order
2) field types
3) field names

Get rid of your nested if operators!

Monday, March 24th, 2008

Every one of you know how it is disappointing that you can not use

switch

operators with strings, doubles, your custom objects, etc. But anyway sometimes it is possible to get rid of your nested ifs if you will use static maps. Let us consider an example: here we need to set JavaBean properties of certain types:

 protected static Object fillTestBean(Object bean) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
  Method[] methods = bean.getClass().getMethods();  

  for (Method method : methods) {
   if (RTTIUtils.isSetter(method)) {
    Class type = RTTIUtils.getSetterType(method);
    if (type == String.class)
     RTTIUtils.invokeSetter(bean, method, testStr);
    else if (type == boolean.class)
     RTTIUtils.invokeSetter(bean, method, testBoolean);
    else if (type == byte.class)
     RTTIUtils.invokeSetter(bean, method, testByte);
    else if (type == char.class)
     RTTIUtils.invokeSetter(bean, method, testChar);
    else if (type == short.class)
     RTTIUtils.invokeSetter(bean, method, testShort);
    else if (type == int.class)
     RTTIUtils.invokeSetter(bean, method, testInt);
    else if (type == long.class)
     RTTIUtils.invokeSetter(bean, method, testLong);
    else if (type == float.class)
     RTTIUtils.invokeSetter(bean, method, testFloat);
    else if (type == double.class)
     RTTIUtils.invokeSetter(bean, method, testDouble);
    else if (type == Boolean.class)
     RTTIUtils.invokeSetter(bean, method, testBooleanObj);
    else if (type == Byte.class)
     RTTIUtils.invokeSetter(bean, method, testByteObj);
    else if (type == Character.class)
     RTTIUtils.invokeSetter(bean, method, testCharacterObj);
    else if (type == Short.class)
     RTTIUtils.invokeSetter(bean, method, testShortObj);
    else if (type == Integer.class)
     RTTIUtils.invokeSetter(bean, method, testIntegerObj);
    else if (type == Long.class)
     RTTIUtils.invokeSetter(bean, method, testLongObj);
    else if (type == Float.class)
     RTTIUtils.invokeSetter(bean, method, testFloatObj);
    else if (type == Double.class)
     RTTIUtils.invokeSetter(bean, method, testDoubleObj);
    else if (type == Date.class)
     RTTIUtils.invokeSetter(bean, method, testDate);
   }
  }  

  return bean;
 }

(here all variables starting with test are constants)
Seems really annoying to write all this ifs and, also what if we will need to check values? Another function will also need this nested ifs!
In this case I usually do the following (factory method -like solution):

 private static final Map initObjects = new HashMap();
 private static boolean isCosideredType(Class type) {
  return initObjects.keySet().contains(type);
 }
 static {
  initObjects.put(String.class, testStr);
  initObjects.put(boolean.class, testBoolean);
  initObjects.put(byte.class, testByte);
  initObjects.put(char.class, testChar);
  initObjects.put(short.class, testShort);
  initObjects.put(int.class, testInt);
  initObjects.put(long.class, testLong);
  initObjects.put(float.class, testFloat);
  initObjects.put(double.class, testDouble);
  initObjects.put(Boolean.class, testBooleanObj);
  initObjects.put(Byte.class, testByteObj);
  initObjects.put(Character.class, testCharacterObj);
  initObjects.put(Short.class, testShortObj);
  initObjects.put(Integer.class, testIntegerObj);
  initObjects.put(Long.class, testLongObj);
  initObjects.put(Float.class, testFloatObj);
  initObjects.put(Double.class, testDoubleObj);
  initObjects.put(Date.class, testDate);
 }  

 protected static Object fillTestBean(Object bean) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException {
  Method[] methods = bean.getClass().getMethods();  

  for (Method method : methods) {
   if (RTTIUtils.isSetter(method)) {
    Class type = RTTIUtils.getSetterType(method);
    if (isCosideredType(type)) {
     RTTIUtils.invokeSetter(bean, method, initObjects.get(type));
    }
   }
  }  

  return bean;
 }

Creating Web 2.0 RIA applications with Flex and Rails

Monday, March 24th, 2008

Flex now is much for web development: we have OOP there, fine web-services integration, code and layout separation and more.
I personally think that the best way of creating web application is designing (or modeling) how it’ll look like for the end-user, what and what it going to afford to the end-user. So, let us think we already have some Flex web-application and going to connect it to some web-server to make it do something meaningful.
We have at least 4 options here, we can use:

  1. Custom XML-based HTTP service;
  2. Custom non-XML HTTP service;
  3. SOAP-based web-service;
  4. AMF (Adobe proprietary) based service.
1. Custom XML-based HTTP service

Flex will send HTTP request and receive XML answer like following:

<?xml version="1.0" encoding="UTF-8" ?>
<list>
  <item product="Computer">
    <UID>12321</UID>
    <CPU>4Gh</CPU>
    <RAM>2Gb</RAM>
    <HDD>400Gb</HDD>
  </item>
</list>

Pro here is that you can do comparatively small XML here (smaller that SOAP one).
Contra is that you are responsible for constricting XML on the server side and working with it (say, using DOM) on the client side.
It is rather inconvenient to do this additional work dealing with some XML structures, but many systems work just the way I described here.

2. Custom non-XML HTTP service

Similar to previous approach, but here you deal with yourself designed metadata like:

list[
  Computer[
    UID=12321
    CPU=4Gh
    RAM=2Gb
    HDD=400Gb
  ]
]

It can be not so verbose as XML, but you are now responsible for parsing your custom structures by yourself. It has so many troubles that it even does not worth to be considered, unless you write system like AMF by yourself.

3. SOAP-based web-service

Absolutely pain-free method, since now nearly all web-application frameworks have transparent built-in methods for SOAP based web-services. So does Flex. Troubles could begin here when you experience high loads with crowds of users. Constructing and parsing big XMLs will kill your web-servers and channels. SOAP does best with heterogeneous systems integration like those used in b2b, but it is too heavy for ordinary web applications.

4. AMF-based service

Pros here come from the nature of the protocol. It is fast binary over HTTP. Designed just for Rich Internet Applications. Why not to use proprietary protocol for communication with server if you already have chosen proprietary Flex system to be used? The reasons could be: you don’t know how to integrate it in your server and you are afraid of possible troubles by dealing with proprietary technology. Here in this article we will consider both questions.
Let us be more exact. There are 2 versions of the protocol: AMF3 for Flex and AMF0 for Flash. So let us focus on AMF3 only (further in this article I’ll use AMF in meaning AMF3).
There are some frameworks for AMF: Adobe Flex Data Services (http://www.adobe.com/products/flex/dataservices/), AMFPHP (http://amfphp.org/), WebORB (http://www.themidnightcoders.com/weborb/). Maybe there are some others. Frameworks are available for .NET, Java, PHP and Ruby on Rails. But I’ve found only one available for Rails. It is WebORB. So further in this article I’ll describe my experience about dealing with WebORB plugin for Rails.

Flex and Rails

Good news is that Flex applications works fine with Rails via WebORB (see http://www.themidnightcoders.com/weborb/rubyonrails/gettingstarted.htm how to use it). Bad one is that it conflicts with number of other plugins like act_as_attachment (we wrote workarounds by changing the WebORB plugin).

Sessions

Another inconvenience is that WebORB service classes which you write for your web services are plain classes, but not something inherited. So you don’t have those nice features like ones you have for your controllers or SOAP web-services. Therefore, your services are stateless by default, since they do not have an access to the session object (HTTP session maintained via cookie). We wrote some utility classes and slightly changed WebORB to add session object. But you can choose to maintain session on the client side by SharedObject Flex class: http://livedocs.adobe.com/flex/2/langref/flash/net/SharedObject.html

File upload

There are no obvious ways to upload file via AMF. The only way to upload by the Flex that we have found was using FileReference + URLRequest objects. There are some obstacles here. The URLRequest initializes other HTTP Session than AMF one’s. Therefore we can’t identify user who makes URLRequest on the server side. The workaround for this problem is to send additional information with URLRequest to make it possible to identify a user. Another inconvenience is that URLRequest can’t get more than http status code as a result (no messages or values).

Search Engine Optimization and mobile access

Search Engine Optimization (SEO) stays for providing readable HTML data for search engines like google.com, yahoo.com, and others. Usually the main argument against using Flash/Flex is the absence of SEO possibility. But there is a workaround for this issue. The trick here is that you can create a simple xHTML site with all SEO information and then a user loading such page, JavaScript will load your Flex on corresponding page. The big advantage of this approach is that it automatically makes your site available for mobile devices (WAP 2.0) if you use xHTML Mobile Profile DTD.

Types mapping

By tests we’ve found that it is the next (Flex <-> Ruby):

  1. int <-> Fixnum
  2. Numeric <-> Float
  3. Date <-> Time
  4. String <-> String
  5. Boolean <-> Boolean

Be aware, that if you choose “:decimal” type for database column it will not be mapped to convertible Ruby type and therefore not accessible in Flex.

There is an interesting site concerning Flex and Ruby questions: http://flexonrails.net/. I could recommend you to look throw this article: http://www.flex888.com/2007/09/20/10-flex-and-ruby-on-rails-integration-examples.html
and this one http://webddj.sys-con.com/read/295396.htm

Good luck!