If there's one piece of advice I could give ..

16 July, 2008

So I've been thinking about things, thinking about the state of web development. What could I write about to could help out some new recruits and budding developers. (Note this is a long one, so get some coffee, sit back, read, and I'd love to see your thoughts and opinions at the end ...). In a nutshell: I have a rather entrepreneurial friend back in New Zealand, he consulted at a Software company I worked for once. Over time we became good friends.. One day him and his business partner came up with a widget. And sold a few, and then needed to sell some more. Then one day he gave me a call. You can imagine as a web developer the conversation "Yeah some some company wants [insert horrendous figure here] to build us an e-commerce site" pffwaaaattt (coffee all over desk)... And so began a new relationship. Realising the scope of work was BIG, I actually called up one of my dev mates. "Oi, I've got some work for us, keen?" Gave him the specifics. We agreed to do it 50/50 (side note, later on I ended up taking it on 100%). We struck a deal. I drew up a contract and we got underway. It's one thing sitting at a desk job, saying something will work, and then meh, it doesn't, this happened or that happened, whatever the reason, your thing doesn't work. There's a kazillion reasons why something won't work, or can't be done, or is late etc. Depending on your character this will bother you, or not (hopefully the former!). It doesn't *really* teach you responsibility. Now, taking someones money personally, and promising delivery of something, with nobody else to shoulder the workload. Now that's responsibility. There's only you and your Mac/PC. So long as the two of you are both in working condition, and you haven't bitten off more than you can chew well there's no excuses. Everyone reading this should be familiar with the actual mechanics of building something, but most often you're shielded from the business elements. Why are you building what you're building ? Is some Business Analyst telling you chinese whispers. Do you really know ? It's all about the vision. This isn't some contrived management tactic, there's a reason people put it on the top of briefing/requirements docs, if you buy into the ultimate business goal, then you will be far better at doing what you need to do. There is a famous saying in New Zealand - "Make the boat go faster" an entire army of engineers, yachtsman, craftsman, tacticians were all about one single minded goal - making the boat go faster (and they did, Black Magic won the Americas Cup). In our case it was all about selling the widgets. By being both a friend, and supplier, you realise you're taking money from this company, your friend, to build something. They're going to have to make that money up by selling product. So, you'd better do what you can to help them sell that product. By keeping the vision at the forefront of your mind you're not going to use technology for technology's sake. You're not going to waste time spending 10 hours getting some little bit working when it doesn't matter. You are going to learn how to prioritise - especially if you're doing this in your hometime. Once you've wasted 3 evenings in a row and not gotten any further along the path to completing your objective you'll quickly learn what's important! This WILL make you a better developer. Too often I read posts about the top x number of things looking for when hiring a developer. Technical brilliance is IMNHO focused on WAY too much. By doing the process from start to finish, you'll realise, the minor technical bits are quite small in the overall scheme of things (unless of course you need to build some ninja fast product requiring complex calculations) Note as I've been writing this Ilya put up a great post mentioning the jelly jar, another way of looking at this issue You will hear and see a lot people who are singularly focused on one technology, one piece of the puzzle, they're specialists. That's great. But a piece of code, or a sql call, or a config file does not a web app make. If you have to do everything from ordering a server to getting the finished app up and ready to login, you'll realise there are a lot of pieces of the puzzle. By doing everything yourself you'll begin to realise the other side of the fence is not as nearly black magic as you thought it was. Gaining experience in all aspects, from server config, mysql setup, dns setup, playing with cron will make you a lot more well rounded. By becoming more experienced in different aspects, you'll realise you can do a lot more. [As a side note, this is also why I think working in a startup, is a damned good thing. Every dev should do it at least once!] Along the way, your client is going to ask you for things, lots of things. And you're going to have to manage that feature request cycle. Now who knows better - you or the customer ? The just say no philosophy that is becoming pervasive in web app development school of thought is scaring me. My client loves it when stuff gets implemented. I don't just say no every request. Where stuff doesn't make sense, or can be done better, I talk through it with them. But if I just said no everytime. Well the relationship not likely go far. Don't get me wrong, I see it's place, but you have to use judgement, and know where it applies. Don't take it literally. When you're close to the customer, you'll realise their daily pain. Walk through the system with them, understand every support request - what lead to it, why, what can you do better ? Now, why did I say in my opening statement maintaining an app. Long term there is no greater thing than maintaining what you wrote. In our day jobs, we move on, client's move on, the code moves on. But invariably the business doesn't - it stays there and so does the site. By maintaining something yourself you get an appreciation for the movement in technology(when we first wrote this app, the nearest thing to a published framework were the PEAR libraries, nobody had yet come up with a solid stack). Now 3-4 years later I'm rolling in Rails into the mix. You'll understand the value of commenting the tricky bits. it always comes up as a reminder, just last week I was all over some code questioning "WTF did I do here?" especially when the business decision hadn't been written down beside the code. Along with gaining a much fuller appreciation of clean, modular, readable and reusable code. Also you'll get the chance to refactor and it makes you (well at least it does for me) feel good. Some crufty bit of code you haven't touched for 6 months, and you get to make it look better and work better. Nice ! This might seem counter to what I've been saying. But I think this is how a lot of new technologies get adopted. People are playing on pet projects and attempt to use a new technology. Doing your own app, you get to make the choice. It's either going to work or it's not. And you have to live with the win's or losses. Whereas in your day job there might not be anyway on gods green earth you're going to implement technology x as the impact on a large team is huge, but on your own time - it's your choice. You get to play with jQuery for instance (whichs rock extremely hard by the way), or mix and match Rails and PHP. Can you imagine what a system architect is going to say when you propose that in your day job? No f-cking way. Of course, you have to pick your moments and rationalise why you're choosing that technology. What is it really doing better for you... This is where doing a project for yourself shines. I saw a great clip by Tony Robbins the other day, must say I've never seen him before, and not likely to buy his products, however he did say something that that resonated with me loudly - too many people blame the lack of resources time,money etc but ultimately their failures are not about lack of resources, but the lack of THEM being RESOURCEFUL. This is what I'm talking about with this post. Maybe it's a really long winded way of putting it, but by building and maintaining your own app, in order to do it successfully you'll have to be resourceful. You'll have to learn, prioritise, be accountable, responsible, problem solve, etc and it will all matter because.. You'll get this at the end of the day. That's what I appreciate in developers. People who when faced with a challenge won't back down. They will find different approaches to a problem. They will try and try to get something running, they'll go away, rethink the problem and have another crack at it. Once done, they'll polish it, make it look work better/faster/ etc to acheive the end goal/vision. Having done that they'll take pride in it and say "I did that, I think it's cool and it rocks, and here's why ... ". Going back to my original opening statement, doing a project yourself gives you the opportunity to do so, virtually unrestrained. You'll get a tonne of challenges from technical, emotional, financial, time, the whole gamut. But by taking on the responsibility to do it yourself, (or be responsible for delivery yourself - you could farm the whole lot out, then you've got a whole new set of problems!), it means you have to meet and break through each one of those challenges. The only constraints in general, are your time and motivation. A number of years down the track you can look back on it, and go 'damn that feels good' When I get the chance to interview people one of my questions is always Feel free to answer it here, I'd like to see what makes other people tick..

Read More

Rails + PHP sharing the same session

10 April, 2008

Ya know there's times in your life you do things that feel 'wrong'. This somehow feels that way, but one of my buddies wanted to know how it's done, so here it is: I've got an application I maintain in PHP which has been in production for a good number of years. It's stable, works really well, however like any application I need to keep putting in enhancements, the pain curve of doing this is exponential with the time I've been using Rails, so over a couple of years you can imagine the pain is pretty high. Last week I thought to myself, enough is enough. I'm sick of writing PHP, I could do this so much faster in Rails. I've been churning away on a rewrite in the background, in Rails as and where I have time but I wanted a 'fix it now' kind of solution. So, why not have the same virtual host serve out both Rails & PHP, so long as the Rails app can find out if a user is currently logged in, then I can piece by piece enhance/replace the PHP app. Turns out it was pretty damned simple. Here's a quick guide assuming 1- Both apps are sharing the same database 2- In the session you're storing a user_id of the logged in user 3- App uses cookies So here we go...

1. Virtual Host Config

The first thing we need to do is get Rails to run under the same vhost as the PHP scripts are run. This is easy, just adding a ProxyPass directive into the Apache vhost for the site back to your mongrel(cluster), so lets say we had a REST resource "some_resource", you'd add in the ProxyPass line below

    ...
    DocumentRoot "/path/to/your/php/app/html"
    ProxyPass /some_resource http://127.0.0.1:3000/some_resource
    ...

Note that in production this would pass through to a balancer of course. The unintended consequence of this is that you also can share all of your assets served from your existing app without having to duplicate them in your Rails app.

2. Sessions - PHP

The next thing for this to work is we need to know for the Rails app that the PHP app has logged a user in - we need to share the sessions. There's not too much black magic here. When you start your session in the PHP app (well at least mine!) PHP was storing in a named cookie eg "myappname" a hash value via
session_name( 'myappname' );
. This hash value is used to look up the session tmp files stored on the server, inside those session files are the serialized objects that PHP stores in $_SESSION global. So you have three options. 1. The "read from file system and unserialize the session" route 2. Store the session in memcached and have both PHP/Rails connect to memcached 3. Use the db to store sessions and logged in user_id's, then load the user on each page load. Note there is a page on this on the rails wiki, devoted to approaches 1 & 2. However if you're not storing a tonne of variables in the $_SESSION then approach number 3 - the path of least resistance - will likely be just dandy for you... In my database I created a shared_sessions table - using a rails migration (detailed in step 3 below) This stored a unique key "session_hash", as well as other fairly understandable columns "user_id", "updated_at". As we're logging in and out from the PHP app, this will mostly maintain the sessions table. So I added a quick couple of functions Application_SetSession() and Application_ClearSession(). Application_SetSession() simply writes into the shared_sessions table the hash value from the cookie $_COOKIE['myappname'], the corresponding user_id, as well as the time of update, it looks something like this:
function Application_SetSharedSession($user_id)
{
    global $DB;
    $session_hash = $DB->real_escape_string($_COOKIE['myappname']);
    $qry = "REPLACE INTO shared_sessions SET `session_hash` = '{$session_hash}', 
                      `user_id` = '{$user_id}', `updated_at` = NOW()";
    if ( !$DB->query($qry) ) throw new DBException($qry);
}
ClearSession() clears out the appropriate shared_session record. As you can well imagine ClearSession() is called when the user logs out, SetSession() when they login as well as every page load. Your PHP app will now be setting/clearing the shared_session records as appropriate.

3. Sessions - Rails

  rails myphphack
  cd myphphack
  script/generate model SharedSession
  script/generate model User
  script/generate scaffold SomeResource name:string ... 
Right now you need to fill out the SharedSession model's migration, and delete the user model migration (it's already in the database!). In the SharedSession migration, make sure you're setting the unique index on session_hash, otherwise REPLACE INTO won't work. So, first we need to load the user on the Rails side. To do this we need look up the SharedSession model for the session hash, from the cookie that was set by PHP. It's available of course, doesn't care who set it we have access to it.
class ApplicationController < ActionController::Base
  before_filter :restore_user
  ...
  protected
  def restore_user
    unless @user = User.restore_from_php(cookies[:myappname])
      redirect_to '/login.php'
    end
  end
  ...
