Behind the Scenes: Building Proofessor

Una Kravets, Former Viget

Article Category: #Code

Posted on

What happens when you take a group of college-aged interns and tell them they can create anything they want? A booze app.

Last year's interns created an awesome interactive storybook remake of Jack and the Beanstalk. This year, each Viget office had enough interns to create their own individual projects. At HQ, our ideas ranged from campaigns for non-profits, to a website for a local restaurant, to geolocation scavenger hunt games. There was a lot of debate over the topic, but ultimately, like any good group of college students, we unanimously agreed to create a practical mixology app called Proofessor.

What's Proofessor?

Basically, the way it works is, you open the site and select what spirits, liquors, or mixers you have available and would like to use. Then, the available recipe list filters down to fit your selected parameters and you can click on different recipe names to learn how to make them. If you're indecisive like me, you can simply shake your mobile device, and Proofessor will flip to a random recipe for you. The site is responsive and works on both desktop and mobile, though it is intended to be used as a web app on a device's home screen.

Setting Up a Virtual Host

One pretty cool trick I learned here was how to set up a virtual hosting environment. This means that instead of going to localhost, i could label the host url anything (professor.dev is what I used for the app and in the example below) and, with a server running, could access the site by going to that url (professor.dev) in a browser window.

You must first add it to your hosts file (located at your computers root directory /etc/hosts and add this line:

127.0.0.1 proofessor.dev

before these lines:

255.255.255.255 broadcasthost
::1 localhost
fe80::1%lo0 localhost

** Note: for some reason, editing this file in Sublime Text on my computer caused a slew of issues as invisible characters were created (this basically created a huge error and I lost access to everything -- big ups to Lawson for realizing this was the problem and fixing it).

Then, in the httpd configuration file in your Apache Server (I'm using MAMP, so mine is located at Applications/MAMP/conf/apache/httpd.conf), add these lines to the end:

<VirtualHost *:80>
 DocumentRoot /Users/Una/Sites/proofessor/public
 ServerName proofessor.dev
 ServerAlias "proofessor.dev.*.*.*.*.xip.io"
</VirtualHost>

This will enable the professor.dev virtual host on your system. The server alias, with all of the *'s, allows any person/device on the same wifi network to access the site as well using a service called xip.io by 37Signals. Replace the *'s with the wifi ip address address of your computer (this may change for each wifi session) which can be found in your system's preferences (and is different than you COMPUTER's ip address - so don't try going to findmyip.com). Then use that number instead of *'s to access the site. I.e. proofessor.dev.10.0.0.10.xip.io would be the link.

Anybody who is on the same wifi connection can now access your website from any device. This is how my teammates were able to upload recipes to the database at the same time as I worked on the buildout -- all possible via a CMS that I set up before the design of Proodessor was finalized. I must admit, it was pretty awesome to be working on the code for this web app and watch the recipe count slowly increase.

Choosing a CMS

The CMS that Proofessor is built on is called Craft. Developed by Pixel and Tonic, version 1 was released on June 4th of this year, just a few days before my internship began (perfect timing!) Nobody at Viget had any prior experience with this specific CMS (because, well, its brand new), but Trevor introduced it to the team in a lab share, and we decided that Proofessor could be a great opportunity to try it out.

I thought that the learning curve would be relatively steep, but I'm pleasantly surprised with how intuitive and user-friendly Craft turned out to be. Content is organized by sections of entries, which have custom field sets of user-specified fields. Individual bits of information are entered into the fields. Entries can be cross-referenced (i.e. the ingredients here are a different type of entry with an image asset, yet I can access these image assets by selecting ingredients inside of Recipes). It sounds a little confusing, but once you start using it, you get the hang of it pretty quickly. Here's an example of how ingredients and recipes look in the back-end:

You can then access these variables in the layout via the field's slug and by using Twig, the tempting agent that Craft uses. Curly bracket syntax is used within content blocks to insert field entries from Craft.

  • {% %} = functions
  • {{ }} = variables
  • {# #} = comments

This reads from the table above to represent the list of ingredients in the Recipe entry view:

{% for row in entry.specificingredient %}
 <li class="specific-ingredient">
 {{ row.ammount }} {{ row.unit }} {{ row.ingredientName }}
 </li>
{% endfor %}

It's also possible to access these variables in ANY view by specifying what section of entries you are looking for ('recipes' in this case). This is how the titles of all recipes showed up on the index page:

<ul class="recipe-list">
 {% for entry in craft.entries.section('recipes').order('title').limit(200).find() %}
 <li class="single-recipe-block">
 <a class="{% for ingredient in entry.ingredients %} {{ ingredient.slug }} {% endfor %}" href="{{ entry.url }}">
 {{ entry.title }}
 </a>
 </li>
 {% endfor %}
</ul>

Using Craft was really a joy; the small, growing community (and its developers themselves) were extremely supportive throughout the process.

All of the Javascripts

Writing the javascript to make the app actually run/function/work/do things was absolutely the most difficult part of the process for me. I went into this without much javascript development experience, and was confused by namespacing, event binding, and scope. Tommy had a really fun time explaining the "this" keyword in different contexts without actually using the word "this" in his explanation (which was hilarious because "this relates to this" is what anyone would initially want to say -- so props on some creative speech twists to avoid it).

I used this basic structure for all of my javascript files:

window.PROOF || (PROOF = {}); //define a namespace (only ONCE) -- I used PROOF for Proofessor

(function($, window, document, undefined) {
 var _common = PROOF.common = { //this is your js object
 init: function() {
 this.setVars();
 this.bindEvents();
 },

 setVars: function() {
 // set all variables here
 this.helloString = "hello" ; // also _common.helloString
 },

 bindEvents: function() {
 // set event listeners for your functions here
 },

 // the rest of your functions go here

 _common.init(); // don't forget to init!
})(jQuery, window, document);

Be a Defender of Simplicity

This is something Ryan, one of the developers here, said at our all-hands summer meeting (TTT). He called developers the "defenders of simplicity" in a project's lifespan. That really stuck with me. To understand the complexity of a request, and make decisions on whether it is worth it or not, is an important skill and an important part of the process. Saying 'no' to something is definitely not necessarily a bad thing.

There were a lot of opinions and concepts for this project, and debates ranged from changing the accent color to adding music to animating almost every little thing on the page. Clearly, you can't have it all or there will just be a jumbled mess. We had to nix some features (such as favorites and an Instagram feed, among other things) and animations (there was just so much going on already when we actually saw it all together!) in the interest of time and sanity.

One of the things that got cut very last minute (it was even there when the app was initially released!) was a countdown that visually showed the numbers filtering up or down as the number of available recipes changed. This one was a feature I was particularly proud of because it was the first javascript function I wrote from a base conceptual/algorithmic level (without help!). However, the filtering was slowing down the site, and caused problems with the recipe count, and we got some negative feedback on its impact on mobile speed. Ultimately, removing this feature did make a noticeable speed performance upgrade on mobile.

Proofessor.co is now live and ready for action! Download it to your phone's home screen or just open it in your browser, and enjoy!

Related Articles