ReadMe, a simple professional networking app built with Node, Postgres, and EJS
In the second quarter of our 6-month Galvanize course we were introduced to the back end at last. Mainly this meant a tour through Node and Express, databases via Postgres and Knex, templating with EJS, and a grab-bag of peripheral topics.
As in the last quarter, we completed the unit with a 1-week self-directed project. We were placed in groups of 3 for this one — a totally different dynamic from the q1 project.
After ~65 hours of code we ended up with ReadMe — a kind of lightweight mashup of Tinder, LinkedIn, and EventBrite, intended to make professional networking events less superficial and more meaningful. If you want to play around, you can sign in as firstname.lastname@example.org, pw ‘barack’. Please don’t wreck the place. A pretty-thorough explainer can be found on the About page.
The big picture — team dynamics
For me, the theme of this project was maintaining momentum, and hitting goals, while working within a group of disparate skill levels.
It seems sensible to talk about this head-on rather than understate it: I was, by far, the most experienced and competent engineer on my team. I’m about 7 years older than my two teammates, already have a whole adolescent career in the software space, and showed up to this course with very few distractions, ready to put my whole self into the learning. These various advantages have meant that I can easily absorb the material from this unit, and that in general I could plan / build / test / commit much faster than my teammates.
The point here is not that I was better-than — this is not a competition, but a rich learning exercise. But the point was for us to be aware of our varying capacities: we needed to all row together, even if our oars were moving different amounts of water. And then the personal challenge for me was to exercise patience and empathy, to accept that I couldn’t go at the same speed as I would solo, and to balance the dual concerns of (a) mentoring my teammates while also (b) shipping code myself.
My role(s) — PM, tech lead, architect
I ended up as the official project manager for the week, as well as de facto tech lead and architect. I tried deliberately not to seize all this responsibility, but my teammates were happy for me to exercise my project mgmt. background. If I did the work to keep us on track, that would free them up to focus more exclusively on writing code.
So as project manager, I kept our backlog organized on Trello and Smartsheet. This meant collecting some initial user stories from my teammates, then writing a lot more of my own, noting issues and assigning them throughout the week.
At my old job, Smartsheet was a mainstay for clearing through milestones. I borrowed some of the formatting that I used in our old project plan, and worked up an API route chart that we gradually checked off throughout the week.
As architect, I drew up the structure for our database. The idea behind the app was to connect people with networking events, but ultimately to each other by way of temporary profiles. We’d need a table for users and events, and then one table to relate users to events, and another to relate users to each other. The ERD went down on a whiteboard, was captured in a photo, and referred to many times throughout the week as we wrote logic for our routes and queries.
We had a brief point of debate on the tech stack. I asked the team if they’d like to try building the front-end as an Angular single-page app, and thus the back-end as a simple RESTful API. They were into that idea, but after some discussion, we concluded this would add complexity and pressure to the project, as I was the only one who had had any exposure to Angular. For that reason we used a more conventional architecture — rendering on the server side with EJS — since our curriculum had explicitly covered this sort of stack in the weeks prior.
Highlights and fun features
I got to build a ton of the functionality for this app, and there were several pieces that I’m proud of:
Learned about blowfish encryption, hash functions, work factors, and so on. Turns out, basic authentication is pretty simple, thanks to the bcrypt npm module.
- Passing relevant data among routes and middleware
We did several things with req.session and req.locals — namely, storing a hashed user_id as a cookie when a visitor is authenticated. We used this for a few other things …
- Friendly redirects with user messaging
If an un-authenticated user hits a protected route, or a user triggers a CRUD operation that changes the state of the app, we use an EJS conditional to render a friendly message in three different flavors — confirms in green, warnings in yellow, and errors in red. The message is persisted using the req.session object, then cleared whenever it’s rendered within a route.
- Basic social functionality
We used a dating-like dynamic where users can request a connection, but that connection doesn’t do anything unless it’s mutual. Checking for mutual connections (and marking the appropriately) was an integral part of CRUD operations on the connections table.
- Responsive design
Since this app was built to be used at networking events we needed to build it mobile-first. This was a lot of fun. Lots of flexbox, lots of vw and vh, and a bit of absolute and fixed positioning. We used BEM conventions for the CSS, wrote 80% of the declarations for a small screen, and added a small section within a media query for desktop users.
- Templating with multi-part EJS files
- Knex Promises — lots of them
This wasn’t a ‘feature’ per se, but just a complexity that we handled nicely. Plenty of our pages required multi-part queries into our database. In these cases we used nested promises, or in some cases Promise.all() to handle the composite payload coming back. We packaged that data into object manifests and then passed them to the view engine for rendering.
OK so how’d it go with the team?
Once the app reached a certain level of complexity, my teammates started asking to work on peripheral features so as to play safely without introducing major bugs. This meant that by about day 4, I had taken over as principal engineer on the whole app, and my two teammates spent the remainder of the week on non-critical features which didn’t entirely make it into the finished product.
^^ Depending on your priorities, this could have been a misstep. On the one hand, I was happy to give my teammates a break, put on my headphones, and go full-throttle to deliver something that worked well, within the allotted timeframe. On the other hand, perhaps my teammates missed out on an important learning opportunity here. We valued product over process here, and maybe I should have insisted that my teammates fight through their bugs and learn more the hard way. Hard to say the best path there.
Suffice it to say, in the back half of the week I got the chance to go full-speed and ship a bunch of features, and my teammates got a chance to focus on learning over producing. At very worst, everyone got out of this week what he put into it, which is just as well.
Wrap up, and what’s next
Our presentation went great, insofar as we got a positive reaction and a lot of encouragement to keep up development of this idea.
So, sometime later this spring, if I find the time, I’m planning on rebuilding this from scratch with a single-page architecture … and probably a new name. This was merely a proof of concept — I doubt anybody would ever use this app alone because it’s clunky and just another app without a huge value proposition on its own.
Rather, with the next-gen rebuild, the idea will be to sit on top of other APIs like EventBrite and MeetUp. This way, our prospective users don’t have to do much to get started, and get some immediate value out of our core proposition. Should be an interesting exercise, at very least.