Skip to main content

Command Palette

Search for a command to run...

What a Long, Strange Trip...

A wedding, a newborn, Code the Dream, Sprout, and a year of commits I never quite found time to write about.

Updated
26 min readView as Markdown
What a Long, Strange Trip...
M
Web developer building full-stack applications with JavaScript, React, Node.js, and modern web APIs.

The last time I posted was on April 28, 2025. I know the exact date because it was the same day I got married.

Looking back, that might explain why this blog settled down soon after.

Not because I stopped programming. I was still building, learning, and working through plenty of code. I just quit writing about it.

As time passed, the blog seemed to drift further down the backlog. When I found myself with some free time, I was more likely to spend it squashing bugs, working on a project, or learning something new than writing about any of it.

So before I start writing about what comes next, I should probably explain what has happened since then.

Because it was a year.

First, a tiny detail I forgot to mention

While participating in a Chingu Voyage, I met my wife.

Yes, that Chingu.

The online platform that put together teams of software engineers and agile leaders to build projects suitable to their abilities, argue politely about Git branches, and every once in a while spend twenty minutes figuring out who forgot to pull before opening a PR.

Before this past year, I had completed several Chingu Voyages, working as a developer and a product owner, and even as a mentor. One of those Voyages just happened to work out particularly well.

I met her.

As far as I am aware, almost nobody over there knows about it. It never really came up, and there never seemed to be a natural moment in a Discord channel to mention it. Plus it all escalated well after that Voyage ended.

This blog has always been about my experience writing code and sharing the lessons I've learned in order to help other developers grow and tap into their potential.

So this may seem like it comes out of left field, but Chingu gave me teammates, portfolio projects, experience working on software teams...

...and a wife.

Maybe not in that order.

You might say that it was a successful Voyage.

Before the Baby, There Was Baby Book

Before summer could even arrive, we found out our lives were about to change again!

We found out we were expecting a son, due November 7. We began to think about all of the little things that come with two people becoming parents.

Naturally, we both looked at each other and said:

We could probably build an app for this.

So we began working on an idea we called Baby Book.

In the first phase, it was only a household task and grocery list tracking app. The long-term plan was to track milestones, achievements, appointments, and eventually the little things one parent might miss while the other was there—so we could stay on the same page.

More or less, we set out to build a shared record of our new favorite person's life as it began to unfold.

We never did polish the application to the original design plan, but for a little while it was actually useful.

When she went into labor, I threw together a quick feature for helping her with breathing and contractions. When our son was born, Baby Book shifted toward the realities of parenthood. We started tracking feeding times, which side she breastfed on, diaper changes, and little notes.

It did not take long before we did what most new parents probably do.

We fell into a rhythm and stopped stressing over those details as much.

Our need for this app faded, and Baby Book quietly moved into the category titled:

I should really come back to this someday.

And I still may.

Some of the original idea could still be useful today, especially around milestones and giving us an easy way to share the little things the other parent might miss.

But it is not exactly at the top of the backlog right now.

Then October Happened

Our son was supposed to arrive on November 7.

Apparently, he had his own release schedule. He arrived October 12, about four weeks early.

Anybody who has had an infant can probably relate to what happened to my schedule next. If you haven't, imagine handing your calendar to a tiny version of yourself that only speaks babble, uses his tongue to read, and thinks 3:17 in the morning is the perfect time to discuss politics.

That is roughly the system, right?

The funny part is that another fairly important date had happened only five days earlier.

On October 7, I was accepted into Code the Dream's React course.

Code the Dream Was Already in Motion

I had actually applied to Code the Dream months earlier, around April 2025.

The timing of the whole thing could have been a little better. But it is not like I brought the baby home, learned a thing or two about our new tiny boss, and decided:

You know what this situation needs?

Another commitment.

The decision had already been made.

I had tested out of the Intro to Programming course, which is how I ended up going directly into React.

By this point, I knew that it was going to be a challenge, but it seemed reasonable enough.

Strangely enough, his early arrival may actually have made the start of the course easier. I lost some preparation time, but I gained a few weeks to settle into being a parent before React started. And that made a big difference.

By the time the React cohort started, I was not deciding whether I wanted to begin another programming course while raising a newborn. I had already committed to the course.

Now I just had to figure out what continuing looked like under completely different circumstances.

The answer was very different from the way I had worked before.

Long, uninterrupted coding sessions became harder to find. Development started happening in smaller windows: thirty minutes here, an hour there, whatever time happened to exist between everything else.

If twenty minutes of a thirty-five-minute session were spent trying to remember what I had been doing the last time I opened the project, that was a problem.

