Монолитные устаревшие системы (Legacy Systems), развивавшиеся годами без формализованной архитектуры и документации, аккумулируют тысячи неявных бизнес-правил, распределенных по процедурному коду, триггерам баз данных, глобальным переменным и побочным эффектам. Попытка переписать такой код вслепую неизбежно приводит к утрате критических пограничных условий (edge cases), нарушению целостности данных и финансовым потерям.
Классический подход к обратному инжинирингу вручную не масштабируется: анализ сотен тысяч строк спагетти-кода с высокой цикломатической сложностью требует экспоненциальных временных затрат. В свою очередь, прямая передача гигантских монолитных файлов в контекстное окно больших языковых моделей (LLM) приводит к эффекту «потери в середине» (Lost in the Middle), галлюцинациям в бизнес-инвариантах и упущению неявных связей.
Инженерное решение 2026 года объединяет детерминированный статический анализ AST (Abstract Syntax Tree), построение графов вызовов (Call Graphs) и агентные пайплайны декомпозиции. Агент оперирует не «сырым» текстом, а изолированными программными срезами (Program Slices), извлекая чистые контракты, инварианты предметной области и формализуя их в исполняемые спецификации и визуальные диаграммы (Mermaid / PlantUML).
Процесс обратного инжиниринга строится на конвейере преобразования неструктурированного процедурного кода в формализованную архитектурную модель через синтаксическое расслоение:
[Legacy Source Code (PHP/Monolith)]
│
▼ (Static Analysis: Tree-sitter / PHP-Parser)
[Abstract Syntax Tree (AST)] ──► [Symbol Table & Call Graph (CFG)]
│
▼ (Program Slicing: Data & Control Dependencies)
[Isolated Slices / Execution Paths]
│
▼ (AI Analysis Engine: Structured Invariant Extraction)
[Formal Contracts & Business Invariants (Zod / JSON Schema)]
│
├──► [Mermaid Sequence & State Diagrams]
└──► [Executable Specifications (Gherkin / OpenAPI)]if/else и неявными зависимостями от сессии.$wpdb и фильтров apply_filters для безопасного выноса логики заказов в изолированный headless-сервис.$_POST / $_GET.Для извлечения логики агент использует двухфазный пайплайн: детерминированное построение AST-среза и последующий структурированный анализ агентом с валидацией через Zod.
Рассмотрим пример legacy-функции расчета скидок и оформления заказа, содержащей процедурный спагетти-код с глобальным состоянием:
<?php
// Legacy-обработчик оформления заказа (спагетти-код без типизации)
function process_legacy_order($user_id, $items, $coupon = null) {
global $wpdb, $current_user_session;
$total = 0;
$applied_discount = 0;
$tier = 'STANDARD';
// Неявная зависимость: выборка внутреннего ранга из кастомной таблицы
$user_meta = $wpdb->get_row("SELECT * FROM legacy_user_stats WHERE uid = " . intval($user_id));
if ($user_meta && $user_meta->orders_count > 50 && $user_meta->total_spent > 100000) {
$tier = 'PLATINUM';
} elseif ($user_meta && $user_meta->orders_count > 10) {
$tier = 'GOLD';
}
foreach ($items as $item) {
$price = floatval($item['price']) * intval($item['qty']);
// Скрытое правило: на категорию 42 скидка tier не действует
if (isset($item['category_id']) && $item['category_id'] == 42) {
$total += $price;
continue;
}
if ($tier === 'PLATINUM') {
$price = $price * 0.85; // 15% скидка
} elseif ($tier === 'GOLD') {
$price = $price * 0.92; // 8% скидка
}
$total += $price;
}
// Обработка купона с мутацией сессии
if ($coupon !== null && !empty(trim($coupon))) {
$c_res = $wpdb->get_row("SELECT * FROM coupons WHERE code = '" . esc_sql($coupon) . "' AND is_active = 1");
if ($c_res) {
// Инвариант: купон не может уменьшить чек ниже 500 единиц
$discount_amount = floatval($c_res->amount);
if ($total - $discount_amount < 500) {
$applied_discount = $total - 500;
$total = 500;
} else {
$applied_discount = $discount_amount;
$total -= $discount_amount;
}
$current_user_session['last_applied_coupon'] = $coupon;
}
}
// Прямой сайд-эффект: сохранение в БД минуя ORM
$wpdb->insert('orders', [
'user_id' => $user_id,
'final_amount' => $total,
'discount_amount' => $applied_discount,
'user_tier' => $tier,
'created_at' => date('Y-m-d H:i:s')
]);
return [
'order_id' => $wpdb->insert_id,
'amount' => $total,
'tier' => $tier
];
}Для автоматизированного извлечения бизнес-правил запускается TypeScript-агент, использующий структурированный вывод Vercel AI SDK и схему Zod для формализации требований:
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
// Схема извлеченной бизнес-спецификации
const BusinessRuleSchema = z.object({
entity: z.string().describe('Основная бизнес-сущность (например, Order, Pricing, UserTier)'),
invariants: z.array(
z.object({
ruleId: z.string().describe('Идентификатор инварианта (например, RULE-TIER-01)'),
description: z.string().describe('Четкая формулировка бизнес-правила'),
conditions: z.array(z.string()).describe('Входные условия срабатывания правила'),
edgeCases: z.array(z.string()).describe('Пограничные условия (ограничения снизу/сверху)'),
sideEffects: z.array(z.string()).describe('Мутации состояния базы, сессии или внешних API'),
})
),
stateTransitions: z.array(
z.object({
fromState: z.string(),
toState: z.string(),
trigger: z.string(),
})
),
mermaidDiagram: z.string().describe('PlantUML или Mermaid Sequence/State диаграмма процесса'),
});
export type BusinessRuleSpec = z.infer<typeof BusinessRuleSchema>;
export async function reverseEngineerLegacyCode(
sourceCode: string,
functionName: string
): Promise<BusinessRuleSpec> {
const prompt = `
Ты — Staff Reverse-Engineering Architect. Проведи глубокий статический анализ предоставленного исходного кода функции ${functionName}.
ТРЕБОВАНИЯ:
1. Извлеки ВСЕ скрытые бизнес-правила, включая жестко закодированные константы (hardcoded thresholds).
2. Выяви скрытые мутации глобального контекста (сессии, прямое обращение к SQL).
3. Найди инварианты предметной области (какие ограничения никогда не должны нарушаться).
4. Построй строгую диаграмму Mermaid Sequence, иллюстрирующую потоки данных и ветвления.
Исходный код:
\`\`\`php
${sourceCode}
\`\`\`
`;
const { object } = await generateObject({
model: openai('gpt-4o', { structuredOutputs: true }),
schema: BusinessRuleSchema,
prompt,
temperature: 0.1, // Минимизация недетерминизма для точности анализа
});
return object;
}Результат выполнения агента формирует спецификацию бизнес-логики и диаграмму потока, готовую к включению в Living Documentation и спецификацию требований:
### Извлеченные инварианты ценообразования (Generated Spec)
#### Инвариант RULE-TIER-01 (Определение ранга лояльности):
- **Условие Platinum:** `orders_count > 50` И `total_spent > 100000` -> Скидка 15% (`price * 0.85`).
- **Условие Gold:** `orders_count > 10` -> Скидка 8% (`price * 0.92`).
- **Исключение (Blacklist Category):** Категория `category_id = 42` исключена из применения любых скидок по рангу лояльности.
#### Инвариант RULE-COUPON-02 (Нижний предел чека):
- При применении купона итоговая сумма (`total`) не может быть ниже жесткого лимита `500.00`. Если скидка превышает доступный остаток, скидка принудительно урезается: `applied_discount = total - 500`.
#### Mermaid Sequence Diagram потока вычислений:
\`\`\`mermaid
sequenceDiagram
autonumber
participant Client
participant OrderEngine as Order Engine
participant DB as MySQL (wpdb)
participant Session as Global Session
Client->>OrderEngine: process_legacy_order(userId, items, coupon)
OrderEngine->>DB: SELECT * FROM legacy_user_stats WHERE uid = userId
DB-->>OrderEngine: orders_count, total_spent
Note over OrderEngine: Определение User Tier (PLATINUM/GOLD/STANDARD)
loop Для каждого элемента корзины
alt Category ID == 42
Note over OrderEngine: Игнорировать tier-скидку
else Tier скидка применима
Note over OrderEngine: Применить 15% (Platinum) или 8% (Gold)
end
end
opt Купон передан
OrderEngine->>DB: SELECT * FROM coupons WHERE code = coupon
DB-->>OrderEngine: coupon data
alt (total - discount) < 500
Note over OrderEngine: Усечение скидки до порога floor = 500
else
Note over OrderEngine: Вычет полной суммы купона
end
OrderEngine->>Session: set last_applied_coupon = coupon
end
OrderEngine->>DB: INSERT INTO orders (user_id, final_amount, tier, ...)
DB-->>OrderEngine: order_id
OrderEngine-->>Client: { order_id, amount, tier }
\`\`\`Попытка скопировать файл на 5000 строк напрямую в окно контекста модели приводит к пропуску пограничных условий ветвления (switch/case, вложенные циклы). Решение: предварительный статический парсинг AST, вычисление цикломатической сложности и изоляция методов в Program Slices до отправки агенту.
В спагетти-коде часто присутствуют дефекты (например, конкатенация строк в математических операциях или отсутствие блокировки строк при списании баланса). Агент без проверочных правил может объявить баг «требованием заказчика». Всегда помечайте подозрительные участки тегом ANOMALY_SUSPECTED для подтверждения архитектором.
Legacy-функции нередко меняют суперглобальные массивы ($_SESSION, $GLOBALS, глобальные переменные WordPress $post, $authordata). Если агент анализирует только входные параметры (arguments) и возвращаемое значение (return), скрытый сайд-эффект будет утерян, что приведет к регрессионным сбоям в смежных модулях.
В устаревших архитектурах встречаются рекурсивные вызовы через систему событий или хуков (Hook Recursion). Построение графа зависимостей без детекции циклов приводит к зацикливанию анализаторов и искажению иерархии вызовов.
Парсинг исходных файлов в Abstract Syntax Tree с помощью Tree-sitter или PHP-Parser, удаление форматирования.
Картирование связей между функциями, внешними библиотеками и SQL-запросами, детекция цикломатических путей.
Выделение изолированных блоков кода, управляющих ключевыми переменными предметной области.
Запуск LLM-агента со строгой схемой Zod для генерации предикатов, условий и сайд-эффектов.
Автоматическая компиляция извлеченных данных в диаграммы Mermaid Sequence/State и спецификации Gherkin.
Сопоставление полученных инвариантов с логами продакшена и историческими транзакциями БД.