Architecture¶
Nadzoring is structured in concentric layers following the principles of Clean Architecture, Single Responsibility (SRP), DRY, and KISS. This page explains the layout so that contributors and integrators know where each concern lives.
Package Layout¶
src/nadzoring/
├── cli.py # Entry-point: registers command groups
├── __main__.py # python -m nadzoring
│
├── commands/ # CLI layer — Click command groups
│ ├── dns_commands.py # dns group
│ ├── network_commands.py # network-base group
│ └── arp_commands.py # arp group
│
├── dns_lookup/ # Domain layer — DNS business logic
│
├── network_base/ # Domain layer — network diagnostics
│
├── arp/ # Domain layer — ARP security
│
└── utils/ # Cross-cutting utilities
├── errors.py # Exception hierarchy
├── validators.py # Input validation functions
├── formatters.py # Output formatting (table/json/csv/html)
└── decorators.py # @common_cli_options decorator
Layer Responsibilities¶
- CLI layer (
commands/) Owns only Click option parsing, progress bars, and output dispatch. Must not contain business logic. Calls domain-layer functions and passes results to formatters.
- Domain layer (
dns_lookup/,network_base/,arp/) Contains all business logic. Modules are scoped to a single concern (SRP). Functions return typed dicts or dataclasses; they never print or call Click.
- Cross-cutting (
utils/) Shared helpers with no dependency on domain modules.
errors.pydefines the exception hierarchy.validators.pycontains pure functions.formatters.pyknows only about Python built-ins.
Design Principles Applied¶
- SRP — Single Responsibility Principle
Each module owns exactly one concern.
validation.pyvalidates records;health.pyscores them;utils.pyresolves queries. Formatting lives inutils/formatters.py, not in domain modules.- DRY — Don’t Repeat Yourself
Empty result dicts are built by factory helpers (
_make_empty_result,_make_result).Record extraction is dispatched through a
_EXTRACTORSmap instead of a longif/elifchain.CLI options are injected via the
@common_cli_optionsdecorator.
- KISS — Keep It Simple
Complex operations (trace, poisoning detection) are broken into small private functions with a single clear name. Public functions have one entry point with documented parameters and return values.
- Error handling
Domain functions never raise on expected failures (DNS errors, network timeouts, missing PTR records). All failures are returned as structured data so that CLI and scripting callers can handle them uniformly. Only truly unexpected errors (programming mistakes, missing system commands) are allowed to propagate as exceptions.
Data Flow¶
User / Script
│
▼
CLI layer (commands/)
│ Click parses args
│
▼
Domain layer (dns_lookup / network_base / arp)
│ Business logic, structured results
│
▼
External systems
│ dnspython, ping3, requests, scapy, system commands
│
▼
Results bubble back up
│
▼
utils/formatters.py
│ table / json / csv / html
│
▼
stdout / file
Adding a New Feature¶
Create a module in the appropriate domain package (e.g.
dns_lookup/myfeature.py).Define a public function with a clear docstring, type hints, and error handling that returns structured data.
Export it from the package
__init__.py.Add a CLI command in the relevant
commands/file using@common_cli_options.Add a formatter in
utils/formatters.pyif needed.Write tests in
tests/.Document it in a new or existing
.rstfile.