AngelHack London 2016- Explor-ing the Possibilities

This article also appears on the AngelHack blog in the Global Hackathon Guest Post Series!


 

Last weekend, I went to AngelHack London. This was my third hackathon. Unlike my previous hackathons, I decided to go in with an idea this time.

The Prep

I moved to a new flat in March and I resolved to keep my bike commute exciting and to discover as much of London as possible by taking at least one new road each commute. I wanted a way to keep track of my progress on this goal, perhaps with a map showing all the roads that I had covered.

In the week leading up to AngelHack, I sketched out a bunch of pseudocode and class diagrams to efficiently calculate which sections of each ride overlapped with previous rides and which sections were new. I was very excited to sink my teeth into this logic, hopefully using C++ and test-driven development, while the rest of my team built a beautiful, usable interface for it.

The Pitch

At the hackathon, after the rules were explained and the sponsors talked through their APIs, participants were invited up on stage for “one-minute pitches” to recruit teammates. I jumped on the opportunity.

I was the first one up and after what felt like about 9 seconds of me mumbling about bikes, the environment, and design, I was promptly shot with a nerf gun and told that my time was up.

The Plan

Despite my incoherent pitch, several people approached me after my pitch. However, even without time constraints, I was still mostly met with blank stares when I tried to explain the idea. Apparently, not everyone likes the idea of extending their already very lengthy commutes just to see a few nice sights. One team member, Elliott, from the video production company Biscuit Bunker, helped to refine the idea and focus on a much simpler minimum viable product. He also came up with the hip, tech-ish name “Explor”.

Armed with a game plan, we split things up. Unfortunately, two of our five team members had to leave unexpectedly, even before dinner!

The Picnic

And then there were three. Pictured in the tweet below are Carlos, Elliott, and me, feeling fresh but somehow looking more bleary-eyed and delirious on Saturday evening than most participants would later look on Sunday afternoon following many more Red Bulls than hours of sleep. I guess the camera caught me mid-blink ūüôā

Carlos had to leave relatively early as well, but thankfully he whipped up an initial html mockup for us.

The Process

I found it so much easier to communicate my ideas to my team through sketching than through words or code. Here are a few of our sketches.

IMG_2993

Elliott had made it clear from the start that he wasn’t a programmer and would not be coding, but could help with graphics and UX. So he worked on our logo and design, and I set out to chip away at tweaking the JavaScript code I copied from the Google Maps API’s documentation.

Once that was mostly done, we started to look at Carlos’s mockup, but neither of us had done much with html or css before.

The Progress

Two amazing AngelHack ambassadors, Harry and Aaron, heard us struggling and offered to help. They made it clear that while they couldn’t code for us, they would be happy to talk us through a thing or two. I can’t thank Harry and Aaron enough for their patience and kindness in helping us along. I gained a lot of confidence in web development and Elliott literally learned to code html and css overnight. By the morning, he was combining our pages, making the styling consistent, and just smashing it in general.

The Product

At the absolute last minute, we remembered that we had to submit a youtube video before our demo. Elliott once again stepped up and somehow made this awesome little video in five minutes flat.

By the 1pm deadline, we managed to have a very simple (but definitely demoable) product, live on the web.

Our demo went well and while we couldn’t compete with the incredible work that some of the other teams did over the weekend, we were very proud that we managed to put something together and we learned a lot in the process.

Thanks, AngelHack!

The Postscript

I’m considering finally implementing that complex ride comparison code that I planned and/or building on the Explor prototype, so if you want to talk commuting, offer advice, or lend a hand, please get in touch!

Connecting Strava and Google Sheets using IFTTT

Update (2016-06-19)

Bad news: My cheeky hack to get Strava data into Google Sheets is no longer necessary.

Good news: Things got a whole lot simpler last month when IFTTT officially started supporting Strava! Instead of following the instructions in this article, I strongly recommend using this IFTTT recipe.


Last year (2014) I made a goal of cycling or running to work at least 100 times. I ended up doing 172!

This year, I moved from Canada to London, but not before doing over 252 commutes! (Note: I stretched the definition of commute to include any time I saved at least 5km of driving or transit)

I won’t reach 300 this year (my original goal) but instead of going sans goal until 2016 (I am very motivated by goals, even if they are completely arbitrary), I decided to set a new goal.

