Nieograniczona pamięć robocza
Podczas gdy ludzie mają problemy z 7±2 elementami w pamięci roboczej, modele AI mogą analizować setki plików jednocześnie, śledząc zależności, których nigdy nie dostrzegłbyś ręcznie.
Nawigowanie po milionowych kodach źródłowych przypomina eksplorację rozległego miasta bez mapy. Każda zmiana wywołuje fale w niezliczonych zależnościach, a zrozumienie pełnego wpływu wymaga nadludzkiej pamięci. Ten przewodnik pokazuje, jak asystenci kodowania AI przekształcają tę złożoność w zarządzalne przepływy pracy.
Gdy kod źródłowy przekracza próg miliona linii, tradycyjne podejścia do rozwoju przestają działać. Masz do czynienia z:
Rozwiązaniem nie jest cięższa praca - to wykorzystanie asystentów AI, którzy mogą przetwarzać i rozumieć kod na skalę maszynową, podczas gdy ty skupiasz się na decyzjach architektonicznych.
Nieograniczona pamięć robocza
Podczas gdy ludzie mają problemy z 7±2 elementami w pamięci roboczej, modele AI mogą analizować setki plików jednocześnie, śledząc zależności, których nigdy nie dostrzegłbyś ręcznie.
Zrozumienie semantyczne
AI nie tylko przeszukuje ciągów znaków - rozumie intencję kodu, znajdując koncepcyjnie powiązane funkcje przez różne konwencje nazewnictwa i implementacje.
Wykrywanie wzorców na skalę
Identyfikuje anty-wzorce, zduplikowaną logikę i możliwości optymalizacji, których odkrycie zajęłoby miesiące ręcznego przeglądu kodu.
Bezstrachowy refactoring
Wykonuj rozległe zmiany w tysiącach plików z pewnością, podczas gdy AI śledzi wszystkie wpływy i sugeruje niezbędne dostosowania.
Zanim przejdziemy do strategii, potrzebujesz odpowiednich narzędzi. Te serwery MCP przekształcają sposób, w jaki asystenci AI rozumieją i nawigują po masywnych kodach źródłowych:
Gdy masz do czynienia z milionami linii, tradycyjne wyszukiwanie tekstowe zawodzi. Potrzebujesz zrozumienia semantycznego.
Instalacja dla Claude Code:
claude mcp add code-context -e OPENAI_API_KEY=your-api-key -e MILVUS_TOKEN=your-zilliz-key -- npx @zilliz/code-context-mcp@latest
Instalacja dla Cursor:
Dodaj do ~/.cursor/mcp.json
:
{ "mcpServers": { "code-context": { "command": "npx", "args": ["-y", "@zilliz/code-context-mcp@latest"], "env": { "EMBEDDING_PROVIDER": "OpenAI", "OPENAI_API_KEY": "your-api-key", "MILVUS_TOKEN": "your-zilliz-key" } } }}
Ten serwer używa embeddingów wektorowych do semantycznego rozumienia kodu. Zapytaj “znajdź wszystkie przepływy uwierzytelniania”, a zrozumie koncepcję przez różne implementacje - czy to OAuth, JWT, czy oparte na sesjach.
Do błyskawicznego dopasowywania regex i wzorców w masywnych kodach źródłowych:
Instalacja dla Claude Code:
claude mcp add-json "ripgrep" '{"command":"npx","args":["-y","mcp-ripgrep@latest"]}'
Przykład użycia:
"Użyj ripgrep, aby znaleźć wszystkie komentarze TODO o wysokim priorytecie w kodzie źródłowym""Szukaj wszystkich zapytań SQL, które mogą być podatne na iniekcje""Znajdź wszystkie endpointy API, które nie mają ograniczenia częstotliwości"
Dla wrażliwych kodów źródłowych przedsiębiorstw, które nie mogą korzystać z usług chmurowych:
Luoto Local Code Search używa ChromaDB do lokalnego wyszukiwania wektorowego:
# Konfiguruj środowiskoPROJECTS_ROOT=~/enterprise/codeFOLDERS_TO_INDEX=core-services,payment-engine,user-platform
# Dodaj do Cursorclaude mcp add-json "workspace-code-search" '{"url":"http://localhost:8978/sse"}'
To utrzymuje kod lokalnie, zapewniając jednocześnie możliwości wyszukiwania semantycznego - kluczowe dla usług finansowych, opieki zdrowotnej czy wykonawców obronnych.
Odziedziczyłeś 3-milionowy monolit. Od czego w ogóle zacząć? Oto sprawdzone w boju podejście:
Zacznij od szerokiego zrozumienia architektonicznego:
"Przeanalizuj ten kod źródłowy i stwórz model mentalny architektury systemu.Skup się na:1. Głównych domenach biznesowych2. Granicach usług3. Wzorcach przepływu danych4. Zależnościach zewnętrznych
Przedstaw jako przegląd wysokiego poziomu odpowiedni dla nowego starszego inżyniera."
Następnie zagłęb się w konkretne obszary:
"Używając wyszukiwania code-context, znajdź wszystkie przepływy przetwarzania płatności.Muszę zrozumieć:- Punkty wejścia dla żądań płatności- Zarządzanie stanem podczas przetwarzania- Integrację z zewnętrznymi dostawcami płatności- Obsługę błędów i logikę ponownych prób"
Wykorzystaj indeksowanie kodu źródłowego Cursor:
@codebase "Wyjaśnij architekturę uwierzytelniania i autoryzacji"
@folders services/auth "Jak działa odświeżanie tokenów w tym systemie?"
@search_code "implementacja OAuth""Pokaż mi wszystkie przepływy OAuth2 i wyjaśnij obsługiwane typy grantów"
Użyj widoku outline do nawigacji:
Cmd/Ctrl+Shift+O"payment"# Szybko przeskocz do kodu związanego z płatnościami w plikach
Zrozumienie, jak moduły się łączą, jest kluczowe dla bezpiecznego refactoringu:
"Utwórz wykres zależności dla modułu UserService:1. Od jakich usług zależy?2. Jakie usługi od niego zależą?3. Czy są jakieś zależności cykliczne?4. Które zależności wyglądają problematycznie lub są silnie sprzężone?"
Kontynuuj konkretnymi badaniami:
"UserService zależy od 47 innych usług.Pomóż mi zidentyfikować, które zależności są rzeczywiście niezbędnevs. które można zrefaktoryzować do używania zdarzeń lub interfejsów."
Największy błąd, jaki popełniają programiści z dużymi kodami źródłowymi? Próbowanie załadowania wszystkiego naraz. Twój asystent AI nie musi widzieć wszystkich 3 milionów linii - potrzebuje odpowiedniego kontekstu w odpowiednim czasie.
Myśl o kontekście jak o przybliżaniu na mapie. Zacznij od widoku kontynentu, potem kraj, potem miasto, potem ulica:
Poziom domeny (widok z 10 000 stóp)
"Jakie są główne konteksty ograniczone w tym systemie?""Jak domeny płatności, użytkowników i inwentarza oddziałują?"
Poziom usługi (widok z 1000 stóp)
"W domenie płatności wyjaśnij architekturę usług""Jakie są główne API udostępniane przez usługi płatności?"
Poziom komponentu (widok ze 100 stóp)
"Pokaż mi, jak PaymentProcessor obsługuje transakcje kartą kredytową""Jaka jest strategia ponownych prób dla nieudanych płatności?"
Poziom implementacji (poziom gruntu)
"W PaymentProcessor.processCard(), dlaczego jest timeout 30 sekund?""Czy powinniśmy zrefaktoryzować ten zsynchronizowany blok?"
Wzorzec 1: Hierarchiczne pliki CLAUDE.md
/CLAUDE.md # Konwencje całego systemu/services/CLAUDE.md # Wzorce warstwy usług/services/payment/CLAUDE.md # Reguły specyficzne dla płatności/services/payment/core/CLAUDE.md # Reguły podstawowej logiki płatności
Każdy poziom dziedziczy od swojego rodzica, tworząc ukierunkowany kontekst:
# W /services/payment/CLAUDE.mdTa usługa obsługuje całe przetwarzanie płatności.kluczowe zasady:- Wszystkie kwoty w centach, aby uniknąć liczb zmiennoprzecinkowych- Klucze idempotentności wymagane dla wszystkich transakcji- Zgodność PCI: nigdy nie loguj pełnych numerów kart
Wspólne wzorce w tej usłudze:- Wzorzec repozytorium dla dostępu do danych- Wzorzec poleceń dla operacji płatności- Event sourcing dla historii transakcji
Wzorzec 2: Polecenia przełączania kontekstu
# Wyczyść kontekst między niepowiązanymi zadaniami/clear
# Pracuj nad systemem płatności/add services/payment"Przeanalizuj przepływ przetwarzania płatności"
# Przełącz na system użytkowników/clear/add services/users"Przejrzyj implementację uwierzytelniania"
Wzorzec 1: Kontekst z zakresem za pomocą symboli @
# Szeroki kontekst dla pytań architektonicznych@folders services/payment"Wyjaśnij architekturę płatności"
# Wąski kontekst dla konkretnych zmian@PaymentProcessor.java @PaymentRepository.java"Zrefaktoryzuj, aby używać przetwarzania asynchronicznego"
# Zagadnienia przekrojowe@search "implements PaymentGateway""Wymień wszystkie implementacje bramek płatności"
Wzorzec 2: Reguły specyficzne dla projektu
# W .cursorrules w katalogu głównym projektuPodczas pracy z kodem płatności:- Sprawdź idempotentność wszystkich mutacji- Zweryfikuj zgodność PCI dla danych kart- Upewnij się, że wszystkie kwoty używają centów całkowitych- Dodaj wszechstronne logowanie audytu
Podczas analizy wydajności:- Najpierw sprawdź zapytania bazy danych- Szukaj wzorców zapytań N+1- Zweryfikuj ustawienia puli połączeń- Sprawdź brakujące indeksy
Reguła 80/20 dla kontekstu
80% twoich pytań potrzebuje tylko 20% kodu źródłowego. Nie zaśmiecaj kontekstu rzadko używanymi narzędziami:
# Źle: Ładowanie wszystkiego"Załaduj cały kod i znajdź problemy z wydajnością"
# Dobrze: Ukierunkowane ładowanie"W potoku przetwarzania zamówień (services/orders/pipeline/),zidentyfikuj wąskie gardła w Order.process() przez Order.ship()"
Progresywne rozszerzanie kontekstu
Zacznij wąsko i rozszerzaj tylko gdy potrzeba:
# Krok 1: Zrozum problem@OrderService.java "Dlaczego przetwarzanie zamówień trwa 5+ sekund?"
# Krok 2: Rozszerz na powiązane usługi@orders/ @inventory/ "Czy opóźnienie wynika ze sprawdzeń inwentarza?"
# Krok 3: Włącz infrastrukturę@orders/ @database/migrations/ @config/"Czy to może być problem z indeksowaniem bazy danych?"
Refactoring milionowego kodu źródłowego to jak renowacja szpitala podczas trwania operacji. Nie możesz wszystkiego wyłączyć do przepisania. Oto jak wprowadzać systematyczne ulepszenia bezpiecznie:
Twój kod źródłowy Node.js ma 50 000 funkcji callback. Ręczna migracja zajęłaby lata. Oto podejście wspomagane przez AI:
Faza 1: Odkrywanie i planowanie
"Używając ripgrep, znajdź wszystkie wzorce callback w kodzie źródłowym.Skategoryzuj je według:1. Proste callbacki (pojedyncza operacja asynchroniczna)2. Łańcuchy callbacków (wiele sekwencyjnych operacji)3. Równoległe callbacki (wiele współbieżnych operacji)4. Callbacki error-first z złożoną obsługą błędów5. Callbacki ze współdzielonym stanem lub domknięciami
Wygeneruj raport złożoności migracji."
Przykładowa odpowiedź:
Znaleziono 47 832 wzorce callback:- Proste callbacki: 31 245 (65%) - Niskie ryzyko- Łańcuchy callbacków: 9 823 (21%) - Średnie ryzyko- Równoległe callbacki: 4 234 (9%) - Wysokie ryzyko- Złożona obsługa błędów: 1 830 (4%) - Wysokie ryzyko- Callbacki ze współdzielonym stanem: 700 (1%) - Bardzo wysokie ryzyko
Zalecana kolejność migracji: Zacznij od prostych callbackóww funkcjach narzędziowych, potem przejdź do warstwy usług...
Faza 2: Tworzenie wzorców migracji
"Dla każdego typu wzorca callback utwórz bezpieczny szablon migracji.Uwzględnij:1. Wzorzec transformacji2. Przypadki graniczne, na które należy zwrócić uwagę3. Strategię testowania4. Plan wycofania"
AI generuje wzorce wielokrotnego użytku:
// Przedfunction loadUser(id, callback) { db.query('SELECT * FROM users WHERE id = ?', [id], (err, result) => { if (err) return callback(err); callback(null, result[0]); });}
// Po (z kompatybilnością wsteczną)async function loadUser(id, callback) { // Obsługuj zarówno styl callback jak i promise if (callback) { try { const result = await db.query('SELECT * FROM users WHERE id = ?', [id]); callback(null, result[0]); } catch (err) { callback(err); } } else { const result = await db.query('SELECT * FROM users WHERE id = ?', [id]); return result[0]; }}
// Przedfunction processOrder(orderId, callback) { loadOrder(orderId, (err, order) => { if (err) return callback(err); validateInventory(order.items, (err, valid) => { if (err) return callback(err); if (!valid) return callback(new Error('Insufficient inventory')); chargePayment(order.paymentInfo, (err, charge) => { if (err) return callback(err); updateOrderStatus(orderId, 'completed', callback); }); }); });}
// Poasync function processOrder(orderId, callback) { try { const order = await loadOrder(orderId); const valid = await validateInventory(order.items); if (!valid) throw new Error('Insufficient inventory'); const charge = await chargePayment(order.paymentInfo); const result = await updateOrderStatus(orderId, 'completed');
if (callback) callback(null, result); else return result; } catch (err) { if (callback) callback(err); else throw err; }}
Faza 3: Zautomatyzowana migracja
"Używając wzorców migracji, przekształć wszystkie proste callbackiw katalogu utils/. Dla każdego pliku:1. Zastosuj transformację2. Zachowaj kompatybilność wsteczną3. Dodaj komentarze deprecation4. Aktualizuj lub utwórz testy5. Śledź status migracji"
Dla masywnych wysiłków refactoringu, koordynuj wiele instancji AI:
Podziel kod źródłowy
"Przeanalizuj zależności modułów i zasugeruj, jak podzielićkod źródłowy do równoległego refactoringu przez 4 programistów.Minimalizuj konflikty między zespołami."
Utwórz gałęzie funkcji
git checkout -b refactor/team1-user-servicesgit checkout -b refactor/team2-payment-servicesgit checkout -b refactor/team3-inventory-servicesgit checkout -b refactor/team4-shared-utils
Synchronizuj postęp
"Przejrzyj zmiany we wszystkich gałęziach refactor/*.Zidentyfikuj potencjalne konflikty lub zmiany łamiącemiędzy pracą zespołów."
Testowanie integracji
"Wygeneruj testy integracji, które weryfikują, czy zrefaktoryzowanemoduły działają prawidłowo razem. Skup się na interakcjachgranicznych między terytoriami zespołów."
W milionowych kodach źródłowych problemy z wydajnością kryją się w nieoczekiwanych miejscach. Niewinnie wyglądająca funkcja wywołana w ciasnej pętli może zwalić cały system. Oto jak systematycznie polować na problemy z wydajnością i je naprawiać:
Krok 1: Analiza złożoności algorytmicznej
"Używając analizy kodu, znajdź wszystkie potencjalne algorytmy O(n²) lub gorsze.Dla każdego określ:1. Jak często jest wywoływany2. Typowy rozmiar wejścia3. Czy jest na ścieżce krytycznej4. Sugerowane podejście do optymalizacji"
Przykładowe odkrycia:
Znaleziono 47 potencjalnych algorytmów kwadratowych:
KRYTYCZNE - UserMatcher.findDuplicates()- Wywoływany przy każdej rejestracji użytkownika- Przetwarza 2,3M użytkowników- Obecny czas: ~18 sekund- Naprawa: Użyj podejścia opartego na hash, zmniejszając do O(n)
WYSOKIE - ReportGenerator.crossTabulate()- Wywoływany w nocnych zadaniach wsadowych- Przetwarza macierz 100K x 100K- Obecny czas: ~4 godziny- Naprawa: Użyj reprezentacji macierzy rzadkiej
Zabójca wydajności #1 w dużych aplikacjach? Zapytania bazy danych. Oto systematyczne podejście:
"Przeanalizuj kod źródłowy pod kątem anty-wzorców wydajności bazy danych:1. Zapytania N+1 w użyciu ORM2. Brakujące indeksy na kluczach obcych3. Zapytania bez paginacji4. Niepotrzebne eager loading5. Zapytania wewnątrz pętli
Dla każdego znalezionego problemu podaj:- Lokalizację w kodzie- Szacunkowy wpływ na wydajność- Konkretną naprawę z przykładem kodu"
AI identyfikuje:
// Problem: zapytania N+1 w OrderServiceasync function getOrdersWithItems(userId) { const orders = await Order.findAll({ where: { userId } });
// To tworzy zapytania N+1! for (const order of orders) { order.items = await OrderItem.findAll({ where: { orderId: order.id } }); } return orders;}
Sugerowana naprawa:
// Rozwiązanie: Użyj eager loadingasync function getOrdersWithItems(userId) { const orders = await Order.findAll({ where: { userId }, include: [{ model: OrderItem, as: 'items' }] }); return orders;}
// Lub użyj surowego SQL dla złożonych przypadkówasync function getOrdersWithItemsOptimized(userId) { const query = ` SELECT o.*, JSON_AGG(oi.*) as items FROM orders o LEFT JOIN order_items oi ON oi.order_id = o.id WHERE o.user_id = $1 GROUP BY o.id `; return await db.query(query, [userId]);}
-- AI identyfikuje brakujące indeksy"Znaleziono 23 klucze obce bez indeksów.Zapytania o największym wpływie:
1. OrderItems.order_id (4,2M rzędów) Używany w: OrderService.getOrderDetails() Obecny czas wykonania: 823ms Z indeksem: ~12ms
2. UserSessions.user_id (18M rzędów) Używany w: AuthService.validateSession() Obecny czas wykonania: 1,4s Z indeksem: ~8ms"
-- Wygenerowana migracjaCREATE INDEX CONCURRENTLY idx_order_items_order_idON order_items(order_id);
CREATE INDEX CONCURRENTLY idx_user_sessions_user_idON user_sessions(user_id)WHERE active = true; -- Indeks częściowy dla aktywnych sesji
Wycieki pamięci w dużych aplikacjach są podstępne. Budują się powoli, aż serwery zaczynają się crashować:
"Szukaj typowych wzorców wycieków pamięci:1. Event listenery bez czyszczenia2. Domknięcia trzymające duże obiekty3. Referencje cykliczne4. Rosnące cache bez limitów5. Timery, które nigdy się nie czyszczą
Skup się na długotrwałych usługach i workerach w tle."
AI znajduje problemy takie jak:
// Wyciek pamięci w WebSocketManagerclass WebSocketManager { constructor() { this.connections = new Map(); }
addConnection(userId, socket) { // WYCIEK: Stare połączenia nigdy nie usuwane! this.connections.set(userId, socket);
socket.on('message', (data) => { // WYCIEK: Domknięcie trzyma referencję do całego managera this.handleMessage(userId, data); }); }}
// Naprawa z odpowiednim czyszczeniemclass WebSocketManager { constructor() { this.connections = new Map(); }
addConnection(userId, socket) { // Usuń istniejące połączenie this.removeConnection(userId);
const messageHandler = (data) => { this.handleMessage(userId, data); };
socket.on('message', messageHandler); socket.on('close', () => this.removeConnection(userId));
this.connections.set(userId, { socket, handlers: { message: messageHandler } }); }
removeConnection(userId) { const conn = this.connections.get(userId); if (conn) { conn.socket.removeAllListeners(); this.connections.delete(userId); } }}
Każdy duży kod źródłowy ma swoje warstwy archeologiczne - kod napisany w różnych epokach, przez różne zespoły, z różnymi filozofiami. Część z niego poprzedza kontrolę wersji. Oto jak bezpiecznie wykopywać i modernizować:
Odkryłeś 15 000-liniową procedurę składowaną, która obsługuje cały system rozliczeniowy. Nikt jej nie rozumie, ale przetwarza 10 milionów dolarów dziennie. Oto podejście:
Metoda archeologiczna
"Przeanalizuj tę procedurę składowaną (billing_mega_proc.sql) i:1. Utwórz diagram przepływu wysokiego poziomu2. Wyodrębnij główne reguły biznesowe3. Zidentyfikuj główne transformacje danych4. Znajdź wszelkie ukryte efekty uboczne5. Zasugeruj, jak rozłożyć to na usługi
Traktuj to jak inżynierię wsteczną obcego artefaktu.Bądź bardzo ostrożny z subtelną logiką biznesową."
AI odpowiada strukturalną analizą:
Analiza billing_mega_proc.sql:
ODKRYTE GŁÓWNE REGUŁY BIZNESOWE:1. Ceny poziomowe z 47 szczególnymi przypadkami2. Zniżki dla legacy klientów (niektóre zakodowane na sztywno według ID!)3. Złożone obliczanie podatków z wariantami regionalnymi4. Generowanie ścieżki audytu (pisze do 6 różnych tabel)
UKRYTE ZACHOWANIA:- Wysyła maile bezpośrednio z bazy danych (!)- Aktualizuje inwentarz jako efekt uboczny- Tworzy wpisy księgowe- Ma nieudokumentowany "tryb debug" gdy user_id = 1
STRATEGIA DEKOMPOZYCJI:1. Wyodrębnij silnik cenowy (pure functions)2. Oddzielny serwis kalkulatora podatków3. Przenies wysyłanie maili do kolejki wiadomości4. Utwórz odpowiedni serwis audytu
Zamiast przepisywać wszystko na raz, stopniowo dłavić legacy system:
"Utwórz nowoczesną bramę API, która opakuje legacy system rozliczeniowy.Wymagania:- Endpointy RESTful dla wszystkich operacji rozliczeniowych- Nadal wywoływaj legacy procedurę składowaną wewnętrznie- Dodaj odpowiednią obsługę błędów i logowanie- Zwróć spójne odpowiedzi JSON- Dodaj dokumentację OpenAPI"
To daje ci:
// Nowoczesne API opakowujące legacy system@Post('/billing/calculate')async calculateBilling(@Body() request: BillingRequest) { try { // Nadal wywołuje potworną procedurę składowaną const result = await this.db.callProcedure( 'billing_mega_proc', request.customerId, request.items, request.date );
// Przekształć krypticzną odpowiedź na nowoczesny format return { success: true, invoice: this.transformLegacyInvoice(result), timestamp: new Date().toISOString() }; } catch (error) { // Legacy proc zwraca błędy jako magiczne liczby const errorMessage = this.decodeLegacyError(error); throw new HttpException(errorMessage, 400); }}
"Teraz wyodrębnij obliczanie cen z procedury składowanejdo nowoczesnej usługi. Podejście:1. Utwórz PricingService, który dokładnie odpowiada zachowaniu legacy2. Dodaj wszechstronne testy porównujące wyjścia3. Uruchom oba równolegle i loguj wszelkie różnice4. Po uzyskaniu pewności, przełącz5. Usuń logikę cenową z procedury składowanej"
AI pomaga utworzyć infrastrukturę parallel-run:
async calculatePricing(items: LineItem[]): Promise<Pricing> { // Uruchom obie implementacje const [legacyResult, modernResult] = await Promise.all([ this.runLegacyPricing(items), this.runModernPricing(items) ]);
// Porównaj wyniki if (!this.resultsMatch(legacyResult, modernResult)) { this.logger.warn('Wykryto niezgodność cen', { items, legacy: legacyResult, modern: modernResult, diff: this.calculateDiff(legacyResult, modernResult) });
// Użyj wyniku legacy ale śledź rozbieżność this.metrics.increment('pricing.mismatch'); }
// Zwróć wynik legacy do pełnej walidacji return this.featureFlag('use-modern-pricing') ? modernResult : legacyResult;}
Gdy dokumentacja nie istnieje, testy stają się dokumentacją:
"Ten legacy moduł nie ma testów ani dokumentacji.Utwórz wszechstronną suite testów, która:1. Dokumentuje obecne zachowanie przez nazwy testów2. Ujmuje wszystkie przypadki graniczne, które możesz znaleźć3. Testuje warunki błędów i ich magiczne liczby4. Weryfikuje efekty uboczne
Testy powinny służyć jako żywa dokumentacja."
AI generuje testy charakteryzacyjne:
describe('Legacy OrderProcessor - Obecne zachowanie', () => { describe('Ścieżka szczęśliwa', () => { it('przetwarza standardowe zamówienie z pojedynczym elementem', async () => { // Dokumentuje obecne zachowanie const result = await processOrder({ customerId: 123, items: [{ sku: 'WIDGET-1', quantity: 1 }] });
expect(result.status).toBe(1); // Magiczna liczba: 1 = sukces expect(result.orderId).toMatch(/^ORD-\d{8}$/); // Format: ORD-YYYYMMDD }); });
describe('Przypadki graniczne - odkryte przez testowanie', () => { it('stosuje tajną 50% zniżkę dla klienta ID 777', async () => { // Nieudokumentowane zachowanie znalezione przez eksplorację! const result = await processOrder({ customerId: 777, // Magiczny klient items: [{ sku: 'ANY-ITEM', quantity: 1, price: 100 }] });
expect(result.totalPrice).toBe(50); });
it('zawodzi z kodem błędu -99 gdy inwentarz jest ujemny', async () => { // Więcej magicznych liczb udokumentowanych const result = await processOrder({ customerId: 123, items: [{ sku: 'OUT-OF-STOCK', quantity: 1 }] });
expect(result.status).toBe(-99); // -99 = błąd inwentarza }); });});
W milionowych kodach źródłowych różne zespoły posiadają różne terytoria. Wyzwanie? Wprowadzanie zmian obejmujących wiele domen bez wchodzenia sobie w drogę.
Gdy zespół A musi zrozumieć kod zespołu B:
Generator kontraktów API
"Przeanalizuj usługę płatności (należącą do zespołu FinTech) i wygeneruj:1. Specyfikację OpenAPI dla wszystkich endpointów2. Schematy zdarzeń dla wszystkich publikowanych zdarzeń3. Schematy baz danych dla współdzielonych tabel4. Przykładowe żądania/odpowiedzi5. Typowe scenariusze błędów i obsługę
Sformatuj to dla zespołu mobilnego, który musi się zintegrować."
To tworzy jasne granice:
# Wygenerowany payment-service-api.yamlopenapi: 3.0.0info: title: Payment Service API version: 2.3.0 contact: team: FinTech slack: #team-fintech
paths: /payments/process: post: summary: Przetwórz płatność description: | Obsługuje płatności kartą kredytową, PayPal i ACH. Idempotentne przy użyciu nagłówka X-Idempotency-Key. x-rate-limit: 100 żądań na minutę x-sla: 99.9% uptime, <500ms p99 latency
Przed wprowadzeniem zmian łamiących:
"Muszę zrefaktoryzować metodę UserService.authenticate().Przeanalizuj:1. Wszystkie usługi, które wywołują tę metodę2. Parametry, które przekazują3. Jak obsługują odpowiedź4. Jakie błędy oczekują5. Wszelkie zależności pośrednie
Utwórz plan migracji, który nie zepsuje innych zespołów."
AI dostarcza szczegółowy raport wpływu:
Bezpośredni konsumenci UserService.authenticate():1. APIGateway - 1,247 wywołań - Używa: uwierzytelnianie username/password - Oczekuje: {userId, token, expiresAt} - Obsługa błędów: Łapie tylko AuthError
2. MobileBackend - 892 wywołania - Używa: uwierzytelnianie tokenem biometrycznym - Oczekuje: {userId, token, refreshToken} - Obsługa błędów: Ma logikę ponawiania
3. AdminPortal - 234 wywołania - Używa: uwierzytelnianie tokenem SSO - Oczekuje: {userId, permissions[], token} - Obsługa błędów: Powraca do legacy auth
PLAN MIGRACJI:1. Dodaj nową metodę authenticateV2() z nową sygnaturą2. Aktualizuj authenticate() do wywoływania V2 wewnętrznie3. Powiadom zespoły z 2-tygodniowym oknem migracji4. Monitoruj użycie, pomagaj zespołom migrować5. Zdeprecjonuj starą metodę po 30 dniach
Utrzymuj dokumentację zsynchronizowaną z kodem:
"Wygeneruj diagram modelu C4 pokazujący:- Kontekst: Jak system płatności pasuje do ekosystemu- Kontener: Usługi w domenie płatności- Komponent: Wewnętrzna struktura payment-processor- Kod: Kluczowe klasy i ich relacje
Użyj składni PlantUML, więc jest wersjonowana."
AI generuje:
@startuml Payment System - Container Diagram!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
Person(customer, "Klient", "Dokonuje zakupów")System_Ext(bank, "System bankowy", "Przetwarza transakcje")
System_Boundary(payment, "Domena płatności") { Container(api, "Payment API", "Node.js", "REST API dla operacji płatności") Container(processor, "Payment Processor", "Java", "Podstawowa logika płatności") Container(fraud, "Wykrywanie oszustw", "Python", "Sprawdzenia oszustw oparte na ML") ContainerDb(db, "Payment DB", "PostgreSQL", "Rekordy transakcji") Container(events, "Event Bus", "Kafka", "Zdarzenia płatności")}
Rel(customer, api, "Dokonuje płatności", "HTTPS")Rel(api, processor, "Przetwórz płatność", "gRPC")Rel(processor, fraud, "Sprawdź oszustwo", "HTTP")Rel(processor, bank, "Obciąż kartę", "ISO 8583")Rel(processor, db, "Przechowaj transakcję", "SQL")Rel(processor, events, "Opublikuj zdarzenia", "Kafka")@enduml
"Utwórz podręcznik zespołowy dla domeny płatności, który:1. Wyjaśnia kluczowe koncepcje biznesowe2. Dokumentuje decyzje architektoniczne3. Wymienia typowe zadania z przykładami4. Dostarcza przewodniki rozwiązywania problemów5. Aktualizuje się automatycznie z komentarzy kodu"
Wygenerowana struktura podręcznika:
# Podręcznik domeny płatności
## Koncepcje biznesowe
### Stany płatnościNa podstawie analizy PaymentStateMachine.java:- PENDING: Płatność zainicjowana ale nie przetworzona- PROCESSING: Obecnie autoryzowana- AUTHORIZED: Fundusze zarezerwowane ale nie przechwycone- CAPTURED: Fundusze przeniesione- FAILED: Płatność odrzucona- REFUNDED: Fundusze zwrócone klientowi
## Typowe zadania
### Obsługa nieudanych płatnościZ wzorców PaymentErrorHandler.java:1. Sprawdź powód niepowodzenia w tabeli payment_failures2. Określ, czy ponawianie jest odpowiednie3. Jeśli tak, użyj exponential backoff4. Jeśli nie, uruchom przepływ zwrotu
## Rozwiązywanie problemów
### "Płatność utknęła w PROCESSING"Na podstawie wzorców ostatnich incydentów:1. Sprawdź payment_processor_logs pod kątem timeout2. Zweryfikuj status zewnętrznej bramy3. Szukaj blokad bazy danych4. Rozważ ręczną zmianę stanu
Rozprawmy się z rzeczywistymi wyzwaniami, z którymi spotkasz się w milionowych kodach źródłowych:
Twoja logika powiadomień jest rozproszona w 47 różnych usługach. Czas ją wyodrębnić:
Proces wyodrębniania
"Faza 1 - Odkrywanie:Używając wyszukiwania semantycznego, znajdź CAŁY kod związany z powiadomieniami:- Wysyłanie emaili- Wysyłka SMS- Powiadomienia push- Alerty w aplikacji- Dostarczanie webhooków
Uwzględnij: planowanie, templating, logikę ponawiania i preferencje."
Po którym następuje:
"Faza 2 - Rozplątanie:Dla każdego znalezionego fragmentu kodu powiadomień:1. Jakich danych potrzebuje?2. Jakie usługi wywołuje?3. Co go wyzwala?4. Jak obsługuje niepowodzenia?5. Co by się zepsuło, gdybyśmy to przenieśli?
Utwórz wykres zależności."
Następnie systematycznie wyodrębnij:
"Faza 3 - Projektowanie usługi:Zaprojektuj usługę powiadomień, która:1. Obsługuje wszystkie obecne typy powiadomień2. Dostarcza zunifikowane API3. Zachowuje kompatybilność wsteczną4. Skaluje się niezależnie5. Zawiera strategię migracji
Wygeneruj specyfikację API i plan migracji."
Twoja tabela użytkowników ma 500 milionów rzędów i potrzebuje shardingu:
"Przeanalizuj wzorce dostępu do naszej tabeli użytkowników:1. Jakie zapytania trafiają do tej tabeli?2. Jaki jest stosunek odczytu do zapisu?3. Jak wykonywane są JOIN-y?4. Jaka jest dystrybucja zapytań według user_id?5. Czy są jakieś zapytania globalne?
Zaleć strategię shardingu na podstawie rzeczywistego użycia."
AI odkrywa:
Wyniki analizy:- 89% zapytań filtruje według user_id- 7% to zapytania analityczne (pełne skany tabel)- 4% to zapytania admin (według email, telefon)
Zalecana strategia:- Shard według user_id (oparty na hash, 64 shardy)- Replikuj tabele lookup dla email/telefon- Przenieś analitykę do repliki odczytu- Użyj usługi routingu dla lokalizacji shardów
"Wygeneruj plan migracji dla shardingu bez przestojów:1. Potrzebne zmiany kodu2. Strategię migracji danych3. Procedury wycofania4. Podejście do testowania5. Dodatki do monitorowania"
Plan implementacji:
// Krok 1: Faza dual-writeclass UserRepository { async createUser(data) { // Pisz do starej i nowej const [oldResult, newResult] = await Promise.all([ this.oldDb.insert('users', data), this.shardedDb.insert('users', data, this.getShardKey(data.id)) ]);
// Loguj wszelkie rozbieżności if (!this.compareResults(oldResult, newResult)) { this.alerting.warn('Niezgodność dual-write', { oldResult, newResult }); }
return oldResult; // Nadal zwracaj ze starej DB }
getShardKey(userId) { return userId % 64; // Prosty hash sharding }}
Produkcja jest wolna. Masz 2 godziny na znalezienie i naprawę problemu:
"PILNE: Wydajność produkcji spadła o 70% w ostatniej godzinie.Systematycznie zbadaj:1. Ostatnie wdrożenia2. Wolne zapytania bazy danych3. Opóźnienia usług zewnętrznych4. Wyczerpanie zasobów5. Możliwe wycieki pamięci
Skup się na zmianach z ostatnich 24 godzin."
AI dostarcza strukturalne badanie:
Wyniki badania:
1. OSTATNIE WDROŻENIA (ostatnie 24h): - 14:30: Wdrożono order-service v2.3.1 - 14:35: Rozpoczęła się degradacja wydajności - Korelacja: WYSOKA
2. ZMIANY KODU w v2.3.1: Znalezione w OrderProcessor.java: - Dodano nowy sprawdzacz oszustw wywołujący zewnętrzne API - Brak skonfigurowanego timeout! - Zewnętrzne API odpowiada w 30-60 sekund
3. NATYCHMIASTOWA NAPRAWA: Dodaj timeout do sprawdzania oszustw: ```java // W OrderProcessor.java linii 234 FraudCheckResult result = fraudClient .checkFraud(order) .timeout(Duration.ofMillis(500)) // Dodaj to .onErrorReturn(FraudCheckResult.ALLOW); // Fail open
## Przepływy pracy ciągłego doskonalenia
### Cotygodniowe sprawdzenia zdrowia kodu źródłowego
“Uruchom cotygodniową analizę zdrowia kodu źródłowego:
Porównaj z ostatnim tygodniem i podkreśl trendy.”
### Proaktywne zarządzanie zależnościami
“Przeanalizuj wszystkie zależności pod kątem:
Utwórz priorytetowy plan aktualizacji z oceną ryzyka.”
## Kluczowe wnioski dla sukcesu z milionami linii
<CardGrid> <Card title="Odpowiednie narzędzie, odpowiednia praca" icon="wrench"> Używaj wyszukiwania semantycznego (Zilliz) do zrozumienia, ripgrep do wzorców, lokalnego indeksowania dla wrażliwego kodu. Nie próbuj ładować milionów linii do kontekstu. </Card>
<Card title="Wszystko przyrostowo" icon="rocket"> Nigdy nie próbuj big-bang refactoringu. Używaj flag funkcji, dual writes i stopniowych rolloutów. Pozwól AI pomóc planować bezpieczne, przyrostowe zmiany. </Card>
<Card title="Testy jako dokumentacja" icon="document"> W systemach legacy wszechstronne testy stają się dokumentacją. Używaj AI do generowania testów charakteryzacyjnych, które przechwytują obecne zachowanie. </Card>
<Card title="Partnerstwo człowiek + AI" icon="users"> AI obsługuje pracę mechaniczną - znajdowanie wzorców, generowanie boilerplate, śledzenie zależności. Ludzie dostarczają wiedzę domenową i wizję architektoniczną. </Card></CardGrid>
Praca z milionowymi kodami źródłowymi nie musi być przytłaczająca. Z odpowiednimi narzędziami AI i przepływami pracy możesz nawigować, rozumieć i bezpiecznie modyfikować nawet najbardziej złożone systemy. Kluczem jest myślenie systematyczne i pozwolenie AI obsługiwać skalę, podczas gdy ty skupiasz się na strategii.