Architecture decision records

From Webhuis wiki
Revision as of 15:34, 25 March 2026 by Martin (talk | contribs) (Created page with "<span id="architecture-decision-records"></span> = Architecture Decision Records = {| !width="23%"| Field !width="76%"| Value |- | Document ID | PGCBL-ADD-001 |- | Document Type | Architecture Decision Document |- | System | pgcobol — Prime Numbers Application v1.0 |- | Version | 1.0 |- | Status | Draft — decisions marked [INFERRED] need developer confirmation |- | Owner | Lead Developer / Architect |- | Author | [reverse-engineered from source artifacts] |- | Creat...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Architecture Decision Records[edit]

Field Value
Document ID PGCBL-ADD-001
Document Type Architecture Decision Document
System pgcobol — Prime Numbers Application v1.0
Version 1.0
Status Draft — decisions marked [INFERRED] need developer confirmation
Owner Lead Developer / Architect
Author [reverse-engineered from source artifacts]
Created 2026-03-17
Last modified 2026-03-17
Classification Internal
Parent document PGCBL-TSD-001

Version History[edit]

Version Date Author Status Change Summary
0.1 2026-03-17 Draft All ADRs inferred from source



Table of Contents[edit]

  1. Purpose and Format
  2. ADR-001 — Three-Tier Architecture
  3. ADR-002 — Method-Dispatch Pattern
  4. ADR-003 — Divisors Stored in Database
  5. ADR-004 — GixSQL as SQL Pre-Processor
  6. ADR-005 — Copybooks as Interface Contracts
  7. ADR-006 — Hard-Coded Database Credentials
  8. ADR-007 — No Explicit COMMIT on INSERT
  9. ADR-008 — Odd-Only Sieve Starting at 3
  10. Open Issues



1. Purpose and Format[edit]

An Architecture Decision Record (ADR) captures a single significant design decision: the context that prompted it, the options that were considered, the choice that was made, and the consequences. ADRs are written once and never deleted — if a decision is reversed, a new ADR documents the reversal and links to the original.

This document follows the MADR (Markdown Architectural Decision Records) format, a widely adopted lightweight standard (see https://adr.github.io/madr/).

ADR template[edit]

## N. ADR-NNN — <Short title of the decision>

**Date:** YYYY-MM-DD  
**Status:** Proposed | Accepted | Deprecated | Superseded by ADR-NNN  
**Deciders:** <names or roles>  
**Source:** [CONFIRMED] | [INFERRED from source] | [ASSUMED]

### Context

<What situation or problem prompted this decision? What forces are at play?>

### Decision Drivers

- <driver 1>
- <driver 2>

### Options Considered

| Option | Description | Pros | Cons |
|--------|-------------|------|------|
| A | ... | ... | ... |
| B | ... | ... | ... |

### Decision

<The option chosen and a one-line justification.>

### Consequences

**Positive:**
- <benefit 1>

**Negative / trade-offs:**
- <drawback 1>

**Risks:**
- <risk 1>

### Compliance check

<How to verify this decision is being followed in the codebase.>

2. ADR-001 — Three-Tier Architecture[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [INFERRED from source structure]

Context[edit]

A batch COBOL program could be written as a single monolithic program with all logic, SQL, and output in one place. This project chose to separate concerns into distinct compiled units.

Decision Drivers[edit]

  • Demonstrate a maintainable, layered COBOL design pattern.
  • Allow each tier to be tested, replaced, or modified independently.
  • Keep SQL in one place so that database changes affect only one program.

Options Considered[edit]

Option Description Pros Cons
A Single monolithic program Simple; one file to manage Hard to test; all concerns coupled
B Three-tier (chosen) Separation of concerns; independently testable tiers More files; inter-program calling overhead
C Two-tier (no UI layer) Simpler than three Print formatting coupled to business logic

Decision[edit]

Option B — three-tier (presentation / business logic / data access), each as a separate compiled COBOL program. A fourth orchestrating program (primesmain) manages the session lifecycle.

Consequences[edit]

Positive: - SQL is isolated in primes.cbl; database changes do not affect other programs. - Print formatting is isolated in primesui.cbl; output format changes do not affect logic. - Each program can be called from a test harness independently.

Negative / trade-offs: - Four programs must be compiled and linked instead of one. - Inter-program calls carry a small runtime overhead. - A shared copybook change requires recompiling all programs that use it.

Compliance check[edit]

grep -l "EXEC SQL" *.cbl should return only primes.cbl.
grep -l "OPEN.*fprinter\|WRITE.*file-buffer" *.cbl should return only primesui.cbl.



3. ADR-002 — Method-Dispatch Pattern[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [INFERRED from copybook design]

Context[edit]

COBOL does not have objects, interfaces, or function pointers in the traditional sense. When a caller invokes a subprogram, it can either call different entry points (ENTRY paragraphs) or pass a discriminator value and let the callee dispatch internally. The design must allow each subprogram to expose multiple operations without multiple entry points.

Decision Drivers[edit]

  • Keep the inter-tier interface to a single CALL statement per tier.
  • Allow new operations to be added to a tier without changing the caller’s CALL syntax.
  • Use a pattern that is idiomatic in COBOL and familiar to COBOL programmers.

Options Considered[edit]

Option Description Pros Cons
A Separate CALL per operation (CALL "primes-connect", CALL "primes-fetch" …) Explicit; no dispatch overhead Many CALL statements; callers must know all entry names
B ENTRY paragraph per operation (single program, multiple named entries) Standard COBOL; compiler-enforced Callers must still reference entry names; no single interface point
C Method-dispatch over a control block (chosen) Single CALL; extensible; copybook is the interface contract Verb strings must be kept in sync between copybooks and EVALUATE

Decision[edit]

Option C — a string verb in a copybook field (dal-methods, ui-methods, methods) drives an EVALUATE TRUE inside the called program. The copybook is the published interface; the 88-level conditions make the valid verbs self-documenting.

Consequences[edit]

Positive: - Adding a new operation requires only: a new 88-level condition in the copybook and a new WHEN clause in the callee. - The caller’s CALL statement never changes. - The copybook 88-levels serve as the API documentation.

Negative / trade-offs: - Verb strings are not type-checked at compile time; a misspelled verb silently falls through to the WHEN OTHER error branch. - Result codes (0/1/9/99) are numeric constants, not named conditions at the caller site — callers must remember the convention.

Risks: - Verb string drift: if a verb is renamed in the copybook but not in the callee’s EVALUATE, the operation silently does nothing and returns result 1.

Compliance check[edit]

Every verb listed in a dal-methods / ui-methods / methods 88-level must have a corresponding WHEN clause in the callee’s EVALUATE. Verify with a diff of copybook 88-values against callee WHEN values.



4. ADR-003 — Divisors Stored in Database[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [INFERRED from algorithm and SQL design]

Context[edit]

The trial-division sieve needs a list of previously found primes to use as divisors. These could be held in a COBOL working-storage table (an array), in a flat file, or in the database.

Decision Drivers[edit]

  • Demonstrate database interaction as part of the algorithm (pedagogical goal).
  • Keep the COBOL working-storage footprint small — avoid a large in-memory prime array.
  • Persist divisors so the report can run independently of the generation run.

Options Considered[edit]

Option Description Pros Cons
A In-memory COBOL table Fastest; no I/O Fixed size; lost between runs; defeats the DB demonstration goal
B Flat file Persistent; simple Requires file I/O; not the DB demonstration goal
C Database (chosen) Persistent; demonstrates DB use; divisors and output in same store One SQL query per trial division step — potentially very slow

Decision[edit]

Option C — each divisor is fetched from the primes table by ident using a point SELECT. Generated primes accumulate in the same table as the divisors.

Consequences[edit]

Positive: - Demonstrates the full three-tier pattern end-to-end. - All state is in the database; generation can be interrupted and (in principle) resumed.

Negative / trade-offs: - Performance is heavily dependent on the SELECT prime WHERE ident = :n query. Without an index on ident, this becomes a sequential scan that gets slower as the table grows. - The design requires prime 2 to be pre-seeded in the table before the algorithm starts, since the first divider fetch assumes ident=2 exists.

Risks: - No index on ident is defined in primes_schema.sql (see NFR-PERF-03). This is the most significant performance risk in the system.

Compliance check[edit]

Run \d primes.primes in psql; verify an index on ident is present. If absent, add: CREATE INDEX idx_primes_ident ON primes.primes (ident);



5. ADR-004 — GixSQL as SQL Pre-Processor[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [CONFIRMED — explicit in compiler listing header and DATASRC prefix pgsql://]

Context[edit]

GnuCOBOL does not natively support embedded SQL. An external pre-processor is needed to translate EXEC SQL … END-EXEC blocks into COBOL CALL statements to a SQL runtime library.

Decision Drivers[edit]

  • Open-source toolchain (no licensing cost).
  • PostgreSQL support.
  • Compatible with GnuCOBOL.

Options Considered[edit]

Option Description
ESQL/C bridge Write SQL in C, call from COBOL — complex
OCESQL Another open-source COBOL SQL pre-processor — less PostgreSQL-specific
GixSQL (chosen) Open-source; PostgreSQL-optimised; active development

Decision[edit]

GixSQL — translates EXEC SQL to GIXSQLExec, GIXSQLConnect, GIXSQLConnectReset calls. Connection string prefix pgsql:// is GixSQL-specific.

Consequences[edit]

Positive: - Standard embedded SQL syntax in COBOL source. - PostgreSQL-native driver.

Negative / trade-offs: - GixSQL-specific connection string prefix (pgsql://) and runtime library are not portable to other COBOL SQL pre-processors. - GixSQL is not part of the GnuCOBOL distribution; must be installed separately.

Compliance check[edit]

All SQL pre-processing must be done through GixSQL. Verify no raw CALL "GIXSQLExec" statements appear in handwritten source (only in generated .out files).



6. ADR-005 — Copybooks as Interface Contracts[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [INFERRED from copybook design]

Context[edit]

In a multi-program COBOL system, data shared between programs can be defined redundantly in each program’s WORKING-STORAGE, or defined once in a copybook included by all parties.

Decision[edit]

Define each tier’s control block once in a copybook (primes-session.cpy, primes-dal.cpy, primes-ui.cpy) and COPY it into both the caller’s WORKING-STORAGE and the callee’s LINKAGE SECTION. The copybook is the published interface; changing it is a breaking change affecting all users.

Consequences[edit]

Positive: - Single source of truth for each interface. - Field layout guaranteed to match between caller and callee.

Negative / trade-offs: - Any field size change in a copybook requires recompiling every program that includes it. - Two nearly-identical host-variable copybooks exist (primes-table.cpy vs primes_table.cpy) — the canonical version must be designated and the other retired.

Compliance check[edit]

grep -r "COPY primes-dal" *.cbl — should list only primesgen.cbl (caller) and primes.cbl (callee).



7. ADR-006 — Hard-Coded Database Credentials[edit]

Date: 2025 (inferred)
Status: Accepted (as technical debt — see note)
Deciders: Original developer
Source: [CONFIRMED — visible in primes.cbl lines 14–17]

Context[edit]

Database credentials must be provided to the GixSQL CONNECT call. Options include hard-coding, environment variables, a configuration file, or a secrets manager.

Decision[edit]

Credentials are hard-coded in WORKING-STORAGE of primes.cbl as a pragmatic choice for a demonstration application.

Technical debt note: This decision is explicitly acknowledged as a security defect (NFR-SEC-01). It is documented here so that the decision is visible and the remediation can be tracked. It must not be carried forward to a production deployment.

Recommended remediation[edit]

Replace DBUSR and DBPWD VALUE clauses with:

<syntaxhighlight lang="cobol">ACCEPT DBUSR FROM ENVIRONMENT "PRIMES_DB_USER" ACCEPT DBPWD FROM ENVIRONMENT "PRIMES_DB_PASS"</syntaxhighlight> Or read from a protected configuration file at startup.

Consequences[edit]

Negative: - Credential rotation requires recompilation and redeployment. - Credentials are visible in the binary and in any version-control history. - Violates NFR-SEC-01 and OWASP Secure Coding Practice #3.



8. ADR-007 — No Explicit COMMIT on INSERT[edit]

Date: 2025 (inferred)
Status: Accepted (status uncertain — see note)
Deciders: Original developer
Source: [INFERRED — COMMIT statement is commented out in primes.cbl r83-write-prime]

Context[edit]

The INSERT in r83-write-prime does not issue an explicit COMMIT. The commented-out COMMIT suggests this was a deliberate choice or a deferred decision.

Decision[edit]

Rely on PostgreSQL’s default auto-commit behaviour for individual INSERT statements outside an explicit transaction. The COMMIT is not needed because each INSERT auto-commits.

Note: The report path opens an explicit transaction (START TRANSACTION) via s01-cursor. If the generate path is ever run while a transaction is open (e.g. if the session management is changed), the INSERTs will not auto-commit. This is a latent risk.

Consequences[edit]

Positive: - Simpler code; no COMMIT overhead per row.

Risks: - If a transaction is ever opened on the primes connection before r83-write-prime, the INSERTs will not be committed until an explicit COMMIT or ROLLBACK, and data will be lost on failure.



9. ADR-008 — Odd-Only Sieve Starting at 3[edit]

Date: 2025 (inferred)
Status: Accepted
Deciders: Original developer
Source: [CONFIRMED — ADD 2 TO test-number in r82-next-test-number; initial value 3]

Context[edit]

The sieve must test whether each integer is prime. Testing every integer (2, 3, 4, 5 …) is correct but wasteful: all even numbers greater than 2 are composite and need not be tested.

Decision[edit]

Start the candidate at 3 and advance by 2 (ADD 2 TO test-number), testing only odd integers. Prime 2 is handled as a manual seed rather than by the algorithm.

Consequences[edit]

Positive: - Roughly halves the number of candidates that must be tested, improving performance.

Negative / trade-offs: - Prime 2 must be manually seeded in the database before the algorithm runs (see Assumption A-01). This is an external dependency on an operational step, not a code-enforced constraint.

Compliance check[edit]

Verify test-number is initialised to 3 (odd) and that only ADD 2 TO test-number (never ADD 1) advances the candidate in r82-next-test-number.



10. Open Issues[edit]

ID Issue Owner Target Status
OI-01 All ADRs marked [INFERRED] need confirmation from original developer Lead Dev Open
OI-02 ADR-006 remediation (credentials) has no target date Lead Dev Open
OI-03 ADR-007 (no COMMIT) — confirm the intent is auto-commit, not an oversight Lead Dev Open
OI-04 Duplicate copybooks (ADR-005) — designate canonical version and retire the other Developer Open

Terug naar: Design standards | Cobol and PostgreSQL