Type 0 рефакторинг: стъпката преди първа стъпка

Type 0 рефакторингът е ограничено, запазващо поведението почистване, което прави разхвърляния код четим и безопасен за работа, преди да опиташ истински рефакторинг или да пуснеш hotfix.

Има един вид рефакторинг, който екипите правят постоянно, печелят от него веднага и почти никога не го назовават.

Това е работата, която вършиш точно преди да докоснеш страшния файл. Feature request-ът те принуждава да влезеш в разхвърляния модул. Инцидентът идва, а bug-ът се крие някъде в метод, който изглежда все едно има собствена метеорологична система.

Не препроектираш системата. Не въвеждаш нова абстракция. Не „подобряваш“ нищо по хитър начин.

Просто правиш кода достатъчно четим, за да можеш да работиш.

Започнах да наричам това Type 0 рефакторинг.

Type 0 рефакторингът е подготвително, запазващо поведението почистване, което прави кода по-лесен за разбиране преди архитектурни рефакторинги, performance работа или feature работа.

Това е стъпката „подсуши пода, преди да ремонтираш кухнята“. Повечето екипи вече я правят неформално. Когато я назовеш, тя се превръща в общ инструмент.


Истинската причина Type 0 да съществува: хората имат лимит на работната памет

Ето грубата истина зад идеята:

Моят мозък (и твоят) не е създаден да debug-ва надеждно метод от 2000 реда под напрежение.

Това не е личен дефект. Просто така работи мисленето.

Debugging-ът те кара да държиш едновременно:

  • текущия execution path
  • релевантното състояние
  • какво всъщност означава всяка променлива
  • набора от възможни разклонения
  • последствията от „ако стане това, тогава...“

В малък код това е управляемо.

В голям код с висока cyclomatic complexity се превръща във вероятностно налучкване. Пак можеш да имаш късмет, но е скъпо и рисковано, особено по време на hotfix.

Type 0 е практичен отговор: това е начинът бързо да си купиш яснота, без да поемаш цената и риска на „истински рефакторинг“.


Защо се казва „Type 0“

Името не дойде от голяма теория. Дойде от момент с високо напрежение.

Работех по hotfix. Bug-ът беше заровен в метод, който на практика беше собствена малка вселена — около 2000 реда.

Bug-ът не беше концептуално труден. Методът беше.

Всяко „какво става, ако...“ се разклоняваше в още десет въпроса, а разклоняването не беше от полезния вид. Беше incidental complexity: шум, повторение, неясни имена и структура, която не съвпадаше с менталния модел, нужен за debugging.

Това, от което имах нужда, не беше съвършенство. Имах нужда от debuggability:

  • по-малко разклонения на екран
  • по-ясни „стъпки“ с имена
  • по-малко шум
  • по-малко време да препарсвам току-що прочетеното

Но напрежението във времето не позволяваше по-голям рефакторинг или „идиоматичен redesign“. Да го направя отговорно щеше да е половин ден (или повече), включително ръчно тестване. В hotfix прозорец това не е дисциплина; това е хазарт.

Затова помолих един LLM да предложи възможности за refactoring за класа и този метод, без да му казвам защо.

Той се върна със списък от четири „типа“ рефакторинг. Всички разумни. Всички приложими. Всички твърде скъпи за онзи момент.

После зададе учтивия въпрос:

“Should I start with Type 1?”

Тогава отговорих:

“No. Let’s start with Type 0.”

И дефинирах Type 0 на място: ограничен, механичен набор от промени, които намаляват complexity и увеличават четимостта без да променят поведението или архитектурата.

Методът стана навигируем. Мозъкът ми отново можеше да следи изпълнението. Намерих bug-а, поправих го и го ship-нах без collateral damage.

Затова харесвам името Type 0: това е рефакторингът, който правиш преди „истинските“ типове рефакторинг, особено когато си под напрежение и ти трябва безопасен начин бързо да създадеш яснота.


Проблемът, който Type 0 решава

Повечето съвети за refactoring приемат, че вече можеш да видиш дизайна.

