The other side of innovation.

Your app will have 50 users. Chill.

Your app will have 50 users. Chill.

Confessions of a recovering design patterns addict


Yesterday I found code I wrote in 2020. I built a notification system with Event Sourcing, CQRS, and 3 microservices for a personal reminders app.

Total users: me.

I didn't even use it. Setting phone alarms was easier.


The exact moment everything goes wrong

There's a precise point in every dev's career where the brain breaks. Usually 2 weeks after finishing a "Clean Architecture" course.

Suddenly, this:

const total = price * quantity;

Becomes this:

// calculator.module.ts
// calculator.service.ts  
// multiplication.strategy.ts
// calculation-context.dto.ts
// i-arithmetic-operation.ts

const strategy = this.factory.create(OperationType.MULTIPLY);
const context = this.contextBuilder.build({ price, quantity });
const total = strategy.execute(context);

40 lines of architecture to multiply two numbers.

Somewhere between the course and the code, you lost the ability to write a * b.


Real code I've seen (and written)

The Enterprise Logger™

// I just wanted to console.log("User created")

@Injectable()
class LoggingService {
  constructor(
    private readonly config: LogConfig,
    private readonly formatter: LogFormatter,
    private readonly transport: LogTransport,
    private readonly sanitizer: LogSanitizer,
  ) {}
  
  log(level: LogLevel, message: string, meta?: LogMeta): void {
    const sanitized = this.sanitizer.sanitize(message);
    const formatted = this.formatter.format(level, sanitized, meta);
    this.transport.send(formatted);
  }
}

// Usage:
this.logger.log(LogLevel.INFO, "User created", { userId: user.id });

// What I needed:
console.log("User created:", user.id);

The project? An internal script that ran once a month.


The "Scalable" Email Validation

// email-validator.ts
// email-validation-rule.interface.ts
// email-format-rule.ts
// email-domain-rule.ts
// email-validation-chain.ts
// email-validator.factory.ts

// 6 files for this:
const isValid = email.includes("@");

"But what if we need more complex validations..."

Spoiler: We didn't. It's been 3 years.


The golden rule

Before creating an abstraction, ask yourself:

Do I have more than one implementation RIGHT NOW?

Not "someday." Not "just in case." Now.

If the answer is no, write the simplest, most boring code that works.

The future you're imagining won't happen. And if it does, it'll be so different that your "preparation" will be useless anyway.


The uncomfortable truth

The most maintainable code I've seen looks like a junior wrote it. Short functions. Obvious names. Zero magic.

The least maintainable code looks like an academic paper. Beautiful in diagrams. Hell at 3am.

Your code doesn't need to scale to millions. It needs to:

  • Work
  • Be understandable
  • Not make you cry in 6 months

Architecture is debt. Complexity is compound interest.

Most apps just need to work.

Suscribe to my newsletter

No spam, no sharing to third party. Only you and me.

Member discussion