end
On the user model, we now need a method to find the user from the session_hash:
class User < ActiveRecord::Base
  has_many :shared_sessions
  def self.restore_from_php(session_hash)
    find(:first, :include => :shared_sessions, 
          :conditions => ["shared_sessions.session_hash = ?", session_hash])
  end
end
Easy peasy.

4. Testing time

Run the migration, fire up a mongrel instance on 3000, hit the appropriate vhost, login to your PHP app and go to /some_resource. With any luck you'll be able to hit the /some_resource path with a logged in user.

Now then, it's not quite that simple

The astute ones will notice "Hey what happens if I login from PHP, see /some_resource, then come back directly to /some_resource in future - I could do this at any point in the future, it won't log me out". Exactly, you can handle this one of two ways. Either some nasty cron job thing to clear out the SharedSessions table, or do it as part of the load_user filter in the rails app - ie before restoring the user, SharedSession.delete_all("updated_at < DATE_ADD(NOW(), INTERVAL -15 MINUTES)") or whatever matches your current PHP session timeout settings. You also probably want to do some hash of the user agent, ip address etc and store this away in the shared_session table, then check against it whenever you're finding if a user exists, to try to eliminate cookie theft.

The fine print

It's pretty simple and it works in testing... YMMV. Test the hell out of it in your own application.

