Flagship research · free to cite
The legacy anti-patterns catalog.
An architectural dictionary of the constructs that break modernization programs: what each one does at runtime, how a deterministic engine detects it, and the modern pattern it maps to. 25 patterns at launch, 10 added monthly.
- ALTERCriticalLNACCR02.cbl:412→ state machine
- PERFORM THRUHighLNFEES01.cbl:88-140→ single-entry function
- REDEFINESCriticalLNREC.cpy:14-31→ discriminated union
- COMMAREA stateCriticalLNINQ01.cbl:57→ stateless REST + token
- COND=(4,LT)HighLNDLY01.jcl:22→ explicit step DAG
- patterns at launch
- 25
- patterns at launch
- legacy families covered
- 12
- legacy families covered
- rated Critical for cutover risk
- 7
- rated Critical for cutover risk
- new entries every month
- 10
- new entries every month
Search the catalog
Find the construct. See where it lands.
Filter by legacy family or cutover risk. Each entry has before and after code, the detection method and a generated spec fragment.
25 of 25 entries include an OpenAPI, DMN or JSON Schema fragment.
25 of 25 patterns
- COBOLCritical
ALTER statement
ALTER rewrites the target of a GO TO at runtime, so the control flow you read in the listing is not the control flow that executes.
maps toExplicit state machine - COBOLHigh
GO TO DEPENDING ON
A computed jump table that transfers control to the Nth paragraph in a list, and silently falls through to the next statement when the index is out of range.
maps toDispatch table with explicit default - COBOLHigh
PERFORM THRU fall-through
PERFORM A THRU B runs every paragraph that physically sits between A and B, and GO TO the exit paragraph is the early return, so the unit of behavior is a source range, not a named routine.
maps toSingle-entry function with guard clauses - COBOLCritical
REDEFINES memory overlay
REDEFINES gives the same bytes two or more layouts, usually chosen by a type code elsewhere in the record, so one field name can hold a card token in one row and a packed amount in the next.
maps toDiscriminated union (oneOf with a tag) - COBOLHigh
OCCURS DEPENDING ON
A variable-length table whose current size is held in another field, so record length, field offsets and loop bounds all change at runtime.
maps toBounded array (child collection) - COBOLCritical
COMP-3 packed decimal arithmetic
Fixed-point decimal arithmetic with silent high-order truncation and truncate-or-round rules set per statement, which floating point and careless BigDecimal code do not reproduce.
maps toBigDecimal with explicit scale and rounding mode - COBOLMedium
88-level condition names
Named conditions over a field's values that encode business categories, often with overlapping value lists, where SET name TO TRUE writes only the first value in the list.
maps toEnum with category predicates - COBOLHigh
Copybook sprawl
Hundreds of near-duplicate copybooks, COPY REPLACING variants and same-named members in different libraries, so the record layout a program uses depends on how it was compiled.
maps toVersioned canonical schema - CICSCritical
CICS pseudo-conversational state
Each screen interaction is a separate CICS task, and the conversation's state survives only in the COMMAREA passed on RETURN TRANSID, so business flow is spread across task boundaries.
maps toStateless REST resource with explicit versioning - JCLHigh
JCL condition code chains
COND parameters bypass a step when the condition is true, the reverse of how most people read them, and chains of COND, EVEN and ONLY encode the batch job's real error handling.
maps toExplicit step DAG with run conditions - Data storesHigh
VSAM alternate index coupling
Programs reach a KSDS through alternate index paths defined outside the code, in IDCAMS jobs and JCL, so access patterns, duplicate handling and index maintenance are invisible in the COBOL source.
maps toRelational table with secondary index and explicit queries - Data storesCritical
IMS hierarchical navigation
IMS DB programs navigate a segment hierarchy with DL/I GU, GN and GNP calls whose results depend on current database position, so the query is a sequence of calls, not a statement.
maps toRelational aggregate with foreign keys - Java EEHigh
EJB 2.x entity beans
Persistent objects whose fields, finder queries, relationships and transaction rules are split between abstract Java classes and ejb-jar.xml, with business logic hiding in container callbacks.
maps toJPA entity, repository and transactional service - Java EEMedium
EJB home and remote interfaces
Service boundaries defined by EJBHome and EJBObject interfaces, JNDI lookups and PortableRemoteObject.narrow, where remote calls copy arguments and local calls share them.
maps toCoarse-grained REST contract with DTOs - Java EEHigh
Struts god Action
One Struts Action class that dispatches on a request parameter to dozens of operations, mixing validation, session state, persistence and business rules inside execute().
maps toThin controller per command, domain service underneath - SpringHigh
Spring XML and AOP hidden logic
Behavior added to beans by XML-declared advice, pointcut expressions and transaction rules, so the Java class you read is not the whole of what runs when it is called.
maps toExplicit composition with declared cross-cutting concerns - SOAPMedium
SOAP and WSDL schema coupling
Service contracts fixed in WSDL and XSD, with generated stubs on both sides, where nillable, minOccurs, xsd:choice and SOAP faults carry meaning that a quick JSON port flattens.
maps toOpenAPI 3.1 with JSON Schema 2020-12 and problem details - VB6Critical
VB6 On Error Resume Next
An error handler that swallows every runtime error and continues at the next statement, so failed reads leave stale or default values that later statements write to the database.
maps toExplicit exceptions and result types - VB6High
VB6 global module state
Public variables in .bas modules, implicit default form instances and hidden controls used as variables, so behavior depends on what any form did earlier in the session.
maps toExplicit request context and injected services - .NETHigh
WebForms ViewState and code-behind logic
ASP.NET WebForms pages keep server values in ViewState, round-tripped through the browser, and put business rules in code-behind event handlers tied to the page lifecycle.
maps toSPA front end over a stateless API that rereads authoritative data - .NETMedium
WCF DataContract versioning
WCF service contracts whose wire format depends on DataMember attributes, serializer ordering rules, KnownType declarations and binding configuration, not just on the C# class shape.
maps toVersioned OpenAPI 3.1 schemas with discriminated oneOf - PL/SQLHigh
PL/SQL row-by-row cursor
Large cursor FOR loops that apply business rules one row at a time, with per-row lookups, commits inside the loop and WHEN OTHERS handlers that hide failures.
maps toSet-based query plus explicit rule table - PL/SQLCritical
PL/SQL trigger side effects
Row-level triggers that change values, write to other tables and enforce rules on every DML statement, so business behavior fires no matter which application, script or batch job touched the row.
maps toExplicit domain operation with events via an outbox - T-SQLHigh
T-SQL dynamic SQL rules
Stored procedures that assemble SQL strings from rule tables and parameters and run them with EXEC or sp_executesql, so the business logic is partly data and invisible to plain code reading.
maps toParameterised query with criteria as a reviewed decision table - 4GLMedium
Informix 4GL screen logic
Business rules embedded in INPUT statement control blocks (AFTER FIELD, BEFORE FIELD, ON KEY) and form attributes, interleaved with SQL, so validation and silent corrections exist only in the terminal screen.
maps toRequest schema plus server-side validation and correction rules
Legacy to modern mapping
Every anti-pattern has a target shape.
The catalog at a glance: the legacy construct on top, the modern pattern your engineers build against underneath.
ALTER statement
Explicit state machine
GO TO DEPENDING ON
Dispatch table with explicit default
PERFORM THRU fall-through
Single-entry function with guard clauses
REDEFINES memory overlay
Discriminated union (oneOf with a tag)
OCCURS DEPENDING ON
Bounded array (child collection)
COMP-3 packed decimal arithmetic
BigDecimal with explicit scale and rounding mode
88-level condition names
Enum with category predicates
Copybook sprawl
Versioned canonical schema
CICS pseudo-conversational state
Stateless REST resource with explicit versioning
JCL condition code chains
Explicit step DAG with run conditions
VSAM alternate index coupling
Relational table with secondary index and explicit queries
IMS hierarchical navigation
Relational aggregate with foreign keys
EJB 2.x entity beans
JPA entity, repository and transactional service
EJB home and remote interfaces
Coarse-grained REST contract with DTOs
Struts god Action
Thin controller per command, domain service underneath
Spring XML and AOP hidden logic
Explicit composition with declared cross-cutting concerns
SOAP and WSDL schema coupling
OpenAPI 3.1 with JSON Schema 2020-12 and problem details
VB6 On Error Resume Next
Explicit exceptions and result types
VB6 global module state
Explicit request context and injected services
WebForms ViewState and code-behind logic
SPA front end over a stateless API that rereads authoritative data
WCF DataContract versioning
Versioned OpenAPI 3.1 schemas with discriminated oneOf
PL/SQL row-by-row cursor
Set-based query plus explicit rule table
PL/SQL trigger side effects
Explicit domain operation with events via an outbox
T-SQL dynamic SQL rules
Parameterised query with criteria as a reviewed decision table
Informix 4GL screen logic
Request schema plus server-side validation and correction rules
Methodology
How each entry is detected.
The catalog is not a style guide. Each entry describes a detector the PYD ENTERPRISES engine runs over parsed code, and the evidence it produces. No entry depends on a language model reading the source: the optional model you host only names and describes findings that the deterministic passes already located.
Every executable path in a scanned system is accounted for: extracted as a rule, classified as plumbing, or flagged for review. The anti-patterns here are the most common reasons a path lands in that last bucket.
- 01
Parse to a full AST, not a token stream
Every program, copybook, JCL member, deployment descriptor and stored procedure is parsed by a dialect-aware grammar. Copybooks are expanded with REPLACING applied, so a pattern hidden inside an included member is found at its real position.
- 02
Resolve symbols and storage
Every data name resolves to an offset and a length; every CALL, CICS LINK or XCTL, EJB lookup and Spring bean reference resolves to a target. Patterns such as REDEFINES overlays and VB6 global state are visible only at this layer.
- 03
Build control flow and data flow
The engine builds a control-flow graph per program and a cross-program call graph, then runs reaching-definitions, value-range and slicing passes. ALTER, GO TO DEPENDING ON and PERFORM THRU fall-through are CFG properties; trigger side effects and ON ERROR RESUME NEXT are dataflow properties.
- 04
Match detectors and classify
Each catalog entry is a deterministic detector over those graphs, with a fixed rule set and no sampling. Every hit is classified as a business rule, as plumbing, or as needing review, and carries the file and line range that produced it.
- 05
Map, export and review
The finding links to its modern mapping and, where it applies, to a generated OpenAPI 3.1 path, DMN 1.5 table or JSON Schema. Your engineers review the mapping beside the source lines and sign it off before anyone builds against it.
The Modernization Architect
Ten new anti-patterns a month, with the playbooks that use them.
A monthly deep dive on mainframe decompilation, DMN extraction and legacy migrations. Each issue walks through the new catalog entries and the migration guide where they show up most.
CITE THIS CATALOG
Architects and SI practice leads may quote any entry in RFP responses, discovery reports and architecture reviews with attribution:
PYD ENTERPRISES PRIVATE LIMITED. Legacy Anti-Patterns Catalog (2026). pydenterprises.com/resources/legacy-patterns-catalog
Find every one of these in your code, with line numbers.
Run PYD ENTERPRISES on 100,000 lines of COBOL, Java or .NET in your private VPC and get a pattern inventory with modern mappings in your first week.