Anatomy of an app

The making of SwapMySwag

Rob Cowell
8 min readJan 15, 2019

It began, like so many of my adventures, with a tweet…

The nascent beginnings of a github repository

I’d seen a lot of folks on Twitter sending out swag to each other off the back of a “DM me your address” request (looks at Reid Carlberg). I’d also had a fresh delivery of tasty swag from our friends on the Trailhead team and already folks were asking me for swaps. The lightbulb got switched on pretty quickly — we should make this scalable. There should be an app for that. So I got to work.

How shall we build it, oh Master?

Way back in the mists of time (well, Dreamforce 2011 to be exact), I’d had an even bigger epiphany. I’d had a demo of Play! Framework and Heroku from James Ward (then Developer Evangelist at Heroku, now at Google Cloud Platform).

The speed at which he went from zero to deployed webapp was astonishing and syntactically, the code was totally understandable. The path from defining a few string and integer properties on a class to a fully database-bound website seemed so simple.

Having had considerable enterprise success with the killer combo of Play! and Heroku in the past, I knew this was the platform that would make me most productive for SwapMySwag. Therein lies a very important lesson…

The Play! Framework has come a very long way since I first started using it all those years ago. It’s now on a version 2.x branch, having been massively rearchitected to not only a different underlying platform, but a different programming language — Scala.

The trouble with frameworks

People that know me are already aware that I’m not averse to adding another programming language to my arsenal — I’m already a recovering C# developer, assembly language dabbler, PHP wrangler and enthusiastic GLSL amateur. I was fully prepared to see what Play! 2.x brought to the party. I installed the pre-requisites, I followed the Getting Started steps to confirm was all well.

sbt new playframework/play-java-seed.g8
sbt run

After supplying a couple of parameters (app name and org name), it created a sample project. Then it started to download a metric crapload (US readers — 1 metric crapload is equal to 1.4 imperial craploads) of dependencies from Maven…

At the time of writing here, I’m still waiting for that process to finish, which neatly highlights the first issue — developers just want to get on with developing. I mean, for crying out loud, it’s downloading another copy of Ant (which already exists on my machine for Force.com deployments), Docker, XML libraries and god knows what else. Surely I should be able to add those to my dependencies later, you know, if I need them…

So, bottom line was — sod that, I’m gonna stick to the familiar and functional Play! 1.x line in Java. It works, I know it, I can get on with my app.

Gathering the tools

With experience comes an awareness of the tasks you need to solve and the tools that will help you solve them.

  • Hosting — Heroku
  • Database — Heroku Postgres
  • Image storage — Amazon S3 (more on that later…)
  • Logging — Papertrail
  • Email — Sendgrid

This approach is fundamental to my API-lead philosophy. I’ve spoken at Dev meetups at length in it before. Use the tools that are out there wherever possible.

I also quickly realised that, as much as I love Sublime Text as an editor, a fully-fledged Java IDE would make me far more productive. Out of the box, Play! supports creating project wrappers for Eclipse or IntelliJ IDEA — I chose the latter, because it’s feature rich but more importantly fast.

The object model

One of my absolute favourite things about Play! Framework is how it builds the database for you. Given the following class :-

package models;import play.data.validation.Required;
import play.db.jpa.Model;
import utils.S3Blob;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
@Entity
public class Swag extends Model
{
@Required
public String Name;
@Required
@Lob
public String Description;
@Required
public Integer Quantity;
@Required
@ManyToOne
public User Owner;
public S3Blob Photo; public String imagePath; @Override
public String toString()
{
return this.Name;
}
}

the system will create a Swag table in the database for me *automatically* with an id field as the primary key. You can see there’s some annotations on there to get some useful properties — required fields, many-to-one-relationships, long fields, etc. So the class is pretty lightweight, but what it delivers is the Model of the Model-View-Component approach. Of course, all the heavy lifting is done by those includes we’re bringing in from the Play! Framework.

About that S3Blob reference…

Ah yes, glad you spotted that. The S3Blob is basically a binary file that is wired up to Amazon Web Services S3 for storage. The original implementation of the S3 plugin for Play! was written by the aforementioned James Ward, many years ago. For this project, I uplifted it to the latest (at time of writing) version of Amazon’s API, which meant a few tweaks here and there, but it’s now working happily — and I’ve contributed the changes back to James. This last point is important, as Free Software can only exist if we share code. Now everyone can potentially benefit from my changes in their own projects.

Views and Controllers

Moving on to the V and C in our MVC model, the controllers are fundamental to how we build the app. Not only do they contain the “logic” of the operations we want to carry out, in the context of a web application, they guide how I move data back and forth between the Java backend and the HTML front end. Once again, Play does so much of the hard work here.

I can pass strings, integers, etc around or we can pass whole objects. Play thrives on Plain Ol’ Java Objects (POJO) classes and can quite happily shift them around. This makes it easier to handle forms, for example. On the HTML side I can further leverage Play’s Groovy templates and start walking through those objects :-

