Skip to main content

Loading…

Skip to main content
HomeProjectsPostsApproachesStackResourcesContact
Justin Tsugranes LogoJustin Tsugranes Logo

Justin Tsugranes

HomeProjectsPostsApproachesStackResourcesContact

Stay in the loop

Occasional notes on what I'm building, lessons earned, and the studio behind it.

By subscribing, you agree to receive No spam. Unsubscribe in one click anytime. from Justin Tsugranes. No spam. Unsubscribe anytime. Privacy Policy

© 2026 Total Ventures LLC. All rights reserved.

Privacy PolicyTerms of ServiceCookie Policy
← All approaches

Approach · shipping · in production

KISS, YAGNI, Rule of Three

I apply KISS, YAGNI, and the Rule of Three to ensure I ship the simplest viable solution today, avoiding premature complexity and abstracting only when a pattern explicitly repeats.

The core of my development process adheres to KISS, YAGNI, and the Rule of Three, guiding me to build only what is needed right now and deferring generalized solutions until patterns are undeniable.

What it is

KISS, or "Keep It Simple, Stupid," is a design principle that prioritizes simplicity. I apply this to code, architecture, and even business models. If there's a simpler way to achieve the goal, that's the path I take. YAGNI, "You Ain't Gonna Need It," is the practice of deferring any functionality or infrastructure until it's explicitly required by a user or system. This directly combats premature optimization and speculative building. The Rule of Three dictates that I only refactor and abstract code after I've written similar code three times. The first two instances are often copy-paste; the third is when a true pattern emerges, justifying the investment in generalization.

Why I do it this way

As a solo operator running Total Ventures with AI as my team, resources are always finite. Every line of code, every abstraction, carries a maintenance cost. Premature optimization or abstraction slows down shipping and introduces complexity that might never be needed. I learned the hard way that building for an imagined future often means building the wrong thing. My focus is on getting functional products into users' hands today, gathering real feedback, and iterating. This approach forces me to solve the immediate problem, not an abstract future one. It also aligns directly with a profit-first allocation mindset, ensuring that development effort is spent on validated needs that contribute to the bottom line, rather than speculative engineering.

How it works in practice

When starting a new feature for Total Formula 1 or Pregnancy Power Hour, I write the most direct, often duplicated, code to get it working. If I need a specific API call, I write it directly where it's needed, even if it means duplicating a small helper function. My AI agents, powered by Claude Code and Gemini, are instructed to follow these principles. When I prompt them for a feature, the instructions include prioritizing direct implementation over complex patterns. They generate the simplest working solution first.

Refactoring happens only when I see the exact same logic appear for a third time, across different parts of a codebase or even different micro-services. For example, a specific data transformation before sending to Resend or Stripe might start as inline logic in two separate Vercel functions before being extracted into a shared utility on the third instance. For Inky, I initially considered a complex user permission system. YAGNI dictated I ship with a single admin role. When the need for differentiated user access became clear from actual customer feedback, then I built it. This approach extends to infrastructure: I start with the simplest Firebase functions or Vercel deployments. Only when performance or cost dictates, do I explore more complex setups. It also influences how I think about multiple revenue streams, one back office – each stream starts as a simple integration, then shared components are identified and built out.

Where this breaks down

This approach can lead to initial code duplication, which can be tedious if the "third time" never comes or comes much later. If not managed, the "Rule of Three" can be an excuse for excessive duplication, making the codebase harder to navigate for human and agent alike. It requires discipline to not abstract prematurely, which can feel counter-intuitive to experienced engineers who are used to designing for scale upfront. It relies on effective audits as crons to identify patterns that are ready for extraction; otherwise, they might be missed. The "Rule of Three" can also be subjective – what constitutes "similar enough" code? My agents often flag potential refactors, but the final decision is mine.

FAQs

Doesn't this lead to a lot of duplicated code?
Initially, yes. The point is to validate the pattern's necessity before investing in abstraction. Duplication is cheaper than incorrect abstraction until the pattern is proven. I accept this as a necessary trade-off for speed and validated design.
How do you avoid technical debt with this approach?
I view initial duplication as 'pre-debt' that I'm willing to incur to learn. True technical debt comes from unmanaged complexity. By abstracting only proven patterns, I'm building on solid ground, reducing future refactor risk.
How do your AI agents handle this?
I instruct them to prioritize direct implementation. They'll often generate duplicate code if it's the simplest path. I then use them to identify refactoring opportunities when the Rule of Three is met, acting as a code review layer.

I run this and four other brands. Want to see the operator playbook in detail?

Get the Builder's Playbook →
Written by Justin Tsugranes, Founder, Total Ventures· Founder, Total Ventures · U.S. Army veteran (13 years) · M.M. Jazz Studies, University of South Carolina
Last reviewed July 22, 2026

Related

  • Stop Short of PerfectionI focus development effort on the core user journey, shipping functional products with known imperfections outside that path, because over-polishing non-critical features delays market feedback.
  • CI Local Before CI RemoteI run all CI checks and validations locally before pushing code, ensuring immediate feedback and preventing remote build failures.
  • Commit Often, Push DeliberatelyI use 'Commit Often, Push Deliberately' to maintain a detailed local history of iterative work, ensuring every remote push represents a stable, tested, and deployable state.
  • Tests as DesignI use tests as the initial design specification for new features, ensuring the API is usable and well-defined before writing implementation code.
  • Agent-First DevelopmentAgent-First Development is my method for optimizing codebases for AI agents to write and maintain most of the code, enabling me to scale product development as a solo operator.
  • Fail Fast, Fix FasterThis approach ensures that every error, from local type mismatches to production outages, is immediately and loudly surfaced, making it impossible to ignore and enabling rapid resolution.