En utvecklare öppnar en stor äldre kodbas för första gången. De behöver förstå vad som händer med en kundpost när ett konto stängs: vilka program uppdaterar den, vilka batchjobb som läser den efteråt, vilka fält som ändras längs vägen och om något nedströmssystem är beroende av det slutliga tillståndet. Det naturliga första steget är att söka. De använder grep för att hitta fältnamnet, skannar resultaten, öppnar några filer och börjar läsa. Inom en timme har de hittat referenser i tolv program, tre SQL-skript och en JCL-jobbström. De har också hittat samma fältnamn i sjutton kommentarblock, fyra loggformatsträngar, två testfixturer och en variabel i ett helt orelaterat delsystem som råkar dela samma namn. De kan inte enbart utifrån sökresultaten avgöra vilka av dessa som är faktiska dataläsningar, vilka som är skrivningar, vilka som är transformationer och vilka som är tillfälliga namnkollisioner. De vet vad fältet heter. De förstår ännu inte vad koden gör med det.
Kodförståelse börjar här
SMART TS XL bygger en strukturell modell av hela din kodbas och mappar beroenden över alla språk och plattformar.
Klicka härDenna klyfta mellan att hitta en sträng och att förstå kod är inte en klyfta som bättre sökning stänger. Det är en klyfta mellan två fundamentalt olika typer av undersökningar: en som frågar "var visas den här texten?" och en som frågar "vad gör den här koden?". Textsökning är ett utmärkt svar på den första frågan. Det är inte alls ett svar på den andra frågan, och att blanda ihop de två är en av de mest konsekventa källorna till slöseri med ansträngning, missade beroenden och felaktiga konsekvensbedömningar inom mjukvaruutveckling. Skillnaden är viktigare i stora, heterogena företagssystem än i små moderna kodbaser, eftersom dessa system innehåller årtionden av ackumulerad struktur, beroenden mellan språk och implicita relationer som bara existerar i kodens beteende, inte i någon sträng som visas i dess källfiler. Som undersökts i analysen av kodkvalitetsmått och deras inverkan, en kodbas komplexitet påverkar underhållbarheten avsevärt, och ingen mätvärde som enbart härleds från textmönster fångar de strukturella relationer som styr hur koden faktiskt beter sig.
Vad textsökning egentligen gör
Textsökning är en matchningsoperation för delsträngar som tillämpas på filer som behandlas som råa teckensekvenser. Frågan är en sträng eller ett mönster. Resultatet är en lista över platser där mönstret visas. Verktyget har ingen kunskap om språket i vilket filerna är skrivna, ingen förståelse för grammatiken som ger texten dess struktur och ingen modell för relationerna mellan de kodelement som texten representerar. En grep över en miljon rader COBOL-källkod fungerar på samma modell som en grep över en miljon rader HTML: sekvenser av tecken i filer, grupperade efter filsökväg, returneras när teckensekvensen matchar.
Detta är oerhört användbart för en specifik kategori av uppgifter: att hitta var en känd sträng förekommer, bekräfta att en specifik term används eller saknas, göra en snabb kontroll av namngivningskonventioner, lokalisera filen som innehåller ett specifikt felmeddelande. För dessa uppgifter är textsökning rätt verktyg eftersom dessa uppgifter verkligen handlar om att hitta strängar. Hastigheten, portabiliteten och nollkonfigurationskaraktären hos grep och dess motsvarigheter är funktioner som passar perfekt när frågan är av formen "finns denna sträng i dessa filer, och i så fall var?"
Problemet uppstår när textsökning används för frågor som inte handlar om strängar. ”Vad anropar den här funktionen?” är inte en fråga om var funktionens namn visas. Det är en fråga om anropsgrafen, vilket är en strukturell egenskap i koden som kräver parsning och semantisk analys för att konstrueras. ”Var är det här fältet skrivet?” är inte en fråga om var fältets namn visas. Det är en fråga om dataflöde, vilket kräver förståelse för tilldelningssemantik i det specifika språket för att kunna besvara frågan. ”Vad kommer att gå sönder om jag ändrar det här gränssnittet?” är inte en fråga om var gränssnittets namn visas. Det är en fråga om beroendeförhållanden, vilket kräver att import, arv och koppling mellan moduler löses för att kunna besvara frågan korrekt.
Var och en av dessa frågor använder ett namn som utgångspunkt, vilket gör det frestande att behandla dem som sökuppgifter. Men namnet är bara startpunkten. Svaret finns i kodens strukturella modell, inte i texten i källfilerna.
Brusproblemet: För många resultat som inte betyder någonting
Det första felläget vid textsökning som tillämpas på kodförståelseuppgifter är överproduktion: det ger betydligt fler resultat än vad som är relevant, utan någon mekanism för att identifiera vilka resultat som är strukturellt signifikanta och vilka som är tillfälliga.
En kort identifierare som status, id, type, eller date kan förekomma tusentals gånger i en stor kodbas. Ännu längre identifierare kolliderar mellan språk och namnrymder: calculate_tax Som ett funktionsnamn i en Python-modul producerar ett COBOL-styckenamn, en lagrad procedur i en databas, en JavaScript-hjälp och en sträng i en loggkonfiguration alla matchande textsökningsresultat. Utvecklaren som tar emot dessa resultat måste filtrera dem manuellt och tillämpa sin egen förståelse av koden för att avgöra vilka förekomster som är relevanta. Den manuella filtreringen är i sig en kodförståelseuppgift, vilket innebär att utvecklaren gör det arbete som verktyget skulle göra, utan hjälp från verktyget.
I praktiken filtrerar utvecklare efter intuition och erfarenhet. De inser att ett resultat i en testfil förmodligen inte är en produktionsanropare. De inser att ett resultat i ett kommentarblock är dokumentation, inte ett anrop. De bortser från resultat i filer som de anser vara irrelevanta. Men dessa filter är felbara och overifierbara. Utvecklaren som filtrerar med säkerhet kan ha fel. Utvecklaren som filtrerar försiktigt kan lägga timmar på det. Och i båda fallen är resultatet en uppsättning fynd som återspeglar utvecklarens bedömning, inte en verifierad strukturell analys av koden.
Tänk på ett konkret exempel. En COBOL-utvecklare söker efter ett styckenamn innan den tar bort det:
cobol
SEARCH-RESULTS FOR "CALC-INTEREST":
1. CALC-INTEREST.PGM line 5 : IDENTIFICATION DIVISION.
2. CALC-INTEREST.PGM line 42 : CALC-INTEREST.
3. FINPROCESS.CBL line 178 : PERFORM CALC-INTEREST
4. RPTMONTH.CBL line 91 : * Old routine: CALC-INTEREST replaced by CALC-INT-V2
5. CUSTBATCH.CBL line 234 : PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT
6. DATADICT.txt line 12 : CALC-INTEREST - computes monthly interest for savings accts
7. TESTHARNESS.CBL line 67 : PERFORM CALC-INTEREST
8. ARCHIVEJOB.CBL line 156 : * PERFORM CALC-INTEREST (disabled 2019-03-14)
Av dessa åtta resultat är exakt två aktiva anropare som skulle brytas om stycket togs bort: rad 3 och 5. Rad 2 är definitionen. Rad 4 och 8 är kommentarer. Rad 6 är en datalexikonpost. Rad 7 är en testharness. Att avgöra vilka två av dessa åtta resultat som representerar live-anropsplatser kräver att man läser varje fil i sitt sammanhang, förstår COBOL-syntax och bedömer vad "inaktiverad" i en kommentar på rad 8 faktiskt betyder för exekveringen. Textsökning gav råmaterialet. Kodförståelse gav svaret.
Tystnadsproblemet: Relevanta resultat som aldrig återkommer
Det andra felläget är underproduktion: saknade resultat som är strukturellt signifikanta eftersom de inte uttrycks i en form som textsökningen kan matcha.
Indirekta anrop är den vanligaste källan till saknade resultat. När funktion A anropar funktion B, och funktion B anropar den föråldrade funktionen C, hittar en textsökning efter C:s namn funktion B som en direkt anropare men inte funktion A som en indirekt anropare. Huruvida A är ett relevant resultat beror på syftet med sökningen: om målet är att förstå allt som utlöser C, är A avgörande. Om målet bara är att hitta omedelbara anropare, är A irrelevant. Textsökning kan inte göra denna åtskillnad eftersom den inte har något koncept för en anropsgraf. Den returnerar den text som matchar, utan medvetenhet om vad den matchande texten är en del av.
Referenser mellan språk är en systematiskt saknad kategori. En Java-tjänst som anropar ett COBOL-program med namn via ett mellanprogramlager innehåller COBOL-programnamnet som en strängliteral, som textsökning kan hitta. Men samma Java-tjänst som konstruerar programnamnet dynamiskt, läser det från en konfigurationsfil eller skickar det via ett abstraktionslager innehåller inte namnet alls. Dessa är anropare som textsökning inte kan hitta oavsett hur noggrant den tillämpas. Som undersökts i samband med statisk analys av obfuskerad och dynamiskt genererad kod, när exekveringsvägar uttrycks indirekt via konfiguration, mallar eller mekanismer för körtidsutskick, kan de strukturella relationer de representerar inte återställas enbart från texten i källfiler.
Fältalias och transformationer skapar ytterligare en kategori av tysta missar. Ett COBOL-fält med namnet WS-ACCT-BAL som skrivs till en databaskolumn med namnet ACCT_BALANCE, därefter läst av en Java-tjänst som accountBalance, och så småningom serialiserad som account_balance i ett JSON-svar representerar fyra olika textsträngar för samma dataelement. En sökning efter någon av dessa strängar missar de andra tre. Att veta att alla fyra refererar till samma underliggande affärskoncept kräver förståelse för transformationskedjan, inte att hitta alla förekomster av ett enskilt namn.
Vad kodförståelse faktiskt kräver
Kodförståelse, som en teknisk förmåga, är förmågan att besvara frågor om kod genom att resonera utifrån dess struktur och semantik snarare än dess ytliga text. Det kräver att man bygger och frågar efter en modell av koden som representerar vad koden betyder, inte bara vad den säger.
De tekniska minimikraven för kodförståelse på den nivå som behövs för att stödja utvecklingsuppgifter i stora företagssystem är betydande. Var och en representerar en funktion som textsökning inte har och som ingen kombination av textsökning och manuell ansträngning pålitligt kan replikera i stor skala.
Parsning: Från text till struktur
Det första steget bortom textsökning är parsning: att läsa källkoden enligt grammatiken i dess språk och skapa en strukturerad representation, vanligtvis ett abstrakt syntaxträd, som kodar de syntaktiska relationerna mellan kodelement. En parsad representation av PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT är inte en sträng; det är ett strukturerat objekt som identifierar detta som en PERFORM-sats med ett intervallmål, där båda slutpunkterna är styckenamn i det aktuella programmet, som kan lösas mot programmets PROCEDURE DIVISION-struktur.
Parsning är språkspecifikt. En COBOL-parser förstår COBOL-grammatik. En Java-parser förstår Java-grammatik. En JCL-parser förstår JCL-syntax. I ett flerspråkigt företagssystem kräver kodförståelse en parser för varje språk som finns i miljön, vilket producerar strukturella representationer som kan resoneras kring på ett konsekvent sätt över olika språk. Som diskuterats i den detaljerade undersökningen av Statisk analys av TypeScript på företagsnivå, strukturell och semantisk analys som förstår hur kod är organiserad, hur moduler interagerar och hur kontroll och data flödar genom en applikation är grundlinjen för att gå bortom syntaxkontroll till genuin kodintelligens.
Symbolupplösning: Från namn till entiteter
Efter parsning måste namn i källkoden omvandlas till de entiteter de refererar till. Identifieraren CALC-INTEREST i en PERFORM-sats måste lösas upp till den specifika styckedefinitionen i ett specifikt program eller en specifik hävdbok. Metodnamnet calculateLegacyFee i ett Java-anrop måste lösas upp mot den specifika metoddefinitionen i den specifika klassen, med hänsyn till arv och överbelastning. Kolumnnamnet ACCT_BALANCE i en SQL-fråga måste matchas med den specifika kolumnen i den specifika tabellen i databasschemat.
Symbolupplösning är det som omvandlar ett namn från en sträng till en referens till en specifik, identifierbar kodentitet med en plats, en typ och en uppsättning relationer till andra entiteter. Utan symbolupplösning är alla kodfrågor textfrågor. Med den är en fråga för "alla anropare av denna funktion" en strukturell fråga mot en upplöst graf av anropsrelationer, som endast returnerar de resultat som faktiskt är anrop till den specifika funktionen, inte alla filer där funktionens namn råkar visas.
Symbolupplösning blir dramatiskt mer komplex i flerspråkiga miljöer, där samma koncept namnges på olika sätt över språkgränser. Den språkövergripande upplösningen av fältekvivalenser, undersökt i det bredare sammanhanget av minska medeltiden till återhämtning genom indexering över flera språk, är en förutsättning för all strukturell analys som spårar data eller styr flöden över en språkgräns. Utan den avslutas analysen vid gränsen, och den förståelse den ger är ofullständig.
Kontrollflödesanalys: Förstå exekveringsvägar
Kontrollflödesanalys kartlägger de möjliga exekveringsvägarna genom ett program: vilka grenar tas under vilka villkor, vilka satser är åtkomliga, vilka kodvägar är döda och i vilken ordning satser exekveras i förhållande till varandra. Denna information uttrycks som ett kontrollflödesdiagram, där noder representerar grundläggande block av sekventiell kod och kanter representerar villkorliga eller ovillkorliga överföringar av kontroll.
Kontrollflödesanalys är det som gör det möjligt att besvara frågor som "under vilka förhållanden exekveras denna kodväg?" och "är denna kod nåbar från vilken startpunkt som helst?" Textsökning kan inte besvara dessa frågor eftersom de handlar om exekveringsvägar, inte om var strängar visas. En sats som visas i källkoden kan exekveras eller inte, beroende på de förhållanden som styr grenen den finns i. En funktion som definieras i en modul kan anropas eller inte, beroende på om någon exekveringsväg når en anropsplats. Endast kontrollflödesanalys kan bestämma dessa egenskaper. Som utforskats i undersökningen av prioritera problem med statisk kod under moderniseringen, att förstå vilka kodvägar som faktiskt körs, hur ofta de körs och under vilka förhållanden de aktiveras är det som skiljer handlingsbar analys från resultat som ser betydande ut men inte återspeglar den operativa verkligheten.
Dataflödesanalys: Spåra värden genom kod
Dataflödesanalys spårar hur värden rör sig genom ett program: var en variabel tilldelas, var dess värde läses, vilka transformationer som tillämpas på den mellan tilldelning och användning, och om värdet på en variabel beror på värdet på en annan. Denna information besvarar frågor som "var kommer värdet på detta fält ifrån?" och "vilken kod påverkas om värdet på detta fält ändras?"
Dataflödesanalys är den tekniska grunden för fältspårning, analys av föroreningar och beroendespårning på värdenivå. Den arbetar med programmets kontrollflödesgraf, sprider värdeinformation längs exekveringsvägar och registrerar var värden kommer från, vart de flödar och var de förbrukas. Resultatet är ett dataflödesgraf som kopplar definitioner till användningar över programmets hela exekveringsutrymme, inte bara inom källfilens sekventiella text.
I företagssystem måste dataflödesanalys överbrygga språkgränser för att vara användbar. Ett värde som har sitt ursprung i ett COBOL-program, flyter genom en databasskrivning och sedan läses av en Java-tjänst har ett dataflöde som korsar två språkgränser. Att spåra det flödet kräver dataflödesanalys som förstår COBOL-tilldelningssemantik, SQL-dataförflyttning och Java-variabeltilldelning som en del av samma enhetliga analys, inte som tre separata analyser vars resultat måste kopplas samman manuellt. Som beskrivs i analysen av Kunskapsöverföring från COBOL-företag till moderna utvecklingsteam, förmågan att göra komplexa COBOL-system förståeliga för moderna utvecklare utan att kräva att de behärskar språket beror på att man har strukturell analys som kan representera systemets beteende i en form som överskrider källtexten.
Uppgifterna där skillnaden spelar mest roll
Skillnaden mellan textsökning och kodförståelse är inte akademisk. Den uppstår i specifika utvecklingsuppgifter med hög risk, där fel verktyg producerar resultat som ser kompletta ut men inte är det, och där det får mätbara konsekvenser att agera på ofullständiga resultat.
Konsekvensanalys innan en förändring genomförs
Innan en funktionssignatur ändras, ett fält byts namn på eller beteendet hos ett delat verktyg ändras, behöver en utvecklare veta vad som kommer att påverkas. Detta är konsekvensanalys: att räkna upp varje komponent som är beroende av elementet som ändras, så att ändringen kan göras säkert och alla berörda komponenter kan uppdateras. Konsekvensanalys är en uppgift för att förstå kod. Det kräver att man löser beroendeförhållandena mellan komponenter, går igenom dessa relationer från det ändrade elementet och utåt, och returnerar varje komponent som kommer att påverkas på någon nivå i beroendeträdet.
Textsökning approximerar konsekvensanalys genom att hitta var det ändrade elementets namn visas. Men den kan inte skilja ett beroende från en kommentar, ett direkt beroende från ett transitivt, eller ett aktivt beroende från en referens i död kod. En utvecklare som förlitar sig på textsökning för konsekvensanalys innan en betydande ändring fattar ett säkerhetskritiskt beslut baserat på en approximation. I en liten, enspråkig kodbas kan approximationen vara tillräckligt nära. I ett företagssystem med beroenden mellan språk, delade bibliotek som konsumeras av många tjänster och årtionden av ackumulerade anropsrelationer kan skillnaden mellan vad textsökningen returnerar och den faktiska effekten av ändringen vara betydande.
Tänk på skillnaden i vad dessa två metoder returnerar för en schemaändring till en vanligt förekommande databaskolumn:
| Vad utvecklaren behöver veta | Textsökningsresultat | Resultat av kodförståelse |
|---|---|---|
| Program som läser den här kolumnen | Alla filer som innehåller kolumnnamnet, inklusive kommentarer | Endast program med SQL SELECT-satser som refererar till den här kolumnen |
| Program som skriver den här kolumnen | Samma ofiltrerade lista | Endast program med SQL INSERT- eller UPDATE-satser som skriver till den här kolumnen |
| Tjänster som är beroende av den här kolumnen | Ingen synlighet över flera språk | Java-, Python- och .NET-tjänster som mappar kolumnen till ett objektfält |
| Döda kodreferenser | Ingår i resultaten, omärkt | Utesluten eller flaggad separat |
| Transitiva anhöriga | Inte synlig | Uppräknad till valfritt djup |
| Förtroende för fullständighet | Okänd | Verifierbar mot det indexerade omfånget |
Onboarding och kodnavigering
En utvecklare som är nybörjare på en stor kodbas behöver bygga en mental modell av vad koden gör: hur komponenter ansluts, vilka data flödar genom systemet, vilka program som är ingångspunkter och vilka som är verktyg, och hur exekveringsvägen ser ut för en given affärsprocess. Denna modellbyggande övning är huvudsakligen en kodförståelseuppgift. Textsökning hjälper till att hitta specifika strängar men ger ingen strukturell kontext: den hittar var ett ord visas men inte vilken roll den innehållande koden spelar i systemet.
Kodförståelseverktyg accelererar onboarding genom att göra systemets struktur navigerbar. En interaktiv anropsgraf visar vilka program som anropar vilka andra. En dataflödesspårning visar var ett fält har sitt ursprung och var det hamnar. En kontrollflödesvisualisering visar vilka villkor som styr vilka grenar som körs. En beroendekarta visar vilka komponenter som är säkra att modifiera oberoende och vilka som kräver samordning med andra team. Inget av dessa är produkter av textsökning. De är produkter av den strukturella analys som kodförståelseverktyg utför. Som undersökts i samband med vad är statisk kodanalys, förmågan att navigera komplexitet genom strukturerad analys snarare än genom manuell läsning är det som gör det möjligt för team att arbeta effektivt i system som är för stora för att någon individ ska kunna hålla i huvudet.
Identifiera död kod och oanvända element
Död kod är kod som definieras men aldrig exekveras: funktioner som aldrig anropas, grenar som aldrig nås, variabler som tilldelas men aldrig läses. Att identifiera död kod är en kodförståelseuppgift som kräver att man konstruerar en komplett anropsgraf och bestämmer vilka definierade element som inte har några inkommande anropskanter från någon nåbar startpunkt. Textsökning kan inte identifiera död kod eftersom död kod, per definition, refereras från ingenstans. Avsaknaden av en referens är inte en sträng som textsökning kan hitta.
För borttagning av föråldrade funktioner är identifiering av död kod direkt relevant. Vissa element som verkar vara anropare av en föråldrad funktion kan själva vara död kod: funktioner som skrevs för att anropa den föråldrade funktionen men som aldrig själva anropas och därför inte representerar något aktivt beroende. Att skilja aktiva anropare från döda anropare kräver samma anropsgrafanalys som identifierar död kod i allmänhet. Som undersökts i samband med viktiga refactoringtekniker, statisk användningsanalys ger tillräcklig insikt för att avgöra om funktioner, etiketter, stycken eller moduler någonsin anropas, och den analysen är endast möjlig genom konstruktion av strukturell anropsgraf, inte genom räkning av textförekomster.
Säkerhets- och efterlevnadsgranskning
Säkerhets- och efterlevnadsrevision kräver spårning av känsliga data genom systemet: identifiering av var personligt identifierbar information lagras, vilka kodvägar som kan komma åt den, om åtkomstkontrollkontroller är korrekt placerade i varje exekveringsväg som leder till känsliga data, och om känsliga data kan komma ur systemet via loggning, felmeddelanden eller API-svar. Dessa är dataflödes- och kontrollflödesanalysuppgifter som textsökning approximerar dåligt.
En textsökning efter ett känsligt fältnamn hittar filer som innehåller namnet. Den kan inte avgöra om dessa filer utför auktoriserad åtkomst, obehörig åtkomst eller ingen åtkomst alls. Den kan inte avgöra om en åtkomstkontroll finns i exekveringsvägen som leder till fältåtkomsten. Den kan inte spåra om fältets värde sedan skrivs till en logg eller returneras i ett API-svar som inte borde innehålla det. Taint-analys, som spårar flödet av känsliga värden genom systemet och identifierar var de kan nå otillförlitliga utdata, är en funktion för dataflödesanalys. Det är vad säkerhetsmedvetna kodförståelseverktyg tillhandahåller och vad textsökning inte kan approximera.
Hur SMART TS XL Levererar kodförståelse i hela företaget
SMART TS XL är byggt på premissen att företagssystem kräver strukturell förståelse, inte texthämtning. Dess Software Intelligence-plattform analyserar källkod från alla språk och plattformar i miljön, producerar språkspecifika abstrakta syntaxträd för varje språk och löser upp dessa träd i en enhetlig tvärspråkig graf som representerar de strukturella relationerna för hela systemet. COBOL-program, JCL-jobbströmmar, Java-tjänster, .NET-applikationer, Python-skript, SQL-scheman, TypeScript-moduler och konfigurationsartefakter representeras alla som noder och kanter i denna graf, med relationer uttryckta som typade kopplingar: anrop, dataflöden, inkluderingar i kopieböcker, schemareferenser och ekvivalenser mellan språk.
Plattformens sökfunktion för företag utgör utgångspunkten för kodförståelse, men den fungerar fundamentalt annorlunda än textsökning. Resultaten organiseras efter relationstyp och artefaktstruktur, inte efter strängförekomst. En fråga efter ett fältnamn returnerar definitioner, läsningar, skrivningar, SQL-referenser och inkluderingar i kopieböcker som separat kategoriserade resultattyper, så att en utvecklare som frågar "vad skriver till det här fältet?" får exakt de skrivrelationer som krävs, inte en blandad lista över varje fil där namnet förekommer. Denna strukturella organisation av sökresultat återspeglar den underliggande korsreferensmodellen och ger utvecklare den specifika, handlingsbara information de behöver utan att de behöver filtrera strängförekomster manuellt.
Plattformens konsekvensanalys, anropsgraftraversering, visualisering av kontrollflöden och spårning av dataflöden fungerar alla på samma enhetliga strukturella modell. När en utvecklare identifierar en föråldrad funktion visar anropsgrafen alla anropare på varje nivå i hierarkin. När en schemaändring planeras räknar konsekvensanalysen upp varje konsument på alla språk. När en onboarding-utvecklare behöver förstå en batchprocess gör visualiseringen av kontrollflöden exekveringsvägen navigerbar utan att de behöver läsa hundratals rader källkod sekventiellt. Som undersökts i det bredare sammanhanget av Utvecklarerfarenhet och DX-mätvärden för äldre kodbaser, kodens komplexitet och strukturella inveckling är de faktorer som avgör underhållbarheten, och de verktyg som exponerar dessa strukturella egenskaper snarare än bara yttexten är det som gör komplexa system hanterbara i stor skala.
Skillnaden mellan vad SMART TS XL tillhandahåller och vad textsökning tillhandahåller är skillnaden mellan en besvarad fråga och en påbörjad fråga. Textsökning inleder en undersökning. Kodförståelse fullbordar den.
Den löpande kostnaden för att ersätta sökning med förståelse
Den praktiska konsekvensen av att behandla textsökning som en ersättning för kodförståelse ackumuleras tyst i varje utvecklingsuppgift som kräver strukturell kunskap om kodbasen. Varje konsekvensbedömning som förlitar sig på textsökning bär med sig en okänd mängd missade beroenden. Varje fältspårning som stannar vid en språkgräns lämnar en del av systemet osynlig. Varje identifiering av död kod som räknar strängförekomster istället för att analysera nåbarheten för anropsgrafer inkluderar falska positiva resultat och missar sann död kod. Varje säkerhetsrevision som söker efter känsliga fältnamn istället för att spåra dataflöde genom exekveringsvägar ger en garanti som är ofullständig och overifierbar.
I en liten, enspråkig, ofta modifierad kodbas kan dessa kostnader vara hanterbara. Utvecklare har tillräckligt med kontext för att filtrera sökresultaten korrekt, systemets gränser förstås av alla i teamet, och manuell inspektion fyller tomrummet som textsökningen lämnar tillräckligt snabbt för att undvika allvarliga fel. I ett stort företagssystem med flera språk, årtionden av ackumulerad kod och teamstrukturer som innebär att ingen individ förstår helheten, ökar kostnaderna. Missade beroenden dyker upp i produktionen. Konsekvensbedömningar som var förtroendeingivande i mötesrummet ger överraskande misslyckanden i releasen. Säkerhetsrevisioner som täckte varje strängförekomst missar dataflödesvägarna som exponerar känslig data. Kunskap som fanns i huvudet på utvecklare som sedan dess har gått vidare kan inte rekonstrueras från textsökning eftersom de strukturella relationer de förstod aldrig kodades i någon sträng i källfilerna.
Övergången från textsökning till kodförståelse innebär inte att ett verktyg ersätts med ett annat. Textsökning behåller sin roll för de uppgifter det är lämpat för: stränglokalisering, snabb orientering, konfigurationskontroller och filnavigering. Kodförståelse ger den strukturella analys som textsökning inte kan: anropsgrafer, dataflödesspår, konsekvensanalys, identifiering av död kod och lösning av beroenden mellan språk. De två fungerar på olika abstraktionsnivåer, besvarar olika kategorier av frågor och tjänar olika syften. Kostnaden för att sammanblanda dem betalas i missade beroenden, felaktiga bedömningar och den stadiga ackumuleringen av risker som uppstår genom att göra följdändringar i komplexa system med en ofullständig modell av vad de faktiskt gör.