Golang Meetup Map - 3 Days to Put Markers on a Map. Dear Jelly Beans, Why.

Golang Meetup Map - 3 Days to Put Markers on a Map. Dear Jelly Beans, Why.

TLDR (Spoilers)

Introduction & Showcase

This is the Golang Meetup Map (Github). It takes in a csv input and deploys a webpage that has locations and links to the given meetups on a map.

meetups.csv made very pretty by GitHub

Now Let's Discuss It

Righto. It started with a simple question. What meetups are currently happening? As an organizer of London Gophers I realized I didn't have full knowledge of all the other meetups that were taking place in London, let alone the UK. I didn't want to accidentally have a meetup on the same night as another meetup.

Inspired by my time as an open-mic comedian where a Map of London open mic nights (created by @apuchitnis), made it easier for me to apply and find events. I went to Twitter to ask a question, for the first-ish time.

I got a response, which is an ∞% increase on what usually happens, which directed me to the Developers Conference Agenda (DCA) created by @aurelievache.

It's a pretty amazing initiative and it is incredibly easy to contribute to. You simply need to add your conference to the Readme and it will be featured on the deployed Github Page

Screenshot of the DCA Github Repo, but not the DCA Github Page. Don't ask why.

The only issue is that it covered conferences, not local meetups. Wouldn't it be interesting to marry the two projects together?

Not only to challenge the traditional views of matrimony, but it had been a hot eternity since I'd done a side-project.

MVP Stands for Something or Other

