Хвост ящерицы

В биологии autotomy - это когда животное сбрасывает часть тела, которая больше не помогает. Ящерица отбрасывает хвост, чтобы уйти от хищника. Хвост когда-то был полезен, но для выживания нужно его отпустить. Потом вырастает новый.

Именно так и стоит думать о рефакторинге vibe-coded React Native-приложения.

В ранних AI-coded MVP первый auth flow обычно доезжает до production быстрее, чем кто-либо ожидает. Проблемы начинаются через несколько недель, когда продукт меняется, а команда пытается аккуратно рефакторить код, который она никогда по-настоящему не проектировала. В этот момент ломается login, уплывает user state и растёт количество багов. Они пытаются сохранить код, который нужно было заменить.

Рефакторить AI-generated код дорого, потому что для этого нужно понять замысел, которого у вас никогда не было. Claude Code создал абстракции, которые вы не проектировали. Он принял решения о coupling, которые вы не утверждали. Рефакторинг такого кода означает reverse-engineering архитектурных решений, принятых вероятностно, а не осознанно.

Заменяйте, а не рефакторьте

Альтернатива такая: если модуль удовлетворяет тому же интерфейсу и проходит те же тесты, вы можете заменить его, не понимая старую реализацию. Старый модуль удаляется. Новый занимает его место. Только composition root знает, что произошла замена.

// Module A (Auth v1) -> Interface Contract -> Module A' (Auth v2)

// The old auth module. You don't need to understand it.
// Claude Code generated it. It worked. Now it's done.
class SupabaseAuthService implements AuthService {
  // ... implementation you inherited ...
}

// The new auth module. You designed it. Claude Code helps write it.
class CustomAuthService implements AuthService {
  // ... your clean implementation ...
}

// The composition root is the ONLY place that changes:
const auth: AuthService = useSupabase
  ? new SupabaseAuthService()
  : new CustomAuthService()

Экран логина не меняется. Route guards не меняются. Hooks не меняются. Только composition root знает, что была замена. В этом и сила interface-driven архитектуры, когда вы работаете с AI-generated кодом. Интерфейсы - это ваша страховка от технического долга.

Четыре условия для безопасного удаления

Это работает только при наличии четырёх вещей. Без них вы просто удаляете код и надеетесь на лучшее. С ними вы делаете хирургическую операцию:

  • Defined interfaces - каждый модуль публикует contract. TypeScript types, API schema, чёткие границы. Cursor генерирует код под них. Claude Code их читает. Владельцем остаётесь вы.
  • Boundary enforcement - модули не могут залезать во внутренности друг друга. Это запрещают dependency-cruiser, ESLint или хотя бы конвенции.
  • Contract tests - тесты проверяют интерфейс, а не реализацию. Если новый модуль проходит те же тесты, он эквивалентен по поведению.
  • Clean dependency graphs - никаких циклических зависимостей. Никакого неявного coupling через globals. Import graph должен быть DAG, а не паутиной.

Замена analytics без изменений на экранах

Вы начали с Segment, потому что его предложил Claude Code. Теперь вам нужен PostHog. Старый модуль удаляется. Новый реализует тот же интерфейс. Все call site остаются прежними:

// Before
const analytics = new SegmentAnalytics(writeKey)

// After — same interface, different implementation
const analytics = new PostHogAnalytics(apiKey)

// Every call site stays the same.
// Cursor-generated screens don't change.
analytics.track('purchase_completed', { productId: '123' })
analytics.identify(userId, { plan: 'premium' })

Инстинкт сохранения очень силён. Нам хочется аккуратно пронести текущий код вперёд и не потерять ни одно поведение. Но когда вы работаете с AI-generated кодом, самый безопасный путь часто состоит в том, чтобы отпустить старое. Пишите хорошие интерфейсы. Жёстко держите границы. И будьте готовы удалять.

Autotomy Expo Starter Pack построен именно вокруг этой философии: каждый модуль проектируется под замену, а не под сохранение. Когда ваше vibe-coded приложение упрётся в стену масштабирования, вы не распутываете архитектурные решения Claude Code. Вы просто заменяете их.