diff --git a/README.md b/README.md index 31b9515..c05d522 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,50 @@ NAPALM's `NetworkDriver` defines a common interface for all network devices. In `napalm-device-types` sits in between: it adds one well-typed layer of abstract methods per device category, so every driver for the same category exposes the same interface. +## Design principle: generic vs. device-specific logic + +When adding behavior to a device-type base class, split it along one line: **would +this exact logic work unchanged for a different vendor's driver of the same +device-type, if that driver only implemented the same abstract methods?** + +- If yes, it's generic — implement it once as a **concrete** method on the + device-type base class (here, in this repo). +- If no — it talks to the device itself (a specific REST endpoint, a CLI command, + a vendor-specific payload format) — it belongs in the concrete driver as the + implementation of an **abstract** method the base class declares. + +Concretely: matching/comparison/reconciliation algorithms, orchestration flows, and +generic data shapes belong here. Only the actual device communication belongs in +`vendor/napalm-`. + +**Worked example — firewall rule diff/apply** (`FirewallDriver`): + +```python +class FirewallDriver(DeviceTypeDriver): + # Abstract — every driver implements its own device communication. + def get_firewall_rules(self) -> List[FirewallRuleDict]: raise NotImplementedError + def apply_firewall_rule(self, rule: FirewallRuleDict, *, uuid: Optional[str] = None) -> Dict[str, Any]: raise NotImplementedError + def commit_firewall_rules(self) -> Dict[str, Any]: raise NotImplementedError + + # Concrete — the matching/comparison/orchestration algorithm is identical + # for every firewall vendor, so it lives here once. + def diff_firewall_rules(self, desired: List[FirewallRuleDict]) -> FirewallRuleDiffDict: + ... # matches self.get_firewall_rules() against `desired` by description + + def apply_firewall_ruleset(self, desired: List[FirewallRuleDict]): + ... # computes the diff, calls apply_firewall_rule() per change, commits +``` + +A new driver (FortiGate, pfSense, …) gets `diff_firewall_rules`/ +`apply_firewall_ruleset` for free the moment it implements the three abstract +methods — it never needs to reimplement the reconciliation logic itself. + +This mirrors a similar split already documented on the consumer side, in NetOrk's +`docs/ARCHITECTURE.md` ("Device Warnings — Trennung von Erkennung und +Präsentation"): drivers return raw signals, the higher layer gives them meaning. +Same shape of separation, different axis — device-specific vs. generic here, +detection vs. presentation there. + ## Installation ```bash