So I started leaving myself better notes. I broke problems into smaller pieces. I became more deliberate about commits and less interested in keeping an entire feature in my head.

Without really planning to, becoming a parent forced me to get better at stopping halfway through something while leaving enough breadcrumbs that future me could figure out what past me had been doing.

And then React started.

React, the Second Time Around

I joined Code the Dream's React v3 course as part of the Lark Cohort, which ran from November through February.

Code the Dream was not where I first learned React, or where I first built a full-stack application. I had already built MERN applications, worked with APIs, Express, and MongoDB, and completed several development projects with other people through Chingu.

What CTD gave me was something different.

It gave me several months to go back through technologies I already knew and find the places where my understanding was thinner than I realized.

One of those places was Context.

I had used Context before and understood what it did, but there is a difference between knowing that Context exists and getting comfortable designing state around it, combining it with reducers, deciding what actually belongs there, and thinking about what happens as your component tree gets larger.

Sometimes learning something for the second time is a lot more useful than learning it the first time.

The first time, you are mostly trying to make it work.

The second time, you start asking why it works that way.

That became a recurring theme during the course. It was less:

Here is React.

and more:

You know React. Now let's find the parts you have been getting away with not understanding deeply enough.

My guided project grew throughout the course. Reducers came in, Context became more important, routing got more complicated, external data got involved, state crossed more boundaries, and testing became a larger part of the way I worked.

Eventually something I had built myself six weeks earlier could surprise me, which is always reassuring.

Somewhere during that process, the question I asked after completing something changed.

It used to be:

Does it work?

I would click around a few times, see that everything looked fine, and move on.

Now I am much more likely to ask:

Okay, it works. What breaks it?

What happens if the request fails? What happens if the user refreshes here? What if this state has not hydrated yet? What happens if the component disappears before an asynchronous operation finishes? What happens if somebody clicks the same button five times while the first request is still running?

The happy path is still important.

I just trust it a lot less than I used to.

Then I Went Back Through the Backend

After React, I moved into Code the Dream's Node 26.2 Cohort, which ran from late March through June.

Again, Node and Express were not new territory. I had already built full-stack applications and worked with the MERN stack, but going through a dedicated backend course gave me an opportunity to spend more time on the details instead of treating the backend as whatever needed to exist so the frontend could work.

We spent time with routes, middleware, authentication, validation, error handling, HTTP semantics, database access, and application structure.

One technology I got a lot more practice with was Prisma.

I had used Prisma before CTD, but not enough that I would have called myself particularly comfortable with it. CTD gave me more opportunities to use it deliberately instead of simply following the happy path through an ORM.

That distinction mattered.

There are a lot of technologies I have used. That does not necessarily mean I understand all of the decisions they are making for me.

Knowing how to use a tool is one level.

Knowing what that tool is abstracting away is another.

Then Came Practicum

After finishing the coursework, I joined Code the Dream's Summer 2026 Practicum.

This part felt familiar.

I had already done several team projects through Chingu, so practicum was not my introduction to collaboration, Git, pull requests, requirements, product decisions, or the occasional joy of discovering two developers had spent an afternoon independently solving the same problem.

What made practicum interesting was the amount of structure we had to build around the development itself.

Our team built Sprout, a financial literacy application.

The easiest way I have found to describe it is something like Duolingo pointed at personal finance: short lessons, quizzes, progress tracking, onboarding, and a guided learning path.

The idea was to make a subject people know they should understand feel less like sitting down with a textbook, because almost nobody wakes up Saturday morning thinking:

You know what would really make this weekend? Budgeting terminology.

Sprout was not the project I would have chosen on my own, and I think that made the experience more interesting.

When something is your personal project, you can build whatever you want. On a team, the product does not belong entirely to you. You have to build the thing the group agreed to build.

That is a different skill.

Before We Built Much of Anything, We Built a Backlog

One of the first things I did was start planning.

And then I planned some more.

And then apparently I decided Jira had not suffered enough, because I built a pretty enormous backlog.

There are still plenty of tickets sitting in it that we never touched, and that was intentional. A backlog is not a promise that everything gets built. It is a record of things that could get built.

Berenice and I worked together to decide which parts were actually critical for an MVP. Those moved forward; the rest could wait.

We split the core work across sprint weeks and broke larger ideas into epics, user stories, and smaller tasks. A Jira ticket would often become a GitHub issue. That issue gave us something concrete to build around and could then map to a branch.

Eventually there was a clear line connecting:

idea → epic → story → issue → branch → pull request → application

