DEV Community

Cover image for BeachHacks 7.0 Experience
Justin Fisher
Justin Fisher

Posted on

BeachHacks 7.0 Experience

Preparation (before the event)

1. Project Manager

There was a lot of preparation to be done in the coming weeks of BeachHacks 7.0. I assigned myself to be the Project Manager, and therefore, I had to ensure that the right people were doing the right jobs. I assigned Alexis Martin to be our frontend developer as he specializes in Frontend and UI/UX. I assigned myself to be the backend developer because I have a growing interest in this field. Finally, I assigned Victor Lee to be in charge of the algorithms needed to make Spotify's user data accessible.

2. Backend Developer

Over the last few months, I've been shifting my focus toward backend development. I knew that this hackathon would be a perfect opportunity to practice and improve upon those skills. Before BeachHacks, I made sure to learn how to use Express.js, Node.js, and MongoDB/mongoose.

First few hours (Planning)

Upon arriving and setting up, we wasted no time getting started. As the lead backend developer, I knew that before writing any code, I would have to design a schema and endpoints, and then communicate that to my teammates. I asked my team to give me exactly the data they would need for the frontend and algorithm sections of our code. We pulled out a whiteboard and got to planning.

Image description

From this whiteboard drawing, I created the MongoDB Schema:

{
  user_info: {
    user_id: String,
    username: String,
    profile_img: String,
  },
  user_data: {
    top_artists: [
      {
        artist_name: String,
        artist_img: String,
        genres: [String],
      },
    ],
    top_songs: [
      {
        song_name: String,
        artist_name: String,
        song_img: String,
      },
    ],
    liked_songs: [
      {
        song_name: String,
        artist_name: String,
        song_img: String,
      },
    ],
  },
}
Enter fullscreen mode Exit fullscreen mode

With this Schema, I was able to know exactly what to grab from Spotify’s API. With the Schema ready we also created a flow chart of exactly how we envisioned our app passing this data.

Image description

With all this documented and ready, I started working on the backend.

Hours 4 - 12 (Creating Endpoints)

There were three endpoints I had to make: two gets of /login and /callback and one post of /compare.

The two gets handled the authorization of Spotify’s API. Within the /login handler we called Spotify’s API function: createAuthorizeURL() which returns a URL. I then redirected the user to this URL which takes them to Spotify’s Login and Authorization page. Once authorized it sends a request to our /callback endpoint in which we use the authorization information to create a token.

Spotify Object

We went with Spotify’s API object design scheme for our project. The object comes packed with all the Spotify HTTP Requests within member functions. The issue was we would need to initialize this object every time we used it in the backend which also meant we would have to pass the token throughout the backend. We found a clever way to fix this issue by creating a singleton Spotify object that ensured no redundant code. That looked like so:

const SpotifyWebApi = require("spotify-web-api-node");

class SpotifyObject {
  static instance = null;

  static getSpotifyObject(
    { redirectUri, clientId, clientSecret } = {
      redirectUri: null,
      clientId: null,
      clientSecret: null,
    }
  ) {
    if (!SpotifyObject.instance) {
      SpotifyObject.instance = new SpotifyWebApi({
        redirectUri: redirectUri,
        clientId: clientId,
        clientSecret: clientSecret,
      });
    }
    return SpotifyObject.instance;
  }
}

module.exports = SpotifyObject;

Enter fullscreen mode Exit fullscreen mode

With the Object initialized, we could now make a call to Spotify’s API and grab the authorized user’s profile information, top artists, and top songs. Of course, these functions gave more data than we would need so I created a parser function that grabbed only the data I needed and that fit the Schema. With this parsed information I was able to create a User object and officially add the User to our MongoDB database using mongoose.

Our /compare endpoint was vital to our project as it handled the main function of our web-app, the calculation of match %. The compare endpoint is hit when the end-user types in an user_id into the front end. We take this email and check if they exist within our database if they do we move on, if not I send back an error to the front end. We then send our two users to Victor’s algorithms which returns an object with the data needed to display to the front end:

//This format was requested by Alexis in the front end
const comparisonObject = {
    screen1: {
      user1_image: user1.user_info.profile_img,
      user2_image: user2.user_info.profile_img,
      other_username: user2.user_info.username,
    },
    screen2: {
      genres: topGenres,
    },
    screen3: { artist: topArtists },
    screen4: { song: topSongs },
    screen5: {
      match: compatibility,
    },
  };
Enter fullscreen mode Exit fullscreen mode

The Final Hours (Tradeoffs and Optimizations)

After a quick 1.5-hour nap, we woke up knowing we needed to get Vibe Check demo ready. To do this, we had to not only fix bugs but also make important trade-offs and optimizations under a time crunch.

Spotify's Genres

Issue: The data we were able to use for our app was heavily limited by the data we could receive from Spotify's API. One of the issues we faced was that only artists had genres attached to them. There were around 5 genres for each artist, and we could grab at most 50 artists per user, adding up to a total of 250 genres per user. We felt as though this may not be enough data to calculate an accurate percentage.

The only option we had to get more genre data was to make a Spotify API call for every single song for every single user. This seemed expensive and something we weren't willing to pursue.

Tradeoff: We ultimately decided that the API calls to get more genres would prove to be too expensive and excessive for our web app. We made this decision because if our app grew, these API calls could grow exponentially and become expensive for us. Instead of grabbing more genres, we made our own predefined, broader genre array that would also count as a match on top of the genres Spotify gave.

Example:

our genres: [”indie”, “r&b”, ...]

User 1: genres: ["indie r&b", "modern indie pop"]

User 2: ["indie rap r&b", "modern indie pop"]

In this example our original algorithm would only have one direct match of: “modern indie pop” but with our new implementation we would cross reference our genres and be able to match indie r&b from user1 with indie rap r&b from user2 under our defined r&b Doing this we greatly improved our match rate.

No matching artists/song

Issue: We soon found out that not every user would be able to have matching artists with another user, making for an anticlimactic frontend experience where there could be an empty screen. We could have additionally parsed through every liked song from each user by making another API call, but we wondered if a user’s liked playlist truly represents their favorite songs.

Tradeoff: We decided that instead of this, the end-user would receive recommended songs from the user they entered. We would accomplish this by simply appending a star to let the user know that this was a recommended song from the requested user. We plan on improving the UI and logic for this before eventual deployment.

Example:

Image description

Why Vibe Check?

I believe that the reason we won the best overall project was our commitment to organization and completion. We were ambitious but realistic with Vibe Check. We valued quality over quantity. We made sure that every feature in the project was well planned out and error-proof so that when we got to demoing, it would work. By separating roles, we were able to focus solely on making our particular part of the project amazing. This resulted in a beautiful front end, a tight backend, and a verbose algorithm creating an impressive final result.

Concluding Statements

As the Project Manager and Backend Developer for BeachHacks, I took on the responsibility of ensuring that our team was on track and that we were making progress toward our goals. I had to make some tough decisions and trade-offs to meet our 24-hour time limit.

Despite these challenges, I learned a great deal about project management and backend development during the event. Specifically, I honed my skills in using Express.js, Node.js, and MongoDB/mongoose, as well as learned the importance of clear communication and planning when working with a team. I also gained valuable experience in making difficult trade-offs and prioritizing tasks to meet tight deadlines. Overall, I am proud of the work we accomplished as a team and am excited to continue growing and improving my skills as a developer.

Top comments (0)