Fullstack development can be a complex field, especially when you’re starting from scratch. However, with the right tools and a little bit of effort, it is possible to become effective at it quickly.
Eventually I decided to leave my job and take the leap to work in the new, shiny industry of Web3. After a few months of writing smart contracts and pulling data from blockchains for analysis I realized that while Jupyter Notebooks was an awesome tool to try things out, I couldn’t ship that to my users and clients. Also, the Web3 development libraries and tools for Python were lacking.
Moving to Typescript
It was when I had to work with the Uniswap v3 SDK, which was only available on Typescript, when I decided to swallow my Phythonist pride and learn Typescript since it was probably easier than implementing all of the features I needed directly on Python.
Taking on a challenge
Until one day I got an offer to build a web3 app for a client. The project was very interesting and well paid, so I decided to take it with the condition of starting it a month from that moment. At that point I had realized that my current stack and skills in React and CSS wouldn’t cut it. All that I had done so far in frontend was honestly very simple, quite ugly, fragile in the API and fetching layer and full of boilerplate code.
I have been a fan of the YouTube channel Fireship for a long time, and there had been some technologies that had caught my attention and seemed to solve most of the problems I was facing.
On one side was Next.js, which handled all routing, project structure, and rendering and allowed me to just write backend code in the same file as my components for pages without having to worry about defining APIs and handling data fetching, and as a bonus creating and deploying API endpoints was as simple as creating a handler function in an api folder and deploying using Vercel’s free service. Suddenly, my frontend architecture and deployment procedures became much simpler.
The other tool was Prisma v3. Coming from Python I had worked previously with SQLAlchemy, but the way Prisma schema definition and migration tools seemed super practical and the Typescript interface for making queries and getting typed data on return was very powerful and easy to use.
With those two tools at the base of my stack, NextAuth added for sessions and deployment on Vercel I had already solved most of the structural and deployment problems of my stack, so the next problem was how to make my apps less ugly. Since at this point I had less than a week to start working on the project, a full course in CSS and UI development was out of the question. Luckily, during my participation in hackathons I had seen several people achieving tremendous results in UI in very little time, most of them were using a UI Library like Material UI or Chakra UI. After reading some documentation for the tools, I found Material UI very powerful and easy to get started and decided that “I’m a backend dev, I don’t need to learn CSS”.
Once equipped with those tools, I started work on the project and was very surprised to see how easy it was and how fast I was moving, doing things that previously would have taken a very long time or been very tedious to do. For the first time, I wasn’t dreading working on the frontend of my applications.
Keep iterating your tools and techniques
So far I had found a good toolset to get thing done fast, but there was still quite a lot of room for improvement, as there always is. The first thing to improve was that my page loads were slow since I was using Server Side Rendering for most of my pages. That meant that everytime that my users loaded a page, to see something on the screen (other than a blank background) their request had to go to the Servers for the Vercel’s serverless functions, wait for one or more queries from the database in another datacenter, and then back to the user computer. This was too slow and left the app feeling very unresponsive at times. The first thing I tried was building a caching solution with Redis to reduce time spent on the DB running on the lowest tier of GCP, but this only proved to be a minor improvement in performance and a major pain for all of my code around the cached data and introducing several bugs on the long run. Similar story when I tried to switch most pages to SSG and ISR. For a time I accepted this situation and just put a loading bar on the top to let the user know the SPA was loading, which was a much better improvement in UX than my previous attempts at fixing performance.
The conclusion was that SSR, SSG and ISR weren’t necessarily the correct patterns for the highly dynamic application that I was building. So I had to find a better way. In the process of learning Next.js and improving my react skills I had stumbled upon this awesome content creator called Theo, who in several videos mentioned a library called tRPC which seemed promising.
I decided to take a couple days to try it out and see if it could improve the responsiveness of my app. Created a new branch in git, did the setup, moved the DB queries to the tRPC endpoints, and used the custom hook for data fetching, and added loading spinners for the data using one of return values from the hook.
I was amazed at how well it worked and how easy it was to do. So I proceeded to quickly move most of my previous endpoints and getServerSideProps functions to tRPC and saw a massive improvement in response times for HTML on screen and perceived responsiveness by the users.
It is worth mentioning that tRPC is an awesome library. But a good part of this awesomeness comes from two other libraries from which it is built upon. React Query, which handles start for asynchronous queries in a very elegant and reliable manner and Zod, which lets you define and verify schemas very easily and in a type-safe manner.
With all of this. The app for my client was successfully completed (You can see it here) and went through a couple iterations before I moved on to the next project, where my focus on improvement was on better data validation and inputs integrating tRPC, Zod and React Hook Form and handling a bigger project with multiple apps using a Monorepo for sharing code. I’ll speak about that in a future post.
In short, after some iteration in the pursuit to fit my user’s need and at the same time being able to iterate fast and maintain a good developer experience, this is the stack I’ve currently arrived to:
With some other tools like:
- Zod for most data validation and as source for interfaces
- React Hook Form for handling forms
- React Query for async queries and mutation to external sources
- Turborepo, for handling more than one application in the same repo (useful for code sharing)
- Wagmi for working with ethereum wallets
This will probably keep evolving as time passes, I keep working on more projects and new tools keep being developed by the awesome open source community. I’ll keep posting here as those changes happen.
The T3 Stack
As a final note, while I was in the process of finding this stack so were many people. Previously I had mentioned Theo, who is one of the main people online pushing this stack right now (Switching Material UI for Tailwind, which I’m giving a chance to soo) with the name of the T3 Stack. One awesome thing that has come out of that is a community project called create-t3-app which is cli to facilitate the process of creating an app in this stack without having to go through the lengthy setup process of going through the documentation of each tool, copying and pasting boilerplate, and then figure out how to fit all of it together. Instead, you just run the tool with npx, select what you want to use and get the skeleton for your application’s code with great defaults without writing a single line of boilerplate.