#{list items:swags, as:'swag'}
<tr>
<td><a href="@{SwagHandler.viewSwag(swag.id)}">View&gt;</a></td>
<td>${swag.Name}</td>
<td>${swag.Description}</td>
<td>${swag.Quantity}</td>
<td>${swag.Owner}</td>
<td>
#{if swag.imagePath != null && swag.imagePath.length() > 0}
<img width=128 height=128 src=${swag.imagePath}></img>
#{/if}
#{else}
<img src="/public/images/NoImage.png" width="128" height="128"/>
#{/else}
</td>
</tr>
#{/list}

In this example, I’ve passed a whole list of Swag instances and are walking through it, building up an HTML table and pulling the field properties straight out of each Swag instance. I even have some conditional formatting in there for the images — kinda like Visualforce, eh? ;-)

The “plumbing” of sending things back for processing is pretty straightforward too, when I want to submit forms. If we look at the following snippet, I tell the form what method handles the submission, and I bind a few fields to the object I pass in :-

#{form @saveProfile(), id:'saveProfile', enctype:'multipart/form-data'}
<input type="hidden" id="connectedUser.id" name="connectedUser.id" value="${connectedUser.id}" />
<p class="field">
<label for="connectedUser.fullname">Name</label>
<input type="text" id="connectedUser.fullname" name="connectedUser.fullname" value="${connectedUser.fullname}"/>
</p>

So you can see here, I push the data back to a controller method called saveProfile, passing connectedUser as an object back. The method looks a little like this :-

public static void saveProfile(User connectedUser)
{
connectedUser.save();
viewProfile();
}

I just passed a whole object back from the page and saved it. Play takes care of everything else — magic!

Security

Oh my, so much to think about in this area. First out of the gates, I included Play!’s Security module in our dependencies. As long as I have a User object with at least a username and password field on it, I can use this module to handle authentication. I annotate our Controller classes

@With(Security.class)

and any methods on that class are now only executable by an authenticated user.

The other aspect I wanted to cover was ensuring HTTPS connections. This is actually a little harder than I wanted. Heroku gives us sufficient HTTP headers (x-forwarded-proto) to determine if any given request is encrypted or not. I can check this header value to see if a connection is HTTPS or not and redirect accordingly. To add this to all our classes, I wrote it as an Interception so that the code runs before taking any action. That way I can ensure I always uplift to a secure connection before doing anything.

Bugs, bugs and damned bugs

Admission : I rushed the release.

In order to satisfy the needs of a Salesforce community hungry for swag, the app went “live” on New Year’s Day 2019. Great timing from a marketing perspective, but right away, things weren’t right. Registration was broken, which was a showstopper for getting folks on board. A few tweaks and a git push later, we were in.

Over successive weeks, more issues came to light — people couldn’t log in because mobile phones (notably, iPhones) were capitalizing the first letter of usernames when registering, causing a discrepancy in username checking. Swag notifications were going to the wrong side of a swag exchange, offer quantities were not updating. I took the site down for a couple of days to tackle some of these issues. At the time of writing, some of the bugs still exist, but the site is mostly usable and the first trades have successfully completed.

Back to the future

Earlier, when mentioning I used Amazon S3 for the image storage, I said “more on that later”. So it turns our that S3 isn’t the magic bullet I thought it was. Each push of a new file to S3 counts towards limits. Each read of that file counts towards limits. The growing storage size counts towards limits. This is all becoming strangely familiar and the thing is with AWS — the more you use, the more you pay. As a free, hobby app I really want to keep those costs down.

There’s a couple of approaches I’m researching here — put everything behind a caching proxy like Cloudfront (thanks for the tip Todd Halfpenny) and to solve this and another image issue (y’all uploading things at anything from 6 to 12 megapixels, meaning huge file sizes), I’ve been looking at Cloudinary, which allows us to process the images (rotation, sizing, aspect ratio) for efficiency, as well as also using an S3 backend, that is cached.

There’s also some functionality changes planned — what if you could make an offer on someone’s swag and say to them “pick some stuff from my available swag” rather than pre-determining the offer? What if you could print shipping labels when you receive address details? What if we could provide tracking codes? There’s a whole raft of great suggestions from the userbase and rest assured, I’ve captured them for review on Trello.

Summing up

  • Was it fun to build? Yes, overall. A few extra grey hairs gained over the bugs though
  • Did we learn anything? Tons! I reminded myself how to use Play! 1.x, I learned about the architectural needs of a modern, cloud-based web application and the constraints you need to work under, I’m in the process of learning about Progressive Web Applications from those with greater knowledge and much more
  • Would I do it again with another app? Well, maybe…. ;-)

--

--

Rob Cowell
Rob Cowell

Written by Rob Cowell

Salesforce Dev/Architect with a bunch of unfounded opinions