Cycle 1000km on my “new” bike before the end of the year.

So I made a quick chart in Excel.

newgoal excel

But then I realized that this would be a great opportunity for some tinkering. You see, the Excel chart above requires the dreaded MANUAL DATA ENTRY. If there was a way for me to use my beloved Strava to automatically update a similar chart, I’d be set.

So I tried to plug into the Strava API. But then got a little overwhelmed when it started asking me about authorization codes and application names.

I then went to my favorite “automate everything” site, IFTTT. While they don’t support Strava directly, they do support RSS feeds, and FeedMyRide allows you to create an RSS feed from your Strava activities. IFTTT allowed me to easily create a recipe for hooking up RSS to Google Sheets.

Add in some parsing, some array formulas, and a nice chart et voila: As you can see here, I now have automatic updating of my progress toward my goal!

1000km complete!

I’m a little behind on my goal as I write this(November 24), so stay tuned to see if I manage to catch up!

Update (01/03/2016)

I did it! I ran into a few hiccups along the way, such as four (mostly) unrelated flat tires in two days, an unexpected house move closer to work, and a cold/flu that lingered for a couple weeks, but my mileage at midnight on December 31st, 2015 was 1011.9km*.

mission accomplished!

Mission Accomplished! Me celebrating hitting the 1000km mark on a sunny New Years Eve day at Tower Bridge

*One little disclaimer: I had to cheat a little by including the approximately 50km I cycled in Copenhagen while on vacation there, so technically my new bike’s 2016 mileage was just under 1000km.

Anyway, I found it a very powerful motivator to have my goal out in public for all to see (even though, if we’re being honest, I’d be surprised if more than two people saw said goal). Also, I really enjoyed trying to keep the blue line above the red line in real time. And I absolutely loved exploring the sights of London. I may not keep up the pace of 500 km per month in 2016 but I can see myself continuing to cycle to work most days.

5 Tips for Hackathon Newbies

This past weekend, I entered my first hackathon, called FinTechathon: Hack the Financial Industry.

Hackathon Logo

After a whirlwind of activity, with many ups and downs, my team, “Credit Passport”, ended up winning the award for Best Use of Salesforce Technology! I wish I could take credit but as I explain below, the win was all thanks to my teammates, who put together a great pitch and hacked together an impressive solution in less than 48 hours. Those teammates were:

  • Tommy Nakamura
  • Daniel Forbes
  • Matt Williams
  • Johnny Chan
  • Richard Kirsch
  • Joao Veiga
  • Kavita Kalaichelvan
  • Ann Chen

Without further ado, here’s what I learned.

1) There will be people there who are much stronger coders than you

You will be completely outclassed. It will not be a comfortable feeling. I hate sitting back and letting others make the decision and do the work but I just didn’t have enough confidence (in either the technical aspects or the domain of financials) to take the reins. I was clearly the weakest link on my team and felt really frustrated for the first 24 hours or so. Honestly, I considered just giving up and going home because I was very intimidated and didn’t feel like I was contributing much at all.

Then, midway through Saturday in the Friday to Sunday event, I remembered something I read in The Start-Up of You.

“The most important choice of all is who you choose to surround yourself¬†with.”

-Ben Casanocha, Co-Author, The Start-Up of You (Source: Business Insider)

The best way to grow is to put yourself in those weakest link situations. I didn’t pack up and move from Calgary to London because it would be easy. I did it because it was a push outside of my comfort zone. Same as this hackathon. After I came to terms with this I was able to enjoy myself and learn a ton. I messed around with HTML5 canvases, I configured Heroku to host a prototype, I sketched ideas, and I observed my talented teammates.

2) Everyone is so helpful

I’m sure it varies, but I was blown away by how friendly and helpful everyone was. I expected it to be competitive and cutthroat but it wasn’t. Don’t get me wrong, people were in it to win it, but there was a general feeling of camaraderie over the weekend. I have to especially thank my teammate Matt Williams who, after staying up all night coding, patiently walked me through his work to explain what it did. I even spotted Matt taking the time to sit down with other teams to help them troubleshoot. Everyone wants everyone to succeed.

3) Not just for programmers any more!

