One Month On...

It's been almost exactly one month since we launched the Broadchoice Workspace application, just before Adobe MAX 2008, and during that time hundreds of new users have been downloading the application and starting their 30-day free trials - in addition to our many beta testers who are continuing to use the application on a daily basis. The ArgumentCollection team has been hard at work on a new build of Workspace which went into production this week. We've now surfaced all the trial subscription machinery and added licensing, in time for those 30-day trials to turn into paid subscriptions, and added a file storage usage indicator (a Workspace account gives you 5GB of storage, which may not have been obvious before).

We've also added automatic synchronization of activity in the Workspace back to Salesforce for collaborative spaces that have been created from opportunities. If you create a Note in Workspace, it is automatically added to Salesforce, along with any messaging in the space so that the opportunity history in Salesforce shows all of the collaboration you did to help close a sale. Given how salespeople often feel about the Salesforce.com web interface, this has proved to be very popular in sneak peeks since it provides them with a much simpler way to keep their opportunities up to date in addition to the ability to easily get help from their colleagues in closing sales.

We've also made a number of changes to the user interface in response to feedback from customers. Some are simple tweaks to visual aspects of the UI, some are simplifications to make workflows more intuitive. There's always more polishing to do!

Over the next couple of builds we'll be focusing on streamlining common workflows and making it even easier for new users to start using the application to collaborate with colleagues, as well as giving the iPhone web version lots of love and adding full support for the Blackberry.

Broadchoice Workspace - 2-for-1 license offer ends Sunday

Broadchoice is offering two licenses for the price of one through the end of November. You can download the Workspace application and start your free 30-day trial any time but if you actually place your order before Monday, December 1st, you can benefit from the 2-for-1 pricing and get two user licenses for every $99/year you spend! Happy Thanksgiving!

Unit Testing Improves Your Love Life

Oh, sorry, that was the title of the BACFUG presentation by Bill Shelton and Marc Esher (of MXUnit fame)!

Unit testing has defined my working day. I've been working on the licensing subsystem of the next build of the Broadchoice Workspace today and because we practice Test-Driven Development (thanx Brian!), that means writing unit tests "first" or at least alongside the production code.

I started by writing the License bean and an accompanying LicenseTest. The bean has a handful of properties and two methods. The unit test has nine test methods.

Fairly confident that the bean was correct, I moved on to the data layer. Apart from encryption, this mostly follows our well-tested generic Hibernate DAO. That meant only a couple of unit tests.

Once those tests passed, I moved on to the service layer. Six unit tests for four service methods.

At this point I'm ready to write the remote service facade (which implements user-level security) but I'm fairly confident our licensing subsystem will work as expected. 623 lines of code, just over half of which is unit tests (327 lines to 296 production code). I'll probably add some more data layer unit tests since I have a couple of "untested" methods (they're used in the service layer tests).

Unit tests may seem dull and tedious but they really can make your life easier.

Cocomo Post-MAX

Adobe's Cocomo technology entered public beta at MAX and the day one keynote featured an extremely brief demo of a little of what Cocomo can do. Nigel Pegg (of the Cocomo team) did a couple of sessions during the conference which I had planned to attend but, as is usual with MAX, my schedule got derailed early and often so I didn't make either of them. I'll be writing up my MAX experience on my own blog shortly (and may contribute an extended version as an article for Fusion Authority as I have done with conferences in the past).

Now MAX is over, Nigel has blogged more about Cocomo and talks about what beta testers get access to in terms of source code, documentation and features. Nigel includes a nod to me for contributing the Groovy version of the provisioning script and and a mention of the Broadchoice Workspace which uses Cocomo behind the scenes - and which we demo'd at both the Adobe Partner booth (Wednesday lunchtime) and on the Ribbit booth.

If you didn't get a chance to look at Ribbit, check out this video of Joe and Rick (our CTO) talking about Ribbit integration into Broadchoice Workspace (as a proof of concept for now - would the ability to make phone calls from within the Workspace be valuable to you?).

