This has been, by far, our biggest release and this is likely going to be a very, very long post. Sit back and get comfortable. Go get a coffee. I know that I need one for this.

Release 6 was all about adding features. We had (and have) and very solid core of an architecture. We are very comfortable with our code base. And, we feel that we can extend almost anything on top of that. So, we aggressively chose features to implement in this release cycle. Following are those features

  • Community features
    • Implement a simple messaging system
    • Implement an inbox for users to receive messages
    • Implement a broadcast system for which owners of projects can broadcast messages to users
    • Implement a commenting system for both commenting on line items and projects
  • Projects should be tied to users
    • Users should not be able to localize a project that isn't theirs
    • Users should be able to create their own project based on another's
    • Users should not see other projects in their project list
    • Users should be able to search a list of projects
  • The login window needed to be refactored
  • The menu bar needed to be expanded. This also added the requirement for context sensitive menu items
  • Resource bundles of a language needed to be selectable in some way, instead of showing resources for all languages at one time
    • Users should be able to add a language to a localization
    • Users should be able to delete a language from a localization

That list is pretty big. Surprisingly, we finished almost all of it. In order to accomplish this, the size of our code base doubled and several major refactorings were carried out. We completely ripped out the bottom end of our application and replaced it. We overhauled the controller substructure. We changed how the sidebar worked. We refactored to reduce the size of our setup (AppController). We fixed several bugs. In summary, we did a lot.

Hey, Hey Gooodbyeee

CPKeyedArchiver is a way to serialize objects in Cappuccino. It works very well and we've never found an error in the code. However, our dream when we first started to serialize objects was to be able to serialize them into JSON. The reason for this is that CouchDB, our database backend, stores data in JSON format. We couldn't get a JSONArchiver implemented in the beginning so we fell back to CPKeyedArchiver. It had served us well.

But, time to wave goodbye to our good friend CPKeyedArchiver and welcome in the latest and greatest. Chandler and I (mostly Chandler) worked for about a day and a half to get this working, but we were finally able to produce CPKeyedJSONArchiver. Gasps, awes and the look of wonder should now blanket all of your faces, right? Well, you probably don't really know how awesome it is. But it is awesome, I promise. It will take our Model layer and serialize it to JSON. We can then take that JSON, send it over the wire to our Database, and our database stores it natively. This means that we can now pick apart our Models in our database very similar to the way we could in code. It is also smaller (likely due to the fact that CouchDB stores JSON natively and handles JSON better) and will allow us to use views in our database. Then, we can get the data over the wire, unarchive it without any crazy unarchive, interpret, separate and evaluate chain. Instead, our objects come out squeaky clean in plain text format rather than an archived format.

Speaking of.. views?

This allowed us to use CouchDB as more than just a datastore. In Couch, there is a concept called views. These views are created by using a map/reduce combination on the databases inside of Couch. So, for example, I could create a listProjectNames view that would map each record to a key/value pair.

//        key          value
    emit(doc._id, {'name':doc.Name});

And, now, we have a view. This view is much faster than pulling the data down for all of the projects and then getting the names for them. So now we have the power to do just about anything with our data with minimal cost. This is some really cool stuff--and I have yet to see any SQL or SQL-like syntax in this project (Now if we could only find a way to rid ourselves of the PHP).

The Community

The Community featureset was a big test for our code base. If we had made a solid, loosely coupled architecture, adding a Community shouldn't be too awful difficult. It turns out that, while we had underestimated the time it would take to create the community features, our framework didn't even blink under the pressures of all this new code.

First, we implemented an Inbox / Detail View system for the mail. We followed the architecture that came before in the Project views and quickly came to realize that we did it stupidly before. Not to be discouraged, Kyle trucked ahead and got the Inbox and Detail View working. He then subsequently implemented the messaging system whose architecture is pretty rough but stable, at the moment. We hope to revisit this in RC7 (in fact, it is already assigned to Chandler).

Users, Projects, Oh my!

In the beginning, we created the idea of a project. The "Project Metaphor," as we called it, was a serious part of the workflow process. Now that we are somewhat happy with that process, we need to make it work in the larger context. This was surprisingly easy. We just needed to attach a user to a project and then create the appropriate controller logic to remap the user interactions. I was really happy with how easily our architecture handled this. There was not much that needed to change in the model layer or view layer. The model layer just needed to be able to get users associated with a project. The view layer didn't change except for features being added (such as the project name, owner name and resource bundles in the navigation bar).

REST API: Reloaded

I mentioned previously the REST API that exists for our application. This API was pretty simple because our database was a simple datastore. But, now, we can use the full power of CouchDB because we store the data in JSON. Cool. Let us see how that works

GET    /api/project/all_docs       list of all projects
GET    /api/project/ID#########    one project
POST   /api/project/ID########     update project
PUT    /api/project                create project
DELETE /api/project/ID######       delete project

the new API looks something like

GET    /api/project/_design/views/find                 list of all projects
GET    /api/project/_design/views/find_by_name/KEY     all projects that match KEY
GET    /api/project/ID#######                          one project
POST   /api/project/ID#######                          update project
PUT    /api/project                                    create project
DELETE /api/project/ID#######                          delete project

which, for the most part, is very similar. However, how to get a list of projects is very different. Also, we can create views that are keyed by name, id, whatever. This is a very powerful API. For release 7, however, we plan to simplify things and attempt to turn /api/project/_design/views/find into /api/project/find for the API (using PHP to translate from our API to Couch's API).

Menu Bar, Login, User Experience, Oh no!

We're starting to move away from "Really Cool Concept" land to "Practical Application" land. And, when we move from the first to the second, certain things become oh-so-important. Like the CEO of Twitter, Evan Williams, recently said, "User experience is everything." OSL is starting to look more and more like a complete, functional desktop application. This is a good thing, we were wanting to get here. Now, we have to focus on the tiny details that concepts can ignore but applications need to make great. Things like the menu bar, how the application reacts to users whom are not logged in trying to do things, how many clicks or actions it takes to get to a certain location, how much overhead is in it for the user, etc.

This is really exciting for us because it is a situation that we haven't had a lot of experience in. Typical school projects hardly ever run longer than 10 weeks and 10 weeks is enough to create a "Really Cool Concept" but nothing of a "Practical Application," especially considering the skillset and time constraints on students. We've been working on this since last fall and we're moving into unfamiliar, really cool territory. We hope to get it right, but learning is a really good objective here.


I could go on and on about this release. This post is long enough already. So I'll get on to doing the metrics.

Release LOC  Classes     Files   Methods     Tests   Methods/Class  LOC/Class    Tests/Method   LOC/Method
1       1424    27          32   69             21   2.56           52.7         0.304          20.6
2       2551    35          39   147            26   4.2            72.9         0.177          17.4
3       2578    37          40   159            38   4.3            69.7         0.239          16.2
4       3436    43          47   216            46   5.03           79.9         0.213          15.9
5       3813    53          58   220            87   4.15           71.9         0.395          17.3
6       7577    84          87   450            171  5.36           90.2         0.38           16.8

As I said before, our code went WAY up. This is due to new features, not a ballooning of our core architecture. This is expected. This is the same for the Classes, Files and Methods metrics.

We added a bunch of tests but couldn't keep up with the features. I think we have a lot of very good tests, but that there are a lot of methods that aren't worth testing.

Methods per Class went up, but I think this is just because of the adding of features. We'll need to monitor this metric to make sure it isn't jumping too high. Same thing for the LOC per Class.

Finally, you can see that our methods are getting smaller (read: better) despite all of the code we've written. We still need to test more but this is a positive sign.