Or maybe hackathons were never just for programmers. I just assumed that they were always just a bunch of coders hacking away, but they’re so much more. Observers were welcome at this hackathon (great for checking things out before diving in). Also, we couldn’t have done it without our fantastic team of BizDevs, who put together a concise, impressive pitch deck. Designers were welcome as well, but unfortunately I didn’t come across very many of them.

4) Roll with it

Plans change. Sure, it’s frustrating when code you’ve been working on has to be thrown out due to an incorrect assumption but that’s just part of the experience. It’s important not to get too attached to your ideas or the work you’ve done.

“Don’t get too attached to your original plan, because it’s probably wrong.”

-Paul Graham (Source: The 18 Mistakes that Kill Startups)

5) They treat you well

Not only is there delicious food non-stop, but where else are you going to have in-person api support at your fingertips? There’s no way that I would have wrapped my head around ColoredCoins if we didn’t have Tal from Colu right there to talk us through it. Oh, and did I mention delicious food and snacks?

IMG_1418

What’s Next?

I started the weekend feeling frustrated but ended it amazingly motivated and inspired. I’m already planning my next hackathon and my solo projects that I want to do on my own as soon as possible!

Comments

Did you learn any other lessons from hackathons? Let me know in the comments below!

Using boost::bind and boost::signals2 to Automatically Propagate Signals

Background

At my previous job, we implement a modified version of the MVVM pattern using C++. Our model followed a hierarchical structure where each item owns zero or more other items. We wanted the View Model to hear about everything that happened in the Model, but we didn’t want the Model to know about the View Model. As far as I know, C++11 doesn’t have any signaling, messaging, or event handling built in, so we decided to use boost::signals2 to allow communication where the sender of a message doesn’t need to know anything about the listener(s).

When hooking up boost::signals2, we used boost::bind to connect member functions as listeners (i.e. slots, subscribers, etc.).

A quick search turned a great StackOverflow question on a similar topic, but that didn’t cover automatic propagation.

boost::bind Syntax

The syntax for boost::bind confuses me regularly. The arguments to boost::bind are as follows:

  1. A function pointer
  2. A reference to the instance that the function should be called on (but only if that function is a member function).
  3. The first parameter that goes into the function (if applicable).
  4. The second parameter that goes into the function (if applicable).
  5. Etc.

Arguments 2 and higher in the list above can be any of the following:

  • variables (ex. bind(f, x), where f is a static function that takes one int and x is an int)
  • constants (ex. bind(f, 7))
  • fancy “placeholder” arguments (ex, bind(f, _1))
    • These are what usually trip me up a little. What the above example means is pass through the first argument.

How to Do It

As a simplified example, let’s pretend that ViewModel needs to know when something in Model has changed, but we don’t want Model to be dependent on ViewModel, as shown in the UML below.

This allows us, for example, to add more view models without having to change anything about the Model.

The following code shows the use of a tree-style “ModelItem” class, where each ModelItem owns zero or more other ModelItems. Signals are automatically connected and sent.

#include "stdafx.h"
#include <iostream>
#include <cstdio> // for getchar

#include "ModelItem.h"
#include "ViewModel.h"


int main()
{
    // Heirarchy of Ownership:
    //
    //    viewModel
    //       |
    //    mainItem
    //    |   |       \
    // itemA itemB itemC
    //         |
    //       itemB1
    //         |
    //       itemB1A
    
    ViewModel* viewModel = new ViewModel();

    auto mainItem = viewModel->GetMainItem();
    auto itemA = mainItem->AddItem("itemA");
    auto itemB = mainItem->AddItem("itemB");
    auto itemB1 = itemB->AddItem("itemB1");
    auto itemB1A = itemB1->AddItem("itemB1A");
    auto itemC = mainItem->AddItem("itemC");

    delete viewModel;

    getchar();

    return 0;
}

The following output is generated.

Item Created: 'MainItem'
Item Created: 'itemA'
Item Created: 'itemB'
Item Created: 'itemB1'
Item Created: 'itemB1A'
Item Created: 'itemC'
Item Deleted: 'itemA'
Item Deleted: 'itemB1A'
Item Deleted: 'itemB1'
Item Deleted: 'itemB'
Item Deleted: 'itemC'
Item Deleted: 'MainItem'