Some Code Statistics for Broadchoice Workspace

Now that the Broadchoice Workspace has been officially released, I thought I'd post a quick entry with some code statistics. I ran the codebase through a line counting tool that gives a breakdown by file, folder, language, etc. We all know that lines of code is not a very good way to judge quality or effort, but it is still interesting in a general way. This is only lines of code, all blank lines and comments were excluded:

  • Total Lines of Code: 50,125
  • Total Files: 633
  • Lines of MXML: 10,784
  • Lines of ActionScript: 12,675
  • Lines of CFML: 7,730
  • Lines of Groovy: 8,878
  • Lines of XML: 1,757
  • Lines of CSS, HTML, JavaScript, etc.: 7,612
  • Lines of SQL: 1,089
  • Lines excluded as comments or blank: 15,778

Concurrency, BlazeDS, data-driven architecture, and Broadchoice Workspace

Broadchoice Workspace has a contact list on the right-hand side. In the launch release we're working on now, it shows everyone you're connected to through groups. Simple enough, right? A simple SQL query that joins you to groups, and groups to member, and there you go.

It's at this point working on a RIA becomes very different from working on a HTML application.

Here's a few of the more fun use cases to consider. They're fun brain-teasers for thinking about how to handle multiple clients running the application.

Concurrent Signup

  1. You're a member of the Acme, Inc. group. Workspace is running.
  2. The owner of the Acme, Inc. group starts the Workspace and adds Ferd McBurfle, a new hire from down in accounting.
  3. Ferd gets the invitation e-mail and signs up for the application, joining the Acme, Inc. group. He should now should up in your contact list. No user gesture should have to be taken on your part: no refresh, no waiting for a periodic refresh, etc.

People View in a Group

  1. After the prior case is complete, you decide to check out the "People" tab in "Acme, Inc." Right now it shows you, the owner, Ferd, and Lumpy McGiblet, the person Ferd just replaced
  2. While you're viewing the people tab, the owner removes Lumpy McGiblet.
  3. You're not in any common groups with Lumpy anymore, so Lump should disappear from your client's view of people. Again, no gesture should have to be required on your part.

Our Approach

I've really enjoyed working on problems like this on the Workspace. Our solution to most of these situations involves using server-side services that broadcast small DTOs to running clients via JMS, "pushed" through amf-polling. Many of these same concepts are possible in ColdFusion, as well.

If you'd like to hear more about this kind of work, feel free to stop any member of the ArgumentCollection at Adobe MAX next week!

Workspace Beta 1 Build 4 is live!

This was primarily a bug fix release as we prepare for our official product launch. Build 4 (3.0.0.rev.5695) includes nearly 60 fixes and enhancements with the most notable being:

  • The invitation mechanism has been fully integrated into the AIR application so you can invite users directly into groups and spaces
  • The login dialog now has options to create a new account and retrieve your password (in case you forgot it!)
  • The activity feed search is greatly enhanced, allowing you to search for replies or by types of content or updates vs new content (essentially all of the "filler" words we add when feed items are constructed are searchable now)
The bug fixes are mostly cosmetic but include the activity feed issue that several people spotted where a content update still said "added" in the feed!

A big thank you goes out to all our beta testers who have really been putting the application through its paces and providing a lot of excellent feedback and some great suggestions!

Email Testing on OSX

Yesterday I blogged about how I set up Groovy/Spring to send both HTML and plain text emails. Today I want to share a tip about testing those emails. I was using postfix on my Mac as SMTP server. This allowed Spring to connect to, and send the email, but the emails would never leave my machine. My coworker Sean had no problem with mail getting out, so I figured I either had some setting wrong or perhaps it was my cable company blocking the traffic.

I googled around a bit and came across this excellent blog article: fully local testing of email sending web apps (on Mac OS X)

