Skip to main content

How to Build Things When You’re the Entire Dev Team

00:13:32:79

Hello, my dear friend!

If you’ve ever tried to build an entire project by yourself, you probably already know where this is going.

It Usually Starts With One Small Feature

There’s a particular moment in every solo developer project.

It usually happens somewhere around 1:13 a.m.

You started the evening thinking:

“I’ll just add authentication.”

Three hours later, you have 14 browser tabs open.

One is a seven-year-old Stack Overflow answer.

One is a Reddit thread where two strangers are arguing about JWTs.

One is the documentation for a service that wants $79/month.

One is a YouTube video recorded by a guy whose microphone sounds like it’s inside a washing machine.

And somewhere in the middle of all that... you realize you are no longer “adding authentication.”

You are designing infrastructure.

Welcome to building software by yourself.

It’s chaotic.

It’s frustrating.

And, weirdly enough, it might be one of the best ways to actually learn how software works.

The Beautiful Problem With Being the Only Developer

When you work on a large engineering team, problems have owners.

Frontend problem?

Frontend team.

Database issue?

Backend.

Deployment?

DevOps.

Analytics?

Data team.

Design?

Someone sends you a Figma link.

But when you build something alone, every problem eventually walks back into your office.

Which is unfortunate.

Because your office might also be your bedroom.

And the engineering team is you.

You choose the database.

You design the schema.

You build the UI.

You figure out authentication.

You deploy the application.

You monitor it.

You break production.

You discover that production is broken.

You fix production.

You then spend twenty minutes wondering why everything worked perfectly on localhost.

This is the hidden advantage of solo projects.

They force you to understand the entire journey between:

“I have an idea.”

and:

“Someone on another computer can actually use this thing.”

Those are very different achievements.

A developer can spend years writing code without ever having to understand how all the pieces fit together.

A solo project doesn’t really give you that luxury.

Eventually, everything becomes your problem.

And that is exactly why you learn so much.

Start With the Product, Not the Architecture Diagram

Developers have a dangerous hobby.

We like designing systems that do not need to exist yet.

You decide to build a movie recommendation website.

Twenty minutes later you’re thinking:

“Should I use Kafka?”

No.

You should probably display a movie first.

One of the best questions you can ask at the beginning of a project is:

What is the smallest version of this that would actually be useful?

Not impressive.

Not infinitely scalable.

Not something worthy of a conference talk.

Useful.

Imagine you want to build an app where people save interesting restaurants.

Your first architecture probably does not need:

  • Kubernetes
  • microservices
  • Redis
  • Kafka
  • three databases
  • an event-driven architecture
  • an AI recommendation engine
  • a service mesh
  • seventeen Docker containers

You need a user.

A restaurant.

And a Save button.

Congratulations.

You have a product.

Everything else can come later.

This sounds obvious until you watch developers spend two weeks building infrastructure for an application with zero users.

Cheap Constraints Are Surprisingly Good Teachers

Eventually your project needs something expensive.

Image storage.

Email.

Maps.

Search.

Video.

Hosting.

Analytics.

Background jobs.

Some API you were absolutely sure would be free.

And then you discover that the beautiful service from the tutorial costs more per month than the current revenue of your company.

Which is zero.

This is where things get interesting.

Because being broke is occasionally an excellent systems architect.

Suppose you need to store thousands of images.

The obvious solution might be:

“Throw them into the first cloud storage service I know.”

Maybe that works.

But then you look at bandwidth costs.

So you start investigating.

Could the images be compressed first?

Could you generate smaller versions?

Could they be cached through a CDN?

Could rarely accessed images use cheaper storage?

Could some assets simply ship with the application?

Do you even need to store every image?

Suddenly the problem changes.

You are no longer asking:

“Which storage provider should I use?”

You are asking:

“Why am I storing this much data in the first place?”

That second question is usually much more valuable.

A lot of optimization happens this way.

Not because somebody woke up particularly excited about efficiency.

But because the bill looked terrifying.

The Sneaky Solution Is Often the Educational One