Here are the details of the classes used.

#pragma once
#include <string>
#include <vector>
#include <boost/signals2.hpp>

class ModelItem; // Forward declaration for the typedefs below.
typedef boost::signals2::signal<void(ModelItem*)> ModelItemSignal;
typedef ModelItemSignal::slot_type ModelItemSlot;


class ModelItem
{
public:
    ModelItem(std::string name);
    ~ModelItem();

    ModelItem* AddItem(std::string name);
    std::string GetName() const;

    void SubscribeItemDeleted(const ModelItemSlot& slot);
    void SubscribeItemCreated(const ModelItemSlot& slot);

private:
    std::string _name;
    std::vector<ModelItem*> _items;

    void ConnectSignals(ModelItem* listener);

    // These wrappers were written because it doesn't seem that boost::bind works with the signal's overloaded () operator.
    void OnItemCreated(ModelItem* item) { _itemCreated(item); }
    void OnItemDeleted(ModelItem* item) { _itemDeleted(item); }

    ModelItemSignal _itemCreated;
    ModelItemSignal _itemDeleted;
};
#include "stdafx.h"
#include "ModelItem.h"
#include <boost/signals2.hpp>
#include <boost/bind.hpp>

using namespace std;
using namespace boost;
using namespace boost::signals2;


ModelItem::ModelItem(string name)
{
    _name = name;
}


ModelItem::~ModelItem()
{
    for (auto item : _items)
    {
        delete item;
    }

    _itemDeleted(this);
}


ModelItem* ModelItem::AddItem(string name)
{
    ModelItem* item = new ModelItem(name);
    _itemCreated(item);
    item->ConnectSignals(this);
    _items.push_back(item);

    return item;
}


string ModelItem::GetName() const
{
    return _name;
}


void ModelItem::SubscribeItemCreated(const ModelItemSlot& slot)
{
    _itemCreated.connect(slot);
}


void ModelItem::SubscribeItemDeleted(const ModelItemSlot& slot)
{
    _itemDeleted.connect(slot);
}


void ModelItem::ConnectSignals(ModelItem* listener)
{
    // Hooks up this ModelItem's signals to listener.
    SubscribeItemCreated(bind(&ModelItem::OnItemCreated, listener, _1));
    SubscribeItemDeleted(bind(&ModelItem::OnItemDeleted, listener, _1));
}
#pragma once
class ModelItem;

class ViewModel
{
public:
    ViewModel::ViewModel();
    ViewModel::~ViewModel();

    ModelItem* GetMainItem() const { return _mainItem; }

    void OnItemCreated(ModelItem* item);
    void OnItemDeleted(ModelItem* item);

private:
    ModelItem* _mainItem;
};
#include "stdafx.h"
#include "ViewModel.h"
#include "ModelItem.h"

#include <iostream>

#include <boost/signals2.hpp>

using namespace std;


ViewModel::ViewModel()
{
    _mainItem = new ModelItem("MainItem");
    OnItemCreated(_mainItem);

    _mainItem->SubscribeItemCreated(bind(&ViewModel::OnItemCreated, this, _1));
    _mainItem->SubscribeItemDeleted(bind(&ViewModel::OnItemDeleted, this, _1));
}


ViewModel::~ViewModel()
{
    delete _mainItem;
}


void ViewModel::OnItemCreated(ModelItem * item)
{
    cout << "Item Created: '" << item->GetName() << "'\n";
}


void ViewModel::OnItemDeleted(ModelItem * item)
{
    cout << "Item Deleted: '" << item->GetName() << "'\n";
}

Notes

  • The above code was compiled with Visual Studio Community 2015.
  • If anyone wants to play with the above code, let me know and I’ll put it up on GitHub.
  • I used raw pointers in this code but if this were production code I would use shared pointers instead.
  • If there are significant differences between different derived classes of ModelItem, this type of design can lead to over-generalized signal arguments. For example, if Bird is a ModelItem and so is Tree and we were to add an ItemChanged signal, that signal could get pretty bloated. (Thanks to Joe Bren for pointing this out.)
  • This may cause slowdowns if the calling of signals takes a non-negligible amount of time and/or the tree is extremely deep. (Again, thanks to Joe Bren for this.)