Launcher Labs (YC21)
We started our company, originally named Newzip (later renamed to Launcher Labs), in 2021. At first our team consisted of Jayme Hoffman handling the business side as CEO, while I focused on the tech side as CTO. I have extensive experience building applications using React and NodeJS. In my previous roles, I served as a front-end lead for several companies and projects.
Tech & tools we used
As part of YC21, our goal was to ship as quickly as possible, with a mindset focused on testing assumptions rapidly. We believed that, once our ideas are validated and we hit PMF, we would have the resources to refactor and optimize our solution, potentially moving to a more performant architecture like microservices or other alternatives.
Of course front-end decision felt into React, where I architected lots of client applications from scratch (ecommerce, marketplace, real estate). However, we recognized the need for a well-known framework that would allow any new team members to get up to speed quickly with minimal effort. Next.js emerged as the best choice for this purpose.
Later on we extended our team to one more full stack developer, product designer and growth person
Past Experience
I began my career in development with .NET. Back in 2008, there weren't many robust JavaScript frameworks for building user interfaces—just some tools like jQuery. Since then, I've been using JavaScript in my day-to-day work, gradually transitioning more toward front-end development.
Nearly a decade later, I had my first encounter with NodeJS when I left a company where I had spent seven years. I decided it was time to build a product from scratch on my own. I immersed myself in NodeJS and back-end JavaScript development, covering everything from databases to deployments. It was a fascinating year as I built my pet project, Liberbee, which is still used by its fans today. During this time, I gained experience with technologies I hadn’t had the opportunity to explore before, such as NodeJS, Express, Redis, MongoDB, Mongoose, Elasticsearch, OAuth2, RBAC, and more. This project also marked the first time I implemented server-side rendering for React, as there were no existing frameworks to handle this at that time.
Naturally, I chose to use NodeJS. The main difference this time was that I decided against building a RESTful API. At that point, I had heard a lot about GraphQL, though I had no prior experience with it. In hindsight, it turned out to be an excellent choice. Personally, I found it much easier to work with GraphQL resolvers than REST API endpoints. For an early-stage startup, where the app’s structure can change almost every week, having a flexible backend that can quickly adapt to evolving needs is crucial.
I also explored the possibility of using well-known backend frameworks. NestJS, in particular, caught my attention, as it promised a lot. However, at that time, we had a general idea of what we wanted to build, and we simply didn’t have the time to learn something new and complex (although we did eventually use NestJS for one project). I was concerned that if we started building on top of a system created by someone else without fully understanding it, we might encounter pitfalls that would be time-consuming to resolve. As a result, we end up with our own architecture, which in retrospect, bears some resemblance to NestJS. This system was sufficient for an MVP, and it allowed for easy modifications and adaptations at any moment. Remarkably, we’ve evolved it into our own backend framework, which we’ve used in almost all the projects we’ve built so far at Launcher Labs.
Custom back-end
(check Github repo)It is a layered architecture with:
- GraphQL Resolver: This serves as the entry point for all API requests. It handles authentication and routes requests to the appropriate domain layer. The resolver is responsible for interfacing with the client-side and managing the initial stages of request processing.
- Domain Layer: This is the top-level layer where the core business logic resides. Each entity within the system has its own domain, encapsulating the specific actions and logic associated with that entity. Domains are capable of interacting with each other, allowing for complex operations that span multiple entities.
- Cross-Domain Transactions: We implemented MongoDB transactions across domains to ensure data consistency and integrity during operations involving multiple domains.
- Datasource Layer: Positioned at the lowest level, this layer is responsible for direct interactions with the database. It abstracts the data access logic, providing a clean interface for the domain layer to retrieve or persist data.
- Security Layer: This layer handles all validation and authorization processes. Initially, we implemented a role-permission-based authorization system, but after several iterations, we streamlined it to focus solely on role-based access control. Our system operates with three primary roles, making the finer granularity of permission-based access unnecessary.
- Token Management: To enhance security, user tokens have a short lifespan. We implemented a refresh token mechanism to maintain user sessions without requiring frequent re-authentication.
- Services Layer: This layer manages integrations with external services and APIs. It provides the necessary interfaces for the domain layer to interact with external resources such as Google Cloud Storage, Google Maps API, OpenAI, Farcaster, and others. Each service is encapsulated within this layer to maintain separation from the core business logic.
Deployments
One of the great benefits of going through YC is that many big tech companies are eager to support your journey. I decided to leverage well-known technologies, and our choice landed on Google Cloud Services. There were other alternatives, but my past experiences influenced this decision as well. I’m very pleased that we made this choice.
We used GKE (kubernetes) for our front and back-end projects and MongoDB Atlas for our storage. Again, all those managed solutions allows you to focus more on your business side and less on the configuration.
For our CI/CD pipeline, I initially set up Travis CI, but eventually migrated to Google Cloud Build.
For our latest projects I also migrated our NextJS front-end from kubernetes to Vercel as it has a in-built CDN and edge environment.
Take aways
During those 4 years, I believe I gained the most of my knowledge. I learned a vast amount of new tools and concepts that I wouldn't learn anywhere else. One of the most important priorities was the need to research and adopt new technologies sometimes daily, and to quickly integrate them into our system. For the early stage startup it is so important to be able to test assumptions as fast as possible, enabling us to ship solutions quickly. There were times when we released new features every day.
As the CTO, my responsibilities included architecting and building the system in a way that it could be easily modified and adapted. The system needed to be prepared for rapid user growth while remaining simple. Every project was essentially an MVP, though some required extensive coding. My day-to-day responsibilities included:
- Make decisions in a company lifecycle
- Architect solution for every assumption we had
- Architect, build and extend a reusable back-end framework
- Configure Google Cloud tools
- Setup CI/CD pipeline and write deployment scripts to deploy a containerized apps on a kubernetes cluster.
- Research, learn and integrate any new tech.
- Write tons of code, unit tests and do a code review
- Recruit devs, manage the team and tasks