Event Hell Is Just Your Login Method

Event systems are something powerful. Whether you're in a microservice, a monolith, or an ACL layer, they make scalability and maintainability actually possible.

"After a user logs in, I want to send them a survey!"

"Just add it to the code after the login happens."

"Where? Before we send the welcome email? After we create the Stripe customer? Maybe after we track the login action but before the..."

I watched this exact conversation happen about seven years ago. When I suggested events, I was told I'd be introducing event hell.

So I showed them what it actually looks like. And why.

The realization was immediate.

Domain events aren't complexity. They're the extraction of complexity that's already there, tangled into your login method like Christmas lights in a garbage bag. With events, you are not adding indirection, but instead, you are acknowledging that "user logged in" means seventeen different things to seventeen different parts of your system, and maybe those seventeen things shouldn't be having a meeting inside one function.

The alternative is what you already have. A method called handleLogin that's 400 lines long and touches Stripe, SendGrid, Segment, your audit log, and somehow also your referral system. That's not simplicity. That's a junk drawer with a function signature.

userLoggedIn.emit({ userId, timestamp })

Then somewhere else, completely decoupled:

on(userLoggedIn, async ({ userId }) => {
  await sendWelcomeEmail(userId)
})

on(userLoggedIn, async ({ userId }) => {
  await createStripeCustomer(userId)
})

on(userLoggedIn, async ({ userId }) => {
  await sendSurvey(userId)
})

Use them!

❤️
Jake

SONG