Knihovny vs. frameworky

Termíny knihovna a framework jsou ve světě programování často používané, ale málokdo by asi dokázal říct, jak přesně spolu souvisí a čím se vlastně od sebe knihovna a framework liší. Framework by se možná na první pokus dal definovat jako ucelený soubor tematicky zaměřených knihoven, ale vystihuje tato definice opravdu vše? Pojďme se na věc podrobněji podívat.

Knihovny

Intuitivní představu o významu pojmu knihovna mají asi všichni programátoři. Velmi vágně řečeno jde o soubor funkcí a tříd poskytující nějaký okruh služeb.

Knihovnu mohou využívat různé aplikace, které ji typicky nebudou využívat samostatně, ale v kombinaci s dalšími knihovnami. Knihovny se také můžou využívat navzájem. Na nejnižší úrovni pak knihovny či samotná aplikace komunikují s vrstvami kódu pod sebou či přímo s hardwarem.

Situace v aplikaci tedy typicky vypadá zhruba takto:

Schéma aplikace využívající několik knihoven

Pro knihovnu z popsaného způsobu využití plynou dva důležité požadavky:

  1. Musí si rozumět s prakticky libovolnou aplikací.
  2. Musí být schopna koexistence s dalšími knihovnami.

Tyto dvě vlastnosti každý kus kódu poskytující nějaký okruh služeb rozhodně nemá. Aby jimi knihovna oplývala, nesmí především nijak ovlivňovat globální stav programu – všechen její vliv musí být lokalizovaný. Součástí toho je, že nesmí provádět policy decisions – říkat aplikaci, co se jak bude dělat.

Několik příkladů v různých programovacích jazycích:

PHP

Knihovna by neměla nastavovat úroveň reportování chyb, vlastní error handler, či jinak ovlivňovat zpracování chyb – to je typické policy decision. Naopak by měla pracovat s jakýmkoliv nastavením zpracování chyb, které si autor programu vymyslí.

Podobnými příklady v PHP jsou nastavení register_globals, magic_quotes_gpc apod.

C++

Knihovna by měla fungovat jak v programech kompilovaných s podporou výjimek, tak v programech kompilovaných bez nich. Byť C++ výjimky má už dlouho, řada projektů je nepoužívá (policy decision) a jejich podporu má při kompilaci vypnutou. Pochopitelně to znamená, že knihovna, která chce být univerzálně použitelná, interně výjimky vůbec nesmí používat (což může být pro jejího autora frustrující).

Ruby

Knihovna v Ruby by neměla rozšiřovat globální třídy jako Object, String, Array atd. Rozšiřování objektů není úplně policy decision, ale je to něco, co podstatně ovlivňuje globální stav programu.

JavaScript

Knihovna by neměla své součásti deklarovat v globálním jmenném prostoru a neměla by měnit prototypy globálních objektů (což je pro všechny praktické účely stejné jako rozšiřování globálních tříd v Ruby).

Myslím, že z příkladů je jasné, jak se má slušná knihovna chovat. Nyní se podívejme na frameworky.

Frameworky

Framework bych definoval jako ucelený soubor tematicky zaměřených knihoven + policy decisions. Situace vypadá takto:

Schéma aplikace využívající framework

Pod frameworkem si v obrázku můžete představit například Rails, Nette, Prototype, ale třeba i Qt nebo GTK+.

Pokud bychom hráli hru "najděte 10 rozdílů" s obrázkem na začátku článku, brzy přijdeme na dvě důležité věci:

  1. Knihoven bylo víc, ale framework je jen jeden.
  2. Aplikace řeší pomocí frameworku všechny požadavky, zatímco knihovny používala jen na specifické úkoly.

Z bodu 1 plyne, že framework nemusí nutně dodržovat pravidla slušného chování pro knihovny a může ovlivňovat globální chování aplikace. Bod 2 pak naznačuje, že framework může (a někdy dokonce musí) být místem, kde je vhodné udělat různé policy decisions.

Není tedy v principu chybou, když například Ruby on Rails předefinovává v globálních objektech kde co a některé aplikační frameworky v C++ požadují, aby aplikace byla kompilována se zapnutou podporou výjimek nebo naopak bez nich.

Právě možnost frameworku definovat policy decisions a přimět programátora aplikace k jejich dodržování považuju za klíčovou vlastnost, která frameworky odlišuje od knihoven.

Závěr

Místo dlouhého povídání by se dal rozdíl situací u knihoven a frameworků vyjádřit i stručněji: Aplikace využívá knihovny, ale je psána ve frameworku. Z tohoto rozdílu plynou i odlišná pravidla, která musí tvůrci knihoven a frameworků dodržovat. Knihovny musí být týmoví hráči, zatímco frameworky si mohou dovolit být občas diktátory. Až tedy příště budete psát kus znovupoužitelného kódu, dobře zvažte, do které kategorie spadá.

Poznámky:

  1. V textu pomíjím možnost existence více frameworků v aplikaci na více úrovních. Myslím, že takto stavěných aplikací není mnoho a při bližším zkoumání by se u nich dost možná přišlo na to, že některý framework je "pouze" knihovna.
  2. Diagramy v článku byly vytvořeny pomocí nástroje ditaa (viz zdrojový kód) a mírně ručně upraveny.