В реални codebase-и:

  • методите са дълги и многоцелеви
  • повтарящи се изрази и incidental complexity крият намерението
  • променливите са криптични ($e, $tmp, $res)
  • мъртъв код и unused imports създават ментален шум
  • „формата“ на кода е толкова разхвърляна, че дори малките промени изглеждат рискови

Когато опиташ „истински refactoring“ върху това (граници, patterns, местене на отговорности), трупаш несигурност върху несигурност:

  • не можеш лесно да кажеш кое поведение запазваш
  • не можеш да предвидиш blast radius-а
  • review-тата се разпадат в субективни спорове
  • хората започват да се страхуват да докосват нещата и бъркотията се натрупва

Type 0 е начинът първо да свалиш когнитивния товар. Той създава стабилна основа, върху която по-дълбоката работа може да се случи безопасно.


Посягай към Type 0, когато...

Type 0 е най-ценен, когато:

  • трябва да debug-ваш бързо (hotfix-и, инциденти), а кодът е твърде голям или разклонен, за да мислиш за него безопасно
  • усещаш, че си „изгубен в метода“ и препрочиташ една и съща секция, защото структурата не помага на работната ти памет
  • кодът е правилен, но нечетим, и не можеш да си позволиш да „почистваш логиката“, а само да я покажеш
  • искаш да намалиш риска преди по-дълбока работа (знаеш, че по-късно ще рефакторираш, но първо ти трябва ясна карта на текущото поведение)
  • искаш да превърнеш tribal knowledge в четима структура, така че debugging-ът да не зависи от един човек

Type 0 не е лукс. В тези случаи често е най-бързият начин да си върнеш контрола.


Дефиниция, която можеш да използваш в екипа си

Type 0 refactoring е набор от микро-рефакторинги, които подобряват четимостта и maintainability, без да променят поведението или архитектурата.

Той е умишлено ограничен. Ограниченията са feature-ът.

Type 0 се състои от четири задължителни sub-pattern-а:

  1. 0a. Method extraction
  2. 0b. Conciseness
  3. 0c. Empathy (pure readability)
  4. 0d. Dead code removal

И следва три твърди правила:

  • Без промени в поведението
  • Без архитектурни промени
  • Без „хитри“ подобрения извън четирите pattern-а

Ако нарушиш тези правила, вече не правиш Type 0 — преминал си в друга категория работа, а тя изисква друга координация, друга строгост в review-то и често друга стратегия за тестване.


Защо изобщо да го назоваваме?

Защото назоваването променя начина, по който екипите се координират.

  • „В този PR правя само Type 0“ казва на reviewer-ите какво да гледат: запазване на поведението и четимост, не архитектурни дебати.
  • „Трябва ни Type 0, преди да рефакторираме това“ е честно признание, че кодът още не е готов за по-дълбока промяна.
  • „Нека направим Type 0 като Step 0“ създава малък ритуал, който те предпазва да строиш върху хаос.

Четирите sub-pattern-а

0a. Method extraction (основата)

Цел: разбий големите методи на малки, фокусирани методи, така че човек да може да чете намерението линейно.

Правила на палеца:

  • разбивай методи, които са твърде дълги, за да ги държиш в работната памет
  • всеки extracted method трябва да прави едно нещо и да има описателно име
  • извличай смислени стъпки, не произволни парчета от N реда

Защо работи (особено при debugging):

  • по-малките методи създават етикети за execution path-а
  • scroll от 2000 реда става кратък orchestration method, през който можеш да минеш наум
  • можеш да сложиш breakpoints на семантични граници („validate input“, „build query“, „apply filters“), вместо да ловуваш

0b. Conciseness (намаляване на incidental complexity)

Цел: махни визуалния шум, за да изпъкне намерението.

Примери:

  • извади повтарящи се изрази в локални променливи
  • извади повтарящи се log contexts / key strings / URL fragments в променливи
  • предпочитай езикови features, които предават намерението директно
  • опрости прекалено бъбривата interpolation

Защо работи:

  • намалява когнитивния товар
  • прави diff-овете по-малки и промените по-безопасни
  • предотвратява copy/paste drift