This article describes how to set up postfix to listen to certain domain names and forward those emails to local account. It then goes on to describe how you can setup a pop3 server to get those mails.

The end result is that you can send email to anything at a particular domain and then use a desktop client to check the mail. This is not only cool for Groovy work but would also be useful for ColdFusion as well. I normally use Spoolmail to check CFML generated mail, but that isn't an option for Railo, and it doesn't give a 'perfect' end user view of the mail (especially for combo plain text/html emails like we are testing).

Plain Text and HTML Emails via Spring

Last week I had to add email support to our application. While this is trivial in ColdFusion, I was expecting quite a battle with Java. I had hoped that maybe Groovy would have a simple solution perhaps, but turns out it was even easier than I could imagine.

My experience with Spring has been pretty minimal. I know how to work with it, and I know how to add stuff and set dependencies and stuff, and so from that it meshed well with what I knew of ColdSpring. But Joe informed me that Spring was a lot more than just a Inversion of Control framework. It also ships with a set of additional features to help developers. So for example, scheduling stuff (which CFML developers get via the scheduler in the Admin) is easy with Spring. As you can probably guess, mail is easy as well.

I won't go into the full details here, but I'll point to the documentation on it and you can read it yourself.

Ok, so far so good. The problem I ran into though was moving from plain text messages to a mail message that supported both the plain text and html text at once. Here was the original code I had for the plain text message:


def subject = "Subject here..."
def emailStr =
"""
$user.firstName $user.lastName,

Etc etc
"""
def msg = new SimpleMailMessage(templateMessage)
msg.setTo(email)
msg.setText(emailStr)
msg.setSubject(subject)
    
try{
mailSender.send(msg)
}
catch(MailException ex) {
println(ex.getMessage())
}

The above should be easy enough to read. The templateMessage object is code injected by Spring and contains the connection information for the mail server (server, port, username, password). That stuff is configured in Spring which is sensible. I also configure the from there since all mail will be using one main from address. After that, all I have to do is set the subject, the To, and the text, then fire it off.

I had hoped that the setText method would perhaps have options for sending HTML email as well. Unfortunately that wasn't the case. (Hey, they did call it simple, didn't they?)

In all my searches at Google I was unable to find a simple example of this. I saw examples using attachments and HTML email, but not a plain+html example. The API docs for things I thought would be a good alternative were pretty confusing. My main issue was that everything wanted a MimeMessage object, and I couldn't figure out how to create it. Finally I realized that Spring had sent me a mailSender object (it's what I was using to send the mail) and had an option to create a mime message:


def msg = mailSender.createMimeMessage()

I could then use a MimeMessageHelper object like so:


def msg = mailSender.createMimeMessage()
def helper = new MimeMessageHelper(msg,true)
helper.setTo(email)
helper.setSubject(subject)
helper.setText(emailStr,htmlStr)
mailSender.send(msg)

That worked like a charm. I probably got half the terminology wrong above, but hopefully this will help others as well. A big thank you goes to Andrew Powell for his help on this.

Meaningful method names are great!

I came across (and added a bit to) a great snippet of code today in the Workspace codebase while fixing a bug on QA. The code represents just how you can use OO to encapsulate complex logic into meaningful behaviors of entities.

We have a business rule that says the following:

"The current user may save a membership in a workspace may be saved if all of the following are true:

1. The membership's user is not already a member in the space. 2. The current user is the owner of the space OR the space is marked public and the current is a member of the space's group."

Thanks to some good method names, the code is easier to understand than the English!

Here it is, in code:


if ( !membership.space.containsMember( membership.user )
     && (
        membership.space.isOwnedBy( currentUser )
        || ( membership.space.isPublic && currentUser.isAMemberOf( membership.space.account ) )
     )
)

Thanks to whichever of my coworkers originally wrote this - it was easy to modify to suit a new need!

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002. Contact Blog Owner