Read More

HTML_QuickForm in .... Rails ?

28 November, 2007

Caution Thinking Out Aloud: Okay the purists have just decided to kill me. Let the religious wars begin ! No seriously, everytime I do some coding in an old PHP app which is heavily dependent on HTML_QuickForm, I keep questioning how possible would it be to convert it across to Rails, and whether any other persons like myself would think all of their Christmases have come at once. Here's my hopefully rational thought processes behind this. Rails is a fantastic CRUD machine. If you want to build single model forms with validations in them, absolutely beautiful. Nothing could feel more clean and make you as a developer go 'thats sweet'. Fantastic. Now try and do a model-less form, with validations, or combine multiple models within one form. Things like the presenter pattern get bandied about. Real world case example - a form to choose options for defining a report. Nothing that you want to put in a model as it's not a represenation of a 'thing' (although some may argue it is). I wonder and am sitting on the fence of, whether to try implementing quickform for rails. For those that haven't been exposed to it, in a nutshell it's a brilliant little php library that lets you create a representation of a form, with rules, pass the form into a renderer which dumps out the html on a page, but that's not all, it assists you in processing the form on submission. So some code can look like this (not syntactically correct, but close enough), which does all of the hard work of writing out html, setting up client side js, and server side processing.
//page myform.php

$myform = new HtmlQuickForm('form_name', 'myform.php'); 
$abc = $myform->addElement('text', 'product_name', 'Product Name:'); 
$myform->addRule('product_name', 'required', 'You must enter a product name'); 
if ($myform->validate()) {
   //process form
   var_dump( $abc->getValue() ); 
} else {
   //setup form 
   $abc->setValue('123')
}

