Editing
Architecture decision records
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
= 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] |- | Created | 2026-03-17 |- | Last modified | 2026-03-17 |- | Classification | Internal |- | Parent document | PGCBL-TSD-001 |} <span id="version-history"></span> == Version History == {| !width="16%"| Version !width="22%"| Date !width="15%"| Author !width="15%"| Status !width="30%"| Change Summary |- | 0.1 | 2026-03-17 | — | Draft | All ADRs inferred from source |} ----- <span id="table-of-contents"></span> == Table of Contents == # [[#1-purpose-and-format|Purpose and Format]] # [[#2-adr-001--three-tier-architecture|ADR-001 — Three-Tier Architecture]] # [[#3-adr-002--method-dispatch-pattern|ADR-002 — Method-Dispatch Pattern]] # [[#4-adr-003--divisors-stored-in-database|ADR-003 — Divisors Stored in Database]] # [[#5-adr-004--gixsql-as-sql-pre-processor|ADR-004 — GixSQL as SQL Pre-Processor]] # [[#6-adr-005--copybooks-as-interface-contracts|ADR-005 — Copybooks as Interface Contracts]] # [[#7-adr-006--hard-coded-database-credentials|ADR-006 — Hard-Coded Database Credentials]] # [[#8-adr-007--no-explicit-commit-on-insert|ADR-007 — No Explicit COMMIT on INSERT]] # [[#9-adr-008--odd-only-sieve-starting-at-3|ADR-008 — Odd-Only Sieve Starting at 3]] # [[#10-open-issues|Open Issues]] ----- <span id="purpose-and-format"></span> == 1. Purpose and Format == 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 <code>https://adr.github.io/madr/</code>). <span id="adr-template"></span> === ADR template === <pre class="markdown">## 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.></pre> ----- <span id="adr-001-three-tier-architecture"></span> == 2. ADR-001 — Three-Tier Architecture == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [INFERRED from source structure] <span id="context"></span> === Context === 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. <span id="decision-drivers"></span> === Decision Drivers === * 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. <span id="options-considered"></span> === Options Considered === {| !width="24%"| Option !width="39%"| Description !width="18%"| Pros !width="18%"| 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 |} <span id="decision"></span> === Decision === Option B — three-tier (presentation / business logic / data access), each as a separate compiled COBOL program. A fourth orchestrating program (<code>primesmain</code>) manages the session lifecycle. <span id="consequences"></span> === Consequences === '''Positive:''' - SQL is isolated in <code>primes.cbl</code>; database changes do not affect other programs. - Print formatting is isolated in <code>primesui.cbl</code>; 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. <span id="compliance-check"></span> === Compliance check === <code>grep -l "EXEC SQL" *.cbl</code> should return only <code>primes.cbl</code>.<br /> <code>grep -l "OPEN.*fprinter\|WRITE.*file-buffer" *.cbl</code> should return only <code>primesui.cbl</code>. ----- <span id="adr-002-method-dispatch-pattern"></span> == 3. ADR-002 — Method-Dispatch Pattern == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [INFERRED from copybook design] <span id="context-1"></span> === Context === 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. <span id="decision-drivers-1"></span> === Decision Drivers === * Keep the inter-tier interface to a single <code>CALL</code> 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. <span id="options-considered-1"></span> === Options Considered === {| !width="24%"| Option !width="39%"| Description !width="18%"| Pros !width="18%"| Cons |- | A | Separate CALL per operation (<code>CALL "primes-connect"</code>, <code>CALL "primes-fetch"</code> …) | 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 |} <span id="decision-1"></span> === Decision === Option C — a string verb in a copybook field (<code>dal-methods</code>, <code>ui-methods</code>, <code>methods</code>) drives an <code>EVALUATE TRUE</code> inside the called program. The copybook is the published interface; the 88-level conditions make the valid verbs self-documenting. <span id="consequences-1"></span> === Consequences === '''Positive:''' - Adding a new operation requires only: a new 88-level condition in the copybook and a new <code>WHEN</code> 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 <code>WHEN OTHER</code> 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. <span id="compliance-check-1"></span> === Compliance check === Every verb listed in a <code>dal-methods</code> / <code>ui-methods</code> / <code>methods</code> 88-level must have a corresponding <code>WHEN</code> clause in the callee’s EVALUATE. Verify with a diff of copybook 88-values against callee WHEN values. ----- <span id="adr-003-divisors-stored-in-database"></span> == 4. ADR-003 — Divisors Stored in Database == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [INFERRED from algorithm and SQL design] <span id="context-2"></span> === Context === 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. <span id="decision-drivers-2"></span> === Decision Drivers === * 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. <span id="options-considered-2"></span> === Options Considered === {| !width="24%"| Option !width="39%"| Description !width="18%"| Pros !width="18%"| 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 |} <span id="decision-2"></span> === Decision === Option C — each divisor is fetched from the <code>primes</code> table by ident using a point SELECT. Generated primes accumulate in the same table as the divisors. <span id="consequences-2"></span> === Consequences === '''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 <code>SELECT prime WHERE ident = :n</code> query. Without an index on <code>ident</code>, 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 <code>ident</code> is defined in <code>primes_schema.sql</code> (see NFR-PERF-03). This is the most significant performance risk in the system. <span id="compliance-check-2"></span> === Compliance check === Run <code>\d primes.primes</code> in psql; verify an index on <code>ident</code> is present. If absent, add: <code>CREATE INDEX idx_primes_ident ON primes.primes (ident);</code> ----- <span id="adr-004-gixsql-as-sql-pre-processor"></span> == 5. ADR-004 — GixSQL as SQL Pre-Processor == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [CONFIRMED — explicit in compiler listing header and DATASRC prefix <code>pgsql://</code>] <span id="context-3"></span> === Context === GnuCOBOL does not natively support embedded SQL. An external pre-processor is needed to translate <code>EXEC SQL … END-EXEC</code> blocks into COBOL CALL statements to a SQL runtime library. <span id="decision-drivers-3"></span> === Decision Drivers === * Open-source toolchain (no licensing cost). * PostgreSQL support. * Compatible with GnuCOBOL. <span id="options-considered-3"></span> === Options Considered === {| !width="38%"| Option !width="61%"| 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 |} <span id="decision-3"></span> === Decision === GixSQL — translates EXEC SQL to <code>GIXSQLExec</code>, <code>GIXSQLConnect</code>, <code>GIXSQLConnectReset</code> calls. Connection string prefix <code>pgsql://</code> is GixSQL-specific. <span id="consequences-3"></span> === Consequences === '''Positive:''' - Standard embedded SQL syntax in COBOL source. - PostgreSQL-native driver. '''Negative / trade-offs:''' - GixSQL-specific connection string prefix (<code>pgsql://</code>) and runtime library are not portable to other COBOL SQL pre-processors. - GixSQL is not part of the GnuCOBOL distribution; must be installed separately. <span id="compliance-check-3"></span> === Compliance check === All SQL pre-processing must be done through GixSQL. Verify no raw <code>CALL "GIXSQLExec"</code> statements appear in handwritten source (only in generated <code>.out</code> files). ----- <span id="adr-005-copybooks-as-interface-contracts"></span> == 6. ADR-005 — Copybooks as Interface Contracts == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [INFERRED from copybook design] <span id="context-4"></span> === Context === 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. <span id="decision-4"></span> === Decision === Define each tier’s control block once in a copybook (<code>primes-session.cpy</code>, <code>primes-dal.cpy</code>, <code>primes-ui.cpy</code>) 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. <span id="consequences-4"></span> === Consequences === '''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 (<code>primes-table.cpy</code> vs <code>primes_table.cpy</code>) — the canonical version must be designated and the other retired. <span id="compliance-check-4"></span> === Compliance check === <code>grep -r "COPY primes-dal" *.cbl</code> — should list only <code>primesgen.cbl</code> (caller) and <code>primes.cbl</code> (callee). ----- <span id="adr-006-hard-coded-database-credentials"></span> == 7. ADR-006 — Hard-Coded Database Credentials == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted (as technical debt — see note)<br /> '''Deciders:''' Original developer<br /> '''Source:''' [CONFIRMED — visible in <code>primes.cbl</code> lines 14–17] <span id="context-5"></span> === Context === Database credentials must be provided to the GixSQL CONNECT call. Options include hard-coding, environment variables, a configuration file, or a secrets manager. <span id="decision-5"></span> === Decision === Credentials are hard-coded in WORKING-STORAGE of <code>primes.cbl</code> as a pragmatic choice for a demonstration application. <blockquote>⚠ '''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. </blockquote> <span id="recommended-remediation"></span> === Recommended remediation === Replace <code>DBUSR</code> and <code>DBPWD</code> 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. <span id="consequences-5"></span> === Consequences === '''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. ----- <span id="adr-007-no-explicit-commit-on-insert"></span> == 8. ADR-007 — No Explicit COMMIT on INSERT == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted (status uncertain — see note)<br /> '''Deciders:''' Original developer<br /> '''Source:''' [INFERRED — COMMIT statement is commented out in <code>primes.cbl</code> r83-write-prime] <span id="context-6"></span> === Context === The INSERT in <code>r83-write-prime</code> does not issue an explicit COMMIT. The commented-out COMMIT suggests this was a deliberate choice or a deferred decision. <span id="decision-6"></span> === Decision === 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. <blockquote>⚠ '''Note:''' The report path opens an explicit transaction (<code>START TRANSACTION</code>) via <code>s01-cursor</code>. 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. </blockquote> <span id="consequences-6"></span> === Consequences === '''Positive:''' - Simpler code; no COMMIT overhead per row. '''Risks:''' - If a transaction is ever opened on the <code>primes</code> connection before <code>r83-write-prime</code>, the INSERTs will not be committed until an explicit COMMIT or ROLLBACK, and data will be lost on failure. ----- <span id="adr-008-odd-only-sieve-starting-at-3"></span> == 9. ADR-008 — Odd-Only Sieve Starting at 3 == '''Date:''' 2025 (inferred)<br /> '''Status:''' Accepted<br /> '''Deciders:''' Original developer<br /> '''Source:''' [CONFIRMED — ADD 2 TO test-number in r82-next-test-number; initial value 3] <span id="context-7"></span> === Context === 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. <span id="decision-7"></span> === Decision === 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. <span id="consequences-7"></span> === Consequences === '''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. <span id="compliance-check-5"></span> === Compliance check === Verify <code>test-number</code> is initialised to 3 (odd) and that only <code>ADD 2 TO test-number</code> (never ADD 1) advances the candidate in <code>r82-next-test-number</code>. ----- <span id="open-issues"></span> == 10. Open Issues == {| !width="18%"| ID !width="18%"| Issue !width="18%"| Owner !width="21%"| Target !width="21%"| 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 |} <hr/> Terug naar: [[Design standards]] | [[Cobol and PostgreSQL]]
Summary:
Please note that all contributions to Webhuis wiki are considered to be released under the GNU Free Documentation License 1.3 or later (see
Project:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Page
Discussion
English
Views
Read
Edit
View history
More
Search
Navigation
Voorpagina
Cobol and PostgreSQL
PostgreSQL
CFEngine
Proxmox
Webhuis Kennisbank
Basale infra
Webhuis bouwstenen
Webhuis configuratie
Webhuis Infra
Webhuis Support
Webhuis Raspberry
Opzet Applicaties
Business Applicaties
Community portal
Current events
Recent changes
Random page
Help
sitesupport
Tools
What links here
Related changes
Special pages
Page information