En udvikler åbner en stor, ældre kodebase for første gang. De skal forstå, hvad der sker med en kundepost, når en konto lukkes: hvilke programmer opdaterer den, hvilke batchjob læser den bagefter, hvilke felter ændres undervejs, og om et downstream-system afhænger af den endelige tilstand. Det naturlige første skridt er at søge. De bruger grep til at finde feltnavnet, scanner resultaterne, åbner et par filer og begynder at læse. Inden for en time har de fundet referencer i tolv programmer, tre SQL-scripts og en JCL-jobstrøm. De har også fundet det samme feltnavn i sytten kommentarblokke, fire logformatstrenge, to testfixtures og en variabel i et helt uafhængigt undersystem, der tilfældigvis deler navnet. De kan ikke ud fra søgeresultaterne alene se, hvilke af disse er faktiske datalæsninger, hvilke der er skrivninger, hvilke der er transformationer, og hvilke der er tilfældige navnekollisioner. De ved, hvad feltet hedder. De forstår endnu ikke, hvad koden gør med det.
Kodeforståelse starter her
SMART TS XL opbygger en strukturel model af hele din kodebase og kortlægger afhængigheder på tværs af alle sprog og platforme.
Klik herDenne kløft mellem at finde en streng og forstå kode er ikke en kløft, som bedre søgning lukker. Det er en kløft mellem to fundamentalt forskellige typer undersøgelser: en, der spørger "hvor vises denne tekst?", og en, der spørger "hvad gør denne kode?". Tekstsøgning er et fremragende svar på det første spørgsmål. Det er slet ikke et svar på det andet spørgsmål, og at sammenblande de to er en af de mest konsistente kilder til spildt arbejde, oversete afhængigheder og forkerte konsekvensanalyser i softwareudvikling. Sondringen er mere vigtig i store, heterogene virksomhedssystemer end i små moderne kodebaser, fordi disse systemer indeholder årtiers akkumuleret struktur, tværsproglige afhængigheder og implicitte relationer, der kun eksisterer i kodens adfærd, ikke i nogen streng, der vises i dens kildefiler. Som undersøgt i analysen af Kodekvalitetsmålinger og deres indflydelse, en kodebas indviklede karakter påvirker vedligeholdelsesevnen betydeligt, og ingen metrik afledt af tekstmønstre alene indfanger de strukturelle relationer, der styrer, hvordan koden rent faktisk opfører sig.
Hvad tekstsøgning rent faktisk gør
Tekstsøgning er en understrengsmatchningsoperation, der anvendes på filer, der behandles som rå tegnsekvenser. Forespørgslen er en streng eller et mønster. Resultatet er en liste over steder, hvor dette mønster vises. Værktøjet har ingen kendskab til det sprog, som filerne er skrevet i, ingen forståelse af den grammatik, der giver teksten dens struktur, og ingen model for relationerne mellem de kodeelementer, som teksten repræsenterer. En grep på tværs af en million linjer COBOL-kildekode fungerer på den samme model som en grep på tværs af en million linjer HTML: tegnsekvenser i filer, grupperet efter filsti, returneres, når tegnsekvensen matcher.
Dette er enormt nyttigt til en specifik kategori af opgaver: at finde, hvor en kendt streng vises, bekræfte, om et specifikt udtryk bruges eller mangler, foretage en hurtig fornuftstjek af navngivningskonventioner, finde den fil, der indeholder en specifik fejlmeddelelse. Til disse opgaver er tekstsøgning det rigtige værktøj, fordi disse opgaver oprigtigt handler om at finde strenge. Hastigheden, bærbarheden og nulkonfigurationsegenskaberne ved grep og dets tilsvarende funktioner er funktioner, der passer perfekt, når spørgsmålet er af formen "findes denne streng i disse filer, og i så fald hvor?"
Problemet opstår, når tekstsøgning bruges til spørgsmål, der ikke handler om strenge. "Hvad kalder denne funktion?" er ikke et spørgsmål om, hvor funktionens navn vises. Det er et spørgsmål om kaldgrafen, som er en strukturel egenskab ved koden, der kræver parsing og semantisk analyse for at kunne konstrueres. "Hvor er dette felt skrevet?" er ikke et spørgsmål om, hvor feltets navn vises. Det er et spørgsmål om dataflow, som kræver forståelse af tildelingssemantik i det specifikke sprog for at kunne besvares. "Hvad vil gå i stykker, hvis jeg ændrer denne grænseflade?" er ikke et spørgsmål om, hvor grænsefladens navn vises. Det er et spørgsmål om afhængighedsrelationer, som kræver løsning af import, arv og kobling på tværs af moduler for at kunne besvares korrekt.
Hvert af disse spørgsmål bruger et navn som udgangspunkt, hvilket gør det fristende at behandle dem som søgeopgaver. Men navnet er kun indgangspunktet. Svaret findes i koden, ikke i teksten i kildefilerne.
Støjproblemet: For mange resultater, der ikke betyder noget
Den første fejltilstand i tekstsøgning, der anvendes til kodeforståelsesopgaver, er overproduktion: der returneres langt flere resultater end relevant, uden en mekanisme til at identificere, hvilke resultater der er strukturelt signifikante, og hvilke der er tilfældige.
En kort identifikator som f.eks. status, id, type eller date kan forekomme tusindvis af gange i en stor kodebase. Selv længere identifikatorer kolliderer på tværs af sprog og navnerum: calculate_tax Som et funktionsnavn i et Python-modul producerer et COBOL-paragrafnavn, en databaselagret procedure, en JavaScript-hjælper og en streng i en logkonfiguration alle matchende tekstsøgeresultater. Udvikleren, der modtager disse resultater, skal filtrere dem manuelt og anvende sin egen forståelse af koden for at bestemme, hvilke forekomster der er relevante. Denne manuelle filtrering er i sig selv en kodeforståelsesopgave, hvilket betyder, at udvikleren udfører det arbejde, som værktøjet skulle udføre, uden hjælp fra værktøjet.
I praksis filtrerer udviklere efter intuition og erfaring. De erkender, at et resultat i en testfil sandsynligvis ikke er et produktionskald. De erkender, at et resultat i en kommentarblok er dokumentation, ikke et kald. De udelukker resultater i filer, de mener er irrelevante. Men disse filtre er fejlbarlige og ikke-verificerbare. Den udvikler, der filtrerer med sikkerhed, kan tage fejl. Den udvikler, der filtrerer forsigtigt, kan bruge timer. Og i begge tilfælde er resultatet et sæt af fund, der afspejler udviklerens vurdering, ikke en verificeret strukturel analyse af koden.
Overvej et konkret eksempel. En COBOL-udvikler søger efter et afsnits navn, før den fjerner 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)
Ud af disse otte resultater er præcis to aktive kaldere, der ville afbrydes, hvis afsnittet blev fjernet: linje 3 og 5. Linje 2 er definitionen. Linje 4 og 8 er kommentarer. Linje 6 er en dataordbogspost. Linje 7 er en testharness. At bestemme, hvilke to af disse otte resultater der repræsenterer live-kaldssites, kræver læsning af hver fil i kontekst, forståelse af COBOL-syntaks og vurdering af, hvad "deaktiveret" i en kommentar på linje 8 rent faktisk betyder for udførelsen. Tekstsøgning leverede råmaterialet. Kodeforståelse gav svaret.
Tavshedsproblemet: Relevante resultater, der aldrig returneres
Den anden fejltilstand er underproduktion: manglende resultater, der er strukturelt signifikante, fordi de ikke udtrykkes i en form, som tekstsøgningen kan matche.
Indirekte kald er den mest almindelige kilde til manglende resultater. Når funktion A kalder funktion B, og funktion B kalder den forældede funktion C, finder en tekstsøgning efter C's navn funktion B som en direkte opkalder, men ikke funktion A som en indirekte opkalder. Om A er et relevant resultat afhænger af formålet med søgningen: hvis målet er at forstå alt, hvad der udløser C, er A kritisk. Hvis målet kun er at finde umiddelbare opkaldere, er A irrelevant. Tekstsøgning kan ikke foretage denne sondring, fordi den ikke har noget koncept for en opkaldsgraf. Den returnerer den tekst, der matcher, uden bevidsthed om, hvad den matchende tekst er en del af.
Referencer på tværs af sprog er en systematisk manglende kategori. En Java-tjeneste, der kalder et COBOL-program ved navn via et middleware-lag, indeholder COBOL-programnavnet som en strengliteral, som tekstsøgning kan finde. Men den samme Java-tjeneste, der konstruerer programnavnet dynamisk, læser det fra en konfigurationsfil eller sender det via et abstraktionslag, indeholder slet ikke navnet. Disse er kaldere, som tekstsøgning ikke kan finde, uanset hvor grundigt det anvendes. Som undersøgt i konteksten af statisk analyse af obfuskeret og dynamisk genereret kode, når udførelsesstier udtrykkes indirekte via konfiguration, skabeloner eller runtime-forsendelsesmekanismer, kan de strukturelle relationer, de repræsenterer, ikke gendannes udelukkende fra teksten i kildefiler.
Feltaliasser og transformationer skaber en anden kategori af tavse fejl. Et COBOL-felt med navnet WS-ACCT-BAL der er skrevet til en databasekolonne med navnet ACCT_BALANCE, efterfølgende læst af en Java-tjeneste som accountBalanceog til sidst serialiseret som account_balance i et JSON-svar repræsenterer fire forskellige tekststrenge for det samme dataelement. En søgning efter en af disse strenge overser de andre tre. At vide, at alle fire refererer til det samme underliggende forretningskoncept, kræver forståelse af transformationskæden, ikke at finde alle forekomster af et enkelt navn.
Hvad kodeforståelse rent faktisk kræver
Kodeforståelse, som en teknisk evne, er evnen til at besvare spørgsmål om kode ved at ræsonnere ud fra dens struktur og semantik snarere end dens overfladiske tekst. Det kræver opbygning og forespørgsel på en model af koden, der repræsenterer, hvad koden betyder, ikke kun hvad den siger.
De minimale tekniske krav til kodeforståelse på det niveau, der er nødvendigt for at understøtte udviklingsopgaver i store virksomhedssystemer, er betydelige. Hver af dem repræsenterer en funktion, som tekstsøgning ikke har, og som ingen kombination af tekstsøgning og manuel indsats pålideligt kan replikere i stor skala.
Parsing: Fra tekst til struktur
Det første skridt ud over tekstsøgning er parsing: læsning af kildekode i henhold til sprogets grammatik og produktion af en struktureret repræsentation, typisk et abstrakt syntakstræ, der koder de syntaktiske forhold mellem kodeelementer. En parset repræsentation af PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT er ikke en streng; det er et struktureret objekt, der identificerer dette som en PERFORM-sætning med et intervalmål, hvor begge slutpunkter er afsnitsnavne i det aktuelle program, der kan løses i forhold til programmets PROCEDURE DIVISION-struktur.
Parsing er sprogspecifik. En COBOL-parser forstår COBOL-grammatik. En Java-parser forstår Java-grammatik. En JCL-parser forstår JCL-syntaks. I et flersproget virksomhedssystem kræver kodeforståelse en parser for hvert sprog, der er til stede i miljøet, hvilket producerer strukturelle repræsentationer, der kan ræsonneres på en ensartet måde på tværs af sprog. Som diskuteret i den detaljerede undersøgelse af Statisk TypeScript-analyse på virksomhedsniveau, strukturel og semantisk analyse, der forstår, hvordan kode er organiseret, hvordan moduler interagerer, og hvordan kontrol og data flyder gennem en applikation, er grundlaget for at gå ud over syntakskontrol til ægte kodeintelligens.
Symbolopløsning: Fra navne til enheder
Efter parsing skal navne i kildekoden omdannes til de enheder, de refererer til. Identifikatoren CALC-INTEREST i en PERFORM-sætning skal opløses til den specifikke afsnitsdefinition i et specifikt program eller en specifik kopibog. Metodenavnet calculateLegacyFee i et Java-kald skal opløses til den specifikke metodedefinition i den specifikke klasse, idet der tages højde for arv og overbelastning. Kolonnenavnet ACCT_BALANCE i en SQL-forespørgsel skal løses til den specifikke kolonne i den specifikke tabel i databaseskemaet.
Symbolopløsning er det, der omdanner et navn fra en streng til en reference til en specifik, identificerbar kodeentitet med en placering, en type og et sæt relationer til andre enheder. Uden symbolopløsning er alle kodeforespørgsler tekstforespørgsler. Med den er en forespørgsel efter "alle kaldere af denne funktion" en strukturel forespørgsel mod en opløst graf af kaldrelationer, der kun returnerer de resultater, der faktisk er kald til den specifikke funktion, ikke alle filer, hvor funktionens navn tilfældigvis vises.
Symbolopløsning bliver dramatisk mere kompleks i flersprogede miljøer, hvor det samme koncept navngives forskelligt på tværs af sproggrænser. Den tværsproglige opløsning af feltækvivalenser, som undersøgt i den bredere kontekst af Reduktion af gennemsnitlig genopretningstid gennem tværsproget indeksering, er en forudsætning for enhver strukturel analyse, der sporer data eller kontrollerer flow på tværs af en sproggrænse. Uden den afsluttes analysen ved grænsen, og den forståelse, den giver, er ufuldstændig.
Kontrolflowanalyse: Forståelse af udførelsesstier
Kontrolflowanalyse kortlægger de mulige udførelsesstier gennem et program: hvilke grene tages under hvilke betingelser, hvilke sætninger er tilgængelige, hvilke kodestier er døde, og i hvilken rækkefølge sætninger udføres i forhold til hinanden. Denne information udtrykkes som en kontrolflowgraf, hvor noder repræsenterer grundlæggende blokke af sekventiel kode, og kanter repræsenterer betingede eller ubetingede overførsler af kontrol.
Kontrolflowanalyse er det, der gør det muligt at besvare spørgsmål som "under hvilke betingelser udføres denne kodesti?" og "er denne kode tilgængelig fra ethvert indgangspunkt?" Tekstsøgning kan ikke besvare disse spørgsmål, fordi de handler om udførelsesstier, ikke om hvor strenge vises. En sætning, der vises i kildekoden, kan udføres eller ikke udføres, afhængigt af de betingelser, der understøtter den gren, den befinder sig i. En funktion, der er defineret i et modul, kan kaldes eller ikke kaldes, afhængigt af om en udførelsessti når et kaldssted. Kun kontrolflowanalyse kan bestemme disse egenskaber. Som undersøgt i undersøgelsen af Prioritering af problemer med statisk kode under modernisering, at forstå hvilke kodestier der rent faktisk udføres, hvor ofte de kører, og under hvilke betingelser de aktiveres, er det, der adskiller handlingsrettet analyse fra resultater, der ser signifikante ud, men ikke afspejler den operationelle virkelighed.
Dataflowanalyse: Sporing af værdier gennem kode
Dataflowanalyse sporer, hvordan værdier bevæger sig gennem et program: hvor en variabel tildeles, hvor dens værdi læses, hvilke transformationer der anvendes på den mellem tildeling og brug, og om værdien af én variabel afhænger af værdien af en anden. Disse oplysninger besvarer spørgsmål som "hvor kommer dette felts værdi fra?" og "hvilken kode påvirkes, hvis dette felts værdi ændres?"
Dataflowanalyse er det tekniske grundlag for feltsporing, analyse af forurening og afhængighedssporing på værdiniveau. Den opererer på programmets kontrolflowgraf, udbreder værdiinformation langs udførelsesstier og registrerer, hvor værdier stammer, hvor de flyder, og hvor de forbruges. Resultatet er en dataflowgraf, der forbinder definitioner med anvendelser på tværs af programmets fulde udførelsesområde, ikke kun inden for kildefilens sekventielle tekst.
I virksomhedssystemer skal dataflowanalyse spænde over sproggrænser for at være nyttig. En værdi, der stammer fra et COBOL-program, flyder gennem en databaseskrivning og efterfølgende læses af en Java-tjeneste, har en dataflow, der krydser to sproggrænser. Sporing af denne flow kræver en dataflowanalyse, der forstår COBOL-tildelingssemantik, SQL-dataflytning og Java-variabeltildeling som en del af den samme samlede analyse, ikke som tre separate analyser, hvis resultater skal forbindes manuelt. Som beskrevet i analysen af Videnoverførsel fra COBOL SMV'er til moderne udviklingsteams, evnen til at gøre komplekse COBOL-systemer forståelige for moderne udviklere uden at kræve, at de mestrer sproget, afhænger af at have strukturel analyse, der kan repræsentere systemets adfærd i en form, der overskrider kildeteksten.
De opgaver, hvor forskellen betyder mest
Sondringen mellem tekstsøgning og kodeforståelse er ikke akademisk. Den dukker op i specifikke udviklingsopgaver med høj risiko, hvor det forkerte værktøj producerer resultater, der ser komplette ud, men ikke er det, og hvor det at handle på ufuldstændige resultater har målbare konsekvenser.
Konsekvensanalyse før en ændring
Før en udvikler ændrer en funktionssignatur, omdøber et felt eller ændrer funktionsmåden af et delt værktøj, skal han vide, hvad der vil blive påvirket. Dette er konsekvensanalyse: opregnelse af alle komponenter, der afhænger af det element, der ændres, så ændringen kan foretages sikkert, og alle berørte komponenter kan opdateres. Konsekvensanalyse er en kodeforståelsesopgave. Det kræver, at man løser afhængighedsrelationerne mellem komponenter, gennemgår disse relationer fra det ændrede element og udad, og returnerer alle komponenter, der vil blive påvirket på ethvert niveau af afhængighedstræet.
Tekstsøgning tilnærmer konsekvensanalyse ved at finde ud af, hvor det ændrede elements navn vises. Men den kan ikke skelne en afhængighed fra en kommentar, en direkte afhængighed fra en transitiv afhængighed eller en aktiv afhængighed fra en reference i død kode. En udvikler, der er afhængig af tekstsøgning til konsekvensanalyse før en væsentlig ændring, træffer en sikkerhedskritisk beslutning baseret på en tilnærmelse. I en lille kodebase med kun ét sprog kan tilnærmelsen være tæt nok. I et virksomhedssystem med tværsproglige afhængigheder, delte biblioteker, der forbruges af mange tjenester, og årtiers akkumulerede kaldrelationer kan forskellen mellem, hvad tekstsøgning returnerer, og den faktiske effekt af ændringen være betydelig.
Overvej forskellen i, hvad disse to tilgange returnerer for en skemaændring til en udbredt databasekolonne:
| Hvad udvikleren har brug for at vide | Søgeresultat for tekst | Resultat af kodeforståelse |
|---|---|---|
| Programmer, der læser denne kolonne | Alle filer, der indeholder kolonnenavnet, inklusive kommentarer | Kun programmer med SQL SELECT-sætninger, der refererer til denne kolonne |
| Programmer, der skriver denne kolonne | Samme ufiltrerede liste | Kun programmer med SQL INSERT- eller UPDATE-sætninger, der skriver til denne kolonne |
| Tjenester afhængige af denne kolonne | Ingen synlighed på tværs af sprog | Java-, Python- og .NET-tjenester, der knytter kolonnen til et objektfelt |
| Døde kodereferencer | Inkluderet i resultaterne, umarkeret | Udelukket eller markeret separat |
| Transitive pårørende | Ikke synligt | Optælles til enhver dybde |
| Tillid til fuldstændighed | Ukendt | Verificerbar mod det indekserede omfang |
Onboarding og kodenavigation
En udvikler, der er ny i en stor kodebase, skal opbygge en mental model af, hvad koden gør: hvordan komponenter forbindes, hvilke data flyder gennem systemet, hvilke programmer er indgangspunkter, og hvilke er værktøjer, og hvordan udførelsesstien ser ud for en given forretningsproces. Denne modelbygningsøvelse er primært en kodeforståelsesopgave. Tekstsøgning hjælper med at finde specifikke strenge, men giver ingen strukturel kontekst: den finder, hvor et ord vises, men ikke hvilken rolle den indeholdte kode spiller i systemet.
Kodeforståelsesværktøjer fremskynder onboarding ved at gøre systemets struktur navigerbar. En interaktiv kaldgraf viser, hvilke programmer der kalder hvilke andre. En dataflowsporing viser, hvor et felt stammer, og hvor det ender. En kontrolflowvisualisering viser, hvilke betingelser der styrer, hvilke grene der udføres. Et afhængighedskort viser, hvilke komponenter der er sikre at ændre uafhængigt, og hvilke der kræver koordinering med andre teams. Ingen af disse er produkter af tekstsøgning. De er produkter af den strukturelle analyse, som kodeforståelsesværktøjer udfører. Som undersøgt i forbindelse med Hvad er statisk kodeanalyse, evnen til at navigere i kompleksitet gennem struktureret analyse i stedet for manuel læsning er det, der gør det muligt for teams at arbejde effektivt i systemer, der er for store til, at nogen enkeltperson kan holde dem i hovedet.
Identifikation af død kode og ubrugte elementer
Død kode er kode, der er defineret, men aldrig udført: funktioner, der aldrig kaldes, grene, der aldrig nås, variabler, der tildeles, men aldrig læses. At identificere død kode er en kodeforståelsesopgave, der kræver konstruktion af en komplet kaldgraf og bestemmelse af, hvilke definerede elementer der ikke har indgående kaldskanter fra noget tilgængeligt indgangspunkt. Tekstsøgning kan ikke identificere død kode, fordi død kode per definition refereres til fra ingenting. Fraværet af en reference er ikke en streng, som tekstsøgning kan finde.
For fjernelse af forældede funktioner er identifikation af død kode direkte relevant. Nogle elementer, der ser ud til at være kaldere af en forældet funktion, kan selv være død kode: funktioner, der blev skrevet til at kalde den forældede funktion, men som aldrig selv kaldes og derfor ikke repræsenterer nogen live-afhængighed. At skelne mellem live-kaldere og døde kaldere kræver den samme kaldgrafanalyse, der identificerer død kode generelt. Som undersøgt i forbindelse med essentielle refactoringteknikker, statisk brugsanalyse giver tilstrækkelig indsigt til at afgøre, om funktioner, etiketter, afsnit eller moduler nogensinde kaldes, og denne analyse er kun mulig gennem strukturel kaldsgrafkonstruktion, ikke gennem optælling af tekstforekomster.
Sikkerheds- og compliance-revision
Sikkerheds- og compliance-revision kræver sporing af følsomme data gennem systemet: identificering af, hvor personligt identificerbare oplysninger er gemt, hvilke kodestier der kan tilgå dem, om adgangskontrolkontroller er korrekt placeret i hver udførelsessti, der fører til følsomme data, og om følsomme data kan undslippe systemet via logføring, fejlmeddelelser eller API-svar. Dette er dataflow- og kontrolflowanalyseopgaver, som tekstsøgning ikke nærmer sig godt nok.
En tekstsøgning efter et følsomt feltnavn finder filer, der indeholder navnet. Den kan ikke afgøre, om disse filer udfører autoriseret adgang, uautoriseret adgang eller slet ingen adgang. Den kan ikke afgøre, om der findes en adgangskontrol i udførelsesstien, der fører til feltadgangen. Den kan ikke spore, om feltets værdi efterfølgende skrives til en log eller returneres i et API-svar, der ikke burde indeholde den. Taint-analyse, som sporer strømmen af følsomme værdier gennem systemet og identificerer, hvor de kan nå upålidelige output, er en funktion til dataflowanalyse. Det er, hvad sikkerhedsbevidste kodeforståelsesværktøjer leverer, og hvad tekstsøgning ikke kan tilnærme sig.
Hvordan SMART TS XL Leverer kodeforståelse på tværs af virksomheden
SMART TS XL er bygget på den præmis, at virksomhedssystemer kræver strukturel forståelse, ikke teksthentning. Dens Software Intelligence-platform analyserer kildekode fra alle sprog og platforme i miljøet, producerer sprogspecifikke abstrakte syntakstræer for hvert enkelt og opløser disse træer i en samlet tværsproglig graf, der repræsenterer de strukturelle relationer i hele systemet. COBOL-programmer, JCL-jobstrømme, Java-tjenester, .NET-applikationer, Python-scripts, SQL-skemaer, TypeScript-moduler og konfigurationsartefakter er alle repræsenteret som noder og kanter i denne graf, med relationer udtrykt som typebestemte forbindelser: kald, datastrømme, kopibogsinkluderinger, skemareferencer og ækvivalenser mellem sprog.
Platformens virksomhedssøgningsfunktion giver indgangspunktet for kodeforståelsesopgaver, men den fungerer fundamentalt anderledes end tekstsøgning. Resultaterne er organiseret efter relationstype og artefaktstruktur, ikke efter strengforekomst. En forespørgsel efter et feltnavn returnerer definitioner, læsninger, skrivninger, SQL-referencer og kopibogsinkluderinger som separat kategoriserede resultattyper, så en udvikler, der spørger "hvad skriver til dette felt?", modtager præcis de skriverelationer, ikke en blandet liste over alle filer, hvor navnet vises. Denne strukturelle organisering af søgeresultaterne afspejler den underliggende krydsreferencemodel og giver udviklere de specifikke, handlingsrettede oplysninger, de har brug for, uden at de manuelt skal filtrere strengforekomster.
Platformens konsekvensanalyse, gennemgang af kaldsgrafer, visualisering af kontrolflow og sporing af dataflow fungerer alle på den samme samlede strukturmodel. Når en udvikler identificerer en udfaset funktion, viser kaldsgrafen alle kaldere på alle niveauer i hierarkiet. Når en skemaændring er planlagt, opregner konsekvensanalysen alle forbrugere på tværs af alle sprog. Når en onboarding-udvikler skal forstå en batchproces, gør visualiseringen af kontrolflowet udførelsesstien navigerbar uden at kræve, at de læser hundredvis af linjer kildekode sekventielt. Som undersøgt i den bredere kontekst af Udviklererfaring og DX-målinger for ældre kodebaser, kodekompleksitet og strukturel kompleksitet er de faktorer, der bestemmer vedligeholdelsesevnen, og de værktøjer, der eksponerer disse strukturelle egenskaber i stedet for blot den overfladiske tekst, er det, der gør komplekse systemer håndterbare i stor skala.
Forskellen mellem hvad SMART TS XL giver, og hvad tekstsøgning giver, er forskellen mellem et besvaret spørgsmål og et påbegyndt spørgsmål. Tekstsøgning starter en undersøgelse. Kodeforståelse fuldender den.
De løbende omkostninger ved at erstatte søgning med forståelse
Den praktiske konsekvens af at behandle tekstsøgning som en erstatning for kodeforståelse akkumuleres lydløst på tværs af enhver udviklingsopgave, der kræver strukturel viden om kodebasen. Enhver konsekvensanalyse, der er afhængig af tekstsøgning, bærer en ukendt mængde oversete afhængigheder. Hvert feltspor, der stopper ved en sproggrænse, efterlader en del af systemet usynligt. Enhver identifikation af død kode, der tæller strengforekomster i stedet for at analysere tilgængeligheden af kaldgrafer, inkluderer falske positiver og overser ægte død kode. Enhver sikkerhedsrevision, der søger efter følsomme feltnavne i stedet for at spore dataflow gennem udførelsesstier, giver en sikkerhed, der er ufuldstændig og ikke-verificerbar.
I en lille, ensproget, hyppigt modificeret kodebase kan disse omkostninger være håndterbare. Udviklere har tilstrækkelig kontekst til at filtrere søgeresultaterne præcist, systemets grænser forstås af alle i teamet, og manuel inspektion udfylder hullet efter tekstsøgning hurtigt nok til at undgå alvorlige fejl. I et stort virksomhedssystem med flere sprog, årtiers akkumuleret kode og teamstrukturer, der betyder, at ingen enkeltpersoner forstår helheden, stiger omkostningerne. Oversete afhængigheder dukker op i produktionen. Konsekvensanalyser, der var tillidsvækkende i mødelokalet, producerer overraskende fejl i udgivelsen. Sikkerhedsrevisioner, der dækkede hver strengforekomst, overser de dataflowstier, der afslører følsomme data. Viden, der blev opbevaret i hovederne på udviklere, der siden er gået videre, kan ikke rekonstrueres fra tekstsøgning, fordi de strukturelle relationer, de forstod, aldrig blev kodet i nogen streng i kildefilerne.
Overgangen fra tekstsøgning til kodeforståelse er ikke en erstatning af ét værktøj med et andet. Tekstsøgning bevarer sin rolle for de opgaver, det er egnet til: strengplacering, hurtig orientering, konfigurationstjek og filnavigation. Kodeforståelse giver den strukturelle analyse, som tekstsøgning ikke kan: kalde grafer, dataflowsporing, konsekvensanalyse, identifikation af død kode og løsning af afhængigheder på tværs af sprog. De to opererer på forskellige abstraktionsniveauer, besvarer forskellige kategorier af spørgsmål og tjener forskellige formål. Omkostningerne ved at sammenblande dem betales i oversete afhængigheder, forkerte vurderinger og den konstante akkumulering af risiko, der følger af at foretage følgeændringer i komplekse systemer med en ufuldstændig model af, hvad de rent faktisk gør.