Ich würde behaupten viel Erfahrung mit dieser Frage zu haben, insbesondere habe ich sehr viel "Szenarion 3" Code refactored, aber ich bekomme die Erfahrung nicht in eine kurze Regel gepresst (wie das so ist mit jeder Erfahrung, die irgendwas Wert ist). Ich habe versucht Links rauszusuchen für Dinge die ich einfach "Seit Jahren mache", nicht für alle Links lege ich meine Hand ins Feuer.
Mindestens zu bedenken:
Oft ist
func_static einfach ein Fall von
The Wrong Abstraction.
Insbesondere (Spezialfall des o. g.) ist der Tradeoff bei "Szenario 3" ja offensichtlich den Check zu duplizieren damit man die Workload nicht duplizieren sondern in
func_static wegabstrahieren kann. Das ist nicht immer der richtige Tradeoff, insbesondere wenn das Verhältnis von Checks zu Workload groß wird.
Wenn zwischen Check und Workload Zeit liegt, weil etwa
func_a erst die Parameter checkt, dann etwas tut und dann erst
func_static aufruft und der Check gegen globalen State geht (was er realistisch regelmäßig tut, who are we kidding) hast du eine race condition in Form der Wette dass sich der globale State nicht geändert hat, seit du den Check gemacht hast. Was hier die korrekte Lösung ist kommt drauf an welche Garantien du geben willst, aber die korrekte Lösung dieses Problems wird in der Regel einen Ablauf vorgeben der orthogonal zu deiner ursprünglichen Frage steht (d.h. deine ursprüngliche "API-Grenze" war möglicherweise nicht an der richtigen Stelle, wenn du fragen musst).
Das obige zusammen erschlägt schon irgendwie 80% der Fälle. Für die anderen 20% kannst du die Duplizierung der Checks vermeiden in dem
func_static ein immutables Objekt akzeptiert das bei Initialisierung gecheckt wird (und dann da immutable, immer gecheckt bleibt). In anderen Worten du musst garantieren, dass jede Initialisierung eines solchen Objekts den Check macht und dass das Objekt nach Initialisierung unveränderlich ist. C ist nicht die komfortabelste Sprache um das zu machen. Der Sinn der Übung ist dass der Aufrufer somit gezwungen wird den Check zu machen, denn er braucht ja das Objekt um den Aufruf zu machen, nur um das explizit hinzuschreiben. Ich habe die AI meines geringsten Misstrauens gefragt wie das Pattern heißt und sie sagt
Parse, don't validate.
Fehlerbehandlung würde ich davon separat sehen. Ein paar unsortierte Links:
Robustness Principle
Let it crash
Fail Fast
Ich habe jetzt wenig Zeit das weiter auseinanderzudividieren, aber ich stimme Jonathan voll zu: wenn du für dich und dein Vergnügen programmierst, lass es crashen. Wenn du an einem System arbeitest dass nicht crashen darf weißt du normalerweise welche Garantien du geben willst und das weitere ergibt sich daraus. Im luftleeren Raum ist das alles akademisch.