Some of my favorite discoveries in programming happen immediately after this sentence:

There has to be another way.

Need search?

Before immediately paying for a dedicated search platform, maybe PostgreSQL full-text search is enough.

Need a queue?

Maybe your existing database can handle the workload for now.

Need analytics?

Maybe you don’t need to collect seventeen million events.

Maybe five carefully chosen events tell you everything useful.

Need a CMS?

Perhaps a small admin page gives you 90% of what you actually need.

Need some automated process?

Maybe a scheduled job is enough.

The point isn’t:

Always use the cheap solution.

That becomes its own form of stupidity.

The point is:

Understand what you are actually paying for.

Sometimes the expensive service is absolutely worth it.

You might be buying reliability.

Engineering time.

Security.

Compliance.

Support.

Or infrastructure that somebody else has already spent ten years figuring out.

That can be an incredible deal.

But you should know why.

“Everyone uses it” is not architecture.

Why Use PostgreSQL Instead of MongoDB?

Developers love questions like this.

Unfortunately, the real answer is deeply annoying:

It depends.

But that answer becomes useful once you understand what it depends on.

Say your application has users, orders, products and payments.

Those things have relationships.

Users create orders.

Orders contain products.

Payments belong to orders.

Relational databases are extremely good at this.

So PostgreSQL starts looking rather attractive.

Now imagine you are storing huge quantities of documents whose structure changes constantly and relationships between those documents are much less important.

A document database might become attractive instead.

Neither technology is magically “better.”

Technology only makes sense relative to a problem.

This applies everywhere.

React versus Vue.

Rails versus Django.

REST versus GraphQL.

AWS versus a tiny VPS.

Serverless versus a server that simply sits there minding its own business.

The useful question is rarely:

Which technology is best?

It is:

Which problems am I accepting by choosing this technology?

Every tool solves problems.

Every tool also introduces new ones.

Good engineering is often choosing the problems you would rather have.

Google Is Part of Programming

There is a weird insecurity developers sometimes have about searching things.

As though “real programmers” are supposed to remember every API method, Linux command, SQL function and Docker flag.

They don’t.

Programming is not a memory competition.

If I forget the exact syntax for a PostgreSQL window function, I search it.

If nginx gives me an error I have never seen before, I search it.

If a framework suddenly decides my database relationship has offended it personally, I search it.

The important skill isn’t memorizing every answer.

It’s learning how to find trustworthy answers quickly.

And that takes practice.

The difference between these two searches is enormous:

“my docker doesn't work”

and:

“Docker Compose PostgreSQL connection refused localhost container”

The second query contains context.

Technology.

Failure mode.

Environment.

That makes Google much more useful.

Good developers don’t necessarily know everything.

They get good at reducing uncertainty.

Reddit Is Weirdly Useful

Official documentation tells you what software is designed to do.

Reddit often tells you what happens after you actually use it.

That distinction matters.

Imagine you’re choosing between two hosting providers.

Their websites both say:

FAST.

SCALABLE.

DEVELOPER FRIENDLY.

REVOLUTIONARY CLOUD INFRASTRUCTURE.

Fantastic.

That tells you almost nothing.

Now search:

provider name reddit

And suddenly you start finding things like:

“Deployment was easy but database pricing became painful after six months.”

Or:

“Support was excellent when our production server died.”

Or:

“Everything is great except this bizarre limitation nobody mentions on the pricing page.”

This is useful information.

Not necessarily correct information.

Reddit is still Reddit.

One person having a bad Tuesday does not constitute an infrastructure benchmark.

But it exposes you to problems marketing pages conveniently forget to mention.

YouTube Is Excellent for the Part Documentation Skips

Documentation is fantastic when you know what you’re looking for.

YouTube is fantastic when you don’t.

Sometimes you don’t need an API reference.

You need someone to show you the entire mental model.

How does Docker actually fit into deployment?

What happens between typing a URL into a browser and your backend receiving the request?

How does OAuth actually work?

