Un développeur ouvre pour la première fois un vaste code source hérité. Il doit comprendre ce qui arrive à une fiche client lors de la fermeture d'un compte : quels programmes la mettent à jour, quels traitements par lots la lisent ensuite, quels champs sont modifiés et si un système en aval dépend de l'état final. Son premier réflexe est de rechercher. Il utilise grep pour trouver le nom du champ, parcourt les résultats, ouvre quelques fichiers et commence à lire. En une heure, il trouve des références dans douze programmes, trois scripts SQL et un flux de travaux JCL. Il trouve également le même nom de champ dans dix-sept blocs de commentaires, quatre chaînes de format de journalisation, deux environnements de test et une variable d'un sous-système totalement différent qui porte le même nom. À partir des seuls résultats de la recherche, il ne peut pas déterminer quelles entrées correspondent à des lectures de données, quelles entrées à des écritures, quelles entrées à des transformations et quelles entrées sont de simples coïncidences. Il connaît le nom du champ, mais il ne comprend pas encore comment le code l'utilise.
La compréhension du code commence ici
SMART TS XL Il construit un modèle structurel de l'ensemble de votre code source, en cartographiant les dépendances à travers chaque langage et plateforme.
Cliquez iciCe fossé entre la recherche d'une chaîne de caractères et la compréhension du code n'est pas un fossé que de meilleures recherches comblent. Il s'agit d'un fossé entre deux types d'interrogations fondamentalement différents : l'une qui demande « où apparaît ce texte ? » et l'autre « que fait ce code ? ». La recherche textuelle est une excellente réponse à la première question. Elle ne répond absolument pas à la seconde, et confondre les deux est l'une des sources les plus fréquentes de gaspillage d'efforts, de dépendances non détectées et d'évaluations d'impact erronées dans le développement logiciel. Cette distinction est plus importante dans les grands systèmes d'entreprise hétérogènes que dans les petits projets modernes, car ces systèmes contiennent des décennies de structure accumulée, des dépendances interlangages et des relations implicites qui n'existent que dans le comportement du code, et non dans une chaîne de caractères quelconque apparaissant dans ses fichiers sources. Comme l'a examiné l'analyse de Les indicateurs de qualité du code et leur impactL'encombrement d'une base de code a un impact significatif sur sa maintenabilité, et aucune mesure dérivée des seuls modèles de texte ne permet de saisir les relations structurelles qui régissent le comportement réel du code.
Que fait réellement la recherche textuelle ?
La recherche textuelle est une opération de correspondance de sous-chaînes appliquée aux fichiers traités comme des séquences de caractères bruts. La requête est une chaîne ou un motif. Le résultat est une liste des emplacements où ce motif apparaît. L'outil ignore tout du langage dans lequel les fichiers sont écrits, de la grammaire qui structure le texte et des relations entre les éléments de code qu'il représente. Une recherche effectuée avec `grep` sur un million de lignes de code COBOL fonctionne selon le même modèle qu'une recherche effectuée avec `grep` sur un million de lignes de code HTML : les séquences de caractères dans les fichiers, regroupées par chemin d'accès, sont renvoyées lorsque la séquence correspond.
Ceci est extrêmement utile pour une catégorie spécifique de tâches : trouver où apparaît une chaîne de caractères connue, confirmer la présence ou l’absence d’un terme spécifique, vérifier rapidement la cohérence des conventions de nommage, localiser le fichier contenant un message d’erreur spécifique. Pour ces tâches, la recherche textuelle est l’outil idéal, car il s’agit avant tout de trouver des chaînes de caractères. La rapidité, la portabilité et la simplicité de configuration de grep et de ses équivalents sont des atouts qui répondent parfaitement à la question : « Cette chaîne de caractères existe-t-elle dans ces fichiers ? Si oui, où ? »
Le problème survient lorsque la recherche textuelle est utilisée pour des questions qui ne portent pas sur des chaînes de caractères. « Qu'est-ce qui appelle cette fonction ? » ne porte pas sur l'emplacement du nom de la fonction. Il s'agit d'une question relative au graphe d'appels, une propriété structurelle du code qui nécessite une analyse syntaxique et sémantique pour être construite. « Où est défini ce champ ? » ne porte pas sur l'emplacement du nom du champ. Il s'agit d'une question relative au flux de données, qui requiert la compréhension de la sémantique des affectations dans le langage concerné. « Qu'est-ce qui sera affecté si je modifie cette interface ? » ne porte pas sur l'emplacement du nom de l'interface. Il s'agit d'une question relative aux relations de dépendance, qui requiert la résolution des importations, de l'héritage et du couplage entre modules pour y répondre correctement.
Chacune de ces questions part d'un nom, ce qui peut inciter à les traiter comme des tâches de recherche. Or, le nom n'est que le point de départ. La réponse se trouve dans la structure du code, et non dans le texte des fichiers sources.
Le problème du bruit : trop de résultats qui ne veulent rien dire
Le premier mode de défaillance de la recherche textuelle appliquée aux tâches de compréhension de code est la surproduction : elle renvoie beaucoup plus de résultats que nécessaire, sans mécanisme permettant d’identifier quels résultats sont structurellement significatifs et lesquels sont fortuits.
Un identifiant court comme status, id, type, date peut apparaître des milliers de fois dans un code source volumineux. Des identifiants encore plus longs peuvent entrer en conflit entre les langages et les espaces de noms : calculate_tax Un nom de fonction dans un module Python, un nom de paragraphe COBOL, une procédure stockée de base de données, une fonction d'assistance JavaScript ou une chaîne de caractères dans une configuration de journalisation produisent tous des résultats de recherche textuelle correspondants. Le développeur qui reçoit ces résultats doit les filtrer manuellement, en s'appuyant sur sa propre compréhension du code pour déterminer les occurrences pertinentes. Ce filtrage manuel constitue en soi une tâche de compréhension du code ; autrement dit, le développeur effectue le travail que l'outil était censé réaliser, sans aucune assistance de sa part.
En pratique, les développeurs filtrent le code en se basant sur leur intuition et leur expérience. Ils savent qu'un résultat dans un fichier de test ne correspond probablement pas à un appel en production. Ils savent aussi qu'un résultat dans un bloc de commentaires est de la documentation, et non un appel. Ils ignorent les résultats dans les fichiers qu'ils jugent non pertinents. Mais ces filtres sont faillibles et impossibles à vérifier. Le développeur qui filtre avec assurance peut se tromper. Celui qui filtre avec prudence peut y consacrer des heures. Et dans les deux cas, le résultat est un ensemble de conclusions qui reflètent le jugement du développeur, et non une analyse structurelle vérifiée du code.
Prenons un exemple concret. Un développeur COBOL recherche le nom d'un paragraphe avant de le supprimer :
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)
Parmi ces huit résultats, seuls deux correspondent à des appelants actifs qui s'interrompraient si le paragraphe était supprimé : les lignes 3 et 5. La ligne 2 est la définition. Les lignes 4 et 8 sont des commentaires. La ligne 6 est une entrée du dictionnaire de données. La ligne 7 est un banc d'essai. Déterminer lesquels de ces huit résultats représentent des sites d'appels actifs nécessite de lire chaque fichier dans son contexte, de comprendre la syntaxe COBOL et d'interpréter la signification du terme « désactivé » dans le commentaire de la ligne 8. La recherche textuelle a fourni les données brutes. La compréhension du code a permis d'obtenir la réponse.
Le problème du silence : des résultats pertinents qui ne sont jamais renvoyés
Le deuxième mode de défaillance est la sous-production : des résultats manquants qui sont structurellement importants parce qu’ils ne sont pas exprimés sous une forme à laquelle la recherche textuelle peut correspondre.
Les appels indirects sont la principale source de résultats manquants. Lorsqu'une fonction A appelle une fonction B, et que cette dernière appelle la fonction obsolète C, une recherche textuelle sur le nom de C trouve la fonction B comme appelante directe, mais pas la fonction A comme appelante indirecte. La pertinence de A dépend de l'objectif de la recherche : si l'objectif est de comprendre tous les événements qui déclenchent C, alors A est essentiel. Si l'objectif est uniquement de trouver les appelants directs, alors A est sans importance. La recherche textuelle ne peut pas faire cette distinction car elle n'a pas de notion de graphe d'appels. Elle renvoie tout texte correspondant, sans tenir compte du contexte dans lequel ce texte apparaît.
Les références interlangages constituent une catégorie systématiquement absente. Un service Java qui appelle un programme COBOL par son nom via une couche intermédiaire contient le nom du programme COBOL sous forme de chaîne littérale, que la recherche textuelle peut trouver. En revanche, le même service Java qui construit le nom du programme dynamiquement, le lit à partir d'un fichier de configuration ou effectue une distribution via une couche d'abstraction ne contient pas du tout ce nom. Ces appelants sont introuvables par la recherche textuelle, même appliquée de manière exhaustive. Comme l'illustre l'analyse dans le contexte de Analyse statique du code obfusqué et généré dynamiquement, lorsque les chemins d'exécution sont exprimés indirectement par le biais de la configuration, des modèles ou des mécanismes de répartition d'exécution, les relations structurelles qu'ils représentent ne sont pas récupérables à partir du seul texte des fichiers sources.
Les alias et transformations de champs créent une autre catégorie d'omissions silencieuses. Un champ COBOL nommé WS-ACCT-BAL qui est écrit dans une colonne de base de données nommée ACCT_BALANCE, lu ultérieurement par un service Java comme accountBalance, et finalement publié en série sous le nom de account_balance Dans une réponse JSON, quatre chaînes de caractères différentes désignent un même élément de données. La recherche de l'une de ces chaînes ne permet pas de trouver les trois autres. Comprendre que ces quatre chaînes font référence au même concept métier sous-jacent nécessite de comprendre la chaîne de transformation, et non de rechercher toutes les occurrences d'un nom donné.
Ce que la compréhension du code exige réellement
La compréhension du code, en tant que compétence technique, est l'aptitude à répondre à des questions sur le code en raisonnant à partir de sa structure et de sa sémantique plutôt que de son texte apparent. Elle nécessite la construction et l'interrogation d'un modèle du code qui représente sa signification, et non seulement son contenu textuel.
Les exigences techniques minimales pour la compréhension du code, au niveau requis pour les tâches de développement dans les grands systèmes d'entreprise, sont considérables. Chacune d'elles représente une capacité que la recherche textuelle ne possède pas et qu'aucune combinaison de recherche textuelle et d'intervention manuelle ne peut reproduire de manière fiable à grande échelle.
Analyse syntaxique : du texte à la structure
La première étape après la recherche textuelle est l'analyse syntaxique : la lecture du code source selon la grammaire de son langage et la production d'une représentation structurée, généralement un arbre de syntaxe abstraite, qui encode les relations syntaxiques entre les éléments du code. Une représentation analysée de PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT n'est pas une chaîne de caractères ; il s'agit d'un objet structuré qui identifie ceci comme une instruction PERFORM avec une cible de plage, où les deux points d'extrémité sont des noms de paragraphe dans le programme actuel, résolubles par rapport à la structure PROCEDURE DIVISION du programme.
L'analyse syntaxique est spécifique à chaque langage. Un analyseur COBOL comprend la grammaire COBOL. Un analyseur Java comprend la grammaire Java. Un analyseur JCL comprend la syntaxe JCL. Dans un système d'entreprise multilingue, la compréhension du code nécessite un analyseur pour chaque langage présent dans l'environnement, produisant des représentations structurelles qui permettent un raisonnement cohérent entre les langages. Comme indiqué dans l'examen détaillé de Analyse statique TypeScript à l'échelle de l'entrepriseL'analyse structurelle et sémantique qui permet de comprendre comment le code est organisé, comment les modules interagissent et comment le contrôle et les données circulent dans une application constitue la base pour aller au-delà de la simple vérification de la syntaxe et parvenir à une véritable intelligence du code.
Résolution des symboles : des noms aux entités
Après l'analyse syntaxique, les noms présents dans le code source doivent être résolus en entités correspondant à celles auxquelles ils font référence. L'identifiant CALC-INTEREST Dans une instruction PERFORM, le nom de la méthode doit correspondre à la définition de paragraphe spécifique dans un programme ou un copybook donné. calculateLegacyFee Dans un appel Java, il faut résoudre la définition de méthode spécifique dans la classe concernée, en tenant compte de l'héritage et de la surcharge. Le nom de la colonne ACCT_BALANCE Dans une requête SQL, chaque élément doit correspondre à la colonne spécifique de la table spécifique du schéma de base de données.
La résolution symbolique transforme un nom (une chaîne de caractères) en une référence à une entité de code spécifique et identifiable, dotée d'un emplacement, d'un type et de relations avec d'autres entités. Sans résolution symbolique, toutes les requêtes de code sont des requêtes textuelles. Grâce à elle, une requête portant sur « tous les appelants de cette fonction » est une requête structurelle interrogeant un graphe résolu des relations d'appel, ne retournant que les résultats correspondant aux appels à la fonction spécifique, et non tous les fichiers où le nom de la fonction apparaît.
La résolution symbolique devient beaucoup plus complexe dans les environnements multilingues, où un même concept est désigné différemment selon les langues. La résolution interlinguistique des équivalences de champs, examinée dans le contexte plus large de réduire le temps moyen de récupération grâce à l'indexation multilingueL'analyse structurelle est une condition préalable à toute analyse qui retrace le flux de données ou de contrôle au-delà d'une frontière linguistique. Sans elle, l'analyse s'arrête à la frontière et la compréhension qu'elle apporte est incomplète.
Analyse du flux de contrôle : Comprendre les chemins d’exécution
L'analyse du flux de contrôle permet de cartographier les chemins d'exécution possibles au sein d'un programme : quelles branches sont empruntées et sous quelles conditions, quelles instructions sont accessibles, quels chemins d'exécution sont vains et dans quel ordre les instructions s'exécutent les unes par rapport aux autres. Ces informations sont représentées sous forme de graphe de flux de contrôle, où les nœuds représentent des blocs de code séquentiel et les arêtes, des transferts de contrôle conditionnels ou inconditionnels.
L'analyse du flux de contrôle permet de répondre à des questions telles que « Dans quelles conditions ce chemin d'exécution s'exécute-t-il ? » et « Ce code est-il accessible depuis n'importe quel point d'entrée ? ». La recherche textuelle ne peut répondre à ces questions car elles concernent les chemins d'exécution, et non l'emplacement des chaînes de caractères. Une instruction présente dans le code source peut s'exécuter ou non, selon les conditions qui conditionnent la branche dans laquelle elle se trouve. Une fonction définie dans un module peut être appelée ou non, selon qu'un chemin d'exécution quelconque atteigne ou non son point d'appel. Seule l'analyse du flux de contrôle permet de déterminer ces propriétés. Comme l'illustre l'examen de… prioriser les problèmes de code statique lors de la modernisationComprendre quels chemins de code s'exécutent réellement, à quelle fréquence ils s'exécutent et dans quelles conditions ils s'activent, c'est ce qui distingue une analyse exploitable de conclusions qui semblent significatives mais qui ne reflètent pas la réalité opérationnelle.
Analyse du flux de données : suivi des valeurs à travers le code
L'analyse du flux de données permet de suivre la circulation des valeurs dans un programme : l'affectation d'une variable, la lecture de sa valeur, les transformations qui lui sont appliquées entre son affectation et son utilisation, et les dépendances entre les valeurs des variables. Ces informations répondent à des questions telles que « D'où provient la valeur de ce champ ? » et « Quel code est affecté par la modification de la valeur de ce champ ? »
L'analyse des flux de données constitue le fondement technique du traçage des champs, de l'analyse de contamination et du suivi des dépendances au niveau des valeurs. Elle opère sur le graphe de flux de contrôle du programme, propageant les informations relatives aux valeurs le long des chemins d'exécution et enregistrant leur origine, leur circulation et leur utilisation. Il en résulte un graphe de flux de données reliant les définitions à leurs utilisations dans l'ensemble de l'espace d'exécution du programme, et non plus seulement au sein du texte séquentiel du fichier source.
Dans les systèmes d'entreprise, l'analyse des flux de données doit s'affranchir des frontières linguistiques pour être utile. Une valeur issue d'un programme COBOL, transitant par une écriture dans une base de données, puis lue par un service Java, présente un flux de données qui franchit deux frontières linguistiques. Le suivi de ce flux exige une analyse des flux de données qui intègre la sémantique d'affectation COBOL, les déplacements de données SQL et l'affectation de variables Java dans une analyse unifiée, et non comme trois analyses distinctes dont les résultats doivent être reliés manuellement. Comme détaillé dans l'analyse de Transfert de connaissances des experts COBOL aux équipes de développement modernesLa capacité à rendre les systèmes COBOL complexes compréhensibles par les développeurs modernes sans exiger d'eux qu'ils maîtrisent le langage repose sur une analyse structurelle capable de représenter le comportement du système sous une forme qui transcende le texte source.
Les tâches où la différence compte le plus
La distinction entre la recherche textuelle et la compréhension du code n'est pas purement théorique. Elle se manifeste concrètement dans des tâches de développement spécifiques et cruciales, où un outil inadapté produit des résultats qui semblent complets mais ne le sont pas, et où agir sur la base de résultats incomplets a des conséquences mesurables.
Analyse d'impact avant toute modification
Avant de modifier la signature d'une fonction, de renommer un champ ou de changer le comportement d'une utilitaire partagée, un développeur doit connaître les conséquences de ces modifications. C'est ce qu'on appelle l'analyse d'impact : recenser tous les composants dépendant de l'élément modifié, afin que la modification soit effectuée en toute sécurité et que tous les composants concernés soient mis à jour. L'analyse d'impact est une tâche de compréhension du code. Elle nécessite de résoudre les relations de dépendance entre les composants, de parcourir ces relations à partir de l'élément modifié et d'identifier tous les composants qui seront affectés à n'importe quel niveau de l'arbre de dépendances.
La recherche textuelle permet d'approximer l'analyse d'impact en repérant l'occurrence du nom de l'élément modifié. Cependant, elle ne fait pas la distinction entre une dépendance et un commentaire, une dépendance directe et une dépendance transitive, ni entre une dépendance active et une référence dans du code mort. Un développeur qui s'appuie sur la recherche textuelle pour analyser l'impact d'une modification importante prend une décision critique pour la sécurité en se basant sur une approximation. Dans un petit projet monolingue, cette approximation peut s'avérer suffisante. En revanche, dans un système d'entreprise comportant des dépendances multilingues, des bibliothèques partagées utilisées par de nombreux services et des décennies d'historique d'appels, l'écart entre les résultats de la recherche textuelle et l'impact réel de la modification peut être considérable.
Considérons la différence entre les résultats obtenus avec ces deux approches suite à une modification de schéma d'une colonne de base de données largement utilisée :
| Ce que le développeur doit savoir | Résultat de la recherche textuelle | résultat de compréhension du code |
|---|---|---|
| Programmes qui lisent cette rubrique | Tous les fichiers contenant le nom de la colonne, y compris les commentaires | Seuls les programmes comportant des instructions SQL SELECT faisant référence à cette colonne |
| Programmes qui rédigent cette rubrique | Même liste non filtrée | Seuls les programmes comportant des instructions SQL INSERT ou UPDATE écrivant dans cette colonne |
| Services dépendant de cette colonne | Aucune visibilité interlingue | Services Java, Python et .NET qui associent la colonne à un champ d'objet |
| Références de code mort | Inclus dans les résultats, non marqués | Exclus ou signalés séparément |
| dépendants transitifs | Invisible | Énuméré à n'importe quelle profondeur |
| Confiance dans l'intégralité | Inconnu | Vérifiable par rapport à l'étendue indexée |
Intégration et navigation dans le code
Un développeur découvrant un vaste projet doit se construire une représentation mentale du fonctionnement du code : comment les composants s’articulent, quels flux de données traversent le système, quels programmes servent de points d’entrée et quels programmes sont des utilitaires, et à quoi ressemble le chemin d’exécution d’un processus métier donné. Cet exercice de modélisation est avant tout une tâche de compréhension du code. La recherche textuelle permet de localiser des chaînes de caractères spécifiques, mais ne fournit aucun contexte structurel : elle indique où un mot apparaît, mais pas le rôle du code qui le contient dans le système.
Les outils de compréhension de code accélèrent l'intégration en rendant la structure du système accessible. Un graphe d'appels interactif montre quels programmes appellent quels autres. Une trace de flux de données indique l'origine et la destination d'un champ. Une visualisation du flux de contrôle montre les conditions qui régissent l'exécution des branches. Une carte des dépendances indique les composants modifiables indépendamment et ceux qui nécessitent une coordination avec d'autres équipes. Aucun de ces éléments ne provient d'une recherche textuelle. Ils sont le fruit de l'analyse structurelle effectuée par les outils de compréhension de code. Comme examiné dans le contexte de Qu'est-ce que l'analyse statique de code ?La capacité à appréhender la complexité grâce à une analyse structurée plutôt qu'à une lecture manuelle est ce qui permet aux équipes de travailler efficacement dans des systèmes trop vastes pour qu'un individu puisse les appréhender entièrement.
Identification du code mort et des éléments inutilisés
Le code mort est du code défini mais jamais exécuté : des fonctions jamais appelées, des branches jamais atteintes, des variables initialisées mais jamais lues. Identifier le code mort est une tâche de compréhension du code qui nécessite la construction d'un graphe d'appels complet et la détermination des éléments définis qui ne reçoivent aucun appel entrant depuis un point d'entrée accessible. La recherche textuelle ne permet pas d'identifier le code mort car, par définition, il n'est référencé nulle part. L'absence de référence n'est pas une chaîne de caractères que la recherche textuelle peut trouver.
Pour la suppression des fonctions obsolètes, l'identification du code mort est directement pertinente. Certains éléments qui semblent appeler une fonction obsolète peuvent eux-mêmes être du code mort : des fonctions écrites pour appeler la fonction obsolète mais qui ne sont jamais appelées et ne représentent donc aucune dépendance active. Distinguer les appelants actifs des appelants morts nécessite la même analyse du graphe d'appels que celle utilisée pour identifier le code mort en général. Comme examiné dans le contexte de techniques de refactorisation essentiellesL'analyse statique de l'utilisation fournit des informations suffisantes pour déterminer si des fonctions, des étiquettes, des paragraphes ou des modules sont invoqués, et cette analyse n'est possible que grâce à la construction d'un graphe d'appels structurel, et non grâce au comptage des occurrences de texte.
Audit de sécurité et de conformité
L'audit de sécurité et de conformité exige de retracer les données sensibles au sein du système : identifier l'emplacement de stockage des informations personnelles, les chemins d'exécution du code y ayant accès, vérifier la présence de contrôles d'accès adéquats sur chaque chemin menant à des données sensibles et déterminer si ces données peuvent s'échapper du système via la journalisation, les messages d'erreur ou les réponses d'API. Il s'agit d'analyses des flux de données et de contrôle que la recherche textuelle ne permet pas d'approximer correctement.
Une recherche textuelle portant sur le nom d'un champ sensible permet de trouver les fichiers contenant ce nom. Elle ne peut cependant pas déterminer si ces fichiers effectuent un accès autorisé, non autorisé ou aucun accès. Elle ne peut pas non plus déterminer si un contrôle d'accès est en place dans le chemin d'exécution menant à l'accès au champ. Enfin, elle ne peut pas retracer si la valeur du champ est ensuite consignée dans un journal ou renvoyée dans une réponse d'API qui ne devrait pas la contenir. L'analyse de contamination, qui suit le flux des valeurs sensibles à travers le système et identifie les points où elles peuvent atteindre des sorties non fiables, est une fonctionnalité d'analyse des flux de données. C'est ce que proposent les outils de compréhension de code axés sur la sécurité et ce qu'une recherche textuelle ne peut pas reproduire.
Comment SMART TS XL Fournit une compréhension du code à l'échelle de l'entreprise
SMART TS XL Cette solution repose sur le principe que les systèmes d'entreprise nécessitent une compréhension structurelle, et non une simple extraction de texte. Sa plateforme d'intelligence logicielle analyse le code source de chaque langage et plateforme de l'environnement, génère des arbres de syntaxe abstraite spécifiques à chaque langage, puis les résout en un graphe interlangage unifié représentant les relations structurelles de l'ensemble du système. Les programmes COBOL, les flux de travaux JCL, les services Java, les applications .NET, les scripts Python, les schémas SQL, les modules TypeScript et les artefacts de configuration sont tous représentés par des nœuds et des arêtes dans ce graphe, les relations étant exprimées par des connexions typées : appels, flux de données, inclusions de copybooks, références de schémas et équivalences interlangages.
La fonctionnalité de recherche d'entreprise de la plateforme constitue le point d'entrée pour les tâches d'analyse de code, mais son fonctionnement diffère fondamentalement de celui de la recherche textuelle. Les résultats sont organisés par type de relation et structure d'artefact, et non par fréquence d'apparition de la chaîne de caractères. Une requête portant sur un nom de champ renvoie les définitions, les lectures, les écritures, les références SQL et les inclusions de copybook sous forme de résultats catégorisés séparément. Ainsi, un développeur demandant « Qu'est-ce qui écrit dans ce champ ? » obtient précisément les relations d'écriture, et non une liste hétéroclite de tous les fichiers où le nom apparaît. Cette organisation structurelle des résultats de recherche reflète le modèle de références croisées sous-jacent et fournit aux développeurs les informations spécifiques et exploitables dont ils ont besoin, sans qu'ils aient à filtrer manuellement les fréquences d'apparition de la chaîne de caractères.
Les fonctionnalités d'analyse d'impact, de parcours du graphe d'appels, de visualisation du flux de contrôle et de traçage des flux de données de la plateforme reposent toutes sur un même modèle structurel unifié. Lorsqu'un développeur identifie une fonction obsolète, le graphe d'appels affiche tous les appelants à chaque niveau de la hiérarchie. Lors de la planification d'une modification de schéma, l'analyse d'impact recense tous les consommateurs dans tous les langages. Lorsqu'un développeur en cours d'intégration doit comprendre un processus par lots, la visualisation du flux de contrôle rend le chemin d'exécution navigable sans qu'il ait à lire des centaines de lignes de code source séquentiellement. Dans le contexte plus large de Métriques d'expérience développeur et d'expérience client pour les bases de code existantesLa complexité du code et la complexité structurelle sont les facteurs qui déterminent la maintenabilité, et ce sont les outils qui exposent ces propriétés structurelles plutôt que le simple texte de surface qui rendent les systèmes complexes gérables à grande échelle.
La différence entre quoi SMART TS XL Ce que la recherche textuelle apporte, c'est la différence entre répondre à une question et en poser une nouvelle. La recherche textuelle initie une investigation. La compréhension du code la conclut.
Le coût permanent du remplacement de la recherche par la compréhension
L'utilisation de la recherche textuelle comme substitut à la compréhension du code a des conséquences pratiques insidieuses qui s'accumulent à chaque étape du développement nécessitant une connaissance structurelle du code. Toute analyse d'impact basée sur la recherche textuelle comporte un nombre inconnu de dépendances non détectées. Toute trace de champ s'arrêtant à une limite de langage laisse une partie du système invisible. Toute identification de code mort comptant les occurrences de chaînes de caractères au lieu d'analyser l'accessibilité du graphe d'appels génère de faux positifs et passe à côté de véritables codes morts. Tout audit de sécurité recherchant des noms de champs sensibles au lieu de suivre le flux de données à travers les chemins d'exécution offre une assurance incomplète et invérifiable.
Dans un petit système monolingue à base de code fréquemment modifiée, ces coûts peuvent être gérables. Les développeurs disposent du contexte nécessaire pour filtrer précisément les résultats de recherche, les limites du système sont comprises par tous les membres de l'équipe et l'inspection manuelle comble rapidement les lacunes de la recherche textuelle, évitant ainsi les erreurs graves. Dans un grand système d'entreprise multilingue, composé de décennies de code accumulé et dont les structures d'équipe font qu'aucun individu n'en a une vision d'ensemble, les coûts s'accumulent. Des dépendances non identifiées apparaissent en production. Les analyses d'impact, rassurantes en réunion, entraînent des défaillances inattendues lors du déploiement. Les audits de sécurité, exhaustifs, passent à côté des flux de données exposant des informations sensibles. Les connaissances acquises par les développeurs ayant quitté l'entreprise ne peuvent être reconstituées par recherche textuelle, car les relations structurelles qu'ils comprenaient n'ont jamais été encodées dans les fichiers sources.
Passer de la recherche textuelle à l'analyse de code ne signifie pas remplacer un outil par un autre. La recherche textuelle conserve son utilité pour les tâches auxquelles elle est adaptée : localisation de chaînes de caractères, orientation rapide, vérification de la configuration et navigation dans les fichiers. L'analyse de code, quant à elle, fournit l'analyse structurelle que la recherche textuelle ne peut offrir : graphes d'appels, traces de flux de données, analyse d'impact, identification du code mort et résolution des dépendances entre langages. Ces deux outils opèrent à des niveaux d'abstraction différents, répondent à des catégories de questions différentes et servent des objectifs distincts. Les confondre peut entraîner des dépendances non identifiées, des évaluations erronées et une accumulation progressive de risques liés à des modifications importantes apportées à des systèmes complexes sans une compréhension complète de leur fonctionnement.