16 minute read

HelloThere

Hello, and welcome! Charlotte Third Places is a project I built to help people explore various ‘third places’ around Charlotte, North Carolina. Third places are social environments separate from home (the “first place”) and work/school (the “second place”) where people come together to build community, exchange ideas, and relax. Think coffee shops, cafes, libraries, casual restaurants, and the like. You can read more about third places as a concept here.

In short, third places play a crucial role in building connections and creating a sense of belonging beyond the confines of home, work, or school. When I first moved to Charlotte, these spaces were invaluable to me. My personal list of third places grew so much that it eventually needed a more organized solution—leading to the creation of Charlotte Third Places. You can check out the project below, or keep reading to see how it was built.

Project Background

I’ll start by establishing that this project is 100% over-engineered, and that’s by design. Have you ever heard the phrase “this meeting could’ve been an email”? Well, this project could’ve been nothing more than a well-organized spreadsheet.

When my list of third places outgrew my notes app, creating a spreadsheet and sharing it with people would’ve been the simplest path forward. In fact, I did exactly that, the first part at least. I transferred my list to an Airtable base, which is essentially a fancy spreadsheet with low-code, database-like functionality. Once I had the data in Airtable, I realized I could easily experiment with it using their API, and that’s when the real fun began. I hit pause on sharing the base because I knew wanted to do something else. Something cooler. Something greater. I wanted to use this project as a learning opportunity. As a chance to play around with frontend development, a domain I don’t use much in my day job (where it’s mostly backend data engineering in Python, Scala, and SQL on Azure).

That’s where the over-engineering came in. It wasn’t because I didn’t understand how simple this project could be. In fact, it was precisely because the concept was so simple that I wanted to challenge myself to do more—and learn as much as I could along the way. Some might say the entire point of a side project as a developer is to over-engineer things in service of learning. Here’s a classic Hacker News thread on the topic. I’m not saying I fully agree with that sentiment, but I am saying I took my time building this site because I wanted to explore. Like sure, you can stick to the linear path in an open-world RPG, but you miss out on so much cool stuff playing that way. Game developers literally spend hours creating things that you only discover if you meander. It’s about the journey sometimes, not the destination.

That being said, my journey to getting this project live was longer than I would’ve liked. It turns out working on hobby projects can be challenging when you have a day job, so the speed of development wasn’t exactly Facebook Meta level “move fast and break things”. There were plenty of times where I met people interested in viewing my list and had to tell them to “wait a week or two” for me to finish the project. Some of those people waited months. There’s at least 1 who waited a year. If you’re reading this, my bad G. Life be lifin. The project is live now, and I’m glad for it. Scroll through the sections below to learn how it was made.

Frontend

Here are the frontend software development tools used to build this project.

Vercel

Vercel is the most developer friendly cloud platform I have every used. Seriously. They have done such an amazing job of making software development and deployments painless for developers. Particularly for hobby projects. Everything just works off your GitHub repo, you can configure most things, either via their portal or a .json file, the documentation is clear and well-written, they have a generous free hobby plan that won’t surprise you (at least, not anymore) with charges. It’s just an all-around awesome platform. Charlotte Third Places is hosted on Vercel. They also happen to be the creators of Next.js.

Next.js

Next.js is the framework behind the site. There was once a time where people wrote vanilla HTML, CSS, and JavaScript to build websites. Those days are long gone. This article has a pretty good accounting of how we got to our present era of frameworks on top of libraries on top of other libraries on top of frameworks. React has emerged as the winner of the JavaScript library race, and Next.js as the framework on top of it (although Remix is rising). Don’t take my word for it though, just reference the latest Stack Overflow Developer Survey for evidence.

These days, there’s so much overlap between the React and Next.js (developed by Vercel) development teams that some are concerned they’re one and the same. Seeing as this is a hobby project, I’m not with the drama when it comes to the trend-chasing nature of frontend development. Everyone and their mama is using Next.js, including many popular websites you’ve likely used. That’s enough justification for me to use it. My experience has been mostly good, although the app router seems overly complex.

React

Next.js is a React framework, so Charlotte Third Places is by extension a React website. React is king. It beat Angular, it beat Backbone, it beat Ember, it knocked out Knockout. The debate is over. React is the JavaScript library of the web. That being said, it has its pros and cons. Among the cons is its complexity. Most of us using React aren’t solving the level of problems Facebook Meta was facing when they created it, but we all benefit from the truly groundbreaking innovations they’ve brought to web development through it. The React team goes hard. Seriously. They’re some of the best software engineers on earth.

These days, the official guidance from React is to use a framework to get started, which says a lot. They’re basically going “lol kid, nobody writes plain React anymore” which to me is like, really? That’s where we’re at now with frontend development? React is already an abstraction over the DOM, it’s primarily written with TypeScript, which is an (awesome) abstraction over JavaScript, and now we have meta-frameworks like Next.js and Remix as abstractions over React itself. So yeah, welcome to web development. As developers, I feel like we have been hoodwinked, bamboozled, led astray, run amok, and flat-out deceived.

