Problém s křehkým binárním rozhraním - Fragile binary interface problem
Problém s křehkým binárním rozhraním neboli FBI je nedostatek určitých objektově orientovaných kompilátorů programovacího jazyka , ve kterých vnitřní změny v podkladové knihovně tříd mohou způsobit, že potomkové knihovny nebo programy přestanou fungovat. Je to příklad softwarové křehkosti .
Tento problém se častěji nazývá problém křehké základní třídy nebo FBC ; tento pojem má však širší význam.
Obsah
Způsobit
K problému dochází v důsledku „zástupce“ používaného u překladačů pro mnoho běžných objektově orientovaných jazyků (OO), což je funkce návrhu, která byla zachována, když se jazyky OO vyvíjely ze starších strukturovaných programovacích jazyků jiných než OO, jako jsou C a Pascal .
V těchto jazycích nebyly žádné objekty v moderním smyslu, ale existoval podobný konstrukt známý jako záznam (nebo „struktura“ v C), který obsahoval řadu souvisejících informací v jedné paměti. K částem v konkrétním záznamu se přistupovalo sledováním počátečního umístění záznamu a znalostí posunu od tohoto počátečního bodu k dotyčné části. Například záznam „osoby“ může mít křestní jméno, příjmení a střední iniciálku, aby programátor zapsal iniciálu, thisPerson.middleInitialkterou kompilátor změní na něco podobného a = location(thisPerson) + offset(middleInitial). Moderní CPU obvykle obsahují pokyny pro tento běžný druh přístupu.
Při prvním vývoji objektově orientovaných překladačů jazyků byla použita velká část stávající technologie překladačů a objekty byly postaveny na vrcholu konceptu záznamu. V těchto jazycích byly objekty označovány podle jejich počátečního bodu a jejich veřejná data, známá jako „pole“, byla přístupná prostřednictvím známého offsetu. Jedinou změnou bylo přidání dalšího pole do záznamu, které je nastaveno tak, aby ukazovalo na neměnnou virtuální tabulku metod pro každou třídu, takže záznam popisuje jak její data, tak metody (funkce). Při kompilaci se posuny používají k přístupu k datům i ke kódu (prostřednictvím tabulky virtuálních metod).
Příznaky
To vede k problému ve větších programech, když jsou vytvářeny z knihoven . Pokud autor knihovny změní velikost nebo rozložení veřejných polí v objektu, posuny jsou nyní neplatné a program již nebude fungovat. To je problém FBI.
Přestože změnám v provádění lze očekávat, že způsobí problémy se zákeřná věc, o FBI, je to, že nic opravdu nezměnilo, pouze dispozice objektu, který je ukrytý v kompilované knihovny. Dalo by se očekávat, že jestliže jeden změní doSomethingna doSomethingElsekteré by to mohlo způsobit nějaký problém, ale v tomto případě můžeme způsobit problémy beze změny doSomething, může to být způsobeno stejně snadno, jako pohybující řádků zdrojového kódu kolem kvůli přehlednosti. Horší je, že programátor má malou nebo žádnou kontrolu nad výsledným rozvržením generovaným kompilátorem, takže tento problém je téměř úplně skrytý před zobrazením.
Ve složitých objektově orientovaných programech nebo knihovnách mohou třídy nejvyšší úrovně dědit z desítek tříd. Každou z těchto základních tříd mohly zdědit také stovky dalších tříd. Tyto základní třídy jsou křehké, protože malá změna jedné z nich by mohla způsobit problémy jakékoli třídě, která z ní dědí, a to buď přímo, nebo z jiné třídy, která ano. To může způsobit, že se knihovna zhroutí jako domeček z karet, protože jednou změnou na základní třídu je poškozeno mnoho tříd. Problém nemusí být zaznamenán při zápisu úprav, pokud je strom dědičnosti složitý. Ve skutečnosti vývojář upravující základní třídu obecně neví, které třídy vyvinuté jinými ji používají.
Řešení
Jazyky
Jedním z řešení problému křehkého binárního rozhraní je napsat jazyk, který ví, že problém existuje a na první místo to nedovolí. Většina jazyků OO psaných na zakázku, na rozdíl od jazyků vyvinutých ze starších jazyků, vytváří všechny své offsetové tabulky v době načítání. V tomto okamžiku budou změny rozložení knihovny „zaznamenány“. Jiné jazyky OO, jako je Self , vytvářejí vše za běhu kopírováním a úpravami objektů nalezených v knihovnách, a proto ve skutečnosti nemají základní třídu, která může být křehká. Některé jazyky, například Java , mají rozsáhlou dokumentaci o tom, jaké změny lze bezpečně provést, aniž by to způsobilo problémy FBI.
Dalším řešením je zapsat mezilehlý soubor se seznamem offsetů a dalších informací z fáze kompilace, známých jako metadata. Linker poté použije tyto informace k opravě, když je knihovna načtena do aplikace. Platformy jako .NET to dělají.
Trh však vybral programovací jazyky, jako je C ++, které jsou skutečně „závislé na poloze“, a proto vykazují FBI. V těchto případech stále existuje řada řešení problému. Jeden z nich zatěžuje autora knihovny tím, že je nechá vložit několik „zástupných“ objektů pro případ, že by v budoucnu potřebovali přidat další funkce (to je vidět na strukturách použitých v knihovně DirectX ). Toto řešení funguje dobře, dokud vám tyto figuríny nedojdou - a nechcete je přidávat příliš mnoho, protože zabírá paměť.
Objective-C 2.0 poskytuje non-fragile instance variables by having an extra level of indirection for instance variable access.
Dalším částečným řešením je použít vzor Bridge , někdy známý jako „ Pimpl “ („Ukazatel na implementaci“). Qt je příkladem takového provedení s. Každá třída definuje pouze jeden datový člen, což je ukazatel na strukturu obsahující implementační data. Je nepravděpodobné, že se změní velikost samotného ukazatele (pro danou platformu), takže změna dat implementace neovlivní velikost veřejné struktury. Tím se však nevyhnete dalším zlomovým změnám, například zavedení virtuálních metod do třídy, která žádnou nemá, nebo změnu grafu dědičnosti.
Linkery
Jiné řešení vyžaduje chytřejší linker. V původní verzi Objective-C formát knihovny umožňoval více verzí jedné knihovny a zahrnoval některé funkce pro výběr správné knihovny při volání. To však nebylo vždy nutné, protože posuny byly potřebné pouze pro pole, protože posuny metod byly shromažďovány za běhu a nemohly způsobit FBI. Vzhledem k tomu, že metody mají tendenci se měnit častěji než pole, měl ObjC na prvním místě několik problémů FBI a ty, které udělal, bylo možné opravit pomocí systému správy verzí. Objective-C 2.0 přidal „moderní běhový modul“, který vyřešil problém FBI také pro pole. Kromě toho jazyk TOM používá pro všechno shromažďování za běhu, což FBI znemožňuje.
Použití statické namísto dynamických knihoven, kde je to možné, je dalším řešením, protože knihovnu pak nelze upravit, aniž byste také znovu zkompilovali aplikaci a aktualizovali použité kompenzace. Statické knihovny však mají své vlastní vážné problémy, například větší binární soubor a neschopnost používat novější verze knihovny „automaticky“, jakmile jsou zavedeny.
Architektura
V těchto jazycích se problém zmenší vynucením jediné dědičnosti (protože to snižuje složitost dědičného stromu) a použitím rozhraní namísto základních tříd s virtuálními funkcemi , protože samotná rozhraní neobsahují kód, pouze záruka, že každý podpis metody, kterou rozhraní deklaruje, bude podporován každým objektem, který implementuje rozhraní.
Metoda distribuce
Celý problém se zhroutí, pokud je k dispozici zdrojový kód knihoven. Pak bude stačit jednoduchá rekompilace.