That process became one of the more valuable parts of practicum for me because a large application does not get built by somebody opening an editor and thinking:

Today I shall implement the application.

You build a small piece. Then another. Then another.

Sometimes several developers were contributing to the same larger feature, so we would use what amounted to a parent or integration branch. Instead of everybody immediately merging their work into development, we could combine related work there first, get the pieces cooperating, fix whatever exploded, and then merge the larger feature.

It added another layer to the Git workflow, but it also prevented development from becoming quite as adventurous.

We Never Really "Finished" an Epic

Something else became apparent pretty quickly: epics are big.

Really big.

When you only have a limited number of weeks, "complete the epic" is often the wrong goal. So we sliced useful pieces out of them instead.

One week we might improve onboarding. Later, we would come back and add something else. The learning path grew incrementally. Admin tools grew incrementally. Accounts grew incrementally. Testing grew incrementally.

Even now, I do not think I could point at many of our larger epics and say:

Yep. Finished forever.

There are still stories sitting in the backlog, but the application works.

That taught me something useful about MVP development. An epic does not have to be complete for part of it to create value. Sometimes the right feature is simply the smallest useful slice of a much larger idea.

In a strange way, I suppose Baby Book had already taught me a smaller version of that lesson.

It never became the application I originally imagined, but for a brief period the pieces we actually needed were useful.

Sometimes software has already done its job before you finish everything you once imagined for it.

Then Sprout Became Complicated

Sprout used React on the frontend, Node and Express on the backend, and MongoDB underneath. We used Tailwind CSS and eventually created a collection of shared components so the UI could stay relatively consistent while different developers worked on different screens.

That became important very quickly.

Without shared components, five developers can somehow invent seven buttons. Each one is slightly different; none of them are necessarily wrong, and together they make the application look like it was assembled by committee.

Because it was.

Shared components gave us some guardrails, but the more interesting architectural decisions happened around the curriculum.

Several members of the team worked together to build our learning material into structured JSON, and a huge part of the application eventually revolved around that structure: lessons, sections, quizzes, questions, answers, and progress.

The JSON became something close to a content engine for the application.

For a while, that worked really well.

Then we started asking uncomfortable questions. Questions like:

Should the correct answers to a quiz really be sitting somewhere the browser can inspect?

Probably not.

One Architecture Decision Created a Whole New Category of Bugs

Eventually we started integrating more of the curriculum data with MongoDB.

Part of the motivation was protecting quiz answers. If the browser receives everything—including which answer is correct—then somebody who knows their way around developer tools can potentially skip the whole "learning" portion of the learning application.

Which feels slightly against the spirit of the thing.

Moving more responsibility to the backend made sense, but architectural decisions rarely arrive alone. This one brought friends: more requests, more synchronization, more state, more opportunities for the frontend and backend to disagree, performance concerns, and some really annoying bugs.

We solved one problem and introduced an entirely different class of problems.

That does not necessarily mean the decision was wrong. It means the decision had a cost, and that might be one of the most useful things Sprout reinforced for me.

Architecture is usually not:

Which solution is correct?

It is more often:

Which set of problems would you rather have?

I may revisit that part of Sprout in the future because I think there are better ways we could protect assessment data without making parts of the experience as expensive or fragile as they became.

But that is also why I am glad we tried it.

You learn a lot more from an architectural decision that creates unexpected problems than one that only exists in a diagram.

Testing Was Only Half of What I Enjoyed

Testing became a major part of my role on the project. I worked with Jest, Vitest, React Testing Library, and Playwright, and I liked the way testing forced us to think beyond the exact sequence of events we pictured when writing a feature.

What happens if the component unmounts? What happens if the network request fails? What if authentication has not finished hydrating? What if somebody double-clicks? What if the frontend thinks a lesson is complete and the backend disagrees?

We found all of those.

But something else ended up being just as interesting to me:

CI.

I really enjoyed working with GitHub Actions and getting our tests running automatically as part of the development workflow.

There is something deeply satisfying about turning:

Somebody should probably run the tests before we merge this.

into:

The repository literally will not let us forget.

That felt like another step beyond simply knowing how to write tests.

A test suite sitting on somebody's laptop is useful. A test suite that runs automatically against changes is infrastructure.

Once I started working on that side of the project, I found myself liking it quite a bit: tests, coverage, automated checks, GitHub Actions, deployment workflows, and all the little pieces that make it harder for a team to accidentally ship something broken.

None of those things are particularly flashy.

But they make everything else easier to trust.

Some Bugs Deserve Their Own ZIP Code

We still had plenty of bugs.