We’re all awash in a cauldron of complexity, crafted by genius web developers who built solutions to problems that are far less common than the frameworks they unleashed on the world would have you believe. I know that Facebook Meta needs Server Side Rendering and Incremental Static Regeneration, but do you? Do you really? I think most websites really could survive, and work well, with just HTML, CSS, and JavaScript (or some good old jQuery). That being said, I do really like TypeScript. TypeScript is fun. I’ve suffered under the ambiguous hand of JavaScript before, and coming from the backend side of development, writing code for the web that’s type-safe and properly linted was a joy.

To be clear, I write partially in jest here. I like building software—frontend, backend, complex, simple, framework, no framework, it don’t matter. I’ll figure it out, and have fun along the way.

Shadcn/UI

Styling is one of the hardest parts of web development, which is why style libraries have become so popular. There are countless options, each with its own pros and cons. Among them is shadcn/ui, which stands out because it’s not a traditional library. Instead, it’s a set of reusable components that you, as a developer, copy directly into your app and fully own. Unlike typical libraries where you rely on a third party to maintain updates as the web evolves, with shadcn/ui, you have complete control. You own the code from the start, it works out of the box, and if something needs changing, it’s entirely up to you. Yet, there’s still community support, since plenty of other developers are taking the same approach. Shout out to shadcn for creating a solution that became so popular, Vercel brought him onto their team. Charlotte Third Places relies heavily on shadcn/ui components, and they work beautifully throughout the project.

That being said, shadcn/ui is built on top of yet another library: Radix UI. Radix UI, in turn, is built on React, continuing the layering of abstractions that has become so common in modern web development. So, to break it down: we have Next.jsshadcn/uiRadix UIReact. And oh, throw Tailwind CSS (more on that later) somewhere in there. So yeah. Welcome to web development.

Tailwind CSS

I’m going to try and not say anything snarky about Tailwind CSS, a CSS framework that gives you shorthand classes and configuration for streamlined styling. It’s, I mean it’s yet another abstraction on top of a foundational building block of the web, Cascading Style Sheets, which itself has grown so much in capability that I question if you really need a framework on top of it (looking at you SASS and LESS). Charlotte Third Places uses Tailwind CSS because shadcn/ui uses Tailwind CSS. It’s an inherited dependency. I don’t dislike it. It makes some things easier, other things harder, and overall, it works well. So, yeah. I think I managed to not say anything snarky.

Backend

Here are the backend software development tools used to build this project.

Airtable

The data storage solution. I started with the notes app on my phone before moving to Airtable. I then second guessed my decision and spent some time writing a NoSQL Firebase Firestore solution. I quickly realized Firestore wasn’t the answer when I found myself writing custom rules to support consistent schemas across documents. NoSQL is a great (webscale) solution for unstructured data, like social media, but that wasn’t what I was dealing with, so it wasn’t for me. If you ever find yourself considering NoSQL, and Firestore specifically, read these articles first. They helped me reach a “it’s a no from me dawg” place of enlightenment.

I then wanted to try my hand at PostgreSQL. I’m familiar with Transact SQL and Spark SQL, as they’re consistent parts of my day job, but PostgreSQL is truly its own cool thing. Read this article, and this discussion thread, to learn why. The open source community around Postgres is incredible. I wanted to hop in and make something in that universe. I’m sure one day I’ll find a way to.

Anyways, the places data for this project is stored in an Airtable base. User feedback is also collected through Airtable forms, which write directly to the same base. It’s easy to use, has a solid API, a mobile app that let’s me edit things easily, webhooks, and a generous free plan. Airtable rocks for projects like this. I’m dealing with less than 1 GB of actual data. I don’t need NoSQL or a RDBMS. Airtable will do.

Now, that doesn’t mean I won’t come back to over-engineer the data side of this project sometime in the future. You know, for learning purposes. Growth mindset and all that. I’ve got my eye on Supabase if I do.

Google Maps API

My best friend on this project, Google’s Maps API, specifically the Places API. Much of the data for the places on the site is pulled directly from Google Maps. Information like whether a place has free parking, requires a purchase to use services, offers outdoor seating, or is good for children, dogs, and groups is all available through the Google Maps API. Google seems to know everything about everyone and every place everywhere. It’s a bit scary really, but I try not to think about it. You know, set your mind on things above and such. Got to stay positive. It might be a good time to reread 1984 though. Or Brave New World, which I’ve always thought more realistic. Just saying.

Azure Functions

Azure Functions are one of many “serverless” function solutions available today. Despite the name, “serverless” doesn’t mean there are no servers involved—it just means you don’t have to worry about managing them. In simple terms, a serverless function is a piece of code that runs in the cloud, triggered by an event (like an API call or a scheduled task), that automatically scales to handle the load. You only pay for the time it runs, not for keeping a server up and running 24/7. It’s like renting a power tool by the minute instead of buying and storing one for occasional use. But just to be clear, there is a server—it’s just managed by someone else. The “serverless” part is more about convenience and flexibility. As a general rule, always remember, there’s no such thing as “the cloud”, it’s just someone else’s computer.

