SalesForce $1M Hackathon What I learned

Posted on

This morning I received an email that zip.ly was rejected as a finalist in the Salesforce Hackathon, thus ending a 3 week sprint of software development. Attempting to assemble a product in 3 weeks is an act of insanity but having turned off consulting for the year, a good domain name, and the desire to work on something new; our team jumped in head first. The experience was well worth it as I found myself learning more in these 3 weeks than I learned all year. It was very rewarding and yielded some unexpected fruit in terms of skills and a foundation to build services.

Special thanks to the team at SalesForce who executed the Hackathon. It was perfect but the only thing I would change is adding a RedBull soda fountain onsite next year and forging a partnership with Mels dinner around the corner and keep them open all night for Hackathon attendees. As someone who has run developer events, the execution at Dreamforce was world class.

I learned a metric ton in building zip.ly and I wanted to share the list of technology and what worked great and what did not. As with all technology decisions, perspective matters and over the course of development my option shifted on several technologies in use.

Server-Side I used Python/Flask/Jinga/SQLAlchemy/Postgresql and this was by far the best decision. The server was easy to change and the mature ecosystem surrounding python is a great asset. I quickly found key libraries for handling Imaging and PDF generation in PIL, ReportLab.pdfgen, pyPdf, and xhtml2pdf. If you need to generate any type of PDF document between these 4 you can get the job done fast. The hardest element here was not generating the files themselves but working around not having a file system on Heroku. I found several key workarounds using Pythons StringIO and BytesIO that proved to be excellent solutions to avoiding reading and writing to disk.

For persisting files, I leaned on Amazon Web Services via the Python Boto library. It is a great library and makes working with AWS easy. Once you get keys and permissions set, you can control AWS like a boss with very little code. For example here is the code in boto to write a pdf to S3:

s3 = S3Connection()
s3b = s3.get_bucket( ‘my_bucket’ , validate=False )
key = s3b.new_key( ‘path/to/file.pdf’ )
key.set_contents_from_file( StringIO( pdf_data ) )
The trick with Boto is that keys are optionally pulled from environmental variables so this aligned well with Heroku.

Jinga templating was also a standout as I switched to using extends templating late and it saved us. I was quickly able to reuse assets from a library of markup and violently change our ui late. Looking back I would not have finished the app had we not done this. Jinga just works.

SQLAlchemy is amazing. It is easily one of the best DB/ORM abstractions I have every used. Yes I have used Hibernate, but SQLAlchemy falls into the ORM you can control and avoids the dark mysteries of schema migration hell. Rather than having things be automatic in SQLAlchemy, you have to tell it what to do. Here are a few great examples:

app.config[ ‘SQLALCHEMY_DATABASE_URI’ ] = os.environ[ ‘DATABASE_URL’ ]
db = SQLAlchemy( app )

class Draft( db.Model ):
id = db.Column( db.Integer , primary_key=True )
userid = db.Column( db.Integer )
name = db.Column( db.String( 100 ) )
text = db.Column( db.Text )
signers = db.Column( db.Text )

#careful with these 2
db.drop_all() #drop em all
db.create_all() #generate tables from model classes
In zip.ly I did the db.drop_all() and db.create_all() as part of updating the app. It was trivial to generate schema changes or a whole new schema from our model classes. I will be using this library for years to come A+.

About 1 week into development, the $99 entrance fee was refunded by SalesForce so I decided to spend those funds on an SSL Certificate for zip.ly. I purchased the cert from RapidSSL and learned the ins and outs of generating .CSR .KEY .PEM and applying them successfully to a domain on Heroku. With the SSL cert in place it enabled us to integrate SalesForce.com OAUTH and thus call the SalesForce REST API.

In the process of integrating SalesForce OAUTH2, I struggled with several libraries but quickly fall back to use Requests in Python. In short order I had OAUTH fully working and was able to call the SalesForce REST API for Identity and adding Contacts. The REST API at SalesForce is a real gem to work with given its simplicity. Once you get the AuthToken, you can call any API by setting the Authorization:Bearer header with the AuthToken and adding a JSON payload. This was a gem to work with and makes deeper SalesForce integration easy.

Client-side was a frustratingly bumpy road and while I had great ambitions of having a great Single Page Application, late in development things came unglued so we fell back to server-side page rendering. As part of the learning on the app, we started using AngularJS which is an amazing library when you know what you are doing. Unfortunately while integrating AngularJS with our JSON API, I started to see errors that I did not understand and worse the only choice I could make was to rip it out with the Hackathon deadline looming at 36 hours to go. We will return to AngularJS after learning far more.

The B word Bootstrap. We picked Bootstrap early and I regret the decision. Bootstrap is brittle as you must accept things the Bootstrap way or you will struggle. For some projects it is great and will get you started fast but it is hard technology to integrate when you know exactly what you want. The CSS is filled with important! so you quickly go into important! hell and are covered in some sticky goo that you need solvent to remove. I will not go back to Bootstrap unless they restructure and remove the important! mess within the framework. Again it is great for some things but for detail work it can get hellish. I am tempted to move towards using Topcoat or Pure when we revisit UI selection.

EaselJS, I LOVE YOU! If you want to rock the canvas in an app, look no further than EaselJS. I had to rebuild the signing aspect of the app late to support multiple signatures and embedded text and had it fully working inside of 5hr session onsite at the hackathon. I am now extremely biased towards EaselJS as when pressed for time, this library was predictable and easy to get things pixel perfect. I even had time to spare on this element and decided to add layouts for device orientation to the signature panel. Canvas also pairs really well with FormData in JavaScript as I was able to snap images of the signature panel and iterate over the stored data and upload via XHR. Here is a snippet:

var formData = new FormData();
var len = ziply.imageData.length;
formData.append( “signature_length” , len );
for ( var i=0 ; i<len ; i++ ){
formData.append( “s_” + i , ziply.imageData[i] );
}
var xhr = new XMLHttpRequest();
When it was all said and done, the big discovery in writing zip.ly is the HTML/Markdown/Images to PDF developer workflow. It allowed me to manipulate the PDF generation late in development and template it for end users all while generating PDF rapidly server-side. Our team will be investing more to make zip.ly both a Heroku Add-on and a small business centric native app for document signing on the go. This feels like the right pivot to make in the wake of this 3 week development sprint but we will see what time does to that decision.

I had a great time participating in the SalesForce $1M Hackathon and I walked away having learned a ton and met some great people. I would encourage you to take a risk and build something outside your comfort zone, and see what happens. You will learn a ton and you will be surprised by the results.