What I learned building GradConnect - Application Overview
What I learnt about software development while building a job directory and application tracking platform.
The Problem Space
Applying to graduate jobs in Nigeria tends to happen in a few ways.
- You’re part of a WhatsApp community that shares job postings.
- You’re lucky enough to have well-informed friends or colleagues who pass information along.
- You happen to follow the right person on social media.
GradConnect was built to serve as a platform where users can not only find a collated list of graduate opportunities to apply to, but also track their progress on various applications, prepare for interviews with community-led information, and share their experience of graduate recruitment exercises with other users.
This series of articles looks at how I built the platform and the decisions I made along the way.
The Software Architecture at a High Level
At a high level the application was built using the Client - Server architecture. Each aspect has it’s
own repository. A big criteria for me was being able to have a plug-and-play kind of application where I
am able to make changes without affecting or breaking the whole application. This is why for the client,
I opted to use NextJs and for the server Go.
Why Next.js?
I’ll be honest: I don’t have strong opinions on React frameworks. I have a foundational understanding of JavaScript and React, but not enough depth to argue that one framework is meaningfully better than another for a project of this size. So my decision came down to practical factors: Next.js has excellent documentation, a large enough community that I could find answers to most questions quickly, and a deployment story that didn’t require me to learn a whole new platform. File-based routing and server-side rendering out of the box were nice bonuses for a content-heavy site like a job directory.
In short: I picked the tool that would let me learn as I built, rather than one I’d have to learn before I could build.
Why Go?
The more interesting choice was on the server side, where I had to pick between the two languages I actually know well: Python and Go. Three things tipped the decision toward Go.
Type enforcement that actually means something. I wanted a codebase where a number remained a number. Python has type annotations, but they’re optional and not enforced at runtime. That means the temptation to write code that “just works” without a concrete understanding of why is always there. Go’s compiler doesn’t give you that option, which I find forces clearer thinking up front.
A simpler dependency story. I didn’t want to spend time managing virtual environments or worrying that upgrading one package would break three others. I know tools like uv and pyenv make this much better than it used to be in Python, but Go’s module system and single-binary builds remove the problem rather than manage it. For a side project I want to ship and forget about for weeks at a time, that matters.
A standard library that does the boring parts well. Go’s net/http is production-grade out of the box, and the
standard library covers most of what a small backend needs without pulling in a dozen dependencies. Combined with Go’s
strictness around error handling, this nudged me toward writing code I’d still understand six months later.
In the next post, I’ll walk through the actual architecture, how the client and server talk to each other, where the data lives, and the first set of decisions that will affect how much this thing costs to run.