Anyways, the code that interacts with the Google Maps API and Airtable runs as a Python Azure Function. There’s also logic for retrieving Google Maps reviews through a platform called Outscraper, which bypasses limitations in the native API on how many reviews can be retrieved for a place. That part is handled by an Azure Durable Function. The review data is used for AI-driven sentiment analysis, with the goal of generating adjectives to describe the ambience of each place. This feature is a work in progress and should be visible soon, though it’s not live yet (as of Fall 2024).

Overall, I can’t say I’m terribly enthusiastic about Azure Functions. They work, but the Python implementation has some annoying bugs. This is one area of the project in scope for a rewrite. I’ve got my eye on Vercel Serverless Functions, which also support Python. I’m already hosting on Vercel and using Next.js. Might as well complete the trifecta. You might ask, aren’t you worried about platform lock in? I’d say no, I’m not. Maybe I should be, but I’m not. I try not to worry about tomorrow. Also, I’m not running an Enterprise software solution out here. It’s a side project. If Vercel goes down, I’ll be screwed alongside plenty of others out there. At least we’ll be suffering together.

Others

Here’s other stuff that was used for this project.

  • GitHub Actions - Automation for tasks like periodically refreshing Airtable with data from Google Maps, deploying changes for the Azure Function, and deploying the site itself to Vercel. It’s a powerful tool, well built, very demure. I don’t think I used that now memeable word right. I don’t care.
  • Microsoft Designer - It’s a bit more than just a wrapper around DALL-E. Microsoft has some really cool stuff going on here. Most notably, you can create AI generated icons without a background, so full cutout style. That’s how I got some of the imagery for the site. The thumbnail for this article was generated using Designer as well.
  • Python - My favorite programming language, used for all the data interactions with the Google Maps API, Airtable, Azure Functions, etc.
  • TypeScript - My chosen language for writing React code (the other option is vanilla JavaScript). If you’re coming from the backend side of engineering, I can’t suggest TypeScript enough. It’ll help you stay sane.
  • React Icons - This is cool. You install 1 library and can access just about every Icon set out there. My Icons component makes full use of this. Great project.
  • AG Grid - A seriously awesome data grid/table solution. The team of developers here really outdid themselves. The home page of Charlotte Third Places with cards for each place is built on AG Grid. It’s how all the filtering and sorting is made possible. Whenever I wanted to try and add a feature to the list logic, I’d find it as a simple configuration option in AG Grid. This thing was built by developers for developers, and it’s awesome.
  • Incremental Static Regeneration - This feature from Next.js prevents me from hitting Airtable’s API limits. When you visit Charlotte Third Places, the page doesn’t immediately make an API call to Airtable. Instead, the data is fetched every n hours, cached, and then served to users until the next refresh. It’s a nifty feature—a static page that doesn’t have to be fully static. I know I memed about this feature being overkill earlier in this article, only to reveal now that I’m using it. Well, I can poke fun at something and still acknowledge its merits, can’t I? Why yes indeed, I think I can.
  • React Google Maps - A project by vis.gl that’s responsible for the embedded map view of the places. There’s confusion as to what library is the library to use if you’re implementing Google Maps in React. This is the one Google now officially recommends, but it took them a while to get there. There was great need for standardization, see this post for details on how convoluted the Google Maps in React space is (or was).

Tools I Explored But Didn’t Use

Here’s some tools I explored but ultimately didn’t use for the project.

  • React Native - My first thought for this project was to make it a cross-platform application. Web, iOS, and Android, all using 1 codebase. I did a lot of React Native vs. Flutter research and settled on React Native after some drama in the Flutter community regarding Google’s direction for the project. After about a month of working with React Native (and Expo, which is actually great), I was like, it’s a no from me dawg. This is a side project. A passion project. A hobby project. React Native was giving me headaches I just couldn’t justify for something I wanted to work on for fun. Pivoting to a simple React website made development a lot more fun.
  • Flutter - I’ll start by saying, any framework made or maintained by Google gives me anxiety. Their infamous reputation for killing products has impacted me more than once. I’m scarred, as are many others. Just check out the Google Graveyard to see some examples. That being said, I gave Flutter a full unbiased evaluation, and there was a lot to like, and some stuff to be concerned about. This article from Stack Overflow helped a lot in my evaluation. Another thing that increased my apprehension with Flutter is its use of Dart. It’s just not a language I was looking to build expertise in. Read through this thread for commentary on why it isn’t more used as a programming language.

Closing Thoughts

There you have it, the tech stack revealed. Charlotte Third Places was a labor of love born from a passion to explore and grow. It could’ve been simpler, but embracing a bit of complexity turned it into a rewarding challenge that pushed me to learn more. If you’ve read this far, thanks for reading! You can check out the project using the links below.

Tags:

Categories:

Updated:

Comments