0c. Empathy (чиста четимост)

Цел: пиши за следващия човек, не за compiler-а.

Empathy означава:

  • използвай описателни имена на променливи (избягвай $e, $d, $tmp, освен ако наистина са очевидни)
  • поддържай последователна терминология в модула
  • преименувай подвеждащи имена
  • прави кода self-documenting

Litmus test:

Ако някой чете това в 2 сутринта по време на инцидент, ще му помогне ли да задържи execution path-а в главата си?

0d. Dead code removal (махане на лъжите)

Цел: изтрий всичко, което се преструва, че има значение, но няма.

Примери:

  • unused private methods
  • unused imports
  • commented-out стари подходи
  • deprecated helpers, които никой не вика

Защо работи:

  • по-малко код означава по-малко неща за погрешно разбиране
  • резултатите от search стават надеждни

Какво Type 0 не е

Type 0 не е:

  • промяна на service boundaries
  • въвеждане на нови абстракции или patterns
  • re-architecting на workflow
  • подмяна на библиотеки
  • пренареждане на отговорности между layers
  • „поправяне“ на логика, която подозираш, че е грешна (освен ако изрично не обявиш промяна в поведението и не я тестваш)

Ако се хванеш да казваш:

  • „Докато съм тук, нека също...“
  • „Това би било по-хубаво, ако...“
  • „Вероятно трябва да redesign-нем...“

Може би напускаш Type 0. Това не е лошо само по себе си, но трябва да е умишлено.


Основното обещание: запазване на поведението (и как да остане вярно)

Type 0 работи само ако екипите вярват на обещанието.

И да, прав си да си подозрителен: method extraction може случайно да промени поведение (early returns, variable scope, evaluation order, exception behavior).

Затова Type 0 има нужда от дисциплина, която го държи честен:

Extract as-is, then rename/cleanup.

  • First pass: премести код в методи, без да променяш логиката
  • Second pass: приложи conciseness + empathy
  • Third pass: махни dead code

Практични guardrails:

  • не пренареждай condition checks „за четимост“
  • не заменяй логика с „еквивалентна“ логика, освен ако вече си извън Type 0
  • внимавай с променливи, които преди са били в shared scope
  • третирай „малките“ control-flow разлики като реални разлики

И ако имаш каквато и да е safety net, дори тънка:

  • пусни фокусиран test
  • replay-ни failing scenario-то
  • валидирай единствения path, който докосваш

Type 0 е за това да си бърз — но бърз чрез намаляване на cognitive complexity, не бърз чрез прескачане на safety.


Type 0 като повтаряем екипен ритуал

1) Реши обхвата (timebox помага)

Примери:

  • „Type 0 the hot path before debugging.“
  • „Type 0 only the path touched by this bug fix.“

2) Идентифицирай „гръбнака“ на кода

Намери entry method(s) и branching points. Превърни този гръбнак в четим разказ чрез extraction.

3) Приложи четирите sub-pattern-а по ред

Method extraction → conciseness → empathy → dead code removal.

4) Дръж „Type 0 checklist“ в PR-а си

  • No behavior changes (inputs/outputs unchanged)
  • No architectural moves
  • Methods extracted and named as meaningful steps
  • Repeated expressions extracted where it improves clarity
  • Variables renamed; terminology consistent
  • Dead code and unused imports removed

Финална мисъл

Type 0 refactoring е най-простото обещание, което един developer може да даде:

„Оставям този код по-лесен за работа, отколкото го намерих — без да променям какво прави.“

Понякога е “nice to have”.

А понякога е единственият начин човек безопасно да се движи бързо в mess с висока complexity, особено по време на hotfix.


Коментари

Boris D. Teoharov

Автор

Здравей, аз съм Борис

Не съм писател. Не съм философ. Просто съм backend инженер от България, който живее между Laravel опашки и индекси със стотици милиони редове. През останалото време чета медицина, която няма работа да чета, френски романи, които разбирам наполовина, и каквото още малката ми гумена глава реши да дъвче. Две спасени кучета ме държат честен.