Portál AbcLinuxu, 30. dubna 2025 21:23
Design By Contract (DBC) je programátorské paradigma. Jde o to, že části programu deklarují a mezi sebou dodržují jakési "kontrakty". Nejlépa na příkladu: funkce pro výpočet faktoriálu deklaruje, že jako argument nechce záporné číslo a zaručuje, že vrátí přirozené číslo.
V praxi to znamená, že se třeba k funkcím připisují PRE a POST handlery, které specifukují vstupní podmínky (za jakých podmínek je funkce ochotná pracovat) a výstupní podmínky, tj. co funkce zaručuje po svém návratu. Další možností jsou invarianty, tedy nějaké globálně platné podmínky, například do třídy reprezentující trojúhelník vrazíte středoškolskou poučku, že a + b > c
, kde a,b,c
jsou délky stran trojúhelníku.
Je to tedy hromada kontrol (assercí); a pohledu aspektově orientovaného programování (AOP) se jedná o aspekt.
Na paradigmatu DBC staví jazyk Eiffel, což je imperativní, staticky typovaný jazyk a to dokonce tak, že DBC je TradeMark nějaké firmy kolem. Eiffel je docela dobrý jazyk, ale nikdy se moc nerozšířil. Různé DBC toolkity jsou ale k dispozici pro všelijáké jazyky.
No a teď proč celý zápisek. Je známo, že v dynamických jazycích je možné řadu složitých "vychytávek" implementovat jednoduše. Třeba jednoduchá proxy třída (RPyC) forwardující volání po síti dokáže nahradit CORBU (milióny řádky kódů, které stejně nefungují) .
No dobře, přeháním, ale třeba to DBC nebo AOP lze v takovém Pythonu nebo Ruby vytvořit snadno. Typicky pár modulů, několik set až tisíc řádek.
Stáhl jsem si PyDBC a jeho jednoduchostí jsem byl skoro šokován. Jedná se o 130 řádek, po odstranění GPL licence v hlavičce a mírné deoptimalizace má funkční jádro 30 řádek, o tu eleganci jsem vás, milí linuxáci, nemohl připravit. Zde je modul mydbc.py
def make_wrapped_call(fun, pre = None, post = None): "decorator that calls PRE and POST functions" def wrapped(*args, **kw): if pre: pre(*args, **kw) ret = fun(*args, **kw) if post: post(args[0], ret) return ret return wrapped class DBC(type): 'Metaclass providing Contract behavior. See module docs for usage.' def __init__(cls, clsname, bases, dict): super(DBC, cls).__init__(clsname, bases, dict) for name in dict.keys(): feature = dict[name] if not callable(feature): continue try: pre = dict['%s__pre' % name] except KeyError: pre = None try: post = dict['%s__post' % name] except KeyError: post = None setattr(cls, name, make_wrapped_call(feature, pre, post))
Jedná se o jeden dekorátor, který volá pre a post handlery a pak magickou třídu DBC
. Co dělá magická třída bude jasnější po uvedení příkladu použití:
import mydbc __metaclass__ = mydbc.DBC class Foo: def __init__(self): self.a = 1 def foo__pre(self, b): assert not isinstance(b, str) def foo(self, b): self.a = b def foo__post(self, ret): assert self.a < 5 f = Foo() f.foo(2) # calls foo__pre, foo, foo__post
Třída Foo deklaruje atribut a
a funkci foo
, která atribut nastavuje. Funkce foo má definovány handlery foo__pre
a foo__post
obsahující asserce. Zásadní kouzlo spočívá ve vytvoření globální proměnné __metaclass__
, do které strčíme referenci na naši magickou třídu DBC. Přes __metaclass__
se nabouráme do vytváření instancí tříd, takže pak každou metodu každé vytvořené třídy odekorujeme dekorátorem make_wrapped_call
.
Hezké, ne? Skoro začínám věřit Lisperům, že přidávat do jazyka paradigmata dle libosti za všechny ty závorky stojí.
Tiskni
Sdílej:
self
a ten se může hodit post k původním parametrům přístup mít může, původní autor to ale udělal takhleAha... To se dost divim, čekal bych, že případů, kde je to potřeba, je víc než málo
Poslední větu nechápuV poslední větě
Ale třeba vývoj webovky v Djangu, to je 1000x příjemnější záležitost, než co znám z Javy-Tomcatu. Ono na tom Ruby on Rails něco fakt je.Tak to bych polemizoval. Minimalne je potreba vedet, o jak rozsahlou aplikaci jde. Kdyz vezmete cely Spring stack a EJB3 s Hibernate a chcete v tom napsat blogisek, tak je asi neco spatne
Interface je jen abstraktní třída bez implementace, toho lze v Pythonu dosáhnout taky (vícenásobná dědičnost), na tom nic není. Stejně sémantiku těch funkcí definuje nějaká dokumentace. Rozdíl je prostě v tom, že Java to zkontroluje za překladu, Python až za běhu.Jenze ve svete chybujicich lidi je prave dobre, kdyz mate aparat, ktery vam proste naridi, jak to mate napsat -- proto jsou interfacy dobre. Jinak samozrejme chapu, ze se daji do jiste miry emulovat i v Pythonu.
Ale správná otázka je, jak velkou aplikaci to Django skousne? Největší aplikace, na které jsem dělal bylo ERP v Javě+Struts+Tomcat s devadesáti tabulkama v databázi. To by Python IMO zvládl líp - výpočtů tam moc nebylo (nevadilo by, že je 10x pomalejší), bottleneck byla jednoznačně databáze.No jo, tak Struts
A k tomu XML, to je moc zajímavé. Zatímco u Javy je XML skvělý doplněk, protože umožňuje změny bez rekompilace, v Pythonu je to v podstatě přebytečná technologie. Jelikož se nic nekompiluje, je mnohem pohodlnější mít konfiguraci přímo v PythonuTo jo, jenze mate tu veci jako XPath, XSLT, XQuery, XMLBeans, ktere umoznuji s tim XML delat kejkle skoro bez omezeni -- bez ohledu na technologii. Python konfigurak si rozparsujete v Pythonu a tim to konci. Ale ja fakt, ze se na to musi davat bacha. Stopy XML se na pameti poznajiXML se pak používá jen na komunikaci s okolním světem.
Pak je taky otazka, jestli myslite Django tak jak je, nebo v nem pulku veci vymeniteMísto Django bych zkusil bych Pylons - Ian Bicking a spol. to postavili fakt dobře - dá se vyměnit téměr cokoliv, nasazení na webu je taky jednoduché, prostě samá pozitiva. Slabší je to s dokumentací, ale chystá se kniha. Vzhledem k tomu, že Pylons obsahují jenom malé množství magie, dá se vystačit s existující dokumentací,. V současné době ještě hledám, jak udělat některé věci elegantním způsobem(TM), ale Pylons mají budoucnost.
Problém je v tom, že to je (jak píše IB) "ravioli code" (srovnej se spaghetti code, resp. lasagne code) - spousta malých nástrojů dobře slepená.Jo, presne tak mi to pripadlo. Stripky mikronastroju poslepovane do jednoho
Jo a SQLAlchemy má ještě týden hájení, pak půjde vyměnit taky. (klidně mne upalteNebude nutne).
Princip rozsiritelnosti pomoci taglibs je genialniJasně, až na to, že JSP je (a to i bez použití skriptletů) víc programový kód než HTML šablona. Ne že by na tom běžné šablonovací enginy (Velocity, FreeMarker) byly líp, ale aspoň je v nich jasně vidět co je co, a průměrný webař se tomu za chvilku přizpůsobí. Použití JSPček se tak redukuje na situace, kdy není v týmu žádný HTML otrok, což jsou kupodivu obvykle situace, kde je lepší použít nějaký komponentový framework. (Obráceně to ale neplatí, např. ve Wicketu jsou HTML šablony tak hezky vymyšlené, že s nimi průměrný webař může začít pracovat prakticky ihned.)
Jasně, až na to, že JSP je (a to i bez použití skriptletů) víc programový kód než HTML šablona. Ne že by na tom běžné šablonovací enginy (Velocity, FreeMarker) byly líp, ale aspoň je v nich jasně vidět co je co, a průměrný webař se tomu za chvilku přizpůsobí.A proc by se neprizpusobil JSP? Kdyz neberu v uvahu taglibs psane v Jave, tak se nic krome JSTL a EL ucit nemusi. JSTL je XML (clovek, ktery ma alespon trosku obecnejsi predstavu o XHTML a o tom, ze je to vlastne XML, se nema krome tagu a jejich atributu co ucit) a EL uz primitivnejsi syntax mit ani nemuze... Takovou syntaxi se clovek nauci mnohem rychleji nez nejake to "kolo", co nekdo vymysli. Mluvim samozrejme o XML syntaxi pro JSP. Pokud vim, da se s ni produkovat i cisty text, takze ten sileny paskvil typu
<INPUT TYPE=TEXT NAME=username SIZE=20 VALUE="<%= user.getUsername() %>">
uz snad neni nutne pouzivat...
A proc by se neprizpusobil JSP? Kdyz neberu v uvahu taglibs psane v JaveCož je přesně to, nad čím jste se výše tak rozplýval. Mimochodem i z mého pohledu programátora jsou tagliby celkem zoufalost: když chcete něco komplikovanějšího, musíte taglibu naimplementovat v Javě, což je jednak dost netriviální a jednak generujete HTML z řetězcových konstant, což je opravdu velmi pohodlné. A když použijete tag file, tak zase neuděláte nic zajímavého, protože v tag fajlu nemůžete použít skriptlet (jediná chvíle, kdy jsem fakt zatoužil nějaký napsat
input
y, jak je zvyklý. Tomu říkám separation of concerns.
Mimochodem, fakt vám přijde příjemnější <c:if test="${!loggedIn}">Přihlašte se!</c:if>
než #if(!$loggedIn)Přihlašte se!#end
? Mně ani náhodou.
Nepsal jsem konkretne o psani taglibs v Jave a mel jsem na mysli spise tu druhou moznost. V Jave pisu spis funkce pro EL.A proc by se neprizpusobil JSP? Kdyz neberu v uvahu taglibs psane v JaveCož je přesně to, nad čím jste se výše tak rozplýval.
Mimochodem i z mého pohledu programátora jsou tagliby celkem zoufalost: když chcete něco komplikovanějšího, musíte taglibu naimplementovat v Javě, což je jednak dost netriviální a jednak generujete HTML z řetězcových konstant, což je opravdu velmi pohodlné.To je fakt, to nijak prijemne neni.
A když použijete tag file, tak zase neuděláte nic zajímavého, protože v tag fajlu nemůžete použít skriptlet (jediná chvíle, kdy jsem fakt zatoužil nějaký napsatZbytecne malujete certa na zed. Minimalne tim dosahnete "komponentovatosti" a moznosti nektere veci znovu pouzit.). Fakt bomba.
Dál tu máme tagliby pro generování formulářových políček ve stránce – to je trochu úchylné a vyloženě programátorskocentrické, přitom je poskytuje snad každý MVC framework. A každý má samozřejmě vlastní. Když je framework trochu rozumnější, poskytne i makra pro Velocity a Freemarker (Spring Web MVC), když ne, spoléhá na podporu Freemarkeru pro JSP tagliby (vy víte kdo).Vy delate, jako kdyby tam byly jen tak. Nechat si generovat adresy pro atribut action muze byt docela zasadni vec, kdyz se v pokrocilem stadiu aplikace rozhodnete menit vazby URL. To vazne spolupracujete s lidmi, kteri maji problem pochopit, ze nebudou psat
<form ... />
, ale <form ... />
a vymeni par atributu? Ze se panove ze Struts rozhodli uplne nesmyslne vymenit treba atribut class za styleClass, to uz je jejich vec.
Mimochodem, fakt vám přijde příjemnější <c:if test="${!loggedIn}">Přihlašte se!</c:if> než #if(!$loggedIn)Přihlašte se!#end? Mně ani náhodou.Jo
<s:form ... />
action
bývá prázdný, protože kontrolér renderující formulář se o request později postará i o jeho zpracování. Jinak mi vážně přijde, že přínos speciálních tagů pro renderování formulářů ani zdaleka neodpovídá tomu, že nemůžu použít plain old HTML.
(Obráceně to ale neplatí, např. ve Wicketu jsou HTML šablony tak hezky vymyšlené, že s nimi průměrný webař může začít pracovat prakticky ihned.)Wicket... no, pouzivali jsme to v praci docela dlouho a jeste asi budeme, ale muj skromny nazor je, ze je to z filosofickeho hlediska pekne, ale neproduktivni. I pro relativne jednoduchou funkcionalitu jsou potreba tuny kodu. Ty jejich ultrastrucne sablony mi za to nestoji... A jak se zacnou vynorovat chyby se serializaci a jine, pramenici z toho, ze je to tezce stavova zalezitost.... Nevim, mozna to beru ze spatneho konce, ale pokud chce clovek mit domenove objekty neimplementujici Serializable, tak je to s Wicketem na kocku... samy lazy loading, detachable modely... Uz i kolem Swingu se vynoruji nastroje na deklarativni psani UI, tak nevim, proc bych na webu mel jit v protismeru.
I pro relativne jednoduchou funkcionalitu jsou potreba tuny kodu.Což s běžnými MCV frameworky jistě neplatí, že. Mám opačný dojem. (Teda se Stripes jsem nepracoval, porovnávám konkrétně se Strutsy a Spring MVC)
Ty jejich ultrastrucne sablony mi za to nestoji...To jsou i frameworky s mnohem stručnějšíma šablonama
A jak se zacnou vynorovat chyby se serializaci a jine, pramenici z toho, ze je to tezce stavova zalezitost.... Nevim, mozna to beru ze spatneho konce, ale pokud chce clovek mit domenove objekty neimplementujici Serializable, tak je to s Wicketem na kocku... samy lazy loading, detachable modely...Že je to těžce stavová záležitost je pro dané účely použití spíš výhoda, přijde mi. A stav by mělo tvořit co nejméně informací, rozhodně ne serializované doménové objekty. Lazy loading považuju za nutnost (zvlášť když třeba budu mít doménové objekty připojené k Hibernatí session), i když tady by mohli pánové od Wicketu trochu zapracovat, protože kód začně být poněkud roztahaný. (Na druhou stranu nemám moc představu, jak konkrétně by se to dalo zjednodušit, ale frameworky obvykle píšou ti chytřejší z nás, tak třeba něco vymyslí
Uz i kolem Swingu se vynoruji nastroje na deklarativni psani UI, tak nevim, proc bych na webu mel jit v protismeru.Deklarativní psaní UI… hmm… HTML?
Což s běžnými MCV frameworky jistě neplatí, že. Mám opačný dojem. (Teda se Stripes jsem nepracoval, porovnávám konkrétně se Strutsy a Spring MVC)To, ze neznate Stripes, vas asi omlouva. Jinak bych si musel myslet, ze jste ve Wicketu nenapsal nic trochu vetsiho... Rozdil mezi Stripes a Wicketem ci treba konkretne Spring MVC je velky (SimpleFormController ve Spring MVC je opravdu k zasmani, kdyz clovek zna Stripes). Podivejte se na JTrac, na to co umi a pak na zdrojaky. Krome toho, ze nejsou pradne zdokumentovane a prasacky psane, je jich groteskne velke mnozstvi na to, kolik toho ta aplikace umi....
Že je to těžce stavová záležitost je pro dané účely použití spíš výhoda, přijde mi. A stav by mělo tvořit co nejméně informací, rozhodně ne serializované doménové objekty. Lazy loading považuju za nutnost (zvlášť když třeba budu mít doménové objekty připojené k Hibernatí session), i když tady by mohli pánové od Wicketu trochu zapracovat, protože kód začně být poněkud roztahaný. (Na druhou stranu nemám moc představu, jak konkrétně by se to dalo zjednodušit, ale frameworky obvykle píšou ti chytřejší z nás, tak třeba něco vymyslíJa jsem si na nemoznost serializace DO nestezoval, uvadel jsem to jako prosty fakt)
SimpleFormController ve Spring MVC je opravdu k zasmani, kdyz clovek zna StripesNedělá mi problém tomu věřit, vlastně doufám, že to tak je, protože je to pro mě motivace se na Stripes podívat hlouběji (třeba najdu konečně pořádný MVC framework, takové jsou taky potřeba). Jestli mi Stripes bez obstrukcí (a thread-safe) dá aktuální
HttpServletRequest
a HttpServletResponse
, tak jsem v klidu A co mi jako cloveku, ktery nema problem s JSP, dava princip Wicketu?Asi nic moc (když pominu tu stavovost, která je v jistém směru klíčová, a v jistém směru příšerná, protože jde proti základnímu principu webu). Já mluvím z pozice javisty, který má dva metry od sebe specialistu na HTML.
V jakekoliv ActionBeane (= controller)SimpleFormController ve Spring MVC je opravdu k zasmani, kdyz clovek zna StripesNedělá mi problém tomu věřit, vlastně doufám, že to tak je, protože je to pro mě motivace se na Stripes podívat hlouběji (třeba najdu konečně pořádný MVC framework, takové jsou taky potřeba). Jestli mi Stripes bez obstrukcí (a thread-safe) dá aktuálníHttpServletRequest
aHttpServletResponse
, tak jsem v klidu
staci this.context.getRequest()
a this.context.getResponse()
a thread safe to AFAIK je. Context je ActionBeanContext obalujici klasicke J2EE zalezitosti + Stripes veci.
Pokud budu resit jen signaturu, tak v interface nevytvorite protected ci private metody.A proc bych to taky delal? Interface popisuje rozhrani tridy, tzn. public metody. Nic dalsiho tam nema co delat a nema co tride kecat do toho, jak si danou vec uvnitr implementuje.
Vicenasobna dedicnost je zlo, ktereho se nastesti tvuri jazyka Java vyvarovali.Poroucet programatorum jake konstrukce smi a nesmi pouzivat je mnohem vetsi zlo ktereho se nastesti tvurci dobre navrzenych jazyku vyvarovali.
jsem rad za interfacy a silnou typovou kontrolu v JaveWill Ye Go Lassie GoPrecejen je to trochu prijemnejsi zpusob specifikace kontraktu, i kdyz to samo o sobe nepokryje vse, co DBC.
class Foo: def __init__(self): self.a = 1 def foo(self, b): assert not isinstance(b, str) self.a = b assert self.a < 5
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.