What exactly is happening when Git says rebase?

A good twenty-minute video can give you the map.

Then documentation gives you the street names.

I like thinking about technical research this way:

YouTube gives you intuition.

Documentation gives you precision.

Google gets you unstuck.

Reddit shows you scars.

GitHub shows you how people actually built it.

You want all of them.

GitHub Is Where Things Get Real

There is another place I increasingly find myself searching when something behaves strangely.

GitHub.

Not just repositories.

Issues.

Discussions.

Pull requests.

Source code.

Sometimes the official documentation tells you what a library is supposed to do.

Then you open GitHub and find an issue saying:

“Yeah, this breaks specifically on version 4.7 when running behind a reverse proxy.”

Excellent.

That would have been useful three hours ago.

But this is also where you begin understanding open-source software differently.

A dependency stops being a magical black box.

You can inspect it.

You can see why something behaves the way it does.

You can read conversations between the people who designed it.

Sometimes you even discover that the mysterious bug destroying your afternoon was fixed eleven days ago.

You just haven’t updated the package.

Which is simultaneously wonderful and slightly embarrassing.

And Then AI Showed Up

AI made this entire process stranger.

Because now, instead of searching through ten Stack Overflow posts, you can type:

“Why is this failing?”

And receive an answer immediately.

This is amazing.

It is also dangerous.

Because AI is extremely good at producing code that looks like code written by someone who knows what they’re doing.

That is not always the same thing as code written by someone who knows what they’re doing.

The worst way to use AI is something like this:

  1. Ask for a feature.
  2. Copy the code.
  3. See that it runs.
  4. Move on.

Because now your application contains code you do not understand.

Do that fifty times and something interesting happens.

You are no longer really the developer.

You are the person responsible for a mysterious codebase generated by a very confident intern.

And the intern has disappeared.

Use AI as a Very Fast Technical Partner

AI becomes much more useful when you make it explain itself.

Instead of:

“Build authentication.”

Ask:

“Give me three ways to implement authentication for this application. Explain the security risks, complexity, costs and what makes each approach appropriate.”

Now you’re learning.

Instead of:

“Fix this.”

Ask:

“Explain why this fails first. Then show me the smallest fix.”

Instead of:

“Optimize my database.”

Ask:

“Here is my query and execution plan. What is PostgreSQL doing, where is the expensive operation, and what indexes could help?”

The difference is enormous.

You are not outsourcing thinking.

You are accelerating it.

AI should make your feedback loop faster.

It should help you ask better questions.

It should expose you to solutions you did not know existed.

It should help you understand code that would otherwise take an hour to unpack.

But eventually you should be able to look at the solution and say:

I understand why this works.

Because production has a cruel habit of asking questions that weren’t included in your original AI prompt.

Sometimes AI Makes You Worse

There is another problem.

AI removes friction.

And friction is annoying.

But some friction is educational.

Before AI, if I needed to understand something unfamiliar, I might spend thirty minutes reading documentation, looking through examples and understanding how the pieces connected.

Now I can ask for the final answer in fifteen seconds.

Convenient?

Absolutely.

But if I do that every single time, I slowly stop developing the ability to investigate things myself.

That is where AI becomes dangerous.

Not because it gives you answers.

Because it can make you stop asking questions.

The goal should not be to prove that you can code without AI.

That would be a strange hill to die on.

The goal is to make sure AI increases your capabilities rather than quietly replacing them.

Use it to go faster.

Use it to explore.

Use it to explain.

Use it to challenge your approach.

But occasionally close the chat window.

Read the error.

Open the documentation.

Follow the request through the code.

Figure out what actually happened.

Your future self debugging production at 2 a.m. will appreciate this.

Build One Thing All the Way Through

One of the most useful things you can do as a developer is finish something.

Not 85%.

Not:

“The backend works but I haven’t deployed it.”

Finished.

Build the ugly login page.

Connect the database.

Handle errors.

Deploy it.

Add a domain.

Configure HTTPS.

Make backups.

Log failures.

Try it on your phone.