Some were straightforward, friendly bugs. The sort that basically introduce themselves:

Hello. I am on line 47.

Those are wonderful.

Others required the application to be in exactly the wrong state at exactly the right time.

We had authentication behavior where the frontend could decide where a user should be redirected before it had finished determining whether the user was authenticated. Everything worked unless the timing changed, which is always comforting.

We had asynchronous quiz operations where work could finish after the component that started it no longer existed. We had buttons users could click multiple times while a request was still running. We had lesson progression and quiz completion logic with occasionally incompatible definitions of reality.

Some of those bugs looked completely fine when you clicked through the application manually.

Then an automated test created the right sequence of events and everything fell apart.

Beautiful.

Those are the problems I enjoy the most now: the ones where the solution requires understanding the system rather than simply finding a typo.

Git Got More Interesting Too

Working by yourself gives you a very misleading impression of Git.

You make a branch, write some code, commit it, merge it, and suddenly you feel pretty good about version control.

Working with several developers changes the situation, especially once branches start depending on other branches.

Suddenly Git becomes less:

Save my work.

and more:

Which version of this application represents reality right now?

The parent-branch strategy helped with that. So did smaller pull requests, better issues, and simply talking to each other before two people changed the same area of the application.

That is the funny thing about Git problems.

A surprising number of them are actually communication problems that happen to eventually produce merge conflicts.

Practicum Felt Familiar Because of Chingu

A lot of practicum reminded me of Chingu Voyages, which makes sense because I had already done several Voyages as both a developer and a Product Owner.

Chingu had already taught me that two developers can read the same requirement and walk away with completely different applications in their heads. It had already shown me how important communication becomes once multiple people share a repository, and it had already exposed me to team roles and product planning.

The two programs just approached those experiences differently.

Chingu Does a Great Job Simulating a Product Team

One thing I genuinely like about Chingu is that a Voyage can include several different roles.

Developers may work alongside a Product Owner, Scrum Master, and UI/UX Designer, which creates some separation between responsibilities. A designer is concentrating on how something should look and behave. A Product Owner is shaping priorities and requirements. A Scrum Master helps keep the process moving.

Developers then have to take those ideas and make them real.

And eventually everybody discovers that a button somebody drew in thirty seconds somehow requires half a day to implement correctly.

That structure is useful.

The challenge, particularly in some lower tiers, is that experience levels among developers can vary quite a bit. Everybody might technically satisfy the requirements for the Voyage while having very different levels of comfort with JavaScript, Git, architecture, APIs, or debugging.

Sometimes you discover those differences while trying to ship something.

Which, to be fair, is also pretty realistic.

Code the Dream Gave Us a Different Baseline

Code the Dream's practicum had another advantage: everyone had already completed defined coursework.

That did not make everyone's skills identical—not even close—but it gave us shared reference points. We had all traveled through at least some of the same material before arriving at the project.

The bigger difference was that we did not have every traditional product role separated out. We were mostly developers, so we had to wear more hats ourselves.

Someone had to think about product. Someone had to think about design. Someone had to organize the work and maintain the backlog. Someone had to worry about whether CI was working.

Usually everybody ended up doing more than whatever role they originally imagined themselves doing.

And I think that was good for us.

The People Part

Berenice stepped in beside me as a co-project lead, and that helped me more than I probably said at the time.

She gave me somebody to bounce ideas off of while we built epics, shaped user stories, created tasks, organized Jira, and tried to decide which pieces actually mattered enough to belong in our MVP.

There are a lot of small judgment calls hidden inside project planning. Having another person there to challenge an idea—or confirm that I was not completely overthinking it—made that a lot easier.

Kristen and Maryzabeth took on another enormous part of the application.

They worked together on our initial low-fidelity wireframes, which became high-fidelity wireframes and eventually the foundation for the UI and UX. Then they worked together on developing the curriculum that became the content driving much of Sprout.

Kristen had a particularly good instinct for keeping us connected to the original vision. Software developers are exceptionally talented at taking a reasonable idea and turning it into fourteen features, three dashboards, a notification system, and possibly a social network.

Sometimes somebody has to say:

We probably do not need that.

Kristen was good at that. A lot of her vision made it into the final product precisely because she was willing to pull us back toward the application we had actually agreed to build.

Maryzabeth became one of those people every remote team quietly depends on. She contributed across both frontend and backend work, but she also became our unofficial secretary.

She took notes, documented decisions, and if somebody missed a meeting or standup, she was usually the person making sure they knew what happened.

That sounds like a small thing until you work on a distributed team.

Then you discover that keeping everybody operating from the same version of reality is basically a feature of its own.

