Wrapper und Abstraktionsschichten
« | 01 Mar 2019 | »Wie viele Layer und Abstraktionsschichten “über” einer konkreten Implementierung sind gut und ab wann ist die Grenze des guten Geschmacks erreicht?
Diese Frage stelle ich mir bei jedem Projekt aufs Neue und komme stets zu anderen Ergebnissen.
Konkret geht es diesmal um die Frage, ob es Sinn macht um
malloc()
einen Wrapper herum zu legen.
Jeder vernünftige Entwickler würde sagen:
Nein! Es handelt sich um DIE wichtigste C Funktion, die Basis vieler anderen Funktionen. Man braucht sie nicht umzuleiten.
Das stimmt grundsätzlich auch, denn eine Umwickelung dieser Funktion mit einer anderen führt nur zu einem zusätzlichen Herumspringen im Codespeicher bei der Ausführung, und wirkt sich negativ auf die Cache-Auslastung und Performance aus.
Doch im GATE Projekt findet dennoch eine solche Umleitung
statt, und zwar zu den Funktion gate_mem_alloc()
und
gate_mem_dealloc()
.
Und der Grund dafür ist, dass es unter fast jeder Plattform
einen “Spezial-Modus” gibt, in dem malloc()
nicht zur Verfügung steht.
… und das ist die Treiber und Kernel-Modul Entwicklung.
Nun könnte man mutmaßen, dass die Treiber Entwicklung kein
Primärziel ist (zumindest aktuell noch nicht) und weiter nur die
negativen Aspekte der Umleitung bleiben.
Doch auch das ist (großteils) nicht zutreffend, da das
GATE Framework für statische Kompilierung und Link-Time
Codegeneration ausgelegt ist.
Der Optimizer erkennt in der Regel, dass ein Aufruf von
gate_mem_alloc()
direkt auf malloc()
(im Usermode) umleitet und kann
diesen Aufruf daher “inlinen”, also direkt setzen.
Damit bleibt der Code also weiter bei höchster (bzw. hoher) Effizienz.
Ich bin daher dazu über gegangen bei Framework-Projekten mehr Abstraktion einzubauen, als man es durchschnittlich erwarten würde, im Anbindungen von weiteren mir aktuell noch nicht bekannten Plattformen zu ermöglichen.
Fazit
Es bleibt natürlich immer im Ermessen des Entwicklers bzw. des Teams, wir oft man Wrapper oder höherer Abstraktionsschichten über konkrete Plattform oder Funktions-APIs darüber legt.
Der größte Nachteil von zu viel Abstraktion ist leider, dass man
damit sehr individuelle und proprietäre Schnittstellen schafft, die
niemand kennt und erst viel Dokumentation gelesen werden muss.
Beispiel malloc()
kennt jeder, gate_mem_alloc()
kenne aktuell nur
ich selbst.
Und so geht es vielen Bibliotheksprojekten.
Immer herrscht der Kampf zwischen Abstraktion und einfacher bzw. direkter
Native-API-Nutzung.