// then in any template which dumps out the rails code
$myForm->display(); 
It doesn't seem like much, but put half a dozen or more options on the form, different processing rules, and suddenly it's done a lot of the heavy lifting for you. What would it take to add this to Rails ? How would (I personally) fit it in. It doesn't really sit within either the model, view, or controller. The view should render the output, it doesn't really fit within a model as it's not a representation of a thing. It most closely sits in the controller, but you don't really want to clutter the controller with your form models. Here's some thoughts An initial idea, with everything defined in the controller, then dumped into the view by a @my_form.output
class FormController < Application 
  def do_form
    get_form
    if @myForm.posted 
       #do stuff
    else
       #populate stuff
    end
  end

protected
  def create_report
    @myform = RFormBuilder.new do |f|
       f.call_back_url = { :controller => 'form', :action => 'do_form' }
       f.name = 'myform'
    end
    @myform.add_text( :name => 'product_name', :label => 'Product Name', 
              :rule => { :required => :true, :msg => 'You must add this' } )

  end

end

OR Maybe we add in a new folder in the main app
  /app/
      /controllers
      /models
      /views
      /forms 
        myform.rb
And the treat myform.rb kinda like a model, but kinda not.

class MyForm < RFormBuilder
  defaults :name => 'my_form', :call_back_url => '/myform' 
  text_field :name => 'product_name', :label => 'Product Name', :required => :true
   
  #gets called when form is posted   
  def validate
    return true if field_product_type == 'abc'
  end 
end


# now in FormController 

 def do_form
    get_form
    @my_form = MyForm.new
    if @myForm.valid
       #do stuff
       render :text => @my_form.field_product_name
    else
       #populate stuff
    end
  end

What do you think ? Am I stark raving mad. Could this just work ? I think so and am willing to take up the challenge... Rowan

Read More

Franken-php-rails-apache-stein

08 June, 2007

Every wondered about the possibility of running a rails app, and a php (or anything else for that matter) site together, on one virtual host, on apache. But why? the hordes screamed ... DHH keels over ... the PHP community says ahh just put it in CakePHP... and to you it feels just plain *wrong*. However, there is always that odd need, every now and then, that you have to do it. So here's how. It's really simple, assuming you're using mongrel cluster and setup a balancer in Apache for it, like so in one of the conf files... <Proxy balancer://mybalancer.rowanhick.com> BalancerMember http://localhost:2000 BalancerMember http://localhost:2001 BalancerMember http://localhost:2002 </Proxy> Then on the paths that you want to mash up with your vhost, it's as simple as this... For specific file mapping to an action: ProxyPass /some_path/some_file balancer://mybalancer.rowanhick.com/mycontroller/myaction ProxyPassReverse /some_path/some_file balancer://mybalancer.rowanhick.com/mycontroller/myaction ProxyPreserveHost On For one path mapping to a controller: ProxyPass /some_path/ balancer://mybalancer.rowanhick.com/mycontroller/ ProxyPassReverse /some_path/ balancer://mybalancer.rowanhick.com/mycontroller/ ProxyPreserveHost On Restart and you're away. (even if it feels dirty)

Read More

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.