Everybody ended up bringing something beyond code, and that is the part of team development I find most interesting.

We Also Had Actual Adults in the Room

Code the Dream pairs practicum teams with mentors, and our team had Hector and Mario.

Hector brought real-world software development experience into our conversations, while Mario brought a lot of optimism and was always willing to listen while we worked our way through something.

What helped most was rarely somebody simply handing us an answer. Usually it was somebody with more experience asking a question we had not asked ourselves:

Why did you build it this way?

Sometimes we had a very good answer.

Sometimes the answer turned out to be:

Because that is how it currently is.

Those conversations were useful too.

So What Actually Changed?

This is probably where I would describe the year differently than I would have twelve months ago.

I did not learn that teams exist. I had already worked on teams. I did not learn how to build a full-stack application. I had already built them. I did not discover MERN. I already knew it.

What changed was the level at which I started thinking about all of those things.

I understand React Context better than I did. I am much more comfortable with testing. I have more practical experience with Prisma. I learned more about CI and GitHub Actions than I expected to, and I got more interested in the infrastructure surrounding the code.

I spent more time thinking about how work gets broken down before anyone writes it. I became more deliberate about branch strategies when several pieces of one feature were being developed at the same time. I watched an architectural decision solve one problem while creating three new ones, and I saw how much a shared component library matters when several developers are building the same UI.

More than anything, I got another reminder that software development is full of tradeoffs disguised as decisions.

Maybe that is the biggest thing I got out of this year.

I did not necessarily add another stack to the list of technologies I know.

I got better at seeing the system around them.

The Other Lesson Had Nothing to Do With Code

I also learned that progress does not require the schedule I thought it did.

For a long time, I pictured serious development work happening in large, uninterrupted blocks: a free Saturday, several hours at a desk, headphones on, everything lined up.

That sounds wonderful.

It describes almost none of what the past year looked like.

A lot of this year happened in pieces. Thirty minutes here. An hour after bedtime. A bug before dinner. A pull request during nap time. Reading yesterday's notes because I had absolutely no idea what the version of me from forty-eight hours ago had been thinking.

And somehow it still added up.

I used to think real progress required long stretches of uninterrupted time. It turns out a surprising amount of it comes from getting good at returning.

Open the laptop. Find the note. Read the issue. Make the next change. Commit it. Come back later.

That is not the montage version of learning software development.

It is probably a lot closer to the real one.

The Part That Made Any of This Possible

Outside the project, my wife Jayanti listened to far more discussion about failed tests, authentication bugs, GitHub Actions, pull requests, MongoDB, Render deployments, and merge conflicts than any reasonable marriage contract should require.

She was also there through the much more important part of the year while we figured out how to become parents together.

That included the unfinished Baby Book, the last-minute contraction feature, sleep schedules that were mostly theoretical, and plenty of development sessions squeezed into whatever part of the day happened to survive.

It has been a year.

A really good one, a very busy one, and occasionally a very tired one.

So... What's Next?

Practicum has wrapped.

I may keep tinkering with Sprout. There are still architectural decisions I want to revisit, experiments I want to try, and a Jira backlog large enough to keep several imaginary development teams busy.

But I am also ready to build other things.

I have a Rust game I keep coming back to. I want to contribute to open source properly. Baby Book is still sitting somewhere in the back of my head, too.

And I have a growing list of things from this past year that deserve articles of their own: CI pipelines, testing patterns, authentication races, architecture mistakes, Prisma, React, Rust, and the sort of problems where the first draft of the article usually begins with:

I thought this would be easy.

Those are usually the interesting ones.

I have also applied to Code the Dream's apprenticeship program.

I do not know yet whether I will get in, and strangely, I am okay leaving that part of the story there.

Not knowing.

Because that is actually where I am.

There is a tendency when writing about learning software development to wait until you know how the story ends. Get the job. Finish the project. Earn the certificate. Then go back and write the neat version where everything looks like it was leading somewhere obvious.

Real life rarely gives you that version while you are living it.

Right now, I have finished one thing and I am waiting to find out what comes next. Maybe that is the apprenticeship. Maybe it is a job. Maybe it is open source.

Maybe I disappear into Rust for six months and emerge with something deeply unnecessary.

There are worse outcomes.

What I do know is that I finally want to write again, and I have a lot more to write about than I did when this blog went quiet.

So Journey to Code is back.

Probably a little slower. Definitely with more interruptions.

But I think I am okay with that now.

The last year taught me that progress does not always look like moving quickly. Sometimes it just means you keep coming back.

And, conveniently, I just did.