Chapter 9 — Programming II
Lesson map
Lesson 09 published. Map, example, EX025.
flowchart TD
N0["Learning outcomes"]
N1["9.1 Larger programs"]
N2["9.2 Parsing configurations"]
N3["9.3 Error handling"]
N4["9.4 Reproducibility"]
N5["Working with structured exports"]
N6["Command-line interfaces"]
N7["Code review"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX025"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["9.1 Larger programs"]
N2["9.2 Parsing configurations"]
N3["9.3 Error handling"]
N4["9.4 Reproducibility"]
N5["Working with structured exports"]
N6["Command-line interfaces"]
N7["Code review"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX025"]
[Learning outcomes]
|
v
[9.1 Larger programs]
|
v
[9.2 Parsing configurations]
|
v
[9.3 Error handling]
|
v
[9.4 Reproducibility]
|
v
[Working with structured exports]
|
v
[Command-line interfaces]
|
v
[Code review]
|
v
[Worked example] --> [Exercise EX025]
Learning outcomes
You will (1) structure larger analysis programs; (2) read configuration files safely; (3) handle errors.
9.1 Larger programs
As analysis grows, Kofi splits scripts into modules: parsing, policy evaluation and reporting. Each module has tests.
As scripts grow beyond a page, structure becomes essential. Splitting code into modules by purpose, such as parsing, analysis and reporting, keeps each part small enough to understand. Clear function names, short docstrings, and avoiding global variables make it possible for a colleague to review the code and for Kofi to change one part without breaking another.
A short README explaining how to run the program completes the structure.
9.2 Parsing configurations
Exported firewall configurations are text. Kofi parses them into structured records, rejecting lines he cannot interpret rather than silently skipping them.
Device configurations are text with structure: sections, indentation and keywords. A parser reads that text into data structures such as lists of rules, each with source, destination, service and action fields. Once parsed, rules can be checked automatically for problems such as overly broad sources, duplicates or unused objects. Parsers should be written for synthetic samples first and should report lines they cannot understand rather than silently skipping them.
9.3 Error handling
Programs report clear errors on malformed input, naming the line. Silent failures could hide missing rules.
Real input is messy: files are missing, lines are malformed, values are out of range. A robust script detects these cases, reports them clearly with the line number, and either continues safely or stops. Silent failure is the worst outcome, because a script that ignores a malformed rule may report a clean policy that is actually wrong. Explicit error messages make problems visible to the person running the check.
9.4 Reproducibility
Scripts and synthetic inputs are versioned together, so any result can be regenerated.
A result is reproducible when someone else can run the same script on the same input and get the same output. That requires recording the script version, the input file, and any settings, and avoiding hidden dependencies such as the current date or random values without a fixed seed. Reproducibility turns analysis into evidence that reviewers can trust.
Saving the output alongside these details completes the record.
Working with structured exports
Some council tools export configurations as JSON rather than text. Python's json module loads these into nested dictionaries and lists, which are easier to process reliably than free text. Kofi writes small functions that convert each vendor's export into a common internal format: a list of rules with source, destination, service and action. Converting early means the rest of his analysis code works the same way regardless of where the data came from, and adding support for a new device only requires a new converter.
Command-line interfaces
To make scripts usable by council engineers, Kofi gives them simple command-line options using the argparse module: the input file, an optional output file and a verbose flag. Help text explains each option. This avoids engineers editing code to change file names, which is where mistakes creep in. Each script exits with a non-zero status when it finds a problem, such as a rule that violates policy, so it can be used later in automated checks before a configuration is deployed.
Code review
Before council engineers rely on a script, a second person reads it. Review catches mistakes that tests miss, such as a comparison that treats port 0 as false, and spreads understanding so the council is not dependent on one author. Kofi keeps scripts short enough to review in one sitting and writes comments explaining why, not what. Review comments and their resolutions are kept with the code history, which also shows examiners how quality was checked. Reviewers use a short checklist covering input handling, edge cases and output format.
Worked example
A parser reads "allow staff servers 443" lines into tuples and raises an error on "allow staff" missing fields.
Synthetic case. Data are synthetic.
Errors and limits
Skipping unparseable lines can silently omit rules from analysis.
Exercises
- EX025 — Module split. Name three modules for a policy analysis tool. Rubric: 3 = parse, evaluate, report;; 2 = two;; 1 = one;; 0 = none.
- EX026 — Silent skip risk. Why reject unparseable lines? Rubric: 3 = avoid missing rules;; 2 = safety;; 1 = vague;; 0 = none.
- EX027 — Error message. What should an error message include? Rubric: 3 = line number and content;; 2 = line;; 1 = vague;; 0 = none.
Synthesis
Structured, tested, versioned code makes analysis trustworthy.
Continue studying — chapter 09 of 50
← Chapter 08 (draft) · Course chapter index · Chapter 10 (draft) →