I started drawing up an MVP (Minimum Viable Product) of the 'Gophers Meetup Map'. (A better title, but it's too late now).

I wanted it to be simple. In this recent PR to the DCA  all this contributor had to do was identify the correct place to put their conference, format it correctly and open a PR.

MVP

  • A user can upload changes via CSV.
  • A user can view their meetup on a map.
  • A user shouldn't need to have in-depth knowledge of the internals to upload a meetup.

That's it.

That Wasn't it

I was a bit concerned about starting a new side-project because I thought the side-project police might be on my butt, for not doing anything for 3 years. But then I remembered that I had made them up.

This next section will be a brief run-down of my thought patterns and how I ended up with my current MVP solution.

Road to MVP

Reacting to React

The first step of any project that's been inspired by another project is to copy the project entirely and paint it blue.

The Comedy Map used React however, it soon came apparent React is something I've heard of and that's about it really.

After installing NodeJS via Scoop and getting the default react app running, I decided to bid a hasty retreat.

It's just sitting in my file system. Menacingly.

I knew I wouldn't be able to make a lot of progress, unless I fully understood the tool I was using. And that node_modules folder was around 260MBs of no thank you.

“The best time to learn React was years ago. The second best time is now. But, not if you really really want to get some work done like right now” - Jaminologist

Hugo

Next was Hugo. The London Gophers website was built using Hugo, before my time unfortunately. (By the way the webpage is slightly out of date, I should probably get on that)

I looked around for examples of using Maps and stumbled across this showcase thread that showed off the below site.

Year of the Sunrise • Every sunrise since January 1, 2019
Michigan photographer, Bugsy Sailor, has been photographed every sunrise since January 1, 2019.

Look how absolutely beautiful this Map is!

Credit (@BugsySailor https://yearofthesunrise.com/)

I was tempted, but something else tempted me more. Something from the past.

"What's the quickest way, I could just slap a map on a page and have it look alright?" I asked myself dramatically.

Bootstrap, Baby!

Bootstrap
The most popular HTML, CSS, and JS library in the world.

I can't believe I'd forgotten about Bootstrap. It's on v5, now. It's just living its best life without me.

Bootstrap has a few more extra things, but it's still easy to use. If you're like me and don't understand anything about Frontend development and just want something to be able to look at while you're building an MVP, it's top cat.

Using it again it felt like a cupcake I hadn't eaten since Christmas. Somehow, still in date. In fact, thriving better than ever. And oh so sweet and nostalgic.  

Now, how do I pop in a map?

Google Maps Called, They're Asking About The Rent.

At first I thought Google Maps was the go-to when it comes to Mapping stuff. They have all the data after all.

However, as I was taking a peek at the documentation there was a lot of talk about an 'API_KEY'. Then I saw the usage and billing section.

When I found myself fiddling with the pricing table having not done any work towards an MVP yet, I decided to bid a hasty retreat.

Maybe there's a free option or a lower-limit, but for a small personal project where I wanted to put some funny gophers on a map, I couldn't take these chances.

I didn't want an AWS situation happening

Source:https://old.reddit.com/r/ProgrammerHumor/comments/wrv9v4/personal_projects_in_the_cloud_be_like/

A leaflet on Leaflet

Leaflet.js is great. After all my above research I went on their site, checked out the tutorial, grabbed the code and boom I had a marker on a world map. Job done.

To slightly break tone, if you visit the Leaflet.JS webpage, at time of writing, there is a message from the maintainers. The creator of Leaflet.js is a Ukrainian Citizen who was forced to leave their home due to the ongoing conflict with Russia.

If you have the time I'd recommend visiting the page and giving the message a read, as well as supporting the charities suggested if you are able to.

Leaflet — an open-source JavaScript library for interactive maps
Leaflet is a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps.

I felt it would be improper of me not to mention the above as the work of the both creators and maintainers were critical to this side project.

So We Have The Pieces. But Do We Have Pie Instructions?

With the investigations out the way this was the final MVP stack

  • Go
  • Bootstrap
    • Website layout
  • Leaflet.JS
    • World Map and Custom Markers

And with that I was able to transform this

Name,Date,Icon,Link,Latitude,Longitude
September London Gophers,2022-09-21,LONDON-GOPHERS-300.png,https://www.meetup.com/londongophers/events/287490695/,51.521282,-0.080945
Women Who Go London,2022-09-27,women_who_go_london_400x400.jpg,https://www.meetup.com/women-who-go-london/events/287816448/,51.509335,-0.081453
Go meetup @ Cloud Pirates (Amsterdam),2022-09-28,default.jpg,https://www.meetup.com/golang-amsterdam/events/288223636/,52.375840,4.926071
October London Gophers,2022-10-19,LONDON-GOPHERS-300.png,https://www.meetup.com/londongophers/events/287490709/,51.507217,-0.127586
Example CSV Input

into this

Code Snippets That Don't Really Explain Much

To go over some parts of the code, you have a template index.html that has Go templating syntax {{range .Meetups}} (Loops over an array of Meetups objects).

    // This section loops over the Meetups and puts the markers on the Map
    {{range .Meetups}}
      var icon = L.icon({
      iconUrl: "icons/{{ .Icon}}",
      iconSize: [40, 40],
      popupAnchor: [0, -20]
          });
       var latitude = "{{ .Latitude}}"
       var longitude = "{{ .Longitude}}"
       var marker = L.marker([latitude, longitude], {icon: icon})
      .addTo(map)
      .bindPopup("<b><a href=\"{{ .Link}}\" target=\"_blank\">{{ .Name}}</a></b>");
      marker.on('mouseover',function() {
        this.openPopup();
      });
      marker.on('mouseout',function() {
        this.openPopup();
      });
    {{end}}
snippet from index.html template

This is then fed into the program that uses the csv data to create an array of 'Meetup' objects to then generate the web page with all the meetup information and map markers.

      var icon = L.icon({
      iconUrl: "icons/LONDON-GOPHERS-300.png",
      iconSize: [40, 40],
      popupAnchor: [0, -20]
          });
       var latitude = "51.521282"
       var longitude = "-0.080945"
       var marker = L.marker([latitude, longitude], {icon: icon})
      .addTo(map)
      .bindPopup("<b><a href=\"https:\/\/www.meetup.com\/londongophers\/events\/287490695\/\" target=\"_blank\">September London Gophers</a></b>");
      marker.on('mouseover',function() {
        this.openPopup();
      });
      marker.on('mouseout',function() {
        this.openPopup();
      });
Spot the bug, I can see it and I'm currently sighing loudly

Now, how do I deploy the generated page to the web?

How I Deployed It To The Web.

Spoilers it's GitHub Pages and Actions

Github Pages

I'd never used Github Pages, but it seemed a good enough fit. And the other two projects that inspired this project were using it and who I am to stop copying from them now?

You can use GitHub Pages to host a website about yourself, your organization, or your project directly from a repository on GitHub.com. - About Github Pages

And if the repository is public the hosting is free, so that's always nice.

However, I wanted to build the website using the template via Go and then have it hosted.

GitHub Actions

On no, it's yaml.

It's just sitting in my repo. Menacingly. And I have to talk to it this time :(

I have used Github Actions before, so won't delve too long, but in short it's a way of running a set of commands, known as workflows, that allow you automatically test and deploy your code, among many, many other things.

There's also this awesome action that allows you to deploy to a gh-pages branch. This mean you can build your website and then slap it on a branch, and Github slaps it onto the internet. A veritable chain of light assault.

However, there are currently two smalls things that I found a bit tricky with Github Actions.

  1. How do I test the workflow locally? (Right now, I decided to look that up and found out that maybe you can using Act)
  2. How do I see the exact steps an action is doing.

To continue with point 2, from what I understand, actions are a bunch of commands wrapped together that can have configurations and are then run.

It would be interesting  if you could 'unpack' the action, just to see the steps and commands it was running.

So, in future if I wanted to use a small part of the action (such as pushing to a git branch) I'd be able to see how it was done.

Now, I'm 100% sure this is possible to do, I mean the code and repositories are public I just didn't get a chance to have a long look. Do feel free to let me know if it is.

We've Reached the End so what's next?

While working through this, there were still a few stretch goals I'd like to investigate as well as questions/issues with the current version.

Questions/Issues

  • Having to add an icon of your meetup, might be too big of a step for a contributor, perhaps having only one default icon across everything is fine?
  • If someone outside of the maintainer group adds to the csv, the tests don't run without approval, which could add some friction. But, it makes sense as bad actors exist.
  • What information should be included on the website? The webpage is a bit barren and doesn't explain much.

Stretch Goals

In this recent PR for the DCA, this contributor, updated and archived any conferences that were out of date.

Something I'd need to do for this map. If a meetup is in the past it should not be on the map.

Could this be done automatically? As we already know how to build a template and then deploy it, couldn't a new CSV be built that auto-archives, sorts it self, deletes out-of-date information and then saves the new version in the repo?

Could Golang Meetups be gathered using the Meetup.com API and then have a PR opened with the updated csv, including the icon?

Could the website look a bit prettier and be user-friendly/intuitive to use? (Yes.)

Still, it's something to chip away on and seems like a fun thing to try out and stretch those side-project skills. And perhaps get the police off my back. The ones in my head, not the actual police, that's another blog post.

Au Revoir 👋🏿