Building A Web-App 102: Getting Your Code On

Following on from my post on Building A Web App 101, this post starts to descend into The Business, as it were - the actual writing of code.

Part Two - Getting Your Code On

We've looked at the steps to work out what we want to build (if not, head on back to get some context), it's now getting time to actually write some code. The advantage is that all of this time that I've been playing designer/IA/usability-guy in the last post, I have slowly (and indirectly) been thinking about the basic database schema I'm going to need. In the case of our invoicing system, the page structure suggests that we need to have Clients, Invoices, Charges and Payments as a bare minimum. The Invoice mockup showed some of the fields we need to be storing for those objects too. So, from these hints we can start to build our schema.

Normally I'd use DBDesigner4 or something similar to draw up a chart of my schema, pump out some SQL and generally get to visualise how it's all going to hang together. However, in this case I was able to knock up a few quick sketches on paper, and then plunge straight into writing a new Rails' schema.rb file. For those of you that haven't yet looked at the Rails Migrations, it is a library to allow you to write up your database schema in a vendor neutral Ruby DSL. Check out the screenshot - that's what the Clients table looked like in one version.
Screenshot of part of a Ruby on Rails schema.rb file

Writing up your schema using the Migrations code is handy for a few reasons. Firstly, you don't have to think about all the cruft which Rails expects in a certain way, such as id columns being a specific type.

Secondly (perhaps most importantly) Migrations are (predominantly) vendor neutral - it's the responsibility of the Migration library to produce SQL code for MySQL, PostgresSQL, SQLite (or your database flavour of choice), and you don't have to remember the differences between the versions of SQL. This is seriously handy, as it lowers to barriers to trying new database engines. For example, the test deployment of this project uses SQLite, whereas the development desktop uses MySQL. To the schema.rb file, there is no difference and the structure generated is the same.

Finally, Migrations comes with an entire system for writing (and deploying, rolling back and keeping track of) incremental change scripts (migrations) for your database. At the time of writing, the project these posts are based on has undergone 7 or so changes from the initial writing of schema.rb. These changes range from changing the size of the ABN and ACN fields (I never remember how long they are) to adding entire tables to store previously unrealised information.

So we've now written up a schema.rb, run the rake script to populate our database and we're getting ready to start coding. It's also important to note that at this point in development this schema is incomplete, and we know it - we fully expect to extend it with migrations later. This expectation gives you enormous power, because if you're someone like me (who wants the schema to be perfect) you can easily start off with something basic and beef it up as you go.

We now know where we're storing all of our data - from this point, I started building up a basic Rails app using scaffolding, with the intention of concentrating on our "priority one" items - those on the menu.

Because the end visual product comes to the forefront in this approach, we arranged the general layout first - I don't care if the content we are displaying is only the crude auto-generated tables, so long as it's getting closer to the end result. Visual feedback is always a great boost to performance.

This brings us to another major advantage with creating all of those mockups - you can often just rip your HTML structure and styles out and use them directly in the end product. I was able to do this in our project, and so copied and pasted most of the mockups into the templates as a foundation before linking in all of the code. In this way, implementing the screens becomes simply a process of making the form look how we want, getting the data that we need in, add in any AJAX-ish effects that we wanted (such as as-you-type totaling for charges) and then working out how to save the data. Pretty run of the mill, really - nothing very difficult here, and any Ruby on Rails tutorial will be able to put it far more succinctly than I if you want to find out more.

One notable highlight of this stage was the discovery that ActionMailer, the email library for Rails, can construct multipart messages by naming the templates by a certain convention. This meant that to produce emails with both text/plain and text/html parts it was simply a matter of having two files for each template - for example, invoice_to_client.text.html.rhtml and invoice_to_client.text.plain.rhtml. Why was this important? Well, multipart emails were essential to accommodate clients with different mail-clients (including webmail users), and this made it far easier to produce them.

In the next part of our saga, we'll look at taking care of the project once it starts to get under way - managing code, managing features and managing when you inevitably break things.