Give it to someone who has never seen it before.

Watch them click the one button you assumed nobody would ever click.

Then fix what happens.

That experience teaches something tutorials rarely do:

Software is not code.

Software is code plus users plus infrastructure plus mistakes plus edge cases plus things you absolutely did not expect.

The final 20% of a project often teaches more than the first 80%.

Unfortunately, it is also significantly less glamorous.

Nobody makes motivational TikToks about configuring database backups.

They should.

Complexity Should Be Earned

Imagine your application gets 100 users.

Everything works.

Then 1,000.

Still fine.

Then 10,000.

Now your database is struggling.

Great.

You have earned a scaling problem.

This is a good problem.

Because now you have actual evidence telling you what needs improvement.

Maybe you add caching.

Maybe you optimize queries.

Maybe you move expensive jobs into background workers.

Maybe you introduce a CDN.

Maybe you add read replicas.

Maybe eventually you split part of the system into another service.

Notice the order.

Problem first.

Complexity second.

A surprising amount of bad software architecture happens when developers reverse those two steps.

They install the solution before experiencing the problem.

Then spend six months maintaining the solution.

Your Cheap Workaround Might Become the Better Design

This is one of the stranger things about building projects with limitations.

Sometimes the workaround you create because you cannot afford the “proper” solution ends up being better.

You cannot afford some giant analytics platform.

So instead you define five events that actually matter.

Your analytics become simpler.

You cannot afford massive infrastructure.

So you optimize the application.

It becomes faster.

You cannot afford ten different SaaS products.

So you automate a workflow yourself.

Now you understand the workflow better than before.

Constraints force questions.

And questions often expose unnecessary complexity.

Of course, sometimes the cheap solution is terrible.

Sometimes you spend fourteen hours building something that costs $9/month.

Congratulations.

You have successfully valued your engineering time at sixty-four cents an hour.

There is a balance.

The goal isn’t to avoid spending money.

The goal is to understand the economics of your decisions.

Every Project Leaves You With a Toolbox

This might be the best part.

The first time you configure DNS, it feels mysterious.

The fifth time, it takes three minutes.

The first deployment is terrifying.

Then deployment becomes routine.

The first authentication system feels complex.

Then you recognize the pattern.

The first time you investigate a slow database query, everything looks like ancient hieroglyphics.

Then one day you casually say:

“Looks like we're doing a sequential scan.”

And you realize something.

You didn’t memorize software development.

You collected patterns.

That’s what projects give you.

Little pieces of intuition.

A weird nginx problem.

A database optimization.

A CSS trick.

An API limitation.

A security mistake.

A deployment disaster.

A clever workaround.

A service you discovered because the famous one was too expensive.

Individually, none of these feels revolutionary.

But after enough projects, they start connecting.

Eventually somebody describes a problem and your brain quietly says:

Oh.

I’ve seen something like this before.

That is experience.

The Project Is the Curriculum

There is always another course you could watch before starting.

Another book.

Another tutorial.

Another framework to learn.

Another architecture video with suspiciously perfect rectangles.

At some point, though, you need a problem.

Build something slightly outside your current ability.

Get stuck.

Search.

Read.

Watch.

Ask AI.

Read the documentation.

Search Reddit.

Open GitHub issues.

Find some strange comment from 2019 where a developer named coffeeLord92 accidentally explains the exact bug destroying your afternoon.

Try something.

Break it.

Understand why.

Fix it.

Continue.

That process feels inefficient when you’re inside it.

But it is probably where most of the learning happens.

Because eventually the questions stop being:

“How do I build this?”

And become:

“What is the simplest reliable way to build this?”

Then later:

“What tradeoff am I making?”

And eventually:

“Do I need this at all?”

Those are very different questions.

And that progression is what becoming a better developer actually looks like.

Not knowing every technology.

Not memorizing every command.

Not building the most complicated architecture.

Just becoming slightly better at looking at a messy problem and thinking:

There’s probably a way through this.

Then